limingth 发表于 2005-6-14 00:19:41

Learn lumit Step 16 : 定时器实验

Learn lumit Step 16 : 定时器实验
++++++++++++++++++++++++++++++++++++++++++++++++++++++

    这一节主要介绍定时器的驱动和中断处理。从程序框架上看,timer 基本就是上一节
int0 的一个 copy ,因为它们的机制和处理流程是非常接近的。唯一不同的就是 timer
是由内部定时触发的,不像 int0 那样需要人的参与才能触发中断。

    和上一节同样的,我们也采用了 led 作为系统的辅助输出设备来显示主程序和中断的
执行状态。系统的主程序是通过 led 0, led 1, led 2 的交替闪烁来标识执行状态,其中
timer 会每隔一定长的时间(约1秒)触发一次中断,在中断处理中,我们安装了一个简单的
timer_irq_hooker 函数,对 led 3 做一次闪烁来标识中断程序的执行。

void timer_irq_hooker( void )
{
        // we add a hooker of timer interrupt ( just let led_3 to blink one time )
        led_one_light(3);
        led_delay( 10 );
        led_one_dark(3);
}

int main( void )
{       
        int i = 1;
       
        install_irq_handler( irq_handler );

        timer_install_irq_hooker( timer_irq_hooker );
       
        led_init();
       
        timer_init();
                       
        while(i++)
        {
                led_one_light(i%3);
                led_delay( 200 );
                led_one_dark(i%3);
        }
       
        return 0;
}

    从底层的 timer_driver 实现来说,主要就是使能系统的 timer 0 和设置 interrupt
counter ,同样这些设置方面的工作基本还是采用了 timer_ioctl 来完成。

/* enable timer 0 */
int timer_open( void )
{       
        // disable timer_0
        TMOD = 0;       

        // Clear pending interrupts
        INTPND = 0x00000000;        

        // enable timer 0
           TMOD = 1;

        return 0;
}

int timer_ioctl( unsigned int cmd, unsigned long arg )
{
        switch( cmd )
        {
                // set interrupt counter
                case        TIMER_SET_COUNTER:
                        TDATA0 = *(unsigned int *)arg;
                        break;
       
                // Enable interrupt request and Unmask timer_0 interrupt
                case        TIMER_ENABLE_INTERRUPT:               
                        INTMSK &= ~((1 << 21) | (1 <<10) );
                        break;

                // clear timer 0 pending interrupts
                case        TIMER_CLEAR_INTERRUPT:
                        INTPND |= 1 << 10;
                                       
                default:
                        break;
        }       

        return 0;
}

    可以看出,这一节和上一节无论是代码,或者是结构上都是非常类似的,我们做的
仅仅就是把几个细节方面的代码重新实现了,从主程序框架上看基本没有变化。这也从
另一个方面说明了:一个结构良好的程序框架就会具有良好的可移植性和可扩充性。

viking00000 发表于 2006-3-29 10:52:56

// Clear pending interrupts
INTPND = 0x00000000;

悬挂位清零不是应该写1的么,和后面的
case TIMER_CLEAR_INTERRUPT:
INTPND |= 1 << 10;

冲突啊,究竟这句话是什么意思啊?

jet 发表于 2006-4-1 22:14:08

第一个清零是保证在定时器开启之前悬挂位为0
当定时器中断后,悬挂位会自动置1,要清此位的话,需要写1清零,写1是触发硬件清零,而不是往此寄存器写1。
页: [1]
查看完整版本: Learn lumit Step 16 : 定时器实验