如何通过物理按键终止Arduino程序中正在执行的if条件分支
物理按键终止运行中逻辑的实现方案
完全可以实现,你现有代码无法响应终止按键的核心原因是delay()为阻塞函数,执行delay时MCU会停在当前位置等待计时结束,不会执行按键读取、状态判断等其他代码,因此按下按键不会被识别。
下面提供3种不同改造成本的实现方案:
方案1:拆分阻塞delay(改动最小,适合新手)
如果对计时精度要求不高,只需要把长delay拆分为多次短delay,每次短delay后都检测一次终止按键状态即可,单份delay的拆分粒度越小,按键响应速度越快:
void loop() { val = digitalRead(pushbutton); zhar = digitalRead(pushbutton1); bool abortFlag = false; if (val == LOW) { digitalWrite(fan, HIGH); // 拆分15分钟delay为100ms一次的循环,每次检测按键 for(int i=0; i<9000; i++) { delay(100); if(digitalRead(pushbutton1) == LOW) { abortFlag = true; break; } } if(abortFlag) { digitalWrite(fan, LOW); return; } for (int x = 0; x < 20; x++) { digitalWrite(fan, LOW); delay(400); if(digitalRead(pushbutton1) == LOW) { abortFlag = true; break; } digitalWrite(fan, HIGH); // 拆分15s delay for(int i=0; i<150; i++) { delay(100); if(digitalRead(pushbutton1) == LOW) { abortFlag = true; break; } } if(abortFlag) break; digitalWrite(fan, LOW); delay(2000); if(digitalRead(pushbutton1) == LOW) { abortFlag = true; break; } } if(abortFlag) { digitalWrite(fan, LOW); } } else { digitalWrite(fan, LOW); } }
方案2:非阻塞计时(推荐,无硬件改动)
使用Arduino内置的millis()函数做计时,完全替换掉阻塞的delay(),程序全程不会被卡住,随时可以响应按键操作,计时精度更高:
首先定义全局变量:
unsigned long previousMillis = 0; bool taskRunning = false; int taskStep = 0; int loopCount = 0; int loopStep = 0; bool abortTask = false; const long interval_15min = 900000; const long interval_400ms = 400; const long interval_15s = 15000; const long interval_2s = 2000;
主逻辑代码:
void loop() { val = digitalRead(pushbutton); zhar = digitalRead(pushbutton1); // 检测终止按键 if (zhar == LOW) { abortTask = true; taskRunning = false; digitalWrite(fan, LOW); taskStep = 0; loopCount = 0; loopStep = 0; } // 启动风扇任务 if (val == LOW && !taskRunning && !abortTask) { taskRunning = true; taskStep = 1; previousMillis = millis(); digitalWrite(fan, HIGH); } // 非阻塞执行任务 if (taskRunning && !abortTask) { unsigned long currentMillis = millis(); switch(taskStep) { case 1: // 执行15分钟高电平 if (currentMillis - previousMillis >= interval_15min) { previousMillis = currentMillis; taskStep = 2; loopCount = 0; digitalWrite(fan, LOW); } break; case 2: // 执行20次循环 if (loopCount < 20) { switch(loopStep) { case 0: // 低电平400ms if (currentMillis - previousMillis >= interval_400ms) { previousMillis = currentMillis; digitalWrite(fan, HIGH); loopStep = 1; } break; case 1: // 高电平15s if (currentMillis - previousMillis >= interval_15s) { previousMillis = currentMillis; digitalWrite(fan, LOW); loopStep = 2; } break; case 2: // 低电平2s if (currentMillis - previousMillis >= interval_2s) { previousMillis = currentMillis; loopCount++; loopStep = 0; } break; } } else { // 任务执行完成重置状态 taskRunning = false; taskStep = 0; loopCount = 0; loopStep = 0; } break; } } else { digitalWrite(fan, LOW); // 松开终止按键后重置标记 if (zhar == HIGH) { abortTask = false; } } }
方案3:外部中断(响应速度最快)
如果对终止按键的响应速度要求极高,可以把终止按键接到MCU的外部中断专用引脚(比如Arduino UNO的D2、D3引脚),触发中断时直接修改终止标记位,就算主逻辑有短暂阻塞也能正常响应终止操作。
注意事项
- 机械按键存在物理抖动,建议添加10~20ms的消抖逻辑,避免误触发,可以在第一次检测到按键按下后延时10ms再读一次状态,确认按下再触发终止操作
- 所有方案中终止按键的触发逻辑可以根据你的实际接线调整,默认假设按下为低电平
内容的提问来源于stack exchange,提问作者rami
相关产品推荐
相关产品推荐

