Timer 使用ATmega48PA中断时的未定义行为

Timer 使用ATmega48PA中断时的未定义行为,timer,microcontroller,interrupt,avr,interrupt-handling,Timer,Microcontroller,Interrupt,Avr,Interrupt Handling,我正在构建一个简单的计时器/计数器应用程序,它使用Atmel的ATmega48PA中的正常模式生成延迟,使用计时器1,以恒定的时间间隔切换LED。使用中断时,LED会切换一定的时间,然后切换效果停止,使LED始终亮起! 我相信sei()函数或在SREG中启用全局中断是有原因的,因为我以前在使用中断时曾在同一个微控制器上体验过这种行为 下面是我的问题附带的一段代码片段,尽管任何人都会认为这段代码非常正常,必须正常工作 #include <avr/io.h> #include <a

我正在构建一个简单的计时器/计数器应用程序,它使用Atmel的ATmega48PA中的正常模式生成延迟,使用计时器1,以恒定的时间间隔切换LED。使用中断时,LED会切换一定的时间,然后切换效果停止,使LED始终亮起! 我相信sei()函数或在SREG中启用全局中断是有原因的,因为我以前在使用中断时曾在同一个微控制器上体验过这种行为

下面是我的问题附带的一段代码片段,尽管任何人都会认为这段代码非常正常,必须正常工作

#include <avr/io.h>
#include <atmel_start.h>
#include <util/delay.h>
#include <math.h>
#include <clock_config.h>
#include "avr/iom48pa.h"

#define LOAD_VALUE      49911UL

#define SET_BIT( REG, BIT )                 REG |= ( 1 << BIT )
#define CLR_BIT( REG, BIT )                 REG &= ~( 1 << BIT )
#define TOG_BIT( REG, BIT )                 REG ^= ( 1 << BIT )

void Timer16_Init( void );
void Timer16_DelayMS( unsigned short delayMS );

unsigned short delayMS = 50;

ISR( TIMER1_OVF_vect ){
    Disable_global_interrupt();
    TOG_BIT( PORTC, 2 );
    TOG_BIT( PORTC, 3 );
    TCNT1 = ( ( 4194304 - delayMS ) * 1000 ) / 64;
    Enable_global_interrupt();
}

int main( void ){
    
    /* Initializes MCU, drivers and middle ware */
    atmel_start_init();
     
     /* configure pin 2 and pin 3 in PORTC as output */
     SET_BIT( DDRC, 3 );
     SET_BIT( DDRC, 2 );
     
     Enable_global_interrupt();
     Timer16_Init();
     TCNT1 = ( ( 4194304 - delayMS ) * 1000 ) / 64;

    while( 1 ){
        
    }
}
void Timer16_Init( void ){
    SET_BIT( TCCR1B, CS10 );
    SET_BIT( TCCR1B, CS12 );
    SET_BIT( TIMSK1, TOIE1 );
}
#包括
#包括
#包括
#包括
#包括
#包括“avr/iom48pa.h”
#定义加载值49911UL

#定义SET_BIT(REG,BIT)REG |=(1好的,第一眼看,代码中没有特殊问题。因此,让我们检查一下可能性:

首先您完成了一些32位长的计算,并将结果放入16位寄存器:

TCNT1=((4194304-delayMS)*1000)/64;
它会导致在寄存器中输入不可预测的值。因此,我建议您使用适当的值或在代码中使用(long)和(int)来防止数据溢出

Second您没有输入正确的数据行顺序:

Enable_global_interrupt();
Timer16_Init();
TCNT1 = ( ( 4194304 - delayMS ) * 1000 ) / 64;
您启用了中断,然后初始化了计时器,然后应用了计时器的值。这是不正确的,因为计时器运行并且能够进行中断,但其值尚未设置。顺序必须如下所示:

TCNT1 = ( ( 4194304 - delayMS ) * 1000 ) / 64;    
Enable_global_interrupt();
Timer16_Init();

Third您已在正常模式下使用计时器,输入溢出中断并在中断例程中设置计时器值。我强烈建议您改用比较模式,因为它不需要在中断例程中设置计时器值。

4194304
不适合该部分的16位计时器。t他写了申请说明,告诉你怎么做。请阅读。谢谢你的回答,非常有帮助!