爱特梅尔/ Arduino的:ISR(TIMER0_OVF_vect)将无法编译(“第一定义”中__vector_16)

爱特梅尔/ Arduino的:ISR(TIMER0_OVF_vect)将无法编译(“第一定义”中__vector_16)

问题描述:

我目前工作的一个PWM调制器以“模拟”汽车发动机点火减刑。然后,我将使用它来驱动另一个处理从原始信号(引擎的换向器)转换为干净输出电压的微控制器,并通过RPM计数器的检流计。爱特梅尔/ Arduino的:ISR(TIMER0_OVF_vect)将无法编译(“第一定义”中__vector_16)

这个项目对我来说也是学习如何有在我的微控制器更好的控制的借口。

嗯,我写了一个小程序,用定时器0(8位),我需要触发两个中断服务程序(ISR):

  • TIMER0_OVF_vect:溢出中断
  • TIMER0_COMPA_vect:上比较火

我有以下功能:

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位置ON和OFF。 但是,溢出中断始终处于启用状态。

当我尝试编译,我结束了这些错误:

"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站点。 道歉,如果我错过了正确的搜索字符串!

+0

它看起来像处理'ISR(TIMER0_OVF_vect)测试'在多个地方被定义。 –

您使用Arduino的库,它已经定义了TIMER0_OVF中断处理程序。

如果要定义自己的处理程序为这个中断,您将需要建立项目独立,不使用Arduino的库或工具。

+0

这是真的......所以这主要是由于Arduino库?我不认为我必须这么早地跳到avr-gcc和avr工具链,但无论如何它必须尝试!谢谢您的回复! – bebenlebricolo

我只是使用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上,通过右键单击文本编辑器(一个可以处理Unix行尾字符的文本编辑器 - 记事本无法真正处理此操作)并选择“以管理员身份运行”来完成此操作。

然后,在你的源代码放在这两条线在文件的顶部:

#define _DISABLE_ARDUINO_TIMER0_INTERRUPT_HANDLER_ 

#include <wiring.c> 

注意,其他的Arduino项目是完全按照以前的作品。如果定义了预处理器符号_DISABLE_ARDUINO_TIMER0_INTERRUPT_HANDLER_,则只能禁用中断处理程序。

同样的过程可能也必须应用于TIMER0_COMPA_vect(文件Tone.cpp在同一文件夹中)。

这与一个Arduino乌诺等同,Arduino的IDE 1.8.5,文本编辑器UltraEdit,和Windows 10

+0

非常感谢您的回复。自从我问到这些问题以来,我就深入到Atmel Studio以及优化和模拟的神奇之处。现在对我来说更清楚了。我一定会用你的窍门来做只有arduino的程序,它可以帮助你节省大量的时间/精力(重新设计一个使用Timer1代替Timer0的程序可能会很痛苦)。 – bebenlebricolo

+0

@bebenlebricolo:我发现了一种不切实际的方式来做到这一点(所以其他Arduino项目不受文件'wiring.c'中的变化影响)。我已经更新了我的答案。 (我在为精确的8MHz频率计数器编写软件时遇到了同样的问题(不需要外部元件),我必须使用Timer0和Timer1,利用这两个硬件计数器,使用Timer0输入信号Timer2被用于1.14285714286 MHz的测试信号。) –

+0

@bebenlebricolo:哇!我刚刚发现[Arduino Uno使用陶瓷谐振器](https://learn.adafruit.com/arduino-tips-tricks-and-techniques/arduino-uno-faq)(+/- 0.5%),而不是晶体振荡器(PCB上有一个晶体振荡器,但是用于USB芯片)。陶瓷谐振器在工作中受到了不好的经历(由第三方供应商使用)。频率计数器的最终版本将用于带有晶体振荡器的裸露ATmega328芯片(以及后来的基于DCF77的频率参考)。 –