如何修改Arduino代码实现单次按键停止步进电机与伺服电机?
单次按键停止步进电机与伺服电机的Arduino代码修改方案
问题描述
当前代码需要长按按键才能停止步进电机和伺服电机,希望修改为单次按下按键即可触发停止操作,且停止后保持状态(直到重启或其他触发)。原代码存在两个核心问题:
- 依赖持续检测按键按下状态(
buttonState == LOW),只有长按才会执行停止逻辑; - 伺服电机控制中使用
delay()阻塞程序,导致按键检测被中断,短按可能无法被识别。
修改思路
- 按键触发检测:使用按键下降沿检测(INPUT_PULLUP模式下,按键按下时引脚为LOW),只在按键按下的瞬间触发停止动作,而非持续检测状态;
- 消抖处理:添加按键消抖逻辑,避免机械按键的抖动导致误触发;
- 替换阻塞延时:用
millis()替代delay()控制伺服电机动作,确保程序始终能响应按键输入; - 状态控制:添加全局状态变量
systemActive,标记系统是否处于运行状态,触发停止后锁定状态。
修改后的完整代码
// Include the necessary libraries #include <AccelStepper.h> #include <Servo.h> // Define the pins for the components int irSensor = 7; int servo1Pin = 5; int servo2Pin = 6; int buttonPin = 2; #define MP1 8 // IN1 on the ULN2003 #define MP2 9 // IN2 on the ULN2003 #define MP3 10 // IN3 on the ULN2003 #define MP4 11 // IN4 on the ULN2003 #define MotorInterfaceType 8 // Define the interface type as 8 = 4 wires * step factor (2 for half step) // Initialize the components AccelStepper stepper = AccelStepper(MotorInterfaceType, MP1, MP3, MP2, MP4);//Define the pin sequence (IN1-IN3-IN2-IN4) Servo myServo1; Servo myServo2; // 按键与状态控制变量 bool systemActive = true; // 系统运行状态标记 bool lastButtonState = HIGH; // 上一次按键状态 bool currentButtonState; // 当前按键状态 unsigned long lastDebounceTime = 0; // 消抖时间记录 unsigned long debounceDelay = 50; // 消抖延时(毫秒) // 伺服电机时序控制变量 unsigned long servoTimer = 0; int servoStep = 0; // 伺服动作步骤:0-初始,1-转0度,2-转180度,3-切换第二个伺服,4-转0度,5-转180度 void setup() { Serial.begin(9600); pinMode(irSensor, INPUT); pinMode(buttonPin, INPUT_PULLUP); // Set the button pin mode to input with pull-up resistor myServo1.attach(servo1Pin); myServo2.attach(servo2Pin); // Set up the stepper motor stepper.setMaxSpeed(1000); // Set the maximum motor speed in steps per second stepper.setAcceleration(200); // Set the maximum acceleration in steps per second^2 } void loop() { // 优先处理按键检测 checkStopButton(); if (systemActive) { int irValue = digitalRead(irSensor); if (irValue == 0) { // 用millis()实现非阻塞的伺服动作 runServosNonBlocking(); } else if (irValue == 1) { stepper.setSpeed(500); stepper.runSpeed(); } } else { // 系统停止状态:保持电机和伺服的停止位置 myServo1.write(90); myServo2.write(90); stepper.stop(); } } // 检测停止按键(单次按下触发) void checkStopButton() { currentButtonState = digitalRead(buttonPin); // 消抖逻辑:状态变化且超过消抖延时 if (currentButtonState != lastButtonState) { lastDebounceTime = millis(); } if ((millis() - lastDebounceTime) > debounceDelay) { // 确认状态稳定,且检测到按键按下(下降沿) if (currentButtonState == LOW && lastButtonState == HIGH) { systemActive = false; // 触发停止 Serial.println("系统已停止"); } } lastButtonState = currentButtonState; } // 非阻塞式伺服电机控制 void runServosNonBlocking() { unsigned long currentMillis = millis(); switch(servoStep) { case 0: myServo1.write(0); servoTimer = currentMillis; servoStep = 1; break; case 1: if (currentMillis - servoTimer >= 1000) { myServo1.write(180); servoTimer = currentMillis; servoStep = 2; } break; case 2: if (currentMillis - servoTimer >= 3000) { myServo2.write(0); servoTimer = currentMillis; servoStep = 3; } break; case 3: if (currentMillis - servoTimer >= 1000) { myServo2.write(180); servoTimer = currentMillis; servoStep = 4; } break; case 4: if (currentMillis - servoTimer >= 3000) { servoStep = 0; // 循环动作 } break; } }
代码说明
- 按键检测:通过消抖逻辑捕捉按键按下的瞬间(下降沿),仅触发一次停止动作,无需长按;
- 非阻塞延时:用
millis()替代delay(),确保程序在执行伺服动作时仍能实时响应按键输入; - 状态锁定:
systemActive变量标记系统状态,触发停止后保持停止状态,直到重启或添加重置逻辑。
内容的提问来源于stack exchange,提问作者Atahan Mert Parsak
相关产品推荐
相关产品推荐

