fdv2在fd_v1的基础上主要功能变更:
将 点动按钮改为模式 切换开关(在点动模式和运行模式之间切换),并调整运行按钮的功能以适应不同模式。
-
按钮功能重构:
BUTTON_JOG
改为BUTTON_MODE
:模式切换按钮- 按下时在点动模式(JOG)和运行模式(RUN)之间切换
- 只能在空闲状态(IDLE)下切换模式
BUTTON_RUN
改为BUTTON_ACTION
:动作按钮- 在点动模式下:按下时开始点动运行(类似原点动功能)
- 在运行模式下:按下时启动自动循环(类似原运行功能)
-
状态系统分离:
Mode
枚举:表示系统模式(JOG_MODE 或 RUN_MODE)MotorState
枚举:表示电机状态(IDLE, JOGGING, RUNNING)- 两者独立工作,互不影响
-
LED指示优化:
LED_IDLE
改为LED_JOG
:点动模式指示灯LED_RUN
改为LED_RUN
:运行模式指示灯- 空闲状态:当前模式对应的LED亮
- 点动运行中:JOG LED亮
- 自动循环中:RUN LED亮
-
功能逻辑调整:
- 点动模式:
- 按下动作按钮开始点动运行
- 松开动作按钮立即停止
- 只能正转,速度由速度电位器控制
- 运行模式:
- 按下动作按钮启动自动循环
- 自动循环独立运行直到完成
- 正/反转步数由电位器控制
- 点动模式:
-
默认模式切换开关: -通过修改Mode currentMode切换默认模式
工作流程:
-
模式切换:
- 在空闲状态(IDLE)下按下模式按钮切换模式
- JOG模式:JOG LED亮
- RUN模式:RUN LED亮
-
点动模式操作:
- 按下动作按钮:电机开始点动运行(JOGGING状态,JOG LED亮)
- 松开动作按钮:电机立即停止(返回IDLE状态)
- 速度由速度电位器实时控制
-
运行模式操作:
- 按下动作按钮:启动自动循环(RUNNING状态,RUN LED亮)
- 自动循环独立运行(正转→反转→完成)
- 完成后自动返回空闲状态
-
急停功能:
- 任何状态下按下停止按钮立即停止所有操作
- 系统进入紧急锁定状态
- 释放停止按钮后系统复位
-
直观的模式切换:
- 专用模式按钮切换工作模式
- LED清晰指示当前模式
- 模式切换仅在安全状态(空闲)下允许
-
动作按钮多功能:
- 点动模式:按下即走,松开即停
- 运行模式:触发自动循环
- 统一操作接口,简化用户交互
-
状态指示优化:
- 双LED分别指示模式和运行状态
- 空闲时显示当前模式
- 运行时显示当前活动状态
-
安全设计:
- 急停按钮完全独立,最高优先级
- 模式切换只能在空闲状态进行
- 自动循环完成后自动复位
-
串口调试增强:
- 清晰显示当前模式和电机状态
- 显示自动循环进度
- 显示电位器实时值
//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
-------------------