0

我试图在我的 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++用来编译,代码分布在几个文件之间。

4

3 回答 3

2

鉴于有人在问这个问题两年后通过谷歌来到这里,我想我应该分享我自己对此事的发现。

我的问题中提供的代码是正确的,并假设在中断应该正确触发sei()之后对某处的调用。setupTimer()这个问题就像c0redumb在他的回答中描述的那样 - 引导加载程序弄乱了一些寄存器,从而阻止了代码运行正确。但是,我对这个问题的解决方案与我的情况略有不同,即使在拔下并重新插入电路板后中断也不会触发(自从我提出这个问题以来,引导加载程序可能在两年内发生了变化)。

防止代码和引导加载程序之间发生冲突的最简单方法是简单地删除引导加载程序。通过使用 USBasp 编程器,人们可以简单地将自己的代码加载到板上,从而确保它是唯一在 CPU 上运行的东西。

于 2017-07-19T16:16:13.690 回答
0

这个问题今天也让我很困惑。通过搜索我找到了你的问题。我又做了一些搜索,但没有找到这个答案。我原以为我一定忘记启用某些电路或设置某些标志。最后,用一个 LED 作为我的调试器,我找到了原因。

问题在于引导加载程序,而不是您的代码。为了让它工作,你只需从 USB 上拔下电路板(在通过引导加载程序编写代码之后),然后重新插入,以便引导加载程序在加电时直接跳转到你的代码,它在那里工作。引导加载程序在上传代码时一定做了一些花哨的工作,但在这种情况下之后就不能正常工作了。

作为参考,我使用了 ProMicro 板,我相信它的 Caterina bootloader 与您使用的 Leonardo 板相同。

于 2017-07-18T05:37:24.447 回答
0

你有两个问题:

  1. 你需要确保main()它不会返回,即使它除了等待中断之外什么都不做

  2. 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;
}
于 2015-12-17T12:07:13.320 回答