Arduino旋转编码器定时器非阻塞延时实现技术求助
解决Arduino非阻塞倒计时与旋转编码器同步问题
Hey there! Let's fix your non-blocking countdown issue so you can run the motor alongside it while still handling the rotary encoder input. The main problem with your current code is that the while (i != 0) loop blocks the entire program—once you press the button, the Arduino can't read the encoder or control the motor until the countdown finishes. Here's how to refactor it to be fully non-blocking:
unsigned long previousMillis = 0; const long interval = 1000; // 1秒倒计时间隔 #define outputA 6 #define outputB 7 #define buttonPin 5 int counter = 0; int remainingTime = 0; bool isCountingDown = false; // 标记是否处于倒计时状态 int aLastState; void setup() { pinMode(outputA, INPUT); pinMode(outputB, INPUT); pinMode(buttonPin, INPUT_PULLUP); // 使用内部上拉电阻,无需外接下拉电阻 Serial.begin(9600); aLastState = digitalRead(outputA); } void loop() { // 1. 处理旋转编码器输入(倒计时期间也能正常响应) int aState = digitalRead(outputA); if (aState != aLastState) { if (digitalRead(outputB) != aState) { counter++; } else { counter--; } // 仅在非倒计时状态下更新串口显示设定时间 if (!isCountingDown) { Serial.print("Time (secs): "); Serial.println(counter); } aLastState = aState; } // 2. 处理按键触发(仅在非倒计时状态下启动倒计时) if (!isCountingDown && digitalRead(buttonPin) == LOW) { // 简单消抖,避免按键误触发 delay(50); if (digitalRead(buttonPin) == LOW) { remainingTime = counter; isCountingDown = true; Serial.print("Starting countdown from: "); Serial.println(remainingTime); } } // 3. 非阻塞倒计时逻辑 if (isCountingDown) { unsigned long currentMillis = millis(); // 使用>=判断,避免因代码执行延迟错过精确的时间点 if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; remainingTime--; Serial.println(remainingTime); // 在这里添加你的电机控制代码! // 示例:digitalWrite(motorPin, HIGH); 根据需求调整 if (remainingTime <= 0) { isCountingDown = false; Serial.println("Countdown finished!"); // 倒计时结束后可在此停止电机 // digitalWrite(motorPin, LOW); } } } // 4. 在这里添加需要持续运行的电机控制代码 // (例如:根据其他输入调整电机转速、方向等) }
关键改进说明:
- 非阻塞结构:移除了阻塞程序的
while循环,改用isCountingDown状态变量跟踪倒计时状态,每次loop()循环都会处理编码器、按键、倒计时和电机控制任务,不会出现程序卡顿。 - 按键消抖:添加了50ms的简单消抖,避免按键机械弹跳导致的误触发;如果需要完全非阻塞的消抖,也可以用
millis()实现更复杂的消抖逻辑。 - 内部上拉电阻:将按键引脚设置为
INPUT_PULLUP,无需外接下拉电阻,只需将按键连接引脚和地即可。 - 分离状态变量:
counter存储用户设定的时间,remainingTime跟踪倒计时剩余时间,即使未启动倒计时,也能随时用编码器调整设定值。 - 电机集成点:代码中预留了两处电机控制的位置,分别对应倒计时每秒触发的动作,以及需要持续运行的电机逻辑。
内容的提问来源于stack exchange,提问作者Chandra Sekhar Gudipati
相关产品推荐
相关产品推荐

