送锡器控制系统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;
  }
}

送锡器控制系统fd32_v1

介绍:

本代码为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. 参数调整:

    • 正转步数电位器: 控制自动循环中正转步数
    • 反转步数电位器: 控制自动循环中反转步数
    • 速度电位器: 实时控制电机速度

高级配置

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> // 用于串口通信

// 引脚定义
#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  // 运行模式指示灯

#define DRIVER_ADDRESS  0x00  // TMC2209 UART地址
#define R_SENSE         0.11f // 电流检测电阻值

// 使用硬件串口1与TMC2209通信
HardwareSerial SerialTMC(PA10, PA9); // RX, TX
TMC2209Stepper driver(&SerialTMC, R_SENSE, DRIVER_ADDRESS);

// 操作模式
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;

// 时间跟踪
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); // 默认正转方向

  // 初始化UART通信
  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模式
  driver.pwm_autograd(true);  // 启用自动梯度
  driver.pwm_freq(1);        // PWM频率设置 (修正错误)
}

// 更新LED指示
void updateLEDs() {
  if (motorState == IDLE) {
    digitalWrite(LED_JOG, currentMode == JOG_MODE ? HIGH : LOW);
    digitalWrite(LED_RUN, currentMode == RUN_MODE ? HIGH : LOW);
  } else {
    // 运行时闪烁LED
    static unsigned long lastBlink = 0;
    static bool blinkState = false;

    if (millis() - lastBlink > 500) {
      blinkState = !blinkState;
      lastBlink = millis();
    }

    digitalWrite(LED_JOG, motorState == JOGGING ? blinkState : LOW);
    digitalWrite(LED_RUN, motorState == RUNNING ? blinkState : LOW);
  }
}

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

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

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

  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;
    Serial.println("Warning: CCW steps too low, disabled");
  }

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

  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); // 设置反转方向

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

// 打印调试信息
void printDebugInfo() {
  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.print(" | CS: ");
  Serial.print(driver.cs_actual());

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

void setup() {
  // 初始化串口通信
  Serial.begin(115200);
  while (!Serial); // 等待串口连接
  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);

  // 初始化ADC引脚
  pinMode(POT_STEPS_CW, INPUT_ANALOG);
  pinMode(POT_STEPS_CCW, INPUT_ANALOG);
  pinMode(POT_SPEED, INPUT_ANALOG);

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

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

  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();

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

    lastButtonCheck = currentMillis;
  }

  // 空闲状态处理
  if (motorState == IDLE && !emergencyStop) {
    // 检测动作按钮按下
    if (actionButtonActive && !actionButtonConsumed) {
      if (currentMode == JOG_MODE) {
        // 开始点动运行
        motorState = JOGGING;
        enableMotor();
        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 (!actionButtonActive) {
      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();
      }
    }

    // 检测急停或动作按钮按下停止
    if (emergencyStop || (actionButtonActive && !actionButtonConsumed)) {
      Serial.println("Stopping auto cycle");
      motorState = IDLE;
      disableMotor();
      updateLEDs();
      actionButtonConsumed = true;
    }
  }

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

电位器输入单片机是否需要添加电容?

电位器输入单片机是否需要电容,通常建议加上电容,尤其是在使用ADC(模数转换器)功能时。虽然不是绝对强制要求,但在绝大多数情况下,加上电容能显著提高稳定性、减少噪声和干扰,获得更准确的读数。

以下是详细解释:

  1. 目的:滤波和稳定电压

    • 电位器作为一个模拟电压源(分压器),其输出信号容易受到各种噪声干扰:
      • 电源噪声: 为电位器供电的电源(尤其是开关电源)本身可能带有纹波。
      • 数字噪声: 来自单片机自身或其他数字电路(如GPIO切换、时钟信号)通过电源或地线耦合过来的高频干扰。
      • 环境电磁干扰: 空间中的电磁波可能被较长的连接线拾取。
      • 接触噪声: 电位器滑动触点接触不良或移动时可能产生的瞬时毛刺(电容对此帮助有限)。
    • 当单片机内部的ADC对电位器的输出电压进行采样时,需要一个稳定的输入电压。采样瞬间电压的波动会直接导致转换结果的误差。
    • 电容的作用就是“滤除”这些高频噪声,并在ADC采样瞬间提供一个稳定的电压源。 它就像一个小的水库(电荷库),当输入电压有微小的、快速的波动时,电容可以快速充放电来吸收或补充电荷,从而维持其两端电压的相对稳定。
  2. 电容值选择(推荐):

    • 0.1uF (100nF) 陶瓷电容: 这是最常见最推荐的选择。陶瓷电容具有很低的等效串联电阻和电感,对滤除高频噪声(MHz范围)非常有效。价格低廉,体积小。
    • 可选:10uF 电解电容或钽电容: 如果电路中存在较明显的低频噪声(比如电源低频纹波),可以在0.1uF陶瓷电容的基础上,再并联一个10uF的电解电容或钽电容。这个电容主要用于滤除较低频率的干扰。对于大多数应用,仅一个0.1uF陶瓷电容就足够了。
  3. 连接方式:

    • 将电容连接在单片机的ADC输入引脚地之间
    • 尽量靠近单片机的ADC引脚放置。 缩短电容到引脚的走线长度能最大限度地发挥其滤波效果。
  4. 为什么“需要”电容(总结优点):

    • 提高ADC读数稳定性: 显著减少ADC转换结果的随机跳动,读数更平滑、更精确。
    • 抑制噪声干扰: 有效滤除来自电源、数字电路和环境的噪声。
    • 提升系统鲁棒性: 使系统在稍差的电气环境中也能正常工作。
    • 成本低、实现简单: 添加一个电容几乎不增加成本,电路改动极小。
  5. 什么时候可能“不需要”?

    • 在极其简单、干扰极小的实验环境或玩具应用中。
    • 如果电位器离单片机ADC引脚非常近,连线极短,并且整个系统有非常干净、稳定的电源和接地。
    • 如果不追求高精度或稳定性,对ADC读数的轻微跳动不敏感。
    • 即使在这些情况下,加上电容通常也是有益无害的。

结论:

强烈建议在将电位器输出连接到单片机ADC输入引脚时,在ADC引脚和地之间添加一个0.1uF (100nF) 的陶瓷电容。这是一个简单、廉价且极其有效的措施,可以显著提升模拟信号的质量和ADC读数的准确性与稳定性。忽略这个电容可能会导致ADC读数波动大、不准确,尤其是在有一定电气噪声的环境中。

按钮硬去抖设计

在按钮开关连接到单片机输入时,强烈建议加上一个电容(通常称为“去抖电容”),尤其是在使用机械触点开关时。这不是绝对强制性的,但对于提高系统的可靠性和稳定性至关重要

以下是详细解释:

  1. 按钮抖动问题

    • 机械按钮开关在按下或释放的瞬间,其金属触点不会立即稳定接触或断开,而是会在短时间内发生物理弹跳(通常持续几毫秒到十几毫秒)。
    • 这会导致在期望的单个“按下”或“释放”动作期间,实际电气信号产生一系列快速的通断脉冲(抖动)。
    • 如果单片机直接读取这个抖动的信号,它可能会错误地将一次按键识别为多次按键。
  2. 去抖电容的作用

    • 硬件去抖:在按钮开关两端并联一个小电容(典型值为0.1uF – 0.47uF)是最常见的硬件去抖方法。
    • 工作原理
      • 按下时:当按钮按下闭合瞬间,触点弹跳导致电压波动。电容的存在会吸收这些快速的电压变化,使输入端的电压上升变得相对缓慢(由RC时间常数决定)。
      • 释放时:当按钮释放断开瞬间,触点弹跳导致电压波动。电容会缓慢放电,使输入端的电压下降变得平缓。
    • 效果:电容就像一个低通滤波器,滤除了由于触点抖动产生的高频噪声脉冲,使得输入到单片机引脚的信号变得相对干净和平稳,只有一个清晰的上升沿(按下)或下降沿(释放)。这大大降低了单片机误判的可能性。
  3. 典型电路结构(重要)

    • 除了电容,按钮开关电路通常还需要一个上拉电阻下拉电阻,以确保按钮未按下时,单片机输入引脚有一个确定的逻辑状态(高电平或低电平),而不是悬空(浮空状态会导致读数不稳定和额外功耗)。
    • 常用接法(以低电平有效为例)
      • VCC 通过一个上拉电阻(常用4.7kΩ – 10kΩ)连接到单片机输入引脚。
      • 按钮开关一端接地(GND),另一端连接到单片机输入引脚(同时连接到上拉电阻)。
      • 去抖电容(0.1uF)并联在按钮开关的两端(即接在输入引脚和地之间)。
    • 当按钮未按下时,上拉电阻将输入引脚拉至高电平。
    • 当按钮按下时,输入引脚通过开关短接到地(低电平),电容吸收抖动。
    • 当按钮释放时,上拉电阻缓慢(因电容放电)将输入引脚拉回高电平。
  4. 为什么有时可以不加电容?

    • 软件去抖:如果不在硬件上加电容,可以在单片机程序中实现软件去抖。基本思路是:检测到按键状态变化后,延时一段时间(例如10ms – 50ms,覆盖抖动期),再次读取按键状态。如果状态确认变化了,才认为是一次有效的按键操作。
    • 优点:节省硬件成本(一个电容),灵活性高(可调整延时时间)。
    • 缺点
      • 消耗CPU时间:在延时期间,CPU可能无法处理其他任务(除非使用中断+定时器等更复杂的方法)。
      • 可能遗漏快速按键:如果延时设置过长,可能会遗漏用户非常快速的连续按键。
      • 无法完全消除抖动影响:在最坏情况下,抖动可能恰好发生在软件检测的间隙。
      • 增加程序复杂度:需要编写额外的去抖代码。
  5. 最佳实践:软硬结合

    • 对于大多数应用,推荐同时使用硬件去抖电容和软件去抖
    • 硬件电容:作为第一道防线,大幅削弱抖动的幅度和能量,使输入信号基本可用。
    • 软件去抖:作为第二道防线,进一步确认按键状态,处理硬件未能完全消除的残余抖动,并识别按键的“按下”、“释放”、“长按”等事件。
    • 这种组合提供了最高的可靠性和鲁棒性。硬件去抖让软件的工作更容易、更可靠;软件去抖则提供了灵活性和事件识别能力。
  6. 电容选择注意事项

    • :0.1uF 是最常用且效果良好的值。0.047uF或0.22uF、0.47uF也可用。值太小可能去抖效果不足;值太大会导致按键按下/释放时电压变化过慢,可能影响快速按键识别或增加软件去抖的难度。
    • 类型:陶瓷电容(如X7R, X5R)是最常用、最经济的选择。
    • 耐压:满足电路电压要求(通常远高于5V或3.3V)即可。
    • 位置:尽量靠近按钮开关或单片机输入引脚安装,以减小走线引入的干扰。

总结:

虽然理论上可以通过纯软件实现按键去抖,但强烈建议在按钮开关和单片机输入引脚之间并联一个去抖电容(0.1uF是标准选择)。这结合一个上拉/下拉电阻构成标准的、可靠的输入电路。硬件去抖能显著提高信号质量,减轻软件负担,提升系统整体稳定性。最佳方案是硬件去抖电容 + 软件去抖逻辑 的结合。不加电容仅依赖软件去抖是可行的,但通常不是最优或最可靠的选择。

送锡器控制系统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时,自动禁用反转功能
    • 自动循环将只执行正转部分