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