AVR 定时器溢出中断不工作
AVR timer overflow interrupt not working
你好堆栈溢出的好人。我的问题是一个似乎永远不会执行的中断服务例程 (ISR)!这是有关我的设置的一些信息:
我正在闪烁 avr attiny85。到目前为止,我已经建立了一个项目的基本框架,只有一个 main.c 和两个模块:timer 和 hardwareInit。在定时器模块中,我有一个 timer0_init 函数,我用它来为 CTC 模式设置定时器 0,使其每 1 毫秒溢出一次。这是函数:
void timer0_init( void )
{
cli();
TCCR0B |= 3; //clock select is divided by 64.
TCCR0A |= 2; //sets mode to CTC
OCR0A = 0x7C; //sets TOP to 124 so the timer will overflow every 1 ms.
TIMSK |= 2; //Enable overflow interrupt
sei(); //enable global interrupts
}
设置好计时器后,我添加了一个 ISR 以在每次计数器溢出时增加滴答声,这样我就可以跟踪已经过了多少时间等。
ISR(TIMER0_OVF_vect)
{
cli();
//ticks ++;
PORTB |= ( 1 << PORTB0 );
sei();
}
如你所见,我注释掉了 ticks++,因为它不起作用,并将其替换为 PORTB |= ( 1 << PORTB0 );
,它只是打开一个 LED,所以如果中断被执行,我会知道LED 亮起的证明。
不幸的是,我无法打开它,也看不到我错过了什么。 (为了证明我 1. 将 LED 设置在正确的引脚上,并且 2. 在正确的寄存器中操作正确的位,我只在我的无限循环中放置了这条语句 PORTB |= ( 1 << PORTB0 );
并确认 LED 亮起)
为了进一步解释,这里是我的 main.c:
/*================================= main.c =================================*/
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "timer.h"
#include "hardwareInit.h"
int main(){
//Initialize hardware HERE
DDRB |= ( 1 << PORTB0 ); //set this pin as an output for an LED
SetClockPrescale(1); //internal clock divided by 1 = 8 MHz, from hardwareInit
timer0_init(); //set up timer0 for 1 ms overflow
while(1)
{
/* if( getTicks() > 0 )
{
PORTB |= ( 1 << PORTB0 );
_delay_ms(1000);
PORTB &= ~( 1 << PORTB0 );
_delay_ms(1000);
} */
}
return 0;
}
所以,你在无限循环中看到的是我首先尝试的,但之后没有用,我尝试了一些更简单的东西,只是有一个空循环(注释掉之前的东西),并等待中断被触发,这将打开 LED。
如果您能提供任何帮助,我们将不胜感激。我很困惑为什么这没有用。
正如@andars 正确指出的那样,您使用了错误的 ISR。在 CTC "Clear Timer on Compare" 模式下,定时器永远不会溢出,因为它将在比较匹配时被清除。
所以你也启用了错误的定时器中断。 TIMSK 寄存器的第 1 位启用定时器 0 上的定时器溢出中断。由于前面的原因,不会触发。摘自 datasheet.
当您使用 OCR0A
设置比较值时,您必须启用 位 4 – OCIE0A:Timer/Counter0 输出比较匹配 A 中断启用 .
回到 ISR,您需要 ISR(TIMER1_COMPA_vect)
或 ISR(TIMER1_COMPB_vect)
,具体取决于您在 TIMSK 中设置的位。请注意,比较值也应写入匹配寄存器,OCR0A
或OCR0B
。
请注意,您可以在代码中像使用寄存器名称一样使用位名称,在我看来,它使代码更加透明。
您的代码应更改如下以启用相应的中断:
void timer0_init( void )
{
cli();
TCCR0B |= (1<<CS01) | (1<<CS00); //clock select is divided by 64.
TCCR0A |= (1<<WGM01); //sets mode to CTC
OCR0A = 0x7C; //sets TOP to 124 so the timer will overflow every 1 ms.
TIMSK |= (1<<OCIE0A); //Output Compare Match A Interrupt Enable
sei(); //enable global interrupts
}
ISR:
ISR(TIMER0_COMPA_vect)
{
cli();
//ticks ++;
PORTB |= ( 1 << PORTB0 );
sei();
}
你好堆栈溢出的好人。我的问题是一个似乎永远不会执行的中断服务例程 (ISR)!这是有关我的设置的一些信息: 我正在闪烁 avr attiny85。到目前为止,我已经建立了一个项目的基本框架,只有一个 main.c 和两个模块:timer 和 hardwareInit。在定时器模块中,我有一个 timer0_init 函数,我用它来为 CTC 模式设置定时器 0,使其每 1 毫秒溢出一次。这是函数:
void timer0_init( void )
{
cli();
TCCR0B |= 3; //clock select is divided by 64.
TCCR0A |= 2; //sets mode to CTC
OCR0A = 0x7C; //sets TOP to 124 so the timer will overflow every 1 ms.
TIMSK |= 2; //Enable overflow interrupt
sei(); //enable global interrupts
}
设置好计时器后,我添加了一个 ISR 以在每次计数器溢出时增加滴答声,这样我就可以跟踪已经过了多少时间等。
ISR(TIMER0_OVF_vect)
{
cli();
//ticks ++;
PORTB |= ( 1 << PORTB0 );
sei();
}
如你所见,我注释掉了 ticks++,因为它不起作用,并将其替换为 PORTB |= ( 1 << PORTB0 );
,它只是打开一个 LED,所以如果中断被执行,我会知道LED 亮起的证明。
不幸的是,我无法打开它,也看不到我错过了什么。 (为了证明我 1. 将 LED 设置在正确的引脚上,并且 2. 在正确的寄存器中操作正确的位,我只在我的无限循环中放置了这条语句 PORTB |= ( 1 << PORTB0 );
并确认 LED 亮起)
为了进一步解释,这里是我的 main.c:
/*================================= main.c =================================*/
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "timer.h"
#include "hardwareInit.h"
int main(){
//Initialize hardware HERE
DDRB |= ( 1 << PORTB0 ); //set this pin as an output for an LED
SetClockPrescale(1); //internal clock divided by 1 = 8 MHz, from hardwareInit
timer0_init(); //set up timer0 for 1 ms overflow
while(1)
{
/* if( getTicks() > 0 )
{
PORTB |= ( 1 << PORTB0 );
_delay_ms(1000);
PORTB &= ~( 1 << PORTB0 );
_delay_ms(1000);
} */
}
return 0;
}
所以,你在无限循环中看到的是我首先尝试的,但之后没有用,我尝试了一些更简单的东西,只是有一个空循环(注释掉之前的东西),并等待中断被触发,这将打开 LED。
如果您能提供任何帮助,我们将不胜感激。我很困惑为什么这没有用。
正如@andars 正确指出的那样,您使用了错误的 ISR。在 CTC "Clear Timer on Compare" 模式下,定时器永远不会溢出,因为它将在比较匹配时被清除。
所以你也启用了错误的定时器中断。 TIMSK 寄存器的第 1 位启用定时器 0 上的定时器溢出中断。由于前面的原因,不会触发。摘自 datasheet.
当您使用 OCR0A
设置比较值时,您必须启用 位 4 – OCIE0A:Timer/Counter0 输出比较匹配 A 中断启用 .
回到 ISR,您需要 ISR(TIMER1_COMPA_vect)
或 ISR(TIMER1_COMPB_vect)
,具体取决于您在 TIMSK 中设置的位。请注意,比较值也应写入匹配寄存器,OCR0A
或OCR0B
。
请注意,您可以在代码中像使用寄存器名称一样使用位名称,在我看来,它使代码更加透明。
您的代码应更改如下以启用相应的中断:
void timer0_init( void )
{
cli();
TCCR0B |= (1<<CS01) | (1<<CS00); //clock select is divided by 64.
TCCR0A |= (1<<WGM01); //sets mode to CTC
OCR0A = 0x7C; //sets TOP to 124 so the timer will overflow every 1 ms.
TIMSK |= (1<<OCIE0A); //Output Compare Match A Interrupt Enable
sei(); //enable global interrupts
}
ISR:
ISR(TIMER0_COMPA_vect)
{
cli();
//ticks ++;
PORTB |= ( 1 << PORTB0 );
sei();
}