Atmel / Arduino:ISR(TIMER0_OVF_vect) 无法编译("first defined" in __vector_16)

Atmel / Arduino: ISR(TIMER0_OVF_vect) won't compile ("first defined" in __vector_16)

我目前正在研究用于 "simulate" 汽车发动机点火换向的 PWM 调制器。然后,我将使用它来驱动另一个微控制器,该微控制器处理从原始信号(发动机换向器)到干净输出电压的转换,通过 RPM 计数器的电流计。

这个项目也是我学习如何更好地控制我的微控制器的借口。

嗯,我写了一个小程序,使用timer0(8位),我需要触发两个中断服务程序(ISRs):

我有以下功能:

void configureTimer0(parameters)
{
    cli();

    // Some maths
    TCCR0A = (1<<WGM01) | (1<<WGM00); // I tried to use the "Fast PWM" waveform generation mode
    TCCR0B &= 0b00110000; // 5th and 4th bits are reserved. Every other bits is set to 0.
    TCNT0 = 0; // Initialize counter value to 0

    TCCR0B |= select_prescaler(prescaler); // Custom function to determine the right prescaler
    OCR0A = ext_OnTicks; // Output compare register is set to a predetermined numbers of ticks

    // Enabling overflows interrupt:
    TIMSK0 |= (1 << TOIE0);
    sei(); // Enable interrupts
}

然后在一定条件下,我根据情况将TIMSK0中的OCIE0位开关。 但是,溢出中断始终处于启用状态。

当我尝试编译时,我遇到了这些错误:

"C:\Users\UTILIS~1\AppData\Local\Temp\arduino_build_8383\sketch\PWM_modulator.ino.cpp.o" "C:\Users\UTILIS~1\AppData\Local\Temp\arduino_build_8383/..\arduino_cache_395570\core\core_arduino_avr_uno_a94ab6aaf61dfb93b4a8079c694a14c2.a" "-LC:\Users\UTILIS~1\AppData\Local\Temp\arduino_build_8383" -lm
wiring.c.o (symbol from plugin): In function `__vector_16':

(.text+0x0): multiple definition of `__vector_16'

C:\Users\UTILIS~1\AppData\Local\Temp\arduino_build_8383\sketch\PWM_modulator.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

collect2.exe: error: ld returned 1 exit status

exit status 1
Erreur de compilation pour la carte Arduino/Genuino Uno // Compilation error for Uno board (French)

我尝试使用 ISR(TIMER0_COMPB_vect) 而不是 ISR(TIMER0_OVF_vect) 进行编译,它可以工作,但实际上这不是我程序的重点。

我还尝试了 ISR(TIMER2_OVF_vect),它也是一个 8 位定时器。我可以同步 Timer0 和 Timer2 以达到预期的效果,但我认为这样做不太干净(并且它阻止我使用 Timer2 功能)。

我的代码有问题,但无法理解错误隐藏在哪里。 肯定有一些与 wiring.c.o 文件相关的东西。

PS:自从问题出现以来,我已经寻找了很长时间的解决方案,但我找不到任何方法来正确地询问 Google Stack Overflow 站点。 如果我错过了正确的搜索字符串,我们深表歉意!

您正在使用 Arduino 库,它已经为 TIMER0_OVF 中断定义了一个处理程序。

如果您想为此中断定义自己的处理程序,则需要独立构建项目,而无需使用 Arduino 库或工具。

我只是用了 Timer2 而不是 Timer0。使用 Timer2,我仍然可以像预期的那样在同一定时器上设置溢出和输出比较中断。

这是解决此问题的一种相当简单的方法,但它可能并不适合所有情况。我可能需要修改我的代码并使其适应直接的 avr-gcc / Atmel Studio 编译过程。

可以为 Timer0 提供您自己的处理程序并仍然使用 Arduino 环境。

这是通过(可选)禁用文件 wiring.c(在 Arduino 安装内)中 Timer0 的现有处理程序来完成的。在现有处理程序周围放入条件编译,#ifndef / #endif

#ifndef _DISABLE_ARDUINO_TIMER0_INTERRUPT_HANDLER_

    #if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    ISR(TIM0_OVF_vect)
    #else
    ISR(TIMER0_OVF_vect)
    #endif
    {
        // Copy these to local variables so they can be stored in registers
        // (volatile variables must be read from memory on every access)
        unsigned long m = timer0_millis;
        unsigned char f = timer0_fract;

        m += MILLIS_INC;
        f += FRACT_INC;
        if (f >= FRACT_MAX) {
            f -= FRACT_MAX;
            m += 1;
        }

        timer0_fract = f;
        timer0_millis = m;
        timer0_overflow_count++;
    }

#endif

例如,在 Windows 上,文件 wiring.c 可能位于文件夹 C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino.

请注意,可能需要具有管理权限才能对 wiring.c 进行更改。在 Windows 上,这是通过右键单击文本编辑器(文本编辑器,如 Notepad++ or UltraEdit[1],可以处理 Unix 结束-行字符 - 记事本无法真正处理这个)并选择 "Run as Adminstrator".

然后,在您的源代码中将这两行放在文件的顶部:

#define _DISABLE_ARDUINO_TIMER0_INTERRUPT_HANDLER_

#include <wiring.c>

请注意,对于其他 Arduino 项目,它的工作方式与以前完全一样。仅当定义了预处理器符号 _DISABLE_ARDUINO_TIMER0_INTERRUPT_HANDLER_ 时才禁用中断处理程序。

可能还必须对 TIMER0_COMPA_vect 应用相同的程序(同一文件夹中的文件 Tone.cpp)。

这是使用 Arduino Uno 等效版本、Arduino IDE 1.8.5、文本编辑器 UltraEdit 和 Windows 10.

进行测试的

1.我也希望 Visual Studio Code 可以工作,但我还没有测试过。