使用ATmega328P(C语言)在Arduino Uno上使用定时器生成1秒时间延迟

时间:2014-10-27 14:21:47

标签: timer delay microcontroller avr arduino-uno

硬件:带有ATmega328P的Arduino Uno

软件:Atmel Studio 6.2.1153,Arduino 1.0.6

计算1s所需的周期

  • ATmega328P的时钟频率 = 16M Hz
  • 预分频器CLK / 1024的时钟频率 = 16M / 1024 = 15625 Hz
  • 带预分频器CLK / 1024的时钟周期 =(15625)^ - 1 = 6.4 * 10 ^ -5s
  • 1s周期 = 1 / 6.4 * 10 ^ -5 = 15625周期
  • 1秒所需的周期 = 15625 - 1 = 15624周期= 0x3D08

我的代码

OCR1AH = 0x3D;                      //Load higher byte of 15624 into output compare register
OCR1AL = 0x08;                      //Load lower byte of 15624 into output compare register
TCCR1A = 0b00000000;
TCCR1B = 0b00001101;                //Turn on CTC mode and prescaler of CLK/1024 
while((TIFR1 & (1<<OCF1A)) == 0);   //If OCF1A is set (TCNT1 = OCR1A), break 
TCCR1A = 0;
TCCR1B = 0;                         //Stop the timer
TIFR1 &= ~(1<<OCF1A);               //Clear OCF1A for the next time delay

当我点击&#34;开始调试和中断&#34;并且&#34;跨过&#34;以上代码作为函数。它总是告诉我&#34;跑步&#34;马不停蹄。为什么?怎么解决?


感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

您的配置看起来不错。

当您在调试器中暂停执行代码时,外设(独立于CPU)不会停止。某些架构/微控制器具有额外的硬件寄存器,用于在调试器停止执行代码时停止外设(例如DMA或定时器)。无论如何,AVR没有。

如果您在模拟中运行代码,您应该能够逐步查看按指令设置的所有寄存器。我建议您关闭代码优化以进行调试。

为了在硬件中调试代码(在AVR架构的情况下),您需要额外的调试器。 Arduino提供的调试仅使用在MPU中运行代码的软件,在某些情况下您无法依赖它。

无论如何,你的代码看起来是正确的。唯一的错误:将逻辑1写入TIFR1以清除位。

您应该在循环中运行您的代码以检查计时器是否正常工作:

OCR1AH = 0x3D;                      //Load higher byte of 15624 into output compare register
OCR1AL = 0x08;                      //Load lower byte of 15624 into output compare register
TCCR1A = 0b00000000;
TCCR1B = 0b00001101;                //Turn on CTC mode and prescaler of CLK/1024 
while(1)
{
    while((TIFR1 & (1<<OCF1A)) == 0);   //If OCF1A is set (TCNT1 = OCR1A), break 
    //Blink LED here
    TIFR1 = (1<<OCF1A);               //Writing logic 1 to that register clears it
}

当然如果您不想在循环中运行代码,只需将其删除即可。该代码仅用于测试目的。

修改

请查看Atmega328数据表:http://www.atmel.com/Images/doc8161.pdf,第139-140页,TIFR1寄存器,第1位 - OCF1A:

  

执行相应的中断时,硬件清零OCF1A。也可以通过向该位写入逻辑1来清除OCF1A。

有些位硬件寄存器(通常只能由用户清零,永远不能由用户设置)可以通过写入来清除1.当设置0 连接到位值>写1 给它。写入0被忽略,不会影响寄存器/位值。这可以防止从软件设置位,此时可以仅使用硬件设置位(该情况 - 定时器)。想一想 - 从代码中设置输出比较寄存器是没有意义的。其他操作(读取值,清除位)有意义并且是允许的。

还有一些寄存器只能写入,而不能读取(即读取总是返回相同的值)。

使用硬件寄存器时,请记住始终在数据表中检查如何设置/清除位。