我试图在我的ATmega32U4 leonardo板上创建一个CTC定时器中断。当我连续检查OCF1A
的值时,我检测输出何时达到所需值时没有问题,但是一旦我将代码移入中断,中断就不会触发。
定时器设置:
#include <avr/io.h>
void setupTimer()
{
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= ((0 << CS10) | (0 << CS11) | (1 << CS12)); // set up prescaler
OCR1A = 6249; // 100 ms set up output compare value for interrupt
TIMSK1 |= (1 << OCIE1A); // enable interrupt on clock compare
}
有效的循环:
setupTimer();
for (;;) {
if (TIFR1 & (1 << OCF1A)) {
PORTC ^= (1 << PORTC7);
TIFR1 = (1 << OCF1A);
}
}
不起作用的中断:
#include <avr/interrupt.h>
ISR(TIMER1_COMPA_vect) {
PORTC ^= (1 << PORTC7);
}
我必须遗漏一些内容,因为我在教程中看到的上述代码应该可以正常工作。这里有一个有趣的观察是,如果我在调用sei()
时同时在我的代码中同时拥有循环和中断,则LED不会闪烁,就好像OCF1A
寄存器过早被清除一样。
我很确定在这种情况下它是无关紧要的,但保险丝如下:E:CB,H:D8,L:FF。
我使用avr-g++
进行编译,代码分散在几个文件之间。
答案 0 :(得分:1)
鉴于有人在问这个问题两年后通过谷歌来到这里,我想我应该就此问题分享我自己的发现。
我的问题中提供的代码是正确的,并且假设在sei()
中断应该正确触发之后某处调用setupTimer()
。问题就像在他的回答中描述的c0redumb一样 - 引导加载程序正在弄乱一些寄存器,从而阻止代码运行correclty。然而,我对这个问题的解决方案略有不同,因为在我的情况下,即使在拔出并重新插入电路板后,中断也不会触发(自从我提出这个问题以来,两年内引导程序可能已经发生了变化)。 / p>
防止代码和引导加载程序之间冲突的最简单方法是简单地删除引导加载程序。通过使用USBasp编程器,可以简单地将自己的代码加载到电路板上,从而确保它是唯一在CPU上运行的代码。
答案 1 :(得分:0)
你有两个问题:
您需要确保main()
即使在等待中断时没有做任何事情也不会返回
您需要在设置完所有内容后通过sei()
启用中断。
这是一个工作示例(我将LED端口更改为PB5
,因为我已经在Arduino Uno上测试了这个,并且已经内置了一个LED)
#include <avr/interrupt.h>
#include <avr/io.h>
void main ()
{
DDRB |= 1 << DDB5;
TCCR1B |= 1 << WGM12;
TCCR1B |= 1 << CS12;
OCR1A = 6249;
TIMSK1 |= 1 << OCIE1A;
sei();
for(;;);
}
ISR(TIMER1_COMPA_vect)
{
PORTB ^= 1 << PORTB5;
}
答案 2 :(得分:0)
这个问题今天也困扰着我。通过搜索我找到了你的问题。我做了更多的搜索,发现没有答案。我以为我一定忘记启用某些电路或设置一些标志。最后,使用LED作为我的调试器,我找到了原因。
问题在于引导程序,而不是代码。为了使它工作,你只需从USB上拔下电路板(在通过引导程序编写代码之后),然后重新插件,这样引导加载程序会在上电时直接跳转到你的代码,并且它可以在那里工作。引导加载程序必须在上传代码时做了一些花哨的步法,并且在这种情况下不能很好地工作。
作为参考,我使用了ProMicro板,我相信Caterina引导程序与您使用的Leonardo板相同。