AVR ATmega32U4 定时器比较中断不触发
AVR ATmega32U4 Timer compare interrupt not triggering
我试图在我的 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++
编译,代码分布在几个文件中。
你有两个问题:
你需要确保 main()
不会 return 即使它除了等待中断什么都不做
设置完所有内容后,您需要通过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;
}
这个问题今天也很困扰我。通过搜索我找到了你的问题。我在周围进行了更多搜索,但没有找到答案。我以为我一定是忘记启用某些电路或设置一些标志。最后,我用一个 LED 作为我的调试器,我找到了原因。
问题出在引导加载程序上,而不是您的代码。为了让它工作,你只需从 USB 上拔下电路板(在通过引导加载程序编写代码后),然后重新插入,以便引导加载程序在加电时直接跳转到你的代码,它在那里工作。 bootloader 一定是在上传代码的时候做了一些花哨的步法,在这种情况下并没有很好地工作。
作为参考,我使用了一块 ProMicro 板,我相信它具有与您使用的 Leonardo 板相同的 Caterina 引导加载程序。
鉴于有人在这个问题被问到 google 两年后来到这里,我想我应该分享我在这个问题上的发现。
我的问题中提供的代码是正确的,假设在 setupTimer()
之后的某处调用了 sei()
中断应该正确触发。这个问题正如 c0redumb 在他的回答中所描述的那样 - 引导加载程序弄乱了一些寄存器,从而阻止了代码 运行 正确。然而,我对这个问题的解决方案与我的情况略有不同,即使在拔下并重新插入电路板后也不会触发中断(自从我提出这个问题以来,引导加载程序可能在两年内发生了变化)。
防止代码和引导加载程序之间发生冲突的最简单方法是简单地删除引导加载程序。通过使用 USBasp 程序员,可以简单地将自己的代码加载到开发板上,从而确保它是 CPU.
上唯一的 运行
我试图在我的 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++
编译,代码分布在几个文件中。
你有两个问题:
你需要确保
main()
不会 return 即使它除了等待中断什么都不做设置完所有内容后,您需要通过
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;
}
这个问题今天也很困扰我。通过搜索我找到了你的问题。我在周围进行了更多搜索,但没有找到答案。我以为我一定是忘记启用某些电路或设置一些标志。最后,我用一个 LED 作为我的调试器,我找到了原因。
问题出在引导加载程序上,而不是您的代码。为了让它工作,你只需从 USB 上拔下电路板(在通过引导加载程序编写代码后),然后重新插入,以便引导加载程序在加电时直接跳转到你的代码,它在那里工作。 bootloader 一定是在上传代码的时候做了一些花哨的步法,在这种情况下并没有很好地工作。
作为参考,我使用了一块 ProMicro 板,我相信它具有与您使用的 Leonardo 板相同的 Caterina 引导加载程序。
鉴于有人在这个问题被问到 google 两年后来到这里,我想我应该分享我在这个问题上的发现。
我的问题中提供的代码是正确的,假设在 setupTimer()
之后的某处调用了 sei()
中断应该正确触发。这个问题正如 c0redumb 在他的回答中所描述的那样 - 引导加载程序弄乱了一些寄存器,从而阻止了代码 运行 正确。然而,我对这个问题的解决方案与我的情况略有不同,即使在拔下并重新插入电路板后也不会触发中断(自从我提出这个问题以来,引导加载程序可能在两年内发生了变化)。
防止代码和引导加载程序之间发生冲突的最简单方法是简单地删除引导加载程序。通过使用 USBasp 程序员,可以简单地将自己的代码加载到开发板上,从而确保它是 CPU.
上唯一的 运行