我是编程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模式的工作方式有误解,如果有人可以简单地向我解释它,或者我的代码有任何其他问题,我将不胜感激。
答案 0 :(得分:2)
我注意到一件事可能会导致您看到的问题。
您正在使用行TIFR1 |= (1<<OCF1A);
清除OCF1A位。您非常频繁地运行该行,因此很有可能在设置OCF1A时,您的代码会在if语句看到设置之前立即将其清除。您无法控制何时设置该位。它可以在循环的任何时候发生。
仅应在确认OCF1A为1后清除它,如下所示:
if (TIFR1 & (1 << OCF1A))
{
PORTD ^= (1 << PORTD6);
TIFR1 |= (1 << OCF1A);
}