You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AVR ATmega32A-PU的INT0中断触发导致MCU复位问题求助

ATmega32A-PU INT0中断触发导致MCU复位问题

问题现象

编程ATmega32A-PU时遇到INT0中断异常:每当PD2引脚的上升沿触发INT0中断时,MCU会复位,程序重新执行main函数开头的代码。TIMER0_COMP_vect中断运行完全正常。

代码片段

#define F_CPU 16000000 // 16 MHz clock speed

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

volatile unsigned int T2StopFlag = 0;
volatile unsigned int initialized = 0;
volatile unsigned long millis_value = 0;


#include "Includes\csrc\u8g2.h"
#include "display.h"
#include "utility.h"

// (utility.h includes:)
/* ----------------------------------------------------------------------- */

IRS(INT0_vect)
{
        PORTA &= ~(1<<6);   // MotorOFF();      
        PORTA &= ~(1<<4);   // RV1OFF();        
        PORTA &= ~(1<<5);   // RV2OFF();        
        T2StopFlag = 1;     // T2StopFlag setzen
}


ISR(TIMER0_COMP_vect)           // ISR for millis();
{
    millis_value++; // Increment millisecond every 1ms
}

unsigned long millis()
{
    unsigned long m;
    
    cli();                  
    m = millis_value;
    sei();

    return m;
}


/* ----------------------------------------------------------------------- */


#include "systemcheck.h"
#include "executions.h"
#include "states.h"
#include "modusoperandi.h"


/* ----------------------------------------------------------------------- */

    
int main(void)
{   

// --- ISR for T2 (INT0) --- //   <- Causes program to restart.
    MCUCR = 0x03;   // 0b 0000 0011 -> INT0 rising edge, INT1 not
    GICR = 0x40;    // 0b 0100 0000 -> INT0 set, INT1 set INT2 not

    
// --- ISR for millis(); --- //  <- Works just fine.
    TCCR0 = 0x0B;   // Clock source: System Clock   // Mode: CTC top=OCR0
    TCNT0 = 0x00;   // Timer/Counter 0 initialization
    OCR0 = 0xF9;    // Clock value: 250.000 kHz (16MHz/64)
    TIMSK = 0x02;   // Enable compare match interrupt for timer 0
    
// --- Enable global interrupt --- //
    sei();


        // ---- StartUp Sequence ---- //
    
    StartUpSeqDemo();   // Run Start Up Sequence once
    ServiceModeReq();   // Request Command to enter Service Mode
    
    // ---- Loop ---- //


    while(1)
    {   
               /* ... */
        
    }   // while(1); end
}         // int main(void); end

已尝试操作

  • 将INT0配置为上升沿触发的中断服务程序
  • 怀疑millis()函数中的cli()和sei()导致问题,注释后结果无变化
  • DMFR

预期结果

  • 程序正常运行,INT0中断触发后继续执行当前任务

实际结果

  • 程序重启,执行while(1)之前的代码

额外编译警告信息

IRS(INT0_vect)存在如下编译警告,而ISR(TIMER0_COMP_vect)无警告:

Warning     type of '__vector_1' defaults to 'int' [-Wimplicit-int]
Warning     return type defaults to 'int' [-Wimplicit-int]
Warning     control reaches end of non-void function [-Wreturn-type]

修改为带返回值的int类型IRS(INT0_vect)后,警告减少为:

Warning     type of '__vector_1' defaults to 'int' [-Wimplicit-int] 

问题根源与解决思路

核心错误:中断宏拼写错误

你把AVR中断服务程序的宏ISR()写成了IRS(),这是导致所有问题的根本原因:

  • AVR的ISR()宏是专门用来定义中断服务函数的,它会自动处理中断上下文的寄存器保存/恢复、设置正确的函数类型(无返回值的void),并将函数地址关联到对应的中断向量表。
  • 错误的IRS()宏不存在,编译器会把它当成普通函数处理,生成的代码不符合中断执行的上下文要求。当INT0中断触发时,程序跳转到这个错误的函数执行,会破坏寄存器状态或程序计数器,最终导致MCU复位。

解决步骤

  1. 修正宏拼写:把IRS(INT0_vect)改为ISR(INT0_vect)
  2. 确保函数类型正确:中断服务函数必须是void类型,不需要返回值(删除你尝试添加的int返回值)
  3. 重新编译:修正后所有编译警告会消失,中断触发时程序能正常执行ISR逻辑,不会复位

额外检查点

  • 修正GICR配置的注释:GICR = 0x40是仅使能INT0(BIT6),注释里写的"INT1 set"是错误的,避免后续混淆
  • 检查PD2引脚硬件:如果修正后仍有异常,排查是否有尖峰干扰导致误触发,或者引脚电平是否符合要求

内容的提问来源于stack exchange,提问作者M.Grae

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 00:10:47