Avr-gcc:定时器/计数器中断与 UART 冲突?
请考虑以下示例(在 Arduino IDE 0022、Ubuntu 11.04、Arduino AtMEGA 2560 上尝试过),其中我尝试启动计时器/计数器中断并同时使用 Arduino Serial
类:
volatile uint8_t sreg;
// Timer 0 interrupt routine
ISR(TIMER0_COMPA_vect, ISR_NAKED)
{
sreg = SREG; /* Save global interrupt flag */
cli(); /* Disable interrupts */
digitalWrite(34, not((bool)digitalRead(34)));
SREG = sreg; /* Restore global interrupt flag */
reti(); // must for ISR: return and enable interrupt
}
void setup() {
pinMode(13, OUTPUT);
pinMode(34, OUTPUT);
Serial.begin(115200);
Serial.println("Hello from setup");
delay(200);
}
void loop() {
digitalWrite(13, HIGH);
Serial.println("Hello from loop: A");
digitalWrite(13, LOW);
delay(200);
digitalWrite(13, HIGH);
#if 1 // register update part
cli(); // disable interrupts
GTCCR = 0b10000011; // halt timers
// set up Timer/Counter 0
TCCR0A = 0b00000010; // CTC; normal mode (don't use output pin)
TCCR0B = 0b00000101; // no force output; CTC; ... and clock select: prescale 1024
TCNT0 = 0; // init the actual counter variable
TIMSK0 = 0b00000010; // enable (only) Compare Match A Interrupt
OCR0A = 125; //the top value, to which the running counter is compared to
GTCCR = 0b00000000;
sei(); // Enable interrupts once registers have been updated
digitalWrite(13, LOW);
delay(200);
#endif
digitalWrite(13, HIGH);
Serial.println("Hello from loop: B");
digitalWrite(13, LOW);
delay(200);
}
例如,通过串行打印输出将是:
Hello from setup
Hello from loop: A
Hello from loop: B
Hello from loop: A
Hello from loop: B
...然后所有处理将停止(通过 LED 引脚 13 和 34 上缺乏动作来指示);我想,这就是芯片世界中所谓的 BSOD :) 从表面上看,一旦 ISR 例程第一次启动,就会停止。
如果取出“寄存器更新部分”,则串行打印输出将永远运行,如预期的那样 - 而且(如预期的那样),没有 ISR 运行。但是,如果保留了“寄存器更新部分”,并且注释了两行“Serial.println(...
”) - 那么程序仅打印“Hello from setup” - 但中断确实运行(如引脚 34 上的脉冲所证明),
这似乎告诉我,您不能同时在 ATMega2560 上运行定时器 ISR 和 UART - 这是愚蠢的,因为我以前曾成功使用过,同类 所以,我想知道我想要做的
事情(同时具有串行打印输出和引脚脉冲)对于这种架构来说基本上是不可能的 - 或者我只是在设置中遗漏了一些东西
? , 干杯!
(只是想指出,这个 Serial 类实际上对 Arduino IDE 包中的 HardwareSerial.cpp 中的类定义进行操作;并且该类定义了接收 USART 中断例程;认为这可能是问题所在 - 但我再次使用了相同的方法在 ATMega328 中,我在那里看到它工作..)
Please consider the following example (tried on Arduino IDE 0022, Ubuntu 11.04, Arduino AtMEGA 2560), where I'm trying to start a timer/counter interrupt and use the Arduino Serial
class at the same time:
volatile uint8_t sreg;
// Timer 0 interrupt routine
ISR(TIMER0_COMPA_vect, ISR_NAKED)
{
sreg = SREG; /* Save global interrupt flag */
cli(); /* Disable interrupts */
digitalWrite(34, not((bool)digitalRead(34)));
SREG = sreg; /* Restore global interrupt flag */
reti(); // must for ISR: return and enable interrupt
}
void setup() {
pinMode(13, OUTPUT);
pinMode(34, OUTPUT);
Serial.begin(115200);
Serial.println("Hello from setup");
delay(200);
}
void loop() {
digitalWrite(13, HIGH);
Serial.println("Hello from loop: A");
digitalWrite(13, LOW);
delay(200);
digitalWrite(13, HIGH);
#if 1 // register update part
cli(); // disable interrupts
GTCCR = 0b10000011; // halt timers
// set up Timer/Counter 0
TCCR0A = 0b00000010; // CTC; normal mode (don't use output pin)
TCCR0B = 0b00000101; // no force output; CTC; ... and clock select: prescale 1024
TCNT0 = 0; // init the actual counter variable
TIMSK0 = 0b00000010; // enable (only) Compare Match A Interrupt
OCR0A = 125; //the top value, to which the running counter is compared to
GTCCR = 0b00000000;
sei(); // Enable interrupts once registers have been updated
digitalWrite(13, LOW);
delay(200);
#endif
digitalWrite(13, HIGH);
Serial.println("Hello from loop: B");
digitalWrite(13, LOW);
delay(200);
}
As the example is, the printout via serial will be:
Hello from setup
Hello from loop: A
Hello from loop: B
Hello from loop: A
Hello from loop: B
... and then all processing will stop (indicated by lack of action on both LED pin 13 and 34); I guess, this is what you would call a BSOD in the chip world :) Superficially, the halt happens as soon as the ISR routine kicks in for the first time.
If you take out the "register update part", then the serial printout runs forever, as expected - and also (as expected), there is no ISR running. However, if the "register update part" is left, and the two "Serial.println(...
" lines are commented instead - then the program prints only "Hello from setup" - but the interrupt does run (as evidenced by pulses on pin 34).
Which seems to tell me, that you cannot run a timer ISR and the UART on the ATMega2560 at the same time - which is silly, given that I had previously used, with success, the same kind of approach on an ATMega328.
So, I'm wandering whether what I want to do (have both serial printout and pins pulsing) is fundamentally impossible with this architecture - or am I just missing something in the setup?
Thanks in advance for any answers,
Cheers!
(Just wanted to note that this Serial class actually operates on a class definition in HardwareSerial.cpp in the Arduino IDE package; and this class defines the reception USART interrupt routines; thought this may be the problem - but again, I used the same approach in ATMega328, where I had seen it work.. )
EDIT: Repost on Avr-gcc: Timer/counter interrupts conflicting with UART? - Arduino Forum
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好的,我刚刚在 ATMega168 和 ATMega328 上重新运行了相同的代码 - 它按预期工作(带有
Serial.write
的主循环和 ISR 例程都在运行);所以它一定是 ATMEGA2560 特定的问题 - 而不是一般编程的问题...编辑:简短的答案是 - 使用不同的计时器,因为 Timer0 已被 Arduino API 使用。
(有关更多信息,请参阅 Arduino 论坛上的转发)。
干杯!
Ok, I just re-ran the same code on ATMega168 and ATMega328 - and it works as expected (both main loop with
Serial.write
, and ISR routine, are running); so it must be an ATMEGA2560 specific problem - and not a problem with programming in general ...EDIT: The short answer is - use a different timer, because Timer0 is already in use by the Arduino API.
(for more, see the repost on Arduino forum).
Cheers!