Arduino test函数运行异常 按键后直接触发die函数问题排查
问题说明
- 约束要求:循环逻辑不能依赖
if函数实现判断分支 - 故障现象:
- 按下按键后,无论
colour与light取何值,都会直接进入die()函数,生命值从2跳变为-1 - 按键按下时,绝大多数场景下会重复执行
test()函数,直到程序触发终止逻辑
- 按下按键后,无论
- 原有问题代码:
boolean test(void) { if (light==0) { return false; } ; if ( BIT_IS_SET(PINB, 2) ) { if ((colour==1 && light==4)||(colour==0 && light==5)) { mark=mark+100; light=0; return true; } else { life=life-1; analogWrite(SPEAKERPIN,200); delay(10); analogWrite(SPEAKERPIN,0); light=0; return true; } ; } delay(10); if(BIT_IS_SET(PINB, 3)) { if ((colour==1 && light==5)||(colour==0 && light==4)) { mark=mark+100; light=0; return true; } else { life=life-1; analogWrite(SPEAKERPIN,200); delay(10); analogWrite(SPEAKERPIN,0); light=0; return true; } } return false; } void loop() { game(); while(test()==false) { } ; if(life<0) { die(); } }
故障根因
- 无按键锁存/释放检测逻辑:机械按键按下后会保持几十毫秒的有效触发电平,原代码检测到按键电平触发后,没有等待按键释放就返回。主循环
loop会在按键保持按下的周期内反复执行game()→test()流程,每轮都触发一次扣血逻辑,初始2点生命值连续扣3次就会跳到-1,直接触发死亡逻辑。 - 分支逻辑冗余冲突:检测到PINB2按键触发后,无论匹配是否成功都会直接
return true,后续的10ms消抖延时、PINB3按键检测逻辑永远不会执行,两个按键实际只有一个能生效。 - 循环判断依赖多层if嵌套:不符合需求的实现约束,多层嵌套也容易引入逻辑漏洞。
修复方案(无if依赖实现)
用位运算+三目运算符+状态查表替代所有循环内的if分支判断,同时增加按键释放等待逻辑,避免单次按键重复触发:
// 匹配状态查表:match_map[colour][light] = 1为按键匹配加分,0为不匹配扣血 const uint8_t match_map[2][6] = { [0] = {[4] = 0, [5] = 1}, // colour=0时,PB3对应light=4、PB2对应light=5 [1] = {[4] = 1, [5] = 0} // colour=1时,PB2对应light=4、PB3对应light=5 }; #define KEY_MASK ((1<<2)|(1<<3)) boolean test(void) { // 三目运算替代if判断light状态 return (light == 0) ? false : // 位运算读取按键状态,非0代表有按键按下 ((PINB & KEY_MASK) != 0) ? ( // 10ms消抖 delay(10), // 二次确认按键电平,位运算判断按下的键位 uint8_t key = PINB & KEY_MASK, // 等待按键释放,避免重复触发 while(PINB & KEY_MASK), // 查表判断当前按键与灯光、颜色是否匹配 uint8_t is_match = (key == (1<<2)) ? match_map[colour][light] : match_map[colour][light] ^ 1, // 匹配加分/不匹配扣血+蜂鸣提示,用逗号表达式顺序执行 is_match ? (mark += 100) : ( life -=1, analogWrite(SPEAKERPIN,200), delay(10), analogWrite(SPEAKERPIN,0) ), // 复位灯光状态 light = 0, true ) : false; } void loop() { game(); // 循环等待test返回true,无if嵌套 while(!test()); // 三目运算替代if判断生命值 (life < 0) ? die() : (void)0; }
- 所有循环判断、分支选择都通过位运算、三目运算符、查表实现,没有依赖if语句做分支控制
- 增加了10ms硬件消抖+按键释放等待逻辑,单次按键按下只会触发一次判定,不会连续扣血
- 去掉了冗余的空语句和不可达代码,两个按键的判定逻辑统一处理,不会出现分支被截断的问题
内容的提问来源于stack exchange,提问作者lokhin sham
相关产品推荐
相关产品推荐

