AVR汇编下ATMega328p INT0外部中断无法触发问题求助
AVR汇编INT0中断无法触发的问题排查与修复
你的代码存在以下几处问题,按影响优先级排序:
1. 核心错误:EIMSK寄存器写入指令错误
ATMega328p的EIMSK(外部中断掩码寄存器)属于低地址IO寄存器,IO地址为0x1D,仅支持使用out指令直接写入IO空间。
你使用sts EIMSK, r16写入时,默认头文件中EIMSK定义为IO地址0x1D,sts指令是向数据空间写入,数据空间0x1D对应通用寄存器r29的地址,根本没有写入到中断控制寄存器,导致INT0中断从未开启。
修复方案:将sts EIMSK, r16改为out EIMSK, r16。
2. PD2引脚输入模式配置不合理
你通过cbi PORTD, 0x02将PD2设置为浮空输入,没有开启内部上拉,引脚电平处于不确定状态,即使外接触发信号也可能无法正常识别电平变化。
修复方案:如果你的触发逻辑是外部拉低PD2触发中断,将cbi PORTD, 0x02改为sbi PORTD, 0x02开启内部上拉电阻,引脚默认电平为高,外部拉低即可触发。
3. EICRA配置存在冗余(可选优化)
你写入EICRA的值为0x05(二进制00000101),除了配置INT0为电平变化触发外,还意外开启了INT1的电平变化触发,属于多余配置。
如果你的需求是INT0电平变化触发,修改为ldi r16, 0x01即可;如果需要其他触发模式,调整对应位即可:
- 下降沿触发:
ldi r16, 0x02(ISC01=1,ISC00=0) - 上升沿触发:
ldi r16, 0x03(ISC01=1,ISC00=1)
4. 中断服务程序写法存在隐患
你使用全局寄存器r16保存LED状态,虽然当前主循环不会修改r16,但后续代码扩展后很容易出现冲突。更可靠的LED翻转方式是直接写PINB寄存器:向PIN寄存器的对应位写1即可自动翻转IO电平,不需要额外寄存器保存状态。
修正后的完整代码
.list .org 0x0000 rjmp main .org 0x0002 rjmp INT0_ISR .org INT_VECTORS_SIZE .def dreg = r18 main: cli ldi r17, LOW(RAMEND) out SPL, r17 ldi r17, HIGH(RAMEND) out SPH, r17 ; 设置栈指针 sbi DDRB, 0x05 ; 设置PB5为输出(对应D13) sbi PORTB, 0x05 ; 初始点亮LED cbi DDRD, 0x02 ; 设置PD2为输入 sbi PORTD, 0x02 ; 开启PD2内部上拉 ldi r16, 0x01 ; 使能INT0中断 out EIMSK, r16 ; 改用out指令写EIMSK ldi r16, 0x02 ; 配置INT0为下降沿触发 sts EICRA, r16 sei loop: rjmp loop INT0_ISR: push r17 in r17, SREG ; 保存状态寄存器 sbi PINB, 5 ; 直接翻转PB5电平 out SREG, r17 ; 恢复状态寄存器 pop r17 reti ; 退出中断
内容的提问来源于stack exchange,提问作者Chandler Klüser
相关产品推荐
相关产品推荐

