AVR交通灯系统中断按键与LED工作异常 运行时4颗LED全亮
问题排查与修复方案
核心错误点
- 全局状态变量
state未显式初始化,默认值为枚举第一个值EW,无法进入启动初始化逻辑 - 主循环无计时等待逻辑,会无限高速执行端口切换,LED高频闪烁人眼识别为常亮
- 定时器中断逻辑不满足计时需求,没有区分正常模式和行人模式的不同计时阈值
- 行人模式触发逻辑不符合需求,没有等待当前通行阶段走完再切换
- 未引入
<stdbool.h>头文件,boolean类型编译会报错
修复后完整代码
#include <avr/io.h> #include <avr/interrupt.h> #include <stdbool.h> volatile uint8_t second = 0; volatile bool buttonPressed = false; enum light_state {EW, SN, PES_FIRST, PES_SECOND, START_UP}; enum light_state state = START_UP; int main(void) { DDRB = 0xFF; // 所有PB引脚设为输出 PORTB = 0x00; // 初始所有LED熄灭 DDRD &= ~(1 << 2); // PD2设为输入 PORTD |= (1 << PORTD2); // 启用上拉电阻 // 外部中断0配置,下降沿触发 EIMSK |= (1 << INT0); EICRA |= (1 << ISC01); EIFR |= (1 << INTF0); // 定时器1配置,CTC模式,1024预分频,1秒触发一次中断 TCCR1B |= (1 << WGM12) | (1 << CS12) | (1 << CS10); OCR1A = 15624; // 16MHz/1024 -1 = 15624,对应1秒 TIMSK1 |= (1 << OCIE1A); sei(); while (1) { switch(state) { case START_UP: PORTB = 0x00; second = 0; state = SN; // 初始进入SN阶段:LED1+LED4亮 break; case SN: // SN阶段:LED1(PB1)、LED4(PB4)亮4秒 PORTB = (1 << PB1) | (1 << PB4); if(second >=4) { second = 0; if(buttonPressed) { state = PES_FIRST; // 有按键,进入行人模式第一阶段 buttonPressed = false; } else { state = EW; // 无按键,进入EW阶段 } } break; case EW: // EW阶段:LED2(PB2)、LED3(PB3)亮4秒 PORTB = (1 << PB2) | (1 << PB3); if(second >=4) { second = 0; state = SN; } break; case PES_FIRST: // 行人模式第一阶段:LED2+LED5亮2秒 PORTB = (1 << PB2) | (1 << PB5); if(second >=2) { second = 0; state = PES_SECOND; } break; case PES_SECOND: // 行人模式第二阶段:LED2+LED3亮2秒 PORTB = (1 << PB2) | (1 << PB3); if(second >=2) { second = 0; state = SN; } break; default: state = START_UP; break; } } } // 按键中断 ISR(INT0_vect) { buttonPressed = true; } // 定时器中断,1秒触发一次 ISR(TIMER1_COMPA_vect) { second++; }
修复说明
- 新增了行人模式的两个状态
PES_FIRST和PES_SECOND,分别对应LED5亮2秒、LED3亮2秒的阶段,LED2全程保持点亮 - 主循环增加计时判断,只有计时到对应阈值才切换状态,避免端口高速翻转
- 状态初始化显式指定为
START_UP,启动时所有LED熄灭 - 增加
<stdbool.h>头文件引入,解决bool类型编译问题 - 行人模式触发逻辑只有在SN阶段结束后才会进入,符合“等待LED1、LED4熄灭后再工作”的需求
内容的提问来源于stack exchange,提问作者Trần Thiên
相关产品推荐
相关产品推荐

