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