问题在于时序行为完全错误(因素30)。
我有一台运行8 Mhz的ATmega 644PA(没有设置CKDIV8保险丝)。
我想要每1 ms一次中断。我在比较模式下使用Timer1(16位定时器)。
预分频器由我需要的时序范围选择。
这里1毫秒到2秒。 (通过16位定时器寄存器限制。)
CPU:8.000.000 Hz
预分频器:256
8.000.000 Hz / 256 = 31250周/秒(Hz)
1000 ms = 31250周期
1 ms = 30.25周期(31.25 - 1,定时器寄存器开始0)
从这里我可以计算出来,例如:
100 ms = 3025周期
2s = 60500周期
定时器初始化
cli(); // disable global interrupts
TCCR1A = (1 << WGM01); // CTC ON
TCCR1B = 0x04; // Prescaler 256
OCR1A = 30; // set compare reg.
TIMSK1 = (1 << OCIE1A); // set interrupt mask
TCNT1 = 0x00; // set counter reg. to zero
sei(); // enable global interrupts
ISR:
ISR(TIMER1_COMPA_vect)
{
// start own code
...
// end own code
TCNT1 = 0x00; // reset counter reg. to zero after match (same which should CTC do)
}
现在我有一个易变量,它将在ISR函数中递增。
我轮询变量并等待很长时间,直到它达到60500,等于2s。
在它之后,我只是设置了一个led。
我通过电话测量它,它需要1分钟,直到LED继续。
因子30 =&gt;需要很长时间。 60秒除以2为30
我也尝试使用外部程序来计算它,它得出了相同的结果。 (0x1E = 30)
Screenshot http://image.prntscr.com/image/14bd89cb111d4653bd27a9e8a8719b93.png
有人知道我的错误在哪里?
答案 0 :(得分:1)
2秒是60500个周期。但是你的ISR每1毫秒递增一次volatile变量。当然,变量需要60.5秒才能达到60500。
作为旁注,最好更改比较值,而不是重置TCNT,以避免时序漂移。也就是说,让计数器自由运行,并使用OCR1A += 31;
命中下一个中断。像你一样重置TCNT将忽略ISR内的时间。