问题描述
对于计时器,我想每秒切换一个 LED。我使用的是ATMega32,时钟频率是1MHz。我可以使用 8 位计数器达到 0.1 秒,并且对于每 10 个定时器中断,我会闪烁 LED。
#define F_cpu 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
typedef unsigned char u8_t;
typedef unsigned short u16_t;
void func();
int main(void)
{
DDRC = 0x80;
TCCR0 |= (1 << WGM01); // CTC bit.
TCCR0 |= (1 << CS02) | (1 << CS00); // Prescalar = 1024.
OCR0 = 98; // 98 ticks correspond to roughly 0.1 second with 1024 prescaler
TimsK |= (1 << OCIE0);
TCNT0 = 0;
sei();
while(1)
{
if (!(TIFR & (1 << OCF0))) {
func();
}
}
}
void func()
{
static u8_t extra_time = 0;
if (extra_time == 10)
{
extra_time = 0;
PORTC ^= 0x80;
}
else extra_time++;
TIFR |= (1 << OCF0);
}
在前面的代码中,我没有为 TIMER0_COMP_vect
中断定义 ISR。
来自数据表:
当 Timer/Counter0 和计数器之间发生比较匹配时,OCF0 位被设置(1) OCR0 中的数据——输出比较寄存器 0。 OCF0 执行时由硬件清零 相应的中断处理向量。 或者,OCF0 通过写一个逻辑 1 到 国旗。当 SREG 中的 I 位、OCIE0(定时器/计数器 0 比较匹配中断使能)和 OCF0 置位(一),Timer/Counter0 比较匹配中断被执行。
强调我的。
因此,通过强调的句子,我可以检查 OCF0 位是否为零,如果是,我可以“处理”on-compare-match 事件。
但是,LED 的闪烁频率要高得多(每次闪烁之间甚至不到十分之一秒,但我当然无法测量)。
如果我只是在 TIMER0_COMP_vect
上设置 ISR 并且不检查任何内容,这工作正常,但我想知道为什么 OCF0 总是(?)逻辑 0,因此“打开”,即使我将它设置为每次 func()
调用都很高。这种方法有什么问题。
解决方法
继续阅读数据表中的下一行
当 SREG 中的 I 位、OCIE0(定时器/计数器 0 比较匹配中断使能)和 OCF0 置位(1)时,定时器/计数器 0 比较匹配中断被执行。
然后看看你的代码
- 您已启用比较匹配中断
TIMSK |= (1 << OCIE0);
- 您已启用全局中断(SREG 中的 I 位)
sei();
- 因此,每当设置输出比较标志
OCF0
时,中断的所有 3 个条件都已发生,并且会自动触发中断
当一个中断被触发时,程序的执行流程会跳转到这个中断对应的特定内存位置来执行代码并处理它,
但是你没有为这个中断提供任何代码(没有ISR),所以微控制器不知道他能做什么,因为你没有告诉他,所以他会RESET
等等,没有 Handler 保持触发的中断使微控制器保持 重置
最后,当你添加一个空的 ISR 时,你会提供一个代码,告诉微控制器在这个中断被触发时什么都不做,并且微控制器不会重置,因为他知道如何处理它
如果您想自己跟踪 OCF0
标志,请删除此行
TIMSK |= (1 << OCIE0);