电子说
原理图
为什么要使用计时器?
大多数微控制器项目都需要使用精心计时的事件,包括多任务,位冲击协议,测量等等。这些定时事件可以通过在循环的每次迭代中使用递增计数器来在软件中完成。但是,这会浪费可用于执行其他操作的CPU资源,并且此类循环的使用可能难以正确计时。这就是定时器被引入微控制器的原因。现在它们非常普遍,很少找到没有控制器的控制器。
大多数ATmega设备至少有一个定时器,ATmega168有三个定时器。因此,在本教程中,我们将看看定时器0以及在两种不同模式下使用时如何将它用于定时事件:正常和比较。
定时器0
定时器0是一个通用的8位定时器,具有一些相当强大的功能,包括比较模式,快速PWM生成和波形生成功能。虽然定时器0可能看起来很复杂,但实际上它使用起来相当简单,只要你了解其工作原理背后的基础知识。
定时器0外设布局
首先,AVR上的定时器几乎与一个由链中的一堆触发器组成的简单向上计数器相同。每次定时器计时时,它都会递增一个计数器寄存器,用于跟踪当前定时器的值。
当定时器达到最大值然后计时时(timer0是一个8位计数器,这意味着它最大值为255),定时器回绕到0并设置定时器溢出位。此位可用于查看计数器是否已溢出,并且在确定特定代码段是否已停止或未响应的情况下非常有用。
定时器通常可以来自不同的源,包括内部时钟源和外部I/O引脚。这意味着外部威廉希尔官方网站 可以提供方波,使定时器递增,或者微控制器本身可以递增定时器(这通常用作时钟源)。
一些定时器(如定时器0)有比较单位,允许定时器在定时器等于某个值时触发中断。当微控制器需要执行在特定时间过去时执行的事件时,这非常有用。
一个这样的例子涉及在需要每64uS发送一次脉冲同步脉冲时创建视频信号(朋友)。其他示例包括多任务,其中微控制器可以每毫秒切换到不同的任务。一旦匹配发生,也可以使这样的比较单元清除定时器,这样用户就不必自己重置定时器。
定时器0:正常模式
在正常模式下,定时器0将在每个时钟递增,并且一旦计数器超过其最高值值(255,因为它是一个8位定时器),定时器回绕到值0并设置溢出位(TOV0位在寄存器TIFR0中找到)。
设置定时器0运行在正常模式下,WGM02-WGM01位需要设置为0(注意; WGM02位于TCCR0B中,而位WGM01和WGM00位于寄存器TCCR0A中。
寄存器TCCR0A和TCCR0B中的波形位
定时器0:CTC模式
比较匹配模式(CTC)上的清除定时器与普通模式类似,除非定时器达到的值寄存器OCR0A,定时器清零(复位为0x00)。这可用于创建定时事件,包括延迟和中断,而无需使用软件资源(全部在硬件中完成)。
当定时器等于OCR0A的值时,则设置OCF0A,表示匹配在定时器和OCR0A之间发生。要在CTC模式下配置定时器0,需要将WGM02-WMG00位设置为0x02。
定时器0时钟源
定时器0可以通过外部源(通过T0引脚)或内部I/O时钟提供时钟。某些I/O时钟源可以如表所示进行预分频,时钟源选择位可在TCCR0B寄存器中找到。
从显示预分量选项的ATmega数据表中提取
关于中断标志的注意事项
重要的是要注意AVR是为了清除标志,你必须在标志上写一个逻辑的。这意味着,例如,如果要清除溢出标志,则将1写入写入0的寄存器INSTEAD。
示例1:正常模式
此模式显示在正常模式下使用定时器0来打开和关闭LED每次计数器翻转(超过255)。
/*
* AVR Timer.c
*
* Created: 08/01/2018 13:16:36
* Author : RobinLaptop
*/
#define setBit(reg, bit) (reg = reg | (1 《《 bit))
#define clearBit(reg, bit) (reg = reg & ~(1 《《 bit))
#define toggleBit(reg, bit) (reg = reg ^ (1 《《 bit))
#define clearFlag(reg, bit) (reg = reg | (1 《《 bit))
#include
int main(void)
{
// Initialize Registers
clearBit(TCCR0A, WGM00); // Configure WGM to be 0x00 for normal mode
clearBit(TCCR0A, WGM01);
clearBit(TCCR0B, WGM02);
setBit(TCCR0B, CS00); // Configure clock source to be clock io at 1024 pre-scale
clearBit(TCCR0B, CS01);
setBit(TCCR0B, CS02);
DDRD = 0xFF; // Make PORT D and output
while (1)
{
// Wait until the TOV0 bit is set
while(!(TIFR0 & (1 《《 TOV0)))
{
}
// Clear the overflow flag by writing a 1 to it. I know, thats dumb but that‘s how it is!
clearFlag(TIFR0, TOV0);
// Toggle the LED (PD0 , Pin 2)
PORTD = PORTD ^ (1 《《 PD0);
}
}
示例2:CTC模式
当定时器0等于OCR0A的值时,该模式将切换LED。一旦匹配发生,定时器将自动复位并设置OCF0A标志。
/*
* Example 2 - CTC.c
*
* Created: 08/01/2018 13:43:06
* Author : RobinLaptop
*/
#define setBit(reg, bit) (reg = reg | (1 《《 bit))
#define clearBit(reg, bit) (reg = reg & ~(1 《《 bit))
#define toggleBit(reg, bit) (reg = reg ^ (1 《《 bit))
#define clearFlag(reg, bit) (reg = reg | (1 《《 bit))
#include
int main(void)
{
// Initialize Registers
clearBit(TCCR0A, WGM00); // Configure WGM to be 0x00 for normal mode
setBit(TCCR0A, WGM01);
clearBit(TCCR0B, WGM02);
setBit(TCCR0B, CS00); // Configure clock source to be clock io at 1024 pre-scale
clearBit(TCCR0B, CS01);
setBit(TCCR0B, CS02);
DDRD = 0xFF; // Make PORT D and output
OCR0A = 0x7F; // Reset the timer once the value of the timer reaches 127
while (1)
{
// Wait until the OCF0A bit is set
while(!(TIFR0 & (1 《《 OCF0A)))
{
}
// Clear the overflow flag by writing a 1 to it. I know, thats dumb but that’s how it is!
clearFlag(TIFR0, OCF0A);
// Toggle the LED (PD0 , Pin 2)
PORTD = PORTD ^ (1 《《 PD0);
}
}
结论
本教程仅涉及计时器能够做更多事情的计时器。例如,这些定时器可以启用它们的中断,这将允许微控制器在设置标志后立即运行时间敏感的代码。或者,我们可以执行其他代码,而不是使用while循环来等待溢出标志触发,这样可以更有效地利用CPU。很明显,定时器非常强大,可以为大多数项目带来巨大的变化!
全部0条评论
快来发表一下你的评论吧 !