原创 定时器工作原理

2007-6-14 10:50 5746 5 5 分类: MCU/ 嵌入式

定时器是独立运行的,它不占用CPU的时间,不需要指令,只有调用对应的寄存器的时候才需要参与。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


AVR mega16为例,它有三个寄存器,timer0timer1timer2T0T28位定时器,T116位寄存器,T2为异步定时器,三个定时器都可以用于产生PWM


以定时器T0来简单介绍定时器的操作方法,T0有三个寄存器可以被CPU访问,TCCR0TCNT0OCR0,下面看一段ICC生成的定时器初始化程序。


//TIMER0 initialize - prescale:8


// WGM: <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />Normal


// desired value: 1KHz


// actual value: 1.000KHz (0.0%)


void timer0_init(void)


{


TCCR0 = 0x00; //stop


TCNT0 = 0x83; //set count


OCR0 = 0x7D; //set compare


TCCR0 = 0x02; //start timer


}


TCCR0为控制寄存器,用于控制定时器的工作模式细节;


TCNT0T/C 寄存器,它的值在定时器的每个工作周期里加一或减一,实现定时操作,CPU可以随时读写TCNT0


OCR0:输出比较寄存器,它包含一个8 位的数据,不间断地与计数器数值TCNT0 进行比较。匹配事件可以用来产生输出比较中断,或者用来在OC0 引脚上产生波形。


这里说最简单的模式,TCNT一直加一,到达最大值0xFF然后清零,进入下一次计数,在上面的程序中。


TCCR00x00;关闭T0的时钟源,定时器停止工作。


TCNT00x83;设置T/C寄存器的初始值,及让定时器从TCNT00x83开始定时或计数。


OCR0 = 0x7D;设定比较匹配寄存器的值,这个程序里没有使用。


TCCR0 = 0x02;选择时钟源,来自时钟8分频,设置后定时器就开始工作。


初始化后定时器开始工作,TCNT0在每一个定时器时钟加一,当TCNT0等于OCR0的值时,T/C 中断标志寄存器- TIFR中的OCF0 置位,如果这时候TIMSKOCIE01(即允许T0比较匹配中断),并且全局中断允许,比较匹配中断即运行。中断程序中可以对TCNT00CR0进行操作,对定时器进行调整。


TCNT0继续加一,当达到0xFF时,T/C 中断标志寄存器- TIFR中的TOV0置位,如果这时候TIMSKTOIE01(即允许T0溢出中断),并且全局中断允许,溢出中断即运行。中断程序中可以对TCNT00CR0进行操作,对定时器进行调整。


和定时器相关的寄存器还有SREGTIMSK,前者位1控制全局中段允许,后者位1OCIE0)和位0TOIE0)分别控制比较匹配中断和溢出比较匹配中断允许。


实际的过程中,定时器相关寄存器的操作非常灵活,可以在溢出中断中修改TCNT0的值,也可以在中断中修改OCR0的值,后面的实验中会讲到用定时器1修改OCR1A的方法实现1S精确定时。


师傅领进门,修行靠个人,定时器的基本原理说到这里,要更深入的了解定时器,请看数据手册。


定时公式:Time=PRE*(MAX-TCNT0+1) /F_cpu单位S ,其中,PRE为与分频数,本例中为8MAX即为最大值255TCNT0为初始化时的值,本例中为0x83(十进制的131),T_cpu,系统时钟频率,本例中为1000000


本例程序中定时时间为:Time=8*(255-131+1)/1000000=0.001 S ,即为1ms1Khz。可以看出,如果晶振选为8M,则定时时间变为0.000125S,也就是说晶振越大,定时时间越短,预分频越大,定时越长。


在设置时如果你选择1ms,会得到如下结果,和上面的1Khz相同。



//TIMER0 initialize - prescale:8


// WGM: Normal


// desired value: 1mSec


// actual value: 1.000mSec (0.0%)


void timer0_init(void)


{


TCCR0 = 0x00; //stop


TCNT0 = 0x83; //set count


OCR0 = 0x7D; //set compare


TCCR0 = 0x02; //start timer


}


 


//ICC-AVR application builder : 2007-6-9 0:33:58


// Target : M16


// Crystal: 1.0000Mhz


// 用途:演示定时器的工作原理


// 作者:古欣


// AVR与虚拟仪器 http://www.avrvi.com


#include <iom16v.h>


#include <macros.h>


void port_init(void)


{


PORTA = 0x00;


DDRA = 0x03; //PA0 PA1 输出


PORTB = 0x00;


DDRB = 0xFF; //PB 输出


PORTC = 0x00; //m103 output only


DDRC = 0x00;


PORTD = 0x00;


DDRD = 0x00;


}


 


//TIMER0 initialize - prescale:8


// WGM: Normal


// desired value: 1KHz


// actual value: 1.000KHz (0.0%)


void timer0_init(void)


{


TCCR0 = 0x00; //stop


TCNT0 = 0x83; //set count


OCR0 = 0x7D; //set compare


TCCR0 = 0x02; //start timer


}


 


//比较匹配中断


#pragma interrupt_handler timer0_comp_isr:20


void timer0_comp_isr(void)


{


//compare occured TCNT0=OCR0


if(OCR0==0x7D) //调整0x7D


{


OCR0=0x7F;


}


else


{


OCR0=0x7D;


}


PORTA ^= 0x01; //PA0取反


}


 


//溢出中断中断


#pragma interrupt_handler timer0_ovf_isr:10


void timer0_ovf_isr(void)


{


TCNT0 = 0x83; //reload counter value


PORTA ^= 0x01; //PA0取反


}


 


//call this routine to initialize all peripherals


void init_devices(void)


{


//stop errant interrupts until set up


CLI(); //disable all interrupts


port_init();


timer0_init();


 


MCUCR = 0x00;


GICR = 0x00;


TIMSK = 0x03; //timer interrupt sources 允许定时器零匹配和溢出中断


SEI(); //re-enable interrupts


//all peripherals are now initialized


}


 


void main(void)


{


init_devices();


PORTA=0x00;


while(1)


{


PORTB = TCNT0; //任何时候都可以读TCNT0


}


}


 


 


 

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
5
关闭 站长推荐上一条 /3 下一条