【发布时间】:2014-01-02 17:25:10
【问题描述】:
我正在尝试使用 Arduino Uno 板(ATmega328,16 MHz)来实现这一目标。于是我在网上搜索了一下,想到了这样的东西:
unsigned long Time=0;
int main (void)
{
Serial.begin(9600);
cli();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 15999; // Compare value
TCCR1B |= (1 << WGM12)| (1 << CS10); // Prescaler
TIMSK1 |= (1 << OCIE1A); // Enable timer compare interrupt
sei();
while(1) {
Serial.println(TCNT1);
}
return 0;
}
ISR(TIMER1_COMPA_vect)
{
Time++;
Serial.println(Time);
}
我正在尝试实现 1 kHz 的频率,因此我将能够创建几毫秒长的间隔。
这就是为什么我选择比较值是 15999(所以 16000-1)和预分频器等于 1,所以我得到(至少我认为是正确的计算):
Frequency = 16.000.000 MHz/16000 = 1000 Hz = 1 kHz
现在的问题是,即使Serial.println(TCNT1) 向我显示的数字计数到 16000,回零,最多 16000,回零,...,Serial.println(Time) 只计数到 8,它只是停止计数,尽管 TCNT1 仍在计数。
我在某处想过某种溢出,但我想不出在哪里;我想出的唯一一件事是比较值可能太大了——我认为——自2^16 -1=65.535>15999以来显然不是这种情况。
例如,如果我制作预分频器,假设为 64,并保留比较值,Time 将按预期计数。所以我想知道:为什么ISR() 在值为 8 时停止被调用,但在调出预分频器时工作?
【问题讨论】:
-
Time声明在哪里? -
这对我来说看起来像是一个竞争条件,你正在从中断处理程序和主循环中打印。想象一下您将如何实现 Serial.println 以及如果 IRQ 被触发并开始尝试打印而主循环已经在打印不同的消息会发生什么。从中断处理程序调用像这样的高级系统函数根本是一个主要的禁忌,除非你非常确定你在做什么以及库提供的重入保证,它们不像线程那样可以被锁定并安全恢复
-
@doynax 我明白你想说什么,问题是即使我注释掉它仍然会发生,即 Serial.println(TCNT1) ;它仍然只计算时间直到值 8 (如果我也将最后一个 Serial.println() 注释掉并且使输出(即通过 LED 可见)也是如此)
-
@VGD:很好奇,那我不能直接发现问题,我担心我现在手边没有板子。尝试从程序中删除所有不相关的内容,包括串行库,并在中断停止触发后使用调试器闯入程序以检查寄存器。哦,以防万一
标签: c++ timer arduino avr arduino-c++