如需要绘制PCB,设计电路可以和我联系。sunhenu@163.com.
分类: LINUX
2012-04-20 09:48:42
上一次说到,我们第一个驱动蜂鸣器的程序是使用了定时器,间隔的翻转P1.27电平,
这次就谈谈LPC2378的定时器,同时说说中断。
先看main函数中的语句init_timer( TIME_INTERVAL);
从函数名来看是一个定时器初始化函数,形参是定时时间,看看它的数值,
#define Fpclk (Fcclk / 4)
#define TIME_INTERVAL Fpclk/100 – 1
#define Fcclk 50000000
#define Fcco 300000000
Fcclk=50M,Fpclk=12.5M, TIME_INTERVAL=12.5M/100-1=125K-1
具体看看init_timer函数。
DWORD init_timer ( DWORD TimerInterval )
{
timer_counter = 0;
T0MR0 = TimerInterval;
T0MCR = 3; /* Interrupt and Reset on MR0 */
if ( install_irq( TIMER0_INT, (void *)Timer0Handler, HIGHEST_PRIORITY ) == FALSE )
{
return (FALSE);
}
else
{
return (TRUE);
}
}
现在T0MR0=125K-1,它是定时器0的匹配寄存器,就是说如果定时器0计数器值达到了125K-1,它就会产生一个匹配中断,CPU就会处理这个中断。
install_irq( TIMER0_INT, (void *)Timer0Handler, HIGHEST_PRIORITY )这个上一篇文章说过了,
设置中断号,通过VIC使能对应的中断号,设置优先级,还有就是传递中断函数的指针,
中断函数名也代表中断函数的指针。
所以我们就看看Timer0Handler这个函数吧,上面的形参,它使用了void强制类型转换,linux内核里面经常用这样的强制类型转换,有时间我去研究一下这个东西。
看函数吧。
__irq __nested __arm void Timer0Handler (void)
{
T0IR = 1; /* clear interrupt flag */
__enable_interrupt(); /* handles nested interrupt */
timer_counter++;
VICADDRESS = 0; /* Acknowledge Interrupt */
}
这是IAR中中断函数声明的格式,ADS里面没有_nested这个特殊字符。
因为Fpclk的时钟,需要再经历一个分频器然后输出时钟给定时器,这里我们没有设置T0PR,就是默认值0,所以也就没有分频,所以这个函数是定时器计数值到达125K-1,在第125K-1脉冲上升沿,就会产生中断,然后再经历一个中断响应时间,这个函数会被执行。看图
根据上面Fpclk值现在可以计算它的中断间隔时间为(12.5M/100-1)*(1/12.5M)=10MS.
__enable_interrupt(); /* handles nested interrupt */
这个语句好像是IAR的特色,MSP430里面也要经常用到,我没有仔细研究,不过我先不管它,如果你把它注释到,在这个程序里,没有任何影响,我调试过的。
timer_counter++;呵呵,很熟悉吧。
Main函数中
if ( timer_counter >= 0x50 )
{
BEEP_IO ^= BEEP_MASK;
timer_counter = 0;
}
所以BEEP电平大约在10ms*0x50间隔时间后会翻转一次,就是800ms间隔时间。
第一个程序终于说完了啊,其实LPC2378定时器还有1,2,3,它们的设置有点区别的,还有PWM功能,输入捕捉功能等等,诸位就参考其他的资料吧,我这个只是抛砖引玉。
昨天晚上写好,今天上传的。