【问题标题】:Why does my ISR declaration break my program?为什么我的 ISR 声明会破坏我的程序?
【发布时间】:2023-06-14 02:22:01
【问题描述】:

我正在尝试让我的 Arduino Uno R3 上的两个 LED 闪烁(用于学习目的)。我使用 avr-gcc 和 avrdude 来编译和加载我的程序。

我在 main 的 while 循环中使第一个闪烁。我正在尝试使用 Timer0 打开和关闭第二个。

首先,有效的代码:

#include <avr/io.h>
#include <util/delay.h>

int main() {
    TCCR0B |= (1 << CS02) | (1 << CS00);
    TIMSK0 |= (1 << TOIE0);

    DDRD = 1 << PD3;
    DDRB = 1 << PB5;
    PORTB = 0;

    while(1) {
        PORTD ^= 1 << PD3;
        _delay_ms(500);
    }
    return 0;
}

正如预期的那样,这段代码让我的 LED 闪烁,然后每秒重新开始。我也在设置(但不使用)第二个 LED 和计时器。

现在,当我添加一个中断向量时,问题就开始了:

...
#include <avr/interrupt.h>

volatile uint8_t intrs;

ISR(TIMER0_OVF_vect) {
    if (++intrs >= 62) { // meant to execute every second
        PORTB ^= (1 << PB5);
        intrs = 0;
    }
}

int main() {
    intrs = 0;
    ... // old setup
    sei();
    while(1) { ... }
}

现在,所有 LED 都没有闪烁。更奇怪的是,当我删除 sei() 时,它们都不会眨眼。我发现让第一个 LED 再次闪烁的唯一方法是注释掉 ISR 声明或将其标记为 ISR_NAKED

那么,什么给了?

PS:我使用 makefile 来编译和加载。当我运行它时,它看起来像这样:

$ make
avr-gcc -c -Os -DF_CPU=16000000UL -mmcu=atmega328p -Wall -Wextra main.c
avr-gcc -o prog.elf main.o 
avr-objcopy -O ihex -R .eeprom prog.elf prog.hex
avrdude -C/etc/avrdude.conf -v -V -carduino -patmega328p -P/dev/ttyACM0 -b115200 -D -Uflash:w:prog.hex
.. # avrdude logs

【问题讨论】:

  • 如果你设置了一个 0.5Hz 的定时器(TIMER1 可以做到这一点,请参阅8bit-era.cz/arduino-timer-interrupts-calculator.html),这样中断就不会经常被调用并使用if (++intrs &gt;= 2),然后会发生什么?顺便说一句,您的 LED 上有合适的电阻吗?只是检查。
  • 还是不行;我使用了 1Hz 计时器,因为那是我真正想要的,并且摆脱了 intrs。现在两个 LED 都很暗,而且它们似乎每隔一段时间就会非常短暂地闪烁。是的,我只是在它们后面加了一个 220 欧姆的电阻。
  • 刚刚想到intrs,循环一直将intrs设置为0,所以中断可能永远不会看到++intrs &gt;= 62(循环比62Hz中断调用快得多),但你说即使不使用intrs,它也不起作用。嗯。感觉好像我们在这里遗漏了一些非常明显的东西,但我没有看到。
  • 问题似乎不在于程序逻辑。即使添加一个愚蠢的 ISR(例如 INT0_vect 或其他)似乎也会破坏程序 - 将其注释掉使其工作。
  • 我看不出有什么问题。也许您可以检查此处的示例是否有效:microchipdeveloper.com/8avr:interrupts-mega-configuration#toc11 并从中恢复,尽管它看起来与您已经尝试过的非常相似。

标签: avr arduino-uno atmega avr-gcc


【解决方案1】:

我使用带有 setup() 和 loop() 函数的 arduino 框架。这可能不是最佳选择,但它更容易。定时器 0 由wiring.c 使用,它负责延迟功能(不是_delay_ms(),它不使用中断)。这可以禁用,如this post 中所述,或者可以使用计时器 2。在后一种情况下,您的第二个代码可以正常工作。会不会遇到类似的问题?

【讨论】: