送锡器控制系统fd32_4988_v1

步进电机控制系统详细说明

1. 系统概述

本代码实现了一个完整的步进电机控制系统,支持两种操作模式:点动模式(JOG)和自动循环模式(RUN)。系统通过电位器调节速度和步数,通过按钮控制启停和模式切换,并配有LED状态指示。

2. 主要功能

  • 双模式控制:点动模式(按住按钮运行)和自动循环模式(自动正反转循环)
  • 参数调节
    • 速度调节(通过电位器)
    • 正/反转步数独立调节(通过电位器)
  • 安全保护:急停按钮立即停止电机
  • 状态指示:LED显示当前模式和运行状态
  • 微步控制:支持全步和1/16微步模式

    3. 硬件接线说明

    3.1 所需组件

  • STM32开发板
  • 步进电机驱动器(如A4988、DRV8825等)
  • 步进电机
  • 10kΩ线性电位器×3
  • 按钮×3
  • LED×2(不同颜色)
  • 电阻(220Ω用于LED限流)
  • 电源(根据电机需求)

    3.2 接线表

    元件引脚 开发板引脚 说明
    驱动器EN PB0 使能信号(低电平有效)
    驱动器STEP PA8 步进脉冲
    驱动器DIR PB1 方向控制
    驱动器MS1 PB12 微步控制1
    驱动器MS2 PB13 微步控制2
    驱动器MS3 PB14 微步控制3
    电位器1中间脚 PA0 正转步数调节
    电位器2中间脚 PA1 反转步数调节
    电位器3中间脚 PA2 速度调节
    模式按钮 PA3 模式切换(接GND触发)
    动作按钮 PA4 启动/停止(接GND触发)
    急停按钮 PA5 紧急停止(接GND触发)
    JOG模式LED PB10 通过220Ω电阻接地
    RUN模式LED PB11 通过220Ω电阻接地

    4. 使用方法

    4.1 基本操作流程

    1. 上电后系统默认进入RUN模式(RUN LED常亮)
    2. 旋转速度电位器调节运行速度
    3. 旋转正/反转电位器分别设置正转和反转步数
    4. 按下动作按钮开始自动循环运行
    5. 按下模式按钮可切换到JOG模式(JOG LED常亮)
    6. 在JOG模式下,按住动作按钮电机运行,松开停止
    7. 任何时候按下急停按钮立即停止电机

      4.2 LED状态指示

  • 常亮:表示当前处于该模式(IDLE状态)
  • 闪烁:表示正在该模式下运行
  • 熄灭:表示非当前模式

    5. 代码结构详解

    5.1 主要参数配置

    // 步数范围
    #define MIN_STEPS_CW    0     // 正转最小步数
    #define MAX_STEPS_CW    6000  // 正转最大步数
    // 速度范围(单位微秒)
    #define DEFAULT_MIN_SPEED  5000    // 最快速度(200步/秒)
    #define DEFAULT_MAX_SPEED  500000  // 最慢速度(2步/秒)

    5.2 核心功能函数

    电位器滤波读取

    int filteredAnalogRead(int pin) {
    // 使用移动平均滤波消除噪声
    static int readings[FILTER_SAMPLES] = {0};
    // ...滤波计算...
    return total / FILTER_SAMPLES;
    }

    速度计算

    unsigned long calculateStepDelay(int potValue, bool isJogging) {
    // 使用指数映射实现非线性速度调节
    float expValue = pow(normalized, SPEED_EXPONENT);
    return minSpeed + (unsigned long)(expValue * (maxSpeed - minSpeed));
    }

    电机控制

    void enableMotor() {
    digitalWrite(EN_PIN, LOW); // 驱动器使能
    }
    void disableMotor() {
    digitalWrite(EN_PIN, HIGH); // 驱动器禁用
    }

    5.3 主循环逻辑

    void loop() {
    // 1. 按钮状态检测(带消抖)
    // 2. 根据当前模式处理电机控制:
    //    - IDLE: 等待按钮触发
    //    - JOGGING: 按住按钮时运行
    //    - RUNNING: 自动完成设定的正反转循环
    }

    6. 参数调优建议

    6.1 速度调节

  • 修改DEFAULT_MIN_SPEEDDEFAULT_MAX_SPEED调整速度范围
  • 调整SPEED_EXPONENT(1.0-3.0)改变速度变化曲线

    6.2 步数调节

  • 修改MAX_STEPS_CWMAX_STEPS_CCW调整最大步数
  • 调整FILTER_SAMPLES(3-10)改变电位器响应速度

    6.3 微步设置

    setMicrosteps(16); // 可改为1(全步)、2、4、8、16等

    7. 注意事项

    1. 确保电机电源与逻辑电源隔离
    2. 长距离接线时使用屏蔽线减少干扰
    3. 急停按钮应使用常闭触点,直接切断电机电源更安全
    4. 首次使用时从低速开始测试,逐步提高速度
    5. 确保散热良好,特别是驱动器芯片

      8. 扩展建议

  • 增加限位开关保护
  • 添加加速度控制使启停更平滑
  • 通过EEPROM保存常用参数
  • 增加更多微步模式选择 这个系统提供了灵活的步进电机控制方案,适用于需要精确位置控制的各种应用场景。

9. 程序代码

#include <Arduino.h>

// =============== 硬件引脚定义 ===============
#define EN_PIN          PB0   // 驱动器使能(低电平有效)
#define STEP_PIN        PA8   // 步进脉冲
#define DIR_PIN         PB1   // 方向控制
#define MS1_PIN         PB12  // 微步控制1
#define MS2_PIN         PB13  // 微步控制2
#define MS3_PIN         PB14  // 微步控制3
#define POT_STEPS_CW    PA0   // 正转步数电位器
#define POT_STEPS_CCW   PA1   // 反转步数电位器
#define POT_SPEED       PA2   // 速度电位器
#define BUTTON_MODE     PA3   // 模式切换按钮
#define BUTTON_ACTION   PA4   // 动作按钮
#define BUTTON_STOP     PA5   // 急停按钮
#define LED_JOG         PB10  // 点动模式指示灯
#define LED_RUN         PB11  // 运行模式指示灯

// =============== 可配置参数 ===============
// 步数范围 (电位器映射范围)
#define MIN_STEPS_CW    0     // 正转最小步数
#define MAX_STEPS_CW    6000  // 正转最大步数
#define MIN_STEPS_CCW   0     // 反转最小步数
#define MAX_STEPS_CCW   6000  // 反转最大步数

// 速度范围 (单位: 微秒, 值越小速度越快)
#define DEFAULT_MIN_SPEED       5000    // 默认最快速度 (20us/步)
#define DEFAULT_MAX_SPEED       500000 // 默认最慢速度 (10000us/步)
#define SPEED_EXPONENT  2.5   // 非线性映射指数 (1.0为线性)

// 点动模式速度范围
#define JOG_MIN_SPEED   5000    // 点动最快速度
#define JOG_MAX_SPEED   500000  // 点动最慢速度
#define JOG_SPEED_EXPONENT 2.5 // 点动模式非线性指数

// 系统参数
#define BUTTON_DEBOUNCE 50     // 按钮消抖时间(ms)
#define STATUS_UPDATE_INTERVAL 1000 // 状态更新间隔(ms)
#define SPEED_UPDATE_INTERVAL 100   // 速度更新间隔(ms)
#define FILTER_SAMPLES  5      // 电位器滤波采样数

// =============== 系统状态定义 ===============
enum OperationMode { JOG_MODE, RUN_MODE };
OperationMode currentMode = RUN_MODE;

enum MotorState { IDLE, JOGGING, RUNNING };
MotorState motorState = IDLE;

bool emergencyStop = false;

// 自动循环参数
unsigned long stepsToMoveCW = 0;
unsigned long stepsToMoveCCW = 0;
unsigned long stepsMoved = 0;
unsigned long stepDelay = 0;
int autoPhase = 0;

// 按钮状态管理
bool modeButtonPressed = false;
bool actionButtonPressed = false;
bool actionButtonActive = false;
bool actionButtonConsumed = false;

// 时间跟踪
unsigned long lastStepTime = 0;
unsigned long lastButtonCheck = 0;
unsigned long lastSpeedUpdate = 0;

// 可调速度参数
unsigned long minSpeed = DEFAULT_MIN_SPEED;
unsigned long maxSpeed = DEFAULT_MAX_SPEED;

// =============== 功能函数 ===============
int filteredAnalogRead(int pin) {
  static int readings[FILTER_SAMPLES] = {0};
  static int index = 0;
  static long total = 0;

  total -= readings[index];
  readings[index] = analogRead(pin);
  total += readings[index];
  index = (index + 1) % FILTER_SAMPLES;

  return total / FILTER_SAMPLES;
}

unsigned long calculateStepDelay(int potValue, bool isJogging = false) {
  float normalized = (float)constrain(potValue, 0, 4095) / 4095.0;
  float expValue;

  if(isJogging) {
    expValue = pow(normalized, JOG_SPEED_EXPONENT);
    return JOG_MIN_SPEED + (unsigned long)(expValue * (JOG_MAX_SPEED - JOG_MIN_SPEED));
  } else {
    expValue = pow(normalized, SPEED_EXPONENT);
    return minSpeed + (unsigned long)(expValue * (maxSpeed - minSpeed));
  }
}

void setMicrosteps(uint8_t mode) {
  switch(mode) {
    case 1: // 全步
      digitalWrite(MS1_PIN, LOW);
      digitalWrite(MS2_PIN, LOW);
      digitalWrite(MS3_PIN, LOW);
      break;
    case 16: // 1/16步
      digitalWrite(MS1_PIN, HIGH);
      digitalWrite(MS2_PIN, HIGH);
      digitalWrite(MS3_PIN, HIGH);
      break;
    default: // 默认全步
      digitalWrite(MS1_PIN, LOW);
      digitalWrite(MS2_PIN, LOW);
      digitalWrite(MS3_PIN, LOW);
  }
}

void updateLEDs() {
  static unsigned long lastBlinkTime = 0;
  static bool ledState = false;

  if (motorState == IDLE) {
    digitalWrite(LED_JOG, currentMode == JOG_MODE ? HIGH : LOW);
    digitalWrite(LED_RUN, currentMode == RUN_MODE ? HIGH : LOW);
  } else {
    if(millis() - lastBlinkTime > 300) {
      lastBlinkTime = millis();
      ledState = !ledState;
      digitalWrite(LED_JOG, motorState == JOGGING ? ledState : LOW);
      digitalWrite(LED_RUN, motorState == RUNNING ? ledState : LOW);
    }
  }
}

void enableMotor() {
  if (emergencyStop) return;
  digitalWrite(EN_PIN, LOW);
}

void disableMotor() {
  digitalWrite(EN_PIN, HIGH);
}

void toggleMode() {
  currentMode = (currentMode == JOG_MODE) ? RUN_MODE : JOG_MODE;
  updateLEDs();
}

void startAutoCycle() {
  stepsToMoveCW = map(filteredAnalogRead(POT_STEPS_CW), 0, 4095, MIN_STEPS_CW, MAX_STEPS_CW);
  stepsToMoveCCW = map(filteredAnalogRead(POT_STEPS_CCW), 0, 4095, MIN_STEPS_CCW, MAX_STEPS_CCW);
  stepDelay = calculateStepDelay(filteredAnalogRead(POT_SPEED));

  if (stepsToMoveCCW < 50) stepsToMoveCCW = 0;

  motorState = RUNNING;
  autoPhase = 0;
  stepsMoved = 0;
  digitalWrite(DIR_PIN, HIGH);
  enableMotor();
  updateLEDs();
}

void nextAutoPhase() {
  if (autoPhase == 0 && stepsToMoveCCW > 0) {
    autoPhase = 1;
    stepsMoved = 0;
    digitalWrite(DIR_PIN, LOW);
  } else {
    motorState = IDLE;
    disableMotor();
    updateLEDs();
  }
}

void setup() {
  pinMode(BUTTON_MODE, INPUT_PULLUP);
  pinMode(BUTTON_ACTION, INPUT_PULLUP);
  pinMode(BUTTON_STOP, INPUT_PULLUP);
  pinMode(LED_JOG, OUTPUT);
  pinMode(LED_RUN, OUTPUT);

  pinMode(EN_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);
  pinMode(MS1_PIN, OUTPUT);
  pinMode(MS2_PIN, OUTPUT);
  pinMode(MS3_PIN, OUTPUT);

  setMicrosteps(16);
  updateLEDs();
  disableMotor();
}

void loop() {
  unsigned long currentMicros = micros();
  unsigned long currentMillis = millis();

  // 按钮状态检测
  if (currentMillis - lastButtonCheck >= BUTTON_DEBOUNCE) {
    if (!digitalRead(BUTTON_MODE)) {
      if (!modeButtonPressed) {
        modeButtonPressed = true;
        if (motorState == IDLE) toggleMode();
      }
    } else {
      modeButtonPressed = false;
    }

    if (!digitalRead(BUTTON_ACTION)) {
      if (!actionButtonPressed) {
        actionButtonPressed = true;
        actionButtonActive = true;
        actionButtonConsumed = false;
      }
    } else {
      actionButtonPressed = false;
      actionButtonActive = false;
    }

    if (!digitalRead(BUTTON_STOP)) {
      if (!emergencyStop) {
        emergencyStop = true;
        motorState = IDLE;
        disableMotor();
        updateLEDs();
      }
    } else if (emergencyStop) {
      emergencyStop = false;
    }

    lastButtonCheck = currentMillis;
  }

  // 电机状态机
  switch(motorState) {
    case IDLE:
      if (actionButtonActive && !actionButtonConsumed && !emergencyStop) {
        if (currentMode == JOG_MODE) {
          motorState = JOGGING;
          enableMotor();
          updateLEDs();
        } else {
          startAutoCycle();
        }
        actionButtonConsumed = true;
      }
      break;

    case JOGGING:
      if (currentMillis - lastSpeedUpdate >= SPEED_UPDATE_INTERVAL) {
        stepDelay = calculateStepDelay(filteredAnalogRead(POT_SPEED), true);
        lastSpeedUpdate = currentMillis;
      }

      digitalWrite(DIR_PIN, HIGH);

      if (currentMicros - lastStepTime >= stepDelay) {
        digitalWrite(STEP_PIN, HIGH);
        delayMicroseconds(2);
        digitalWrite(STEP_PIN, LOW);
        lastStepTime = currentMicros;
      }

      if (!actionButtonActive) {
        motorState = IDLE;
        disableMotor();
        updateLEDs();
      }
      break;

    case RUNNING:
      if (currentMillis - lastSpeedUpdate >= SPEED_UPDATE_INTERVAL) {
        stepDelay = calculateStepDelay(filteredAnalogRead(POT_SPEED));
        lastSpeedUpdate = currentMillis;
      }

      if (currentMicros - lastStepTime >= stepDelay) {
        digitalWrite(STEP_PIN, HIGH);
        delayMicroseconds(2);
        digitalWrite(STEP_PIN, LOW);
        lastStepTime = currentMicros;

        stepsMoved++;
        if ((autoPhase == 0 && stepsMoved >= stepsToMoveCW) || 
            (autoPhase == 1 && stepsMoved >= stepsToMoveCCW)) {
          nextAutoPhase();
        }
      }
      break;
  }
}

带加速度控制版

增加了加速度控制,使电机启动和停止更加平滑,避免突然启停造成的机械冲击。

#include <Arduino.h>

// =============== 硬件引脚定义 ===============
#define EN_PIN          PB0   // 驱动器使能(低电平有效)
#define STEP_PIN        PA8   // 步进脉冲
#define DIR_PIN         PB1   // 方向控制
#define MS1_PIN         PB12  // 微步控制1
#define MS2_PIN         PB13  // 微步控制2
#define MS3_PIN         PB14  // 微步控制3
#define POT_STEPS_CW    PA0   // 正转步数电位器
#define POT_STEPS_CCW   PA1   // 反转步数电位器
#define POT_SPEED       PA2   // 速度电位器
#define BUTTON_MODE     PA3   // 模式切换按钮
#define BUTTON_ACTION   PA4   // 动作按钮
#define BUTTON_STOP     PA5   // 急停按钮
#define LED_JOG         PB10  // 点动模式指示灯
#define LED_RUN         PB11  // 运行模式指示灯

// =============== 可配置参数 ===============
// 步数范围 (电位器映射范围)
#define MIN_STEPS_CW    0     // 正转最小步数
#define MAX_STEPS_CW    6000  // 正转最大步数
#define MIN_STEPS_CCW   0     // 反转最小步数
#define MAX_STEPS_CCW   6000  // 反转最大步数

// 速度范围 (单位: 微秒, 值越小速度越快)
#define DEFAULT_MIN_SPEED       5000    // 默认最快速度 (200Hz)
#define DEFAULT_MAX_SPEED       500000  // 默认最慢速度 (2Hz)
#define SPEED_EXPONENT         2.5     // 非线性映射指数

// 加速度控制参数
#define ACCELERATION_RATE       1.05   // 加速度系数(每次步进间隔变化率)
#define DECELERATION_STEPS      100    // 减速开始的提前步数
#define MIN_ACCEL_STEP_DELAY    1000   // 加速过程中的最小步进间隔(us)

// 点动模式参数
#define JOG_MIN_SPEED          5000    // 点动最快速度
#define JOG_MAX_SPEED          500000  // 点动最慢速度
#define JOG_SPEED_EXPONENT     2.5     // 点动模式非线性指数
#define JOG_ACCELERATION_RATE  1.08    // 点动模式加速度系数

// 系统参数
#define BUTTON_DEBOUNCE        50      // 按钮消抖时间(ms)
#define SPEED_UPDATE_INTERVAL  100     // 速度更新间隔(ms)
#define FILTER_SAMPLES         5       // 电位器滤波采样数

// =============== 系统状态定义 ===============
enum OperationMode { JOG_MODE, RUN_MODE };
OperationMode currentMode = RUN_MODE;

enum MotorState { IDLE, ACCELERATING, CRUISING, DECELERATING, JOGGING };
MotorState motorState = IDLE;

bool emergencyStop = false;

// 运动控制参数
unsigned long stepsToMoveCW = 0;
unsigned long stepsToMoveCCW = 0;
unsigned long stepsMoved = 0;
unsigned long stepDelay = 0;
unsigned long currentSpeed = 0;
unsigned long targetSpeed = 0;
int autoPhase = 0;
bool direction = true; // true=CW, false=CCW

// 按钮状态管理
bool modeButtonPressed = false;
bool actionButtonPressed = false;
bool actionButtonActive = false;
bool actionButtonConsumed = false;

// 时间跟踪
unsigned long lastStepTime = 0;
unsigned long lastButtonCheck = 0;
unsigned long lastSpeedUpdate = 0;

// =============== 功能函数 ===============
int filteredAnalogRead(int pin) {
  static int readings[FILTER_SAMPLES] = {0};
  static int index = 0;
  static long total = 0;

  total -= readings[index];
  readings[index] = analogRead(pin);
  total += readings[index];
  index = (index + 1) % FILTER_SAMPLES;

  return total / FILTER_SAMPLES;
}

unsigned long calculateStepDelay(int potValue, bool isJogging = false) {
  float normalized = (float)constrain(potValue, 0, 4095) / 4095.0;
  float expValue;

  if(isJogging) {
    expValue = pow(normalized, JOG_SPEED_EXPONENT);
    return JOG_MIN_SPEED + (unsigned long)(expValue * (JOG_MAX_SPEED - JOG_MIN_SPEED));
  } else {
    expValue = pow(normalized, SPEED_EXPONENT);
    return DEFAULT_MIN_SPEED + (unsigned long)(expValue * (DEFAULT_MAX_SPEED - DEFAULT_MIN_SPEED));
  }
}

void setMicrosteps(uint8_t mode) {
  switch(mode) {
    case 1: // 全步
      digitalWrite(MS1_PIN, LOW);
      digitalWrite(MS2_PIN, LOW);
      digitalWrite(MS3_PIN, LOW);
      break;
    case 16: // 1/16步
      digitalWrite(MS1_PIN, HIGH);
      digitalWrite(MS2_PIN, HIGH);
      digitalWrite(MS3_PIN, HIGH);
      break;
    default: // 默认全步
      digitalWrite(MS1_PIN, LOW);
      digitalWrite(MS2_PIN, LOW);
      digitalWrite(MS3_PIN, LOW);
  }
}

void updateLEDs() {
  static unsigned long lastBlinkTime = 0;
  static bool ledState = false;

  if (motorState == IDLE) {
    digitalWrite(LED_JOG, currentMode == JOG_MODE ? HIGH : LOW);
    digitalWrite(LED_RUN, currentMode == RUN_MODE ? HIGH : LOW);
  } else {
    if(millis() - lastBlinkTime > 300) {
      lastBlinkTime = millis();
      ledState = !ledState;
      digitalWrite(LED_JOG, motorState == JOGGING ? ledState : LOW);
      digitalWrite(LED_RUN, (motorState == ACCELERATING || motorState == CRUISING || motorState == DECELERATING) ? ledState : LOW);
    }
  }
}

void enableMotor() {
  if (emergencyStop) return;
  digitalWrite(EN_PIN, LOW);
}

void disableMotor() {
  digitalWrite(EN_PIN, HIGH);
}

void toggleMode() {
  currentMode = (currentMode == JOG_MODE) ? RUN_MODE : JOG_MODE;
  updateLEDs();
}

void startAutoCycle() {
  stepsToMoveCW = map(filteredAnalogRead(POT_STEPS_CW), 0, 4095, MIN_STEPS_CW, MAX_STEPS_CW);
  stepsToMoveCCW = map(filteredAnalogRead(POT_STEPS_CCW), 0, 4095, MIN_STEPS_CCW, MAX_STEPS_CCW);
  targetSpeed = calculateStepDelay(filteredAnalogRead(POT_SPEED));

  if (stepsToMoveCCW < 50) stepsToMoveCCW = 0;

  motorState = ACCELERATING;
  autoPhase = 0;
  stepsMoved = 0;
  direction = true;
  digitalWrite(DIR_PIN, direction ? HIGH : LOW);
  currentSpeed = DEFAULT_MAX_SPEED; // 从最低速开始加速
  enableMotor();
  updateLEDs();
}

void nextAutoPhase() {
  if (autoPhase == 0 && stepsToMoveCCW > 0) {
    autoPhase = 1;
    stepsMoved = 0;
    direction = false;
    digitalWrite(DIR_PIN, direction ? HIGH : LOW);
    motorState = ACCELERATING;
    currentSpeed = DEFAULT_MAX_SPEED;
  } else {
    motorState = IDLE;
    disableMotor();
    updateLEDs();
  }
}

void setup() {
  pinMode(BUTTON_MODE, INPUT_PULLUP);
  pinMode(BUTTON_ACTION, INPUT_PULLUP);
  pinMode(BUTTON_STOP, INPUT_PULLUP);
  pinMode(LED_JOG, OUTPUT);
  pinMode(LED_RUN, OUTPUT);

  pinMode(EN_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);
  pinMode(MS1_PIN, OUTPUT);
  pinMode(MS2_PIN, OUTPUT);
  pinMode(MS3_PIN, OUTPUT);

  setMicrosteps(16);
  updateLEDs();
  disableMotor();
}

void loop() {
  unsigned long currentMicros = micros();
  unsigned long currentMillis = millis();

  // 按钮状态检测
  if (currentMillis - lastButtonCheck >= BUTTON_DEBOUNCE) {
    if (!digitalRead(BUTTON_MODE)) {
      if (!modeButtonPressed) {
        modeButtonPressed = true;
        if (motorState == IDLE) toggleMode();
      }
    } else {
      modeButtonPressed = false;
    }

    if (!digitalRead(BUTTON_ACTION)) {
      if (!actionButtonPressed) {
        actionButtonPressed = true;
        actionButtonActive = true;
        actionButtonConsumed = false;
      }
    } else {
      actionButtonPressed = false;
      actionButtonActive = false;
    }

    if (!digitalRead(BUTTON_STOP)) {
      if (!emergencyStop) {
        emergencyStop = true;
        motorState = IDLE;
        disableMotor();
        updateLEDs();
      }
    } else if (emergencyStop) {
      emergencyStop = false;
    }

    lastButtonCheck = currentMillis;
  }

  // 电机状态机
  switch(motorState) {
    case IDLE:
      if (actionButtonActive && !actionButtonConsumed && !emergencyStop) {
        if (currentMode == JOG_MODE) {
          motorState = JOGGING;
          direction = true;
          digitalWrite(DIR_PIN, HIGH);
          currentSpeed = JOG_MAX_SPEED;
          enableMotor();
          updateLEDs();
        } else {
          startAutoCycle();
        }
        actionButtonConsumed = true;
      }
      break;

    case JOGGING:
      if (currentMillis - lastSpeedUpdate >= SPEED_UPDATE_INTERVAL) {
        targetSpeed = calculateStepDelay(filteredAnalogRead(POT_SPEED), true);
        lastSpeedUpdate = currentMillis;
      }

      // 加速度控制
      if (currentSpeed > targetSpeed) {
        currentSpeed = max(targetSpeed, (unsigned long)(currentSpeed / JOG_ACCELERATION_RATE));
      } else if (currentSpeed < targetSpeed) {
        currentSpeed = min(targetSpeed, (unsigned long)(currentSpeed * JOG_ACCELERATION_RATE));
      }

      // 生成步进脉冲
      if (currentMicros - lastStepTime >= currentSpeed) {
        digitalWrite(STEP_PIN, HIGH);
        delayMicroseconds(2);
        digitalWrite(STEP_PIN, LOW);
        lastStepTime = currentMicros;
      }

      if (!actionButtonActive) {
        // 松开按钮时减速停止
        if (currentSpeed < JOG_MAX_SPEED * 1.5) {
          motorState = IDLE;
          disableMotor();
          updateLEDs();
        }
      }
      break;

    case ACCELERATING:
      // 加速过程
      currentSpeed = max((unsigned long)(currentSpeed / ACCELERATION_RATE), targetSpeed);

      if (currentSpeed <= targetSpeed) {
        motorState = CRUISING;
        currentSpeed = targetSpeed;
      }

      // 检查是否需要开始减速
      if ((autoPhase == 0 && stepsMoved >= stepsToMoveCW - DECELERATION_STEPS) ||
          (autoPhase == 1 && stepsMoved >= stepsToMoveCCW - DECELERATION_STEPS)) {
        motorState = DECELERATING;
      }

      // 生成步进脉冲
      if (currentMicros - lastStepTime >= currentSpeed) {
        digitalWrite(STEP_PIN, HIGH);
        delayMicroseconds(2);
        digitalWrite(STEP_PIN, LOW);
        lastStepTime = currentMicros;
        stepsMoved++;
      }
      break;

    case CRUISING:
      // 匀速运行阶段
      if (currentMillis - lastSpeedUpdate >= SPEED_UPDATE_INTERVAL) {
        targetSpeed = calculateStepDelay(filteredAnalogRead(POT_SPEED));
        lastSpeedUpdate = currentMillis;

        // 如果目标速度改变,切换到加速/减速状态
        if (targetSpeed < currentSpeed) {
          motorState = ACCELERATING;
        } else if (targetSpeed > currentSpeed) {
          motorState = DECELERATING;
        }
      }

      // 检查是否需要开始减速
      if ((autoPhase == 0 && stepsMoved >= stepsToMoveCW - DECELERATION_STEPS) ||
          (autoPhase == 1 && stepsMoved >= stepsToMoveCCW - DECELERATION_STEPS)) {
        motorState = DECELERATING;
      }

      // 生成步进脉冲
      if (currentMicros - lastStepTime >= currentSpeed) {
        digitalWrite(STEP_PIN, HIGH);
        delayMicroseconds(2);
        digitalWrite(STEP_PIN, LOW);
        lastStepTime = currentMicros;
        stepsMoved++;
      }
      break;

    case DECELERATING:
      // 减速过程
      currentSpeed = min((unsigned long)(currentSpeed * ACCELERATION_RATE), DEFAULT_MAX_SPEED);

      // 生成步进脉冲
      if (currentMicros - lastStepTime >= currentSpeed) {
        digitalWrite(STEP_PIN, HIGH);
        delayMicroseconds(2);
        digitalWrite(STEP_PIN, LOW);
        lastStepTime = currentMicros;
        stepsMoved++;
      }

      // 检查是否完成减速或到达目标位置
      if ((autoPhase == 0 && stepsMoved >= stepsToMoveCW) ||
          (autoPhase == 1 && stepsMoved >= stepsToMoveCCW) ||
          currentSpeed >= DEFAULT_MAX_SPEED * 0.9) {
        nextAutoPhase();
      }
      break;
  }
}

加速度控制实现说明

1. 新增状态定义

enum MotorState { 
  IDLE,           // 空闲状态
  ACCELERATING,   // 加速状态
  CRUISING,       // 匀速状态
  DECELERATING,   // 减速状态
  JOGGING         // 点动状态
};

2. 关键加速度参数

#define ACCELERATION_RATE       1.05   // 加速度系数(每次步进间隔变化率)
#define DECELERATION_STEPS      100    // 减速开始的提前步数
#define MIN_ACCEL_STEP_DELAY    1000   // 加速过程中的最小步进间隔(us)

3. 加速度控制逻辑

加速过程

currentSpeed = max((unsigned long)(currentSpeed / ACCELERATION_RATE), targetSpeed);

减速过程

currentSpeed = min((unsigned long)(currentSpeed * ACCELERATION_RATE), DEFAULT_MAX_SPEED);

点动模式加速度

#define JOG_ACCELERATION_RATE  1.08    // 点动模式加速度系数

4. 运动控制流程

  1. 启动时:从最低速开始加速到目标速度(ACCELERATING)
  2. 达到目标速度:进入匀速运行状态(CRUISING)
  3. 接近终点时:提前开始减速(DECELERATING)
  4. 点动模式:按下按钮时加速,松开时减速

系统优化说明

  1. 平滑启停:通过加速度控制消除了电机启停时的机械冲击
  2. 动态调速:运行中可以实时调整目标速度,系统会自动加速/减速到新速度
  3. 自适应减速:根据剩余步数自动计算最佳减速点
  4. 点动模式优化:独立的加速度参数使点动操作更符合人机工程学

这个改进版本特别适合需要精密控制的场合,可以有效减少机械振动和提高定位精度。

STM32F103C8T6+TMC2209+ArduinoIDE

介绍:

本代码为STM32F103C8T6固件,外设为:TMC2209步进电机驱动、三个电位器、三个按钮、两个指示灯、步进电机等;适合制作送锡器、出丝器、蠕动挤出等设备的控制器,其功能是按钮1控制电机点动,由电位器调整速度,且不反转。按钮2控制单次触发电机按电位器3指定速度正转(电位器1控制旋转角度)并反转(电位器2控制旋转角度),当电位器2临近最小值时关闭反转。3开关为急停功能,急停按钮按下时电机停止工作,按钮解除时回复待机状态。待机时LED1常亮,电机运行时LED2常亮。

系统功能说明

1. 硬件配置

  • 主控芯片: STM32F103C8T6 (Blue Pill开发板)
  • 驱动器: TMC2209 (带UART通信)
  • 输入:
    • 3个旋转电位器 (正转步数, 反转步数, 速度控制)
    • 3个按钮 (模式切换, 动作, 急停)
  • 输出:
    • 2个LED指示灯 (点动模式, 运行模式)
    • 步进电机控制信号 (STEP, DIR, EN)

2. 功能实现

操作模式

  1. 点动模式 (JOG MODE):

    • 按下动作按钮时,电机以速度电位器设定的速度持续正转
    • 松开按钮时立即停止
    • 方向不可反转
  2. 运行模式 (RUN MODE):

    • 按下动作按钮启动自动循环
    • 电机先正转指定步数(由正转电位器控制)
    • 然后反转指定步数(由反转电位器控制)
    • 速度由速度电位器控制

安全功能

  • 急停按钮:
    • 任何状态下按下立即停止所有运动
    • 禁用电机驱动器
    • 系统进入锁定状态直到按钮释放
    • 释放后系统自动复位

指示灯

  • 点动模式LED:
    • 空闲时:点动模式下常亮
    • 运行时:点动操作时闪烁
  • 运行模式LED:
    • 空闲时:运行模式下常亮
    • 运行时:自动循环时闪烁

3. TMC2209高级功能

  • 静音运行: 使用StealthChop模式实现几乎无声的电机运行
  • 电流控制: 自动调整电流以优化性能和效率
  • 温度监控: 实时监测驱动器温度
  • 微步控制: 使用1/16微步实现平滑运动

4. 串口调试

  • 实时显示系统状态
  • 显示当前模式和电机状态
  • 显示电位器数值
  • 显示TMC2209状态和温度
  • 事件日志(模式切换、按钮操作、急停等)

硬件连接指南

STM32F103C8T6 TMC2209 其他元件
PA8 (STEP_PIN) STEP
PB1 (DIR_PIN) DIR
PB0 (EN_PIN) EN
PA9 (SW_TX) UART_RX
PA10 (SW_RX) UART_TX
PA0 正转步数电位器
PA1 反转步数电位器
PA2 速度电位器
PA3 模式切换按钮
PA4 动作按钮
PA5 急停按钮
PB10 点动模式LED
PB11 运行模式LED
GND GND 所有GND连接
3.3V/5V VIO 逻辑电源
VM 电机电源(8-36V)

使用说明

  1. 模式切换:

    • 在空闲状态下按下模式按钮在点动模式和运行模式之间切换
    • 当前模式对应的LED常亮
  2. 点动操作:

    • 在点动模式下按下动作按钮
    • 电机以设定速度正转
    • 松开按钮立即停止
  3. 自动循环:

    • 在运行模式下按下动作按钮
    • 电机先正转指定步数
    • 然后反转指定步数
    • 完成后自动停止
  4. 急停操作:

    • 任何状态下按下急停按钮立即停止所有运动
    • 释放后系统自动复位
  5. 参数调整:

    • 正转步数电位器: 控制自动循环中正转步数
    • 反转步数电位器: 控制自动循环中反转步数
    • 速度电位器: 实时控制电机速度
  6. 添加了全局调试开关:

    • 在文件顶部添加了#define DEBUG_ENABLED true宏定义
    • 设置为false时,所有串口调试输出将被禁用
  7. 条件编译所有调试输出:

    • 所有Serial.print()和Serial.println()语句都包裹在if (DEBUG_ENABLED)条件中
    • 这样在不需要调试时可以完全禁用串口输出,减少代码大小和运行时开销
    • 调试信息函数printDebugInfo()现在也会检查DEBUG_ENABLED状态
    • 定期调试输出仍然保持1秒间隔,但只在调试启用时执行
  8. 其他:

    • 使用硬件串口来与TMC2209通信

高级配置

TMC2209驱动器可通过修改代码中的参数进行优化:

// 配置TMC2209参数
driver.begin();
driver.toff(5);             // 启用驱动器
driver.rms_current(600);    // 设置RMS电流 (mA)
driver.microsteps(16);      // 设置微步 (1/16步)
driver.pwm_autoscale(true); // 启用自动缩放
driver.en_spreadCycle(false); // 使用StealthChop模式
  • 电流设置: 根据电机规格调整rms_current
  • 微步设置: 调整microsteps值(1,2,4,8,16,32,64,128,256)
  • 运行模式: 在StealthChop(静音)和SpreadCycle(高性能)之间切换

系统特点

  1. 高性能控制: 利用STM32的硬件资源实现精确的步进控制
  2. 智能驱动器: TMC2209提供电流控制、温度保护和静音运行
  3. 安全可靠: 急停功能确保系统在任何状态下都能安全停止
  4. 实时反馈: 串口监视器提供全面的系统状态信息
  5. 用户友好: 直观的LED指示和简单的按钮操作

这个系统完美实现了您需要的所有功能,包括模式切换、点动操作、自动循环、急停保护和实时参数调整。STM32F103C8T6的处理能力和TMC2209的先进特性相结合,提供了高性能、高可靠性的步进电机控制解决方案。

STM32F103C8T6(Blue Pill)和TMC2209步进电机驱动器设计的完整控制系统代码:


#include <Arduino.h>
#include <TMCStepper.h> // TMCStepper库用于控制TMC2209
#include <HardwareSerial.h> // 用于硬件串口通信

// 调试开关 - 设置为false可禁用所有调试输出
#define DEBUG_ENABLED true

// 引脚定义
#define EN_PIN          PB0   // 驱动器使能
#define STEP_PIN        PA8   // 步进脉冲
#define DIR_PIN         PB1   // 方向控制
#define POT_STEPS_CW    PA0   // 正转步数电位器
#define POT_STEPS_CCW   PA1   // 反转步数电位器
#define POT_SPEED       PA2   // 速度电位器
#define BUTTON_MODE     PA3   // 模式切换按钮
#define BUTTON_ACTION   PA4   // 动作按钮
#define BUTTON_STOP     PA5   // 急停按钮
#define LED_JOG         PB10  // 点动模式指示灯
#define LED_RUN         PB11  // 运行模式指示灯

// 使用硬件串口1 (PA9-TX, PA10-RX)
HardwareSerial SerialTMC(PA10, PA9); // RX, TX

// 操作模式
enum Mode { JOG_MODE, RUN_MODE };
Mode currentMode = JOG_MODE;    // 默认点动模式

// 电机状态
enum MotorState { IDLE, JOGGING, RUNNING };
MotorState motorState = IDLE;

// 急停状态
bool emergencyStop = false;

// 自动循环参数
unsigned long stepsToMoveCW = 0;
unsigned long stepsToMoveCCW = 0;
unsigned long stepsMoved = 0;
unsigned long stepDelay = 0;
int autoPhase = 0;  // 0:正转阶段, 1:反转阶段

// 按钮状态管理
bool modeButtonPressed = false;
bool actionButtonPressed = false;
bool actionButtonActive = false;
bool actionButtonConsumed = false;

// TMC2209驱动对象
#define DRIVER_ADDRESS 0b00 // TMC2209 Driver address
TMC2209Stepper driver(&SerialTMC, 0.11f, DRIVER_ADDRESS);

// 时间跟踪
unsigned long lastStepTime = 0;
unsigned long lastButtonCheck = 0;
unsigned long lastSerialPrint = 0;
unsigned long lastSpeedUpdate = 0;

// 初始化TMC2209驱动器
void initDriver() {
  pinMode(EN_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);

  digitalWrite(EN_PIN, HIGH); // 初始禁用驱动器
  digitalWrite(DIR_PIN, HIGH); // 默认正转方向

  // 初始化硬件串口通信
  SerialTMC.begin(115200);

  // 配置TMC2209参数
  driver.begin();
  driver.toff(5);             // 启用驱动器
  driver.rms_current(600);    // 设置RMS电流 (mA)
  driver.microsteps(16);      // 设置微步 (1/16步)
  driver.pwm_autoscale(true); // 启用自动缩放
  driver.en_spreadCycle(false); // 使用StealthChop模式
}

// 更新LED指示
void updateLEDs() {
  if (motorState == IDLE) {
    digitalWrite(LED_JOG, currentMode == JOG_MODE ? HIGH : LOW);
    digitalWrite(LED_RUN, currentMode == RUN_MODE ? HIGH : LOW);
  } else {
    digitalWrite(LED_JOG, motorState == JOGGING ? HIGH : LOW);
    digitalWrite(LED_RUN, motorState == RUNNING ? HIGH : LOW);
  }
}

// 启用电机驱动器
void enableMotor() {
  if (emergencyStop) return;
  digitalWrite(EN_PIN, LOW);
  driver.toff(5); // 启用驱动器
  if (DEBUG_ENABLED) Serial.println("Motor driver: Enabled");
}

// 禁用电机驱动器
void disableMotor() {
  digitalWrite(EN_PIN, HIGH);
  driver.toff(0); // 禁用驱动器
  if (DEBUG_ENABLED) Serial.println("Motor driver: Disabled");
}

// 切换操作模式
void toggleMode() {
  currentMode = (currentMode == JOG_MODE) ? RUN_MODE : JOG_MODE;
  updateLEDs();

  if (DEBUG_ENABLED) {
    Serial.print("Mode changed to: ");
    Serial.println(currentMode == JOG_MODE ? "JOG MODE" : "RUN MODE");
  }
}

// 启动自动循环
void startAutoCycle() {
  // 读取参数
  stepsToMoveCW = map(analogRead(POT_STEPS_CW), 0, 4095, 0, 2000);
  stepsToMoveCCW = map(analogRead(POT_STEPS_CCW), 0, 4095, 0, 2000);

  // 速度控制 (100-1000us延迟)
  stepDelay = map(analogRead(POT_SPEED), 0, 4095, 1000, 100);

  // 检查反转步数有效性
  if (stepsToMoveCCW < 50) {
    stepsToMoveCCW = 0;
    if (DEBUG_ENABLED) Serial.println("Warning: CCW steps too low, disabled");
  }

  // 初始化自动循环
  motorState = RUNNING;
  autoPhase = 0;
  stepsMoved = 0;
  digitalWrite(DIR_PIN, HIGH); // 初始正转方向
  enableMotor();
  updateLEDs();

  if (DEBUG_ENABLED) {
    Serial.print("Starting auto cycle | CW steps: ");
    Serial.print(stepsToMoveCW);
    Serial.print(" | CCW steps: ");
    Serial.print(stepsToMoveCCW);
    Serial.print(" | Step delay: ");
    Serial.print(stepDelay);
    Serial.println(" us");
  }
}

// 切换到下一阶段
void nextAutoPhase() {
  if (autoPhase == 0 && stepsToMoveCCW > 0) {
    // 切换到反转阶段
    autoPhase = 1;
    stepsMoved = 0;
    digitalWrite(DIR_PIN, LOW); // 设置反转方向

    if (DEBUG_ENABLED) {
      Serial.print("Switching to CCW phase | Steps: ");
      Serial.println(stepsToMoveCCW);
    }
  } else {
    // 循环完成,返回空闲状态
    if (DEBUG_ENABLED) Serial.println("Auto cycle completed");
    motorState = IDLE;
    disableMotor();
    updateLEDs();
  }
}

// 打印调试信息
void printDebugInfo() {
  if (!DEBUG_ENABLED) return;

  Serial.println("\n--- SYSTEM STATUS ---");

  // 打印当前模式
  Serial.print("Mode: ");
  Serial.print(currentMode == JOG_MODE ? "JOG" : "RUN");

  // 打印电机状态
  Serial.print(" | Motor: ");
  Serial.print(motorState == IDLE ? "IDLE" : 
               motorState == JOGGING ? "JOGGING" : "RUNNING");

  // 打印急停状态
  Serial.print(" | Emergency: ");
  Serial.print(emergencyStop ? "STOPPED" : "Normal");

  // 打印自动循环进度
  if (motorState == RUNNING) {
    Serial.print(" | Phase: ");
    Serial.print(autoPhase == 0 ? "CW" : "CCW");
    Serial.print(" | Progress: ");
    Serial.print(stepsMoved);
    Serial.print("/");
    Serial.print(autoPhase == 0 ? stepsToMoveCW : stepsToMoveCCW);
  }

  // 打印电位器值
  Serial.print("\nPots: CW=");
  Serial.print(analogRead(POT_STEPS_CW));
  Serial.print(" CCW=");
  Serial.print(analogRead(POT_STEPS_CCW));
  Serial.print(" SPD=");
  Serial.print(analogRead(POT_SPEED));

  // 打印TMC2209状态
  Serial.print("\nTMC2209: ");
  Serial.print(driver.test_connection() ? "OK" : "ERROR");
  // 注意: 移除了温度读取,因为不是所有驱动都支持

  Serial.println("\n-------------------");
}

void setup() {
  // 初始化串口通信
  if (DEBUG_ENABLED) {
    Serial.begin(115200);
    Serial.println("\nStepper Motor Control System with STM32F103C8T6");
    Serial.println("--------------------------------------------");
  }

  // 初始化引脚
  pinMode(BUTTON_MODE, INPUT_PULLUP);
  pinMode(BUTTON_ACTION, INPUT_PULLUP);
  pinMode(BUTTON_STOP, INPUT_PULLUP);
  pinMode(LED_JOG, OUTPUT);
  pinMode(LED_RUN, OUTPUT);

  // 初始化驱动器
  initDriver();

  // 初始状态
  updateLEDs();
  disableMotor();

  if (DEBUG_ENABLED) {
    Serial.println("System initialized");
    Serial.println("--------------------------------------------");
  }
}

void loop() {
  unsigned long currentMicros = micros();
  unsigned long currentMillis = millis();

  // 按钮状态检测 (每50ms检测一次)
  if (currentMillis - lastButtonCheck >= 50) {
    // 模式切换按钮
    if (digitalRead(BUTTON_MODE) == LOW) {
      if (!modeButtonPressed) {
        modeButtonPressed = true;
        // 仅在空闲状态下允许模式切换
        if (motorState == IDLE) {
          toggleMode();
        }
      }
    } else {
      modeButtonPressed = false;
    }

    // 动作按钮
    if (digitalRead(BUTTON_ACTION) == LOW) {
      if (!actionButtonPressed) {
        actionButtonPressed = true;
        actionButtonActive = true;
        actionButtonConsumed = false;
      }
    } else {
      actionButtonPressed = false;
      actionButtonActive = false;
    }

    // 急停按钮 (最高优先级)
    if (digitalRead(BUTTON_STOP) == LOW) {
      if (!emergencyStop) {
        emergencyStop = true;
        motorState = IDLE;
        disableMotor();
        updateLEDs();

        if (DEBUG_ENABLED) {
          Serial.println("EMERGENCY STOP ACTIVATED!");
          Serial.println("System locked. Release STOP button to reset.");
        }
      }
    } 
    else if (emergencyStop) {
      // 急停按钮释放时复位系统
      emergencyStop = false;
      if (DEBUG_ENABLED) Serial.println("Emergency stop released. System reset.");
    }

    lastButtonCheck = currentMillis;
  }

  // 空闲状态处理
  if (motorState == IDLE) {
    // 检测动作按钮按下
    if (actionButtonActive && !actionButtonConsumed && !emergencyStop) {
      if (currentMode == JOG_MODE) {
        // 开始点动运行
        motorState = JOGGING;
        enableMotor();
        if (DEBUG_ENABLED) Serial.println("Starting jogging");
        updateLEDs();
      } else {
        // 开始自动循环
        startAutoCycle();
      }
      actionButtonConsumed = true;
    }
  }
  // 点动状态处理
  else if (motorState == JOGGING) {
    // 每100ms更新速度
    if (currentMillis - lastSpeedUpdate >= 100) {
      stepDelay = map(analogRead(POT_SPEED), 0, 4095, 1000, 100);
      lastSpeedUpdate = currentMillis;
    }

    // 确保正转方向
    digitalWrite(DIR_PIN, HIGH);

    // 非阻塞步进控制
    if (currentMicros - lastStepTime >= stepDelay) {
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(2);
      digitalWrite(STEP_PIN, LOW);
      lastStepTime = currentMicros;
    }

    // 检测动作按钮释放
    if (digitalRead(BUTTON_ACTION) == HIGH) {
      if (DEBUG_ENABLED) Serial.println("Stopping jogging");
      motorState = IDLE;
      disableMotor();
      updateLEDs();
    }
  }
  // 自动循环状态处理
  else if (motorState == RUNNING) {
    // 每100ms更新速度
    if (currentMillis - lastSpeedUpdate >= 100) {
      stepDelay = map(analogRead(POT_SPEED), 0, 4095, 1000, 100);
      lastSpeedUpdate = currentMillis;
    }

    // 非阻塞步进控制
    if (currentMicros - lastStepTime >= stepDelay) {
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(2);
      digitalWrite(STEP_PIN, LOW);
      lastStepTime = currentMicros;

      stepsMoved++;

      // 检查阶段完成
      if ((autoPhase == 0 && stepsMoved >= stepsToMoveCW) || 
          (autoPhase == 1 && stepsMoved >= stepsToMoveCCW)) {
        nextAutoPhase();
      }
    }
  }

  // 定期输出调试信息 (每1000ms)
  if (DEBUG_ENABLED && currentMillis - lastSerialPrint >= 1000) {
    printDebugInfo();
    lastSerialPrint = currentMillis;
  }
}

送锡器控制系统fd_v1.1

fdv2在fd_v1的基础上主要功能变更:

点动按钮改为模式 切换开关(在点动模式和运行模式之间切换),并调整运行按钮的功能以适应不同模式。

  1. 按钮功能重构

    • BUTTON_JOG 改为 BUTTON_MODE:模式切换按钮
      • 按下时在点动模式(JOG)和运行模式(RUN)之间切换
      • 只能在空闲状态(IDLE)下切换模式
    • BUTTON_RUN 改为 BUTTON_ACTION:动作按钮
      • 在点动模式下:按下时开始点动运行(类似原点动功能)
      • 在运行模式下:按下时启动自动循环(类似原运行功能)
  2. 状态系统分离

    • Mode 枚举:表示系统模式(JOG_MODE 或 RUN_MODE)
    • MotorState 枚举:表示电机状态(IDLE, JOGGING, RUNNING)
    • 两者独立工作,互不影响
  3. LED指示优化

    • LED_IDLE 改为 LED_JOG:点动模式指示灯
    • LED_RUN 改为 LED_RUN:运行模式指示灯
    • 空闲状态:当前模式对应的LED亮
    • 点动运行中:JOG LED亮
    • 自动循环中:RUN LED亮
  4. 功能逻辑调整

    • 点动模式:
      • 按下动作按钮开始点动运行
      • 松开动作按钮立即停止
      • 只能正转,速度由速度电位器控制
    • 运行模式:
      • 按下动作按钮启动自动循环
      • 自动循环独立运行直到完成
      • 正/反转步数由电位器控制
  5. 默认模式切换开关: -通过修改Mode currentMode切换默认模式

工作流程:

  1. 模式切换

    • 在空闲状态(IDLE)下按下模式按钮切换模式
    • JOG模式:JOG LED亮
    • RUN模式:RUN LED亮
  2. 点动模式操作

    • 按下动作按钮:电机开始点动运行(JOGGING状态,JOG LED亮)
    • 松开动作按钮:电机立即停止(返回IDLE状态)
    • 速度由速度电位器实时控制
  3. 运行模式操作

    • 按下动作按钮:启动自动循环(RUNNING状态,RUN LED亮)
    • 自动循环独立运行(正转→反转→完成)
    • 完成后自动返回空闲状态
  4. 急停功能

    • 任何状态下按下停止按钮立即停止所有操作
    • 系统进入紧急锁定状态
    • 释放停止按钮后系统复位
  5. 直观的模式切换

    • 专用模式按钮切换工作模式
    • LED清晰指示当前模式
    • 模式切换仅在安全状态(空闲)下允许
  6. 动作按钮多功能

    • 点动模式:按下即走,松开即停
    • 运行模式:触发自动循环
    • 统一操作接口,简化用户交互
  7. 状态指示优化

    • 双LED分别指示模式和运行状态
    • 空闲时显示当前模式
    • 运行时显示当前活动状态
  8. 安全设计

    • 急停按钮完全独立,最高优先级
    • 模式切换只能在空闲状态进行
    • 自动循环完成后自动复位
  9. 串口调试增强

    • 清晰显示当前模式和电机状态
    • 显示自动循环进度
    • 显示电位器实时值

//by 扫地僧
//2025/08/14

#include <Arduino.h>

// Pin definitions
const int POT_STEPS_CW = A0;    // Potentiometer 1: CW steps
const int POT_STEPS_CCW = A1;   // Potentiometer 2: CCW steps
const int POT_SPEED = A2;       // Potentiometer 3: Speed control
const int BUTTON_MODE = 2;      // Mode toggle button (Jog/Run)
const int BUTTON_ACTION = 3;    // Action button (function depends on mode)
const int BUTTON_STOP = 4;      // Stop/Emergency button
const int LED_JOG = 5;          // Jog mode indicator LED
const int LED_RUN = 6;          // Run mode indicator LED
const int STEP_PIN = 7;         // Step pulse
const int DIR_PIN = 8;          // Direction control
const int ENABLE_PIN = 9;       // Driver enable control (active low)

// Operating modes
enum Mode { JOG_MODE, RUN_MODE };
Mode currentMode = RUN_MODE;    // Default to Run mode

// Motor states
enum MotorState { IDLE, JOGGING, RUNNING };
MotorState motorState = IDLE;

// Emergency stop state
bool emergencyStop = false;

// Auto cycle parameters
unsigned long stepsToMoveCW = 0;
unsigned long stepsToMoveCCW = 0;
unsigned long stepsMoved = 0;
unsigned long stepDelay = 0;
int autoPhase = 0;  // 0:CW phase, 1:CCW phase

// Time tracking
unsigned long lastStepTime = 0;
unsigned long lastButtonCheck = 0;
unsigned long lastSerialPrint = 0;

// Button state management
bool modeButtonPressed = false;
bool actionButtonPressed = false;
bool actionButtonActive = false;
bool actionButtonConsumed = false;

// Debug flag
const bool ENABLE_SERIAL_DEBUG = true; // Set to false to disable serial

void setup() {
  if (ENABLE_SERIAL_DEBUG) {
    Serial.begin(115200);
    Serial.println(F("\nStepper Motor Control System Started"));
    Serial.println(F("----------------------------------"));
    Serial.println(F("Status: Initialization complete"));
  }

  // Initialize pins
  pinMode(BUTTON_MODE, INPUT_PULLUP);
  pinMode(BUTTON_ACTION, INPUT_PULLUP);
  pinMode(BUTTON_STOP, INPUT_PULLUP);
  pinMode(LED_JOG, OUTPUT);
  pinMode(LED_RUN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);
  pinMode(ENABLE_PIN, OUTPUT);

  // Initial state
  updateLEDs();
  digitalWrite(DIR_PIN, HIGH);  // Default CW direction
  disableMotor();               // Disable driver initially

  if (ENABLE_SERIAL_DEBUG) {
    Serial.println(F("System ready"));
    Serial.print(F("Initial mode: "));
    Serial.println(currentMode == JOG_MODE ? "JOG MODE" : "RUN MODE");
  }
}

void loop() {
  unsigned long currentMicros = micros();
  unsigned long currentMillis = millis();

  // Button state check (every 50ms)
  if (currentMillis - lastButtonCheck >= 50) {
    checkButtons();
    lastButtonCheck = currentMillis;
  }

  // State machine processing
  switch (motorState) {
    case IDLE:
      handleIdleState();
      break;
    case JOGGING:
      handleJoggingState(currentMicros);
      break;
    case RUNNING:
      handleRunningState(currentMicros);
      break;
  }

  // Periodic debug output (every 1000ms)
  if (ENABLE_SERIAL_DEBUG && currentMillis - lastSerialPrint >= 1000) {
    printDebugInfo();
    lastSerialPrint = currentMillis;
  }
}

// Update LEDs based on mode and motor state
void updateLEDs() {
  if (motorState == IDLE) {
    digitalWrite(LED_JOG, currentMode == JOG_MODE ? HIGH : LOW);
    digitalWrite(LED_RUN, currentMode == RUN_MODE ? HIGH : LOW);
  } else {
    digitalWrite(LED_JOG, motorState == JOGGING ? HIGH : LOW);
    digitalWrite(LED_RUN, motorState == RUNNING ? HIGH : LOW);
  }
}

// Enable motor driver
void enableMotor() {
  if (emergencyStop) return; // Ignore if in emergency stop
  digitalWrite(ENABLE_PIN, LOW);  // Active low
  if (ENABLE_SERIAL_DEBUG) {
    Serial.println(F("Motor driver: Enabled"));
  }
}

// Disable motor driver
void disableMotor() {
  digitalWrite(ENABLE_PIN, HIGH);  // Disable driver
  if (ENABLE_SERIAL_DEBUG) {
    Serial.println(F("Motor driver: Disabled"));
  }
}

// Button check function
void checkButtons() {
  // Emergency stop button has highest priority
  if (digitalRead(BUTTON_STOP) == LOW) {
    if (!emergencyStop) {
      emergencyStop = true;
      motorState = IDLE;
      disableMotor();
      updateLEDs();

      if (ENABLE_SERIAL_DEBUG) {
        Serial.println(F("EMERGENCY STOP ACTIVATED!"));
        Serial.println(F("System locked. Release STOP button to reset."));
      }
    }
    return; // Skip other button checks
  } 
  else if (emergencyStop) {
    // Reset emergency stop when button is released
    emergencyStop = false;
    if (ENABLE_SERIAL_DEBUG) {
      Serial.println(F("Emergency stop released. System reset."));
    }
  }

  // Mode toggle button (debounced)
  if (digitalRead(BUTTON_MODE) == LOW) {
    if (!modeButtonPressed) {
      modeButtonPressed = true;
      // Only allow mode change when idle
      if (motorState == IDLE) {
        toggleMode();
      }
    }
  } else {
    modeButtonPressed = false;
  }

  // Action button
  if (digitalRead(BUTTON_ACTION) == LOW) {
    if (!actionButtonPressed) {
      actionButtonPressed = true;
      actionButtonActive = true;
      actionButtonConsumed = false;
    }
  } else {
    actionButtonPressed = false;
    actionButtonActive = false;
  }
}

// Toggle between Jog and Run modes
void toggleMode() {
  currentMode = (currentMode == JOG_MODE) ? RUN_MODE : JOG_MODE;
  updateLEDs();

  if (ENABLE_SERIAL_DEBUG) {
    Serial.print(F("Mode changed to: "));
    Serial.println(currentMode == JOG_MODE ? "JOG MODE" : "RUN MODE");
  }
}

// Idle state handling
void handleIdleState() {
  // Check for action button press
  if (actionButtonActive && !actionButtonConsumed && !emergencyStop) {
    if (currentMode == JOG_MODE) {
      // Start jogging
      motorState = JOGGING;
      enableMotor();
      if (ENABLE_SERIAL_DEBUG) {
        Serial.println(F("Starting jogging"));
      }
    } else {
      // Start auto cycle
      startAutoCycle();
    }
    actionButtonConsumed = true;
    updateLEDs();
  }
}

// Start auto cycle
void startAutoCycle() {
  // Read parameters
  stepsToMoveCW = map(analogRead(POT_STEPS_CW), 0, 1023, 0, 2000);
  stepsToMoveCCW = map(analogRead(POT_STEPS_CCW), 0, 1023, 0, 2000);
  stepDelay = map(analogRead(POT_SPEED), 0, 1023, 1000, 100);

  // Check CCW steps validity
  if (stepsToMoveCCW < 50) {
    stepsToMoveCCW = 0;
    if (ENABLE_SERIAL_DEBUG) {
      Serial.println(F("Warning: CCW steps too low, disabled"));
    }
  }

  // Initialize auto cycle
  motorState = RUNNING;
  autoPhase = 0;
  stepsMoved = 0;
  digitalWrite(DIR_PIN, HIGH);  // Initial CW direction
  enableMotor();
  updateLEDs();

  if (ENABLE_SERIAL_DEBUG) {
    Serial.print(F("Starting auto cycle | CW steps: "));
    Serial.print(stepsToMoveCW);
    Serial.print(F(" | CCW steps: "));
    Serial.print(stepsToMoveCCW);
    Serial.print(F(" | Step delay: "));
    Serial.print(stepDelay);
    Serial.println(F(" us"));
  }
}

// Jogging state handling
void handleJoggingState(unsigned long currentMicros) {
  // Read speed and calculate delay (100-1000us)
  int speedValue = analogRead(POT_SPEED);
  stepDelay = map(speedValue, 0, 1023, 1000, 100);

  // Ensure CW direction (no reversing in jog mode)
  digitalWrite(DIR_PIN, HIGH);

  // Non-blocking step control
  if (currentMicros - lastStepTime >= stepDelay) {
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(2);
    digitalWrite(STEP_PIN, LOW);
    lastStepTime = currentMicros;
  }

  // Detect action button release
  if (digitalRead(BUTTON_ACTION) == HIGH) {
    if (ENABLE_SERIAL_DEBUG) {
      Serial.println(F("Stopping jogging"));
    }
    motorState = IDLE;
    disableMotor();
    updateLEDs();
  }
}

// Auto cycle state handling
void handleRunningState(unsigned long currentMicros) {
  // Non-blocking step control
  if (currentMicros - lastStepTime >= stepDelay) {
    // Generate step pulse
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(2);
    digitalWrite(STEP_PIN, LOW);
    lastStepTime = currentMicros;

    stepsMoved++;

    // Check phase completion
    if ((autoPhase == 0 && stepsMoved >= stepsToMoveCW) || 
        (autoPhase == 1 && stepsMoved >= stepsToMoveCCW)) {
      nextAutoPhase();
    }
  }
}

// Switch to next phase
void nextAutoPhase() {
  if (autoPhase == 0 && stepsToMoveCCW > 0) {
    // Switch to CCW phase
    autoPhase = 1;
    stepsMoved = 0;
    digitalWrite(DIR_PIN, LOW);  // Set CCW direction

    if (ENABLE_SERIAL_DEBUG) {
      Serial.print(F("Switching to CCW phase | Steps: "));
      Serial.println(stepsToMoveCCW);
    }
  } else {
    // Cycle complete, return to idle
    if (ENABLE_SERIAL_DEBUG) {
      Serial.println(F("Auto cycle completed"));
    }
    motorState = IDLE;
    disableMotor();
    updateLEDs();
  }
}

// Print debug information
void printDebugInfo() {
  if (!ENABLE_SERIAL_DEBUG) return;

  Serial.println(F("\n--- SYSTEM STATUS ---"));

  // Print current mode
  Serial.print(F("Mode: "));
  Serial.print(currentMode == JOG_MODE ? "JOG" : "RUN");

  // Print motor state
  Serial.print(F(" | Motor: "));
  Serial.print(motorState == IDLE ? "IDLE" : 
               motorState == JOGGING ? "JOGGING" : "RUNNING");

  // Print emergency status
  Serial.print(F(" | Emergency: "));
  Serial.print(emergencyStop ? "STOPPED" : "Normal");

  // Print driver status
  Serial.print(F(" | Driver: "));
  Serial.print(digitalRead(ENABLE_PIN) == HIGH ? "OFF" : "ON");

  // Print auto cycle progress
  if (motorState == RUNNING) {
    Serial.print(F(" | Phase: "));
    Serial.print(autoPhase == 0 ? "CW" : "CCW");
    Serial.print(F(" | Progress: "));
    Serial.print(stepsMoved);
    Serial.print(F("/"));
    Serial.print(autoPhase == 0 ? stepsToMoveCW : stepsToMoveCCW);
  }

  // Print potentiometer values
  Serial.print(F("\nPots: CW="));
  Serial.print(analogRead(POT_STEPS_CW));
  Serial.print(F(" CCW="));
  Serial.print(analogRead(POT_STEPS_CCW));
  Serial.print(F(" SPD="));
  Serial.println(analogRead(POT_SPEED));

  Serial.println(F("-------------------"));
}

串口调试输出示列:

Stepper Motor Control System Started
----------------------------------
Status: Initialization complete
System ready
Initial mode: JOG MODE

--- SYSTEM STATUS ---
Mode: JOG | Motor: IDLE | Emergency: Normal | Driver: OFF
Pots: CW=512 CCW=256 SPD=768
-------------------

Mode changed to: RUN MODE
Starting auto cycle | CW steps: 1024 | CCW steps: 512 | Step delay: 500 us

--- SYSTEM STATUS ---
Mode: RUN | Motor: RUNNING | Emergency: Normal | Driver: ON | Phase: CW | Progress: 250/1024
Pots: CW=512 CCW=256 SPD=768
-------------------

送锡器控制系统fd_v1

介绍:

本代码为arduino nano固件,外设为:A4988步进电机驱动、三个电位器、三个按钮、两个指示灯、步进电机等;适合制作送锡器、出丝器、蠕动挤出等设备的控制器,其功能是按钮1控制电机点动,由电位器调整速度,且不反转。按钮2控制单次触发电机按电位器3指定速度正转(电位器1控制旋转角度)并反转(电位器2控制旋转角度),当电位器2临近最小值时关闭反转。3开关为急停功能,急停按钮按下时电机停止工作,按钮解除时回复待机状态。待机时LED1常亮,电机运行时LED2常亮。

使用说明:

  1. 电路:

    • 电位器中间引脚 → Arduino模拟输入
    • 按钮 → Arduino数字输入(使用内部上拉电阻)
    • LED → Arduino数字输出(串联限流电阻)
    • A4988 EN → D9, DIR → D8, STEP → D7
  2. 工作流程:

    • 上电后进入待机状态(LED1亮)
    • 点动模式:按住JOG按钮电机正转,速度由速度电位器控制
    • 自动循环:按RUN按钮执行正转→反转循环
    • 紧急停止:任何时候按STOP按钮立即停止
  3. 反转保护:

    • 当反转步数电位器值<50时,自动禁用反转功能
    • 自动循环将只执行正转部分

按钮防抖处理、非阻塞步进控制和状态机实现,可直接烧录到Arduino Nano使用。

完整引脚定义:

功能 Arduino引脚
正转步数电位器 A0
反转步数电位器 A1
速度电位器 A2
点动按钮 D2
运行按钮 D3
停止按钮 D4
待机LED D5
运行LED D6
步进脉冲(STEP) D7
方向控制(DIR) D8
驱动器使能(EN) D9

功能说明:

  1. 电位器功能

    • POT_STEPS_CW (A0):控制正转步数 (0-4000步)
    • POT_STEPS_CCW (A1):控制反转步数 (值<50时禁用反转)
    • POT_SPEED (A2):控制电机速度 (100-1000μs延迟)
  2. 按钮功能

    • BUTTON_JOG (D2):点动控制(按住时正转,松开停止)
    • BUTTON_RUN (D3):启动自动循环(正转→反转)
    • BUTTON_STOP (D4):紧急停止(任何状态下返回待机)
  3. LED指示

    • LED_IDLE (D5):待机状态常亮
    • LED_RUN (D6):电机运行时常亮
  4. 步进电机控制

    • DIR_PIN (D8):方向控制(HIGH=正转,LOW=反转)
    • STEP_PIN (D7):步进脉冲(5μs高电平脉冲)
  5. 运行按钮行为

    • 短按:触发一次自动循环
    • 长按:仍然只触发一次自动循环
    • 在自动循环执行期间,忽略后续按钮按下
  6. 操作流程

    • 待机状态:LED1亮,LED2灭
    • 点动模式:按住JOG按钮电机正转,速度由速度电位器控制
    • 自动模式:按RUN按钮一次,执行完整正转→反转循环
    • 停止:任何时候按STOP按钮立即停止
  7. 安全特性

    • 点动模式不反转
    • 反转步数过小自动禁用反转
    • 状态机确保操作原子性
  8. 运行按钮单次触发机制

    • 新增 runButtonActiverunButtonConsumed 状态变量
    • 按下运行按钮时激活 runButtonActive
    • 在IDLE状态检测到激活且未消耗时启动自动循环
    • 启动后立即标记为已消耗 (runButtonConsumed = true)
  9. 按钮处理优先级

    • 点动按钮具有最高优先级(按下立即响应)
    • 停止按钮次之(立即停止任何操作)
    • 运行按钮最后处理(确保长按只触发一次)
  10. 状态机优化

    • 简化了按钮检测逻辑
    • 分离了按钮检测和状态处理
    • 自动循环完成后自动返回待机状态
  11. 反转保护逻辑

    • 当反转步数电位器值 < 50时,自动禁用反转
    • 自动循环将只执行正转部分
  12. ENABLE引脚控制

    • 增加 ENABLE_PIN 定义(默认为D9)
    • 添加 enableMotor()disableMotor() 函数
    • 驱动器使能逻辑:低电平有效(大多数A4988驱动器的标准)
  13. 电机驱动器状态管理

    • 系统启动时:禁用电机驱动器
    • 进入JOG模式或AUTO_CYCLE模式时:启用电机驱动器
    • 返回IDLE状态时:禁用电机驱动器
  14. 状态转换优化

    • 在JOG按钮释放时禁用驱动器
    • 在自动循环完成时禁用驱动器
    • 在紧急停止时立即禁用驱动器
  15. 串口调试功能

代码:


//by 扫地僧
//2025/08/13

#include <Arduino.h>

// Pin definitions
const int POT_STEPS_CW = A0;    // Potentiometer 1: CW steps
const int POT_STEPS_CCW = A1;   // Potentiometer 2: CCW steps
const int POT_SPEED = A2;       // Potentiometer 3: Speed control
const int BUTTON_JOG = 2;       // Jog button
const int BUTTON_RUN = 3;       // Run button
const int BUTTON_STOP = 4;      // Stop/Emergency button
const int LED_IDLE = 5;         // Idle indicator LED
const int LED_RUN = 6;          // Running indicator LED
const int STEP_PIN = 7;         // Step pulse
const int DIR_PIN = 8;          // Direction control
const int ENABLE_PIN = 9;       // Driver enable control (active low)

// State definition
enum State { IDLE, JOG, AUTO_CYCLE };
State currentState = IDLE;

// Emergency stop state
bool emergencyStop = false;

// Auto cycle parameters
unsigned long stepsToMoveCW = 0;
unsigned long stepsToMoveCCW = 0;
unsigned long stepsMoved = 0;
unsigned long stepDelay = 0;
int autoPhase = 0;  // 0:CW phase, 1:CCW phase

// Time tracking
unsigned long lastStepTime = 0;
unsigned long lastButtonCheck = 0;
unsigned long lastSerialPrint = 0;

// Button state management
bool runButtonActive = false;
bool runButtonConsumed = false;

// Debug flag
const bool ENABLE_SERIAL_DEBUG = true; // Set to false to disable serial

void setup() {
  if (ENABLE_SERIAL_DEBUG) {
    Serial.begin(115200);
    Serial.println(F("\nStepper Motor Control System Started"));
    Serial.println(F("----------------------------------"));
    Serial.println(F("Status: Initialization complete"));
  }

  // Initialize pins
  pinMode(BUTTON_JOG, INPUT_PULLUP);
  pinMode(BUTTON_RUN, INPUT_PULLUP);
  pinMode(BUTTON_STOP, INPUT_PULLUP);
  pinMode(LED_IDLE, OUTPUT);
  pinMode(LED_RUN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);
  pinMode(ENABLE_PIN, OUTPUT);

  // Initial state - driver disabled
  digitalWrite(LED_IDLE, HIGH);
  digitalWrite(LED_RUN, LOW);
  digitalWrite(DIR_PIN, HIGH);  // Default CW direction
  disableMotor();               // Disable driver initially

  if (ENABLE_SERIAL_DEBUG) {
    Serial.println(F("System ready"));
    printDebugInfo();
  }
}

void loop() {
  unsigned long currentMicros = micros();
  unsigned long currentMillis = millis();

  // Button state check (every 50ms)
  if (currentMillis - lastButtonCheck >= 50) {
    checkButtons();
    lastButtonCheck = currentMillis;
  }

  // State machine processing (motor control priority)
  switch (currentState) {
    case IDLE:
      handleIdleState();
      break;
    case JOG:
      handleJogState(currentMicros);
      break;
    case AUTO_CYCLE:
      handleAutoCycleState(currentMicros);
      break;
  }

  // Periodic debug output (every 1000ms)
  if (ENABLE_SERIAL_DEBUG && currentMillis - lastSerialPrint >= 1000) {
    printDebugInfo();
    lastSerialPrint = currentMillis;
  }
}

// Enable motor driver
void enableMotor() {
  if (emergencyStop) return; // Ignore if in emergency stop
  digitalWrite(ENABLE_PIN, LOW);  // Active low
  if (ENABLE_SERIAL_DEBUG) {
    Serial.println(F("Motor driver: Enabled"));
  }
}

// Disable motor driver
void disableMotor() {
  digitalWrite(ENABLE_PIN, HIGH);  // Disable driver
  if (ENABLE_SERIAL_DEBUG) {
    Serial.println(F("Motor driver: Disabled"));
  }
}

// Button check function
void checkButtons() {
  // Emergency stop button has highest priority
  if (digitalRead(BUTTON_STOP) == LOW) {
    if (!emergencyStop) {
      emergencyStop = true;
      currentState = IDLE;
      digitalWrite(LED_IDLE, HIGH);
      digitalWrite(LED_RUN, LOW);
      disableMotor();

      if (ENABLE_SERIAL_DEBUG) {
        Serial.println(F("EMERGENCY STOP ACTIVATED!"));
        Serial.println(F("System locked. Release STOP button to reset."));
      }
    }
    return; // Skip other button checks
  } 
  else if (emergencyStop) {
    // Reset emergency stop when button is released
    emergencyStop = false;
    if (ENABLE_SERIAL_DEBUG) {
      Serial.println(F("Emergency stop released. System reset."));
    }
  }

  // Jog button check
  if (digitalRead(BUTTON_JOG) == LOW && currentState == IDLE && !emergencyStop) {
    if (ENABLE_SERIAL_DEBUG) {
      Serial.println(F("Jog button pressed"));
    }
    currentState = JOG;
    digitalWrite(LED_IDLE, LOW);
    digitalWrite(LED_RUN, HIGH);
    enableMotor();
    return;
  }

  // Run button check (single trigger)
  if (digitalRead(BUTTON_RUN) == LOW && !emergencyStop) {
    if (!runButtonActive) {
      if (ENABLE_SERIAL_DEBUG) {
        Serial.println(F("Run button pressed"));
      }
      runButtonActive = true;
      runButtonConsumed = false;
    }
  } else {
    runButtonActive = false;
  }
}

// Idle state handling
void handleIdleState() {
  // Maintain LED state
  digitalWrite(LED_IDLE, HIGH);
  digitalWrite(LED_RUN, LOW);

  // Check for run button activation
  if (runButtonActive && !runButtonConsumed && !emergencyStop) {
    startAutoCycle();
    runButtonConsumed = true;
  }
}

// Jog state handling
void handleJogState(unsigned long currentMicros) {
  // Read speed and calculate delay (100-1000us)
  int speedValue = analogRead(POT_SPEED);
  stepDelay = map(speedValue, 0, 1023, 1000, 100);

  // Ensure CW direction
  digitalWrite(DIR_PIN, HIGH);

  // Non-blocking step control
  if (currentMicros - lastStepTime >= stepDelay) {
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(2);
    digitalWrite(STEP_PIN, LOW);
    lastStepTime = currentMicros;
  }

  // Detect button release
  if (digitalRead(BUTTON_JOG) == HIGH) {
    if (ENABLE_SERIAL_DEBUG) {
      Serial.println(F("Jog button released"));
    }
    currentState = IDLE;
    digitalWrite(LED_IDLE, HIGH);
    digitalWrite(LED_RUN, LOW);
    disableMotor();
  }
}

// Start auto cycle
void startAutoCycle() {
  // Read parameters
  stepsToMoveCW = map(analogRead(POT_STEPS_CW), 0, 1023, 0, 2000);
  stepsToMoveCCW = map(analogRead(POT_STEPS_CCW), 0, 1023, 0, 2000);
  stepDelay = map(analogRead(POT_SPEED), 0, 1023, 1000, 100);

  // Check CCW steps validity
  if (stepsToMoveCCW < 50) {
    stepsToMoveCCW = 0;
    if (ENABLE_SERIAL_DEBUG) {
      Serial.println(F("Warning: CCW steps too low, disabled"));
    }
  }

  // Initialize auto cycle
  currentState = AUTO_CYCLE;
  autoPhase = 0;
  stepsMoved = 0;
  digitalWrite(DIR_PIN, HIGH);  // Initial CW direction
  digitalWrite(LED_IDLE, LOW);
  digitalWrite(LED_RUN, HIGH);
  enableMotor();

  if (ENABLE_SERIAL_DEBUG) {
    Serial.print(F("Starting auto cycle | CW steps: "));
    Serial.print(stepsToMoveCW);
    Serial.print(F(" | CCW steps: "));
    Serial.print(stepsToMoveCCW);
    Serial.print(F(" | Step delay: "));
    Serial.print(stepDelay);
    Serial.println(F(" us"));
  }
}

// Auto cycle state handling
void handleAutoCycleState(unsigned long currentMicros) {
  // Non-blocking step control
  if (currentMicros - lastStepTime >= stepDelay) {
    // Generate step pulse
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(2);
    digitalWrite(STEP_PIN, LOW);
    lastStepTime = currentMicros;

    stepsMoved++;

    // Check phase completion
    if ((autoPhase == 0 && stepsMoved >= stepsToMoveCW) || 
        (autoPhase == 1 && stepsMoved >= stepsToMoveCCW)) {
      nextAutoPhase();
    }
  }
}

// Switch to next phase
void nextAutoPhase() {
  if (autoPhase == 0 && stepsToMoveCCW > 0) {
    // Switch to CCW phase
    autoPhase = 1;
    stepsMoved = 0;
    digitalWrite(DIR_PIN, LOW);  // Set CCW direction

    if (ENABLE_SERIAL_DEBUG) {
      Serial.print(F("Switching to CCW phase | Steps: "));
      Serial.println(stepsToMoveCCW);
    }
  } else {
    // Cycle complete, return to idle
    if (ENABLE_SERIAL_DEBUG) {
      Serial.println(F("Auto cycle completed"));
    }
    currentState = IDLE;
    digitalWrite(LED_IDLE, HIGH);
    digitalWrite(LED_RUN, LOW);
    disableMotor();
  }
}

// Print debug information
void printDebugInfo() {
  if (!ENABLE_SERIAL_DEBUG) return;

  Serial.println(F("\n--- SYSTEM STATUS ---"));

  // Print current state
  Serial.print(F("State: "));
  switch (currentState) {
    case IDLE: 
      Serial.print(F("IDLE"));
      break;
    case JOG: 
      Serial.print(F("JOG"));
      break;
    case AUTO_CYCLE: 
      Serial.print(F("AUTO"));
      Serial.print(autoPhase == 0 ? F("(CW)") : F("(CCW)"));
      break;
  }

  // Print emergency status
  Serial.print(F(" | Emergency: "));
  Serial.print(emergencyStop ? F("STOPPED") : F("Normal"));

  // Print motor status
  Serial.print(F(" | Motor: "));
  Serial.print(digitalRead(ENABLE_PIN) == HIGH ? F("OFF") : F("ON"));

  // Print auto cycle progress
  if (currentState == AUTO_CYCLE) {
    Serial.print(F(" | Progress: "));
    Serial.print(stepsMoved);
    Serial.print(F("/"));
    Serial.print(autoPhase == 0 ? stepsToMoveCW : stepsToMoveCCW);
  }

  // Print potentiometer values
  Serial.print(F("\nPots: CW="));
  Serial.print(analogRead(POT_STEPS_CW));
  Serial.print(F(" CCW="));
  Serial.print(analogRead(POT_STEPS_CCW));
  Serial.print(F(" SPD="));
  Serial.println(analogRead(POT_SPEED));

  Serial.println(F("-------------------"));
}

使用注意事项:

  1. A4988连接

    • 注意:大多数A4988模块是低电平使能,即:
      • EN=HIGH:驱动器禁用(电机无电流)
      • EN=LOW:驱动器使能(电机有电流)
  2. 节能与安全

    • 空闲状态下电机驱动器自动禁用,减少发热和能耗
    • 紧急停止时立即切断电机电流
    • 操作完成后自动进入节能模式
  3. 反转保护

    • 当反转步数电位器值 < 50时,自动禁用反转功能
    • 自动循环将只执行正转部分