将按钮集成到舵机定时控制循环中按钮失效问题求助
问题根因
- 核心问题是使用了
delay()阻塞函数:代码在执行delay(18000)和delay(6000)的过程中,程序完全暂停运行,不会读取按钮状态,所以按钮触发逻辑根本没有机会执行,自然无响应。 - 按钮逻辑不符合需求:当前代码写的是按钮按下时切换舵机角度,不是你需要的「按住转180°、松开回0°」的效果。
- 定时时长不符合需求:你需要的24小时间隔对应毫秒值为
24*60*60*1000 = 86400000,当前代码写的18000仅为18秒。
解决方案
改用非阻塞的millis()计时替代delay(),程序空闲时持续检测按钮状态,同时满足定时触发和按钮触发两个需求,修正后代码如下:
#include <Servo.h> Servo myservo; const int BUTTON_PIN = 8; const int SERVO_PIN = 9; // 定时相关参数 const unsigned long OPEN_INTERVAL = 24UL * 60 * 60 * 1000; // 24小时间隔,单位毫秒 const unsigned long OPEN_DURATION = 6000; // 开门持续6秒 unsigned long lastOpenTime = 0; bool isTimingOpen = false; void setup(){ myservo.attach(SERVO_PIN); Serial.begin(9600); pinMode(BUTTON_PIN, INPUT_PULLUP); myservo.write(0); } void loop(){ unsigned long currentMillis = millis(); // 优先检测按钮状态 int buttonState = digitalRead(BUTTON_PIN); if(buttonState == LOW){ // 按钮按下(INPUT_PULLUP模式下按下为低电平) myservo.write(180); // 按下按钮时重置定时计时,避免刚松开就触发定时开门 lastOpenTime = currentMillis; isTimingOpen = false; }else{ // 按钮松开时,执行定时逻辑 if(!isTimingOpen){ // 到了开门时间 if(currentMillis - lastOpenTime >= OPEN_INTERVAL){ myservo.write(180); isTimingOpen = true; lastOpenTime = currentMillis; }else{ myservo.write(0); } }else{ // 开门时间到了6秒,关门 if(currentMillis - lastOpenTime >= OPEN_DURATION){ myservo.write(0); isTimingOpen = false; lastOpenTime = currentMillis; } } } }
代码说明
- 用
millis()记录时间戳计算时间差,全程无阻塞,程序每轮循环都会检测按钮状态,按钮响应无延迟。 - 按钮优先级高于定时,按住按钮立即开门,松开立即回到关门状态,同时会重置定时计时,避免和定时逻辑冲突。
- 定时参数可以按需修改,默认24小时间隔开门6秒符合你的需求。
内容的提问来源于stack exchange,提问作者Matthew Kerry
相关产品推荐
相关产品推荐

