智能小车47:Atmega328p定时器TC0标准模式
说定时器前,先说一下Atmega328p的几个关键知识点。本文只讲TC0并且是标准模式,其它的还没研究。
1.这个芯片的片内振荡器的频率是多少?
答,1MHz。并且代码里定义F_CPU变量并不会影响振荡器的频率,但会影响_delay_ms函数的执行时间。关于这个影响的试验可以delay1秒,再分别测试1MHz与16MHz的效果就能看出来。而它不影响振荡器的频率,可以通过改变F_CPU值来测试定时器定时执行的程序是否精确得到结论。这个1MHz是从官方手册看到的,如下图选中文字。
这个芯片由内部的8Mhz的RC振荡器与CKDIV8溶丝位的设定最终形成了1Mhz的系统时钟。我开始也不确定我的这个理解是否正确,直到我把这个1Mhz代入公式,看这个值与它的实际定时效果是否一致,才确定这个理解是正确的。
2.avr定时器的原理是什么,怎么计算相关值?
avr定时器是一个单独的模块,就是cpu不运行这个也能照常运行。TC0的结构如下:
数据寄存器TCNT0是个8位寄存器,最大值(top)是0XFF,最小值(bottom)是0X00.一般用count方法,每次加1来计数,到了top值后再加1就是溢出了,我们就可以在溢出时执行ISR(TIMER0_OVF_vect)函数。但也支持指定值(direction)。计数(+1)的时间由clk_t0来决定,而这个值来源于系统时钟与预分频器的综合结果。
预分频器的作用是得到减慢的系统时钟,比如我们设置TCCR0B=0x05,意思就是设置预分频器为1024(查数据手册).
那么我们可以得到clk_t0的时钟为1000000/1024=976(分频后的时钟频率),那么每次计数(+1)的时间为1/976=0.001秒=1毫秒。假如我们要每10毫秒触发一下ISR(TIMER0_OVF_vect)函数,那么计数器需要计数10(10毫秒/1毫秒)次才会执行这个函数了。把TCNT0设置为256-10(0XF6)就可实现这个功能。
这个推导过程,可用个公式来表示TCNT0=256-(TV*F)/N;
TV: 所想要设定的定时时间,单位,us
F: 晶振频率(MHz)
N: 分频因子
代码比较简单,我贴下核心代码:
最后看下实际效果: