AVR CTC计时器频率表观误差

时间:2018-11-04 22:43:40

标签: timer frequency avr timing atmega

我是编程AVR设备的初学者,试图摆脱效率低下的_ms_delay()和_us_delay()阻塞函数,我一直在尝试使用内置计时器来控制基本LED的时序在16位定时器上以CTC定时器模式刷新程序。我的目标是使LED以2 Hz的频率闪烁,持续0.5s,熄灭0.5s。

根据ATMega328P datasheet,CTC输出的频率应为f_CTC = f_Clock /(2N(OCR1A + 1),因为我的芯片是328P Xplained mini,因此它的默认CPU速度为16 MHz,使用上面的公式(N = 64)下,达到我想要的频率所需的OCR1A值应为62499。考虑到所有这些,我编写了以下代码:

#include <avr/io.h>

int main(void)
{
    // Setup for timer TC1 (16-bit) in CTC mode to run at 2 Hz
    TCCR1A = 0x00;
    OCR1A = 62499; // Sets time resolution to 0.5 s
    TCCR1B = 0x0b;
    TCCR1C = 0x00;

    // Set pin directions
    PORTD &= ~(1<<PORTD6);
    DDRD |= (1<<DDD6);

    while (1) 
    {
        if(TIFR1 & (1<<OCF1A))
        {
             PORTD ^= (1<<PORTD6);
        }
        TIFR1 |= (1<<OCF1A);
    }
}

但是,当我运行代码时,LED会以1 Hz的频率闪烁,这可以通过手机计时。另外,当我将OCR1A更改为31249(应将频率增加到4 Hz)时,它似乎以8 Hz的频率闪烁,或者每秒开和关4次。我觉得我对CTC模式的工作方式有误解,如果有人可以简单地向我解释它,或者我的代码有任何其他问题,我将不胜感激。

1 个答案:

答案 0 :(得分:2)

我注意到一件事可能会导致您看到的问题。

您正在使用行TIFR1 |= (1<<OCF1A);清除OCF1A位。您非常频繁地运行该行,因此很有可能在设置OCF1A时,您的代码会在if语句看到设置之前立即将其清除。您无法控制何时设置该位。它可以在循环的任何时候发生。

仅应在确认OCF1A为1后清除它,如下所示:

if (TIFR1 & (1 << OCF1A))
{
    PORTD ^= (1 << PORTD6);
    TIFR1 |= (1 << OCF1A);
}