ATmega128 PORTB.4 LED每2秒明暗交替及按键触发故障求助
问题排查与代码修正
原代码核心问题
- 变量复用导致逻辑冲突:同一个
cnt变量同时用于2秒计时和PWM周期计数,2秒触发后cnt被重置为0,后续PWM逻辑无法正常循环。 - PWM控制逻辑错误:仅在2秒触发的单次中断里修改LED状态和
duration,没有在每次定时器中断中持续执行PWM输出逻辑,导致LED只会保持点亮状态。 - 外部中断冗余判断:中断触发时已经对应按键电平,无需再判断
PIND.x,且缺少按键消抖处理,可能引发误触发。
修正后的代码
#include <mega128.h> #include <delay.h> unsigned char direction = 0; // 分离计时变量:timer2sec_cnt负责2秒周期计数,pwm_cnt负责PWM周期计数 unsigned int timer2sec_cnt = 0; unsigned int pwm_cnt = 0; unsigned int duration = 10; // 初始暗态占空比 const unsigned int MAX_PWM = 1000; // PWM周期总数 const unsigned int TIMER_2SEC_CNT = 62500; // 2秒对应的中断次数(匹配你的时钟配置) interrupt [EXT_INT0] void ext_int0_isr(void) { // 软件消抖:延时后再次确认按键电平 delay_ms(20); if (PIND.0 == 1) { direction = 1; } } interrupt [EXT_INT1] void ext_int1_isr(void) { delay_ms(20); if (PIND.1 == 1) { direction = 2; } } interrupt [TIM0_COMP] void time0_comp_isr(void) { if (direction == 1) { // 处理2秒周期的占空比切换 if (timer2sec_cnt++ >= TIMER_2SEC_CNT) { timer2sec_cnt = 0; // 交替切换duration值,实现亮暗交替 duration = (duration == 10) ? 999 : 10; } // 每次中断都执行PWM亮度控制 if (pwm_cnt < duration) { PORTB = 0x10; // LED点亮 } else { PORTB = 0x00; // LED熄灭 } // PWM周期计数循环 if (pwm_cnt++ >= MAX_PWM) { pwm_cnt = 0; } } else { PORTB = 0x00; // 停止计时,重置计数变量 timer2sec_cnt = 0; pwm_cnt = 0; } } void main(void) { DDRB = 0xff; DDRD = 0x00; PORTD = 0xff; // 使能按键上拉电阻 // 外部中断配置:INT0、INT1上升沿触发 EIMSK |= 0x03; EICRA |= 0x0f; // 定时器0配置:CTC模式,分频64 TIMSK |= 0x02; // 使能比较匹配中断 TCCR0 = 0x0B; // 直接赋值替代两次或运算,避免冗余 OCR0 = 15; // 比较值 SREG.7 = 1; // 全局中断使能 for(;;); }
关键修正点说明
- 变量分离:用
timer2sec_cnt专门计数2秒周期,pwm_cnt负责PWM周期循环,彻底解决变量复用的逻辑冲突。 - PWM持续执行:每次定时器中断都执行LED状态判断,保证
duration的占空比能持续控制LED亮度。 - 周期切换逻辑:仅在2秒到达时切换
duration的值,实现每2秒亮暗交替的需求。 - 按键消抖:在外部中断中加入短延时后再次检测按键电平,避免抖动导致的误触发。
- 定时器配置优化:直接赋值
TCCR0替代两次或运算,代码更简洁清晰。
内容的提问来源于stack exchange,提问作者halli
相关产品推荐
相关产品推荐

