You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 13:47:51