0x6A Logbook

0x6A Logbook
Shi6a的筆記本
  1. 首頁
  2. 程式開發
  3. 正文

ESP32 步進馬達控制完整教學:A4988 驅動器 STEP/DIR 脈衝控制與梯形加減速

2026 年 6 月 15 日 12點熱度 0人點贊 0條評論

步進馬達與 A4988 驅動器

ESP32 步進馬達控制在 CNC、3D 列印、機器手臂等精密定位場景中扮演核心角色。步進馬達將電脈衝轉換為精確的機械角度位移,每個脈衝對應一個固定的步進角(通常 1.8°),無需編碼器回授即可實現開迴路定位。

A4988 是 Allegro 推出的 DMOS 微步進驅動器,內建自動電流衰減、過熱關斷和交叉電流保護,只需 STEP/DIR 兩條訊號線即可控制步進馬達。

ESP32 + A4988 步進馬達控制系統

STEP/DIR 控制時序

A4988 使用最簡潔的 STEP/DIR 介面:

  • STEP:每個上升緣觸發一次步進(或微步進)
  • DIR:邏輯電平決定旋轉方向(HIGH = 順時針,LOW = 逆時針)
  • ENABLE:低電位啟用驅動器輸出
  • MS1/MS2/MS3:微步進模式選擇

A4988 STEP/DIR 脈衝時序

關鍵時序要求:

  • STEP 脈衝寬度:≥ 1μs(A4988 規格)
  • DIR 建立時間:需在 STEP 上升緣前 ≥ 200ns 準備好
  • 最高 STEP 頻率:約 200 kHz(對應 1.8° 馬達 → 1000 RPM)
  • 最小 STEP 低電位時間:≥ 1μs

微步進(Microstepping)

A4988 支援多種微步進模式,透過 MS1/MS2/MS3 三個腳位設定:

MS1 MS2 MS3 微步進 每步角度 (1.8°)
LOW LOW LOW 全步進 (1/1) 1.800°
HIGH LOW LOW 半歩進 (1/2) 0.900°
LOW HIGH LOW 1/4 步進 0.450°
HIGH HIGH LOW 1/8 步進 0.225°
HIGH HIGH HIGH 1/16 步進 0.113°

全步進 vs 1/16 微步進

微步進透過在 A/B 兩相繞組施加正弦/餘弦電流,將一個全步進細分為多個微小步進。優點是運轉更平滑、共振更小、解析度更高;缺點是高微步進時扭力略降。

梯形加減速

步進馬達在高速啟動時可能失步(丟失脈衝),因此需要加減速曲線:

梯形加減速曲線

加減速原理很直觀:

  • 加速階段:STEP 脈衝週期逐漸縮短(頻率逐漸增加),讓馬達平穩提速
  • 等速階段:固定 STEP 頻率,維持目標轉速
  • 減速階段:STEP 脈衝週期逐漸延長,讓馬達平穩停止

ESP32 + A4988 硬體接線

A4988 ESP32 說明
STEP GPIO 26 步進脈衝輸入
DIR GPIO 27 方向控制
ENABLE GPIO 14 啟用 (LOW = 啟用)
MS1 GPIO 16 微步進選擇
MS2 GPIO 17 微步進選擇
MS3 GPIO 18 微步進選擇
VMOT 8-35V 電源 馬達電源 (獨立供電!)
GND GND (共地) ESP32 與電源共地
1A/1B 馬達線圈 A 連接步進馬達
2A/2B 馬達線圈 B 連接步進馬達

Arduino 程式碼:基本控制

// ESP32 步進馬達 — A4988 基本控制
#define STEP_PIN   26
#define DIR_PIN    27
#define ENA_PIN    14

void setup() {
    pinMode(STEP_PIN, OUTPUT);
    pinMode(DIR_PIN,  OUTPUT);
    pinMode(ENA_PIN,  OUTPUT);

    digitalWrite(STEP_PIN, LOW);
    digitalWrite(ENA_PIN, LOW);   // 啟用驅動器
}

void stepMotor(bool dir, int steps, int delay_us) {
    digitalWrite(DIR_PIN, dir ? HIGH : LOW);
    delayMicroseconds(1);  // DIR 建立時間

    for (int i = 0; i < steps; i++) {
        digitalWrite(STEP_PIN, HIGH);
        delayMicroseconds(delay_us);
        digitalWrite(STEP_PIN, LOW);
        delayMicroseconds(delay_us);
    }
}

void loop() {
    // 順時針 200 步 (一圈) - 10 RPM
    stepMotor(true, 200, 1500);
    delay(1000);

    // 逆時針 200 步 (一圈)
    stepMotor(false, 200, 1500);
    delay(1000);
}

使用 AccelStepper 函式庫(推薦)

// ESP32 步進馬達 — AccelStepper 函式庫(內建加減速)
#include <AccelStepper.h>

#define STEP_PIN 26
#define DIR_PIN  27
#define ENA_PIN  14

// 建立步進馬達物件 (driver type = 1: STEP/DIR)
AccelStepper stepper(1, STEP_PIN, DIR_PIN);

void setup() {
    pinMode(ENA_PIN, OUTPUT);
    digitalWrite(ENA_PIN, LOW);  // 啟用

    stepper.setMaxSpeed(1000);       // 最高速度 (steps/s)
    stepper.setAcceleration(500);    // 加速度 (steps/s/s)
    stepper.setSpeed(200);           // 等速速度
}

void loop() {
    // 移動 400 步 (2 圈),內建梯形加減速
    stepper.moveTo(400);
    while (stepper.distanceToGo() != 0) {
        stepper.run();  // 必須在 loop 中頻繁呼叫
    }
    delay(1000);

    // 回到原點
    stepper.moveTo(0);
    while (stepper.distanceToGo() != 0) {
        stepper.run();
    }
    delay(1000);

    // 持續旋轉
    static unsigned long lastMove = 0;
    if (millis() - lastMove > 2000) {
        stepper.move(200);  // 相對移動 200 步
        lastMove = millis();
    }
    stepper.run();
}

自製梯形加減速

// ESP32 步進馬達 — 自製梯形加減速
#define STEP_PIN 26
#define DIR_PIN 27

// 加減速參數
int stepsPerRev = 200;    // 200 steps/rev (1.8°)
long targetPos = 0;
long currentPos = 0;

// 速度曲線參數
float maxSpeed = 800.0;       // steps/s
float accel = 400.0;          // steps/s/s
float currentSpeed = 0.0;     // 目前速度

// 時間
unsigned long lastStepTime = 0;
unsigned long stepInterval = 0;

void setup() {
    pinMode(STEP_PIN, OUTPUT);
    pinMode(DIR_PIN, OUTPUT);
    digitalWrite(STEP_PIN, LOW);
}

void moveTo(long target) {
    targetPos = target;
    currentSpeed = 0;  // 從靜止開始
}

bool runSpeed() {
    // 計算到目標的距離
    long dist = targetPos - currentPos;

    if (dist == 0) return false;

    // 決定方向
    bool dir = dist > 0;
    digitalWrite(DIR_PIN, dir ? HIGH : LOW);

    // 計算減速距離(對稱加減速)
    float decelDist = (currentSpeed * currentSpeed) / (2.0 * accel);

    if (abs(dist) < decelDist) {
        // 需要減速
        currentSpeed -= accel * 0.0001;  // 簡化:每次呼叫減少速度
        if (currentSpeed < 10) currentSpeed = 10;
    } else if (currentSpeed < maxSpeed) {
        // 加速階段
        currentSpeed += accel * 0.0001;
        if (currentSpeed > maxSpeed) currentSpeed = maxSpeed;
    }

    // 計算 STEP 間隔
    stepInterval = 1000000.0 / currentSpeed;  // μs

    // 產生 STEP 脈衝
    if (micros() - lastStepTime >= stepInterval) {
        digitalWrite(STEP_PIN, HIGH);
        delayMicroseconds(2);
        digitalWrite(STEP_PIN, LOW);
        lastStepTime = micros();
        currentPos += dir ? 1 : -1;
    }
    return true;
}

void loop() {
    // 往復運動
    static int phase = 0;
    if (currentPos == targetPos) {
        if (phase == 0) {
            moveTo(800);   // 前進 4 圈
            phase = 1;
        } else {
            moveTo(0);     // 回到原點
            phase = 0;
        }
        delay(500);
    }
    runSpeed();
}

微步進模式設定

// ESP32 步進馬達 — 微步進模式動態切換
#define MS1_PIN 16
#define MS2_PIN 17
#define MS3_PIN 18

void setMicrostep(int mode) {
    // mode: 0=Full, 1=Half, 2=1/4, 3=1/8, 4=1/16
    switch (mode) {
        case 0:  // Full step
            digitalWrite(MS1, LOW);
            digitalWrite(MS2, LOW);
            digitalWrite(MS3, LOW);
            break;
        case 1:  // Half step
            digitalWrite(MS1, HIGH);
            digitalWrite(MS2, LOW);
            digitalWrite(MS3, LOW);
            break;
        case 2:  // 1/4 step
            digitalWrite(MS1, LOW);
            digitalWrite(MS2, HIGH);
            digitalWrite(MS3, LOW);
            break;
        case 3:  // 1/8 step
            digitalWrite(MS1, HIGH);
            digitalWrite(MS2, HIGH);
            digitalWrite(MS3, LOW);
            break;
        case 4:  // 1/16 step
            digitalWrite(MS1, HIGH);
            digitalWrite(MS2, HIGH);
            digitalWrite(MS3, HIGH);
            break;
    }
}

void setup() {
    pinMode(MS1_PIN, OUTPUT);
    pinMode(MS2_PIN, OUTPUT);
    pinMode(MS3_PIN, OUTPUT);

    setMicrostep(4);  // 預設 1/16 微步進(最平滑)
}

// 動態切換策略:
// - 快速移動時:全步進或半步進(扭力大、速度快)
// - 精確定位時:1/8 或 1/16 微步進(解析度高、震動小)
// - 切換時機:必須在馬達停止時切換,不可在運轉中改變

扭力-轉速特性

步進馬達扭力-轉速特性

從扭力曲線可以看出:

  • 低轉速區 (< 200 RPM):扭力接近額定值,適合需要大扭力的應用
  • 中速共振區 (150~350 RPM):扭力波動大,可能產生抖動和噪音,建議避開或使用微步進
  • 高速區 (> 500 RPM):扭力隨轉速增加急遽下降(反電動勢效應),最終達到 pull-out 轉速
  • 微步進影響:1/16 微步進扭力約為全步進的 85%,但運轉更平滑

進階:多軸同步控制

// ESP32 雙軸步進馬達同步控制
#include <AccelStepper.h>

#define STEP_X 26
#define DIR_X  27
#define STEP_Y 33
#define DIR_Y  32

AccelStepper stepperX(1, STEP_X, DIR_X);
AccelStepper stepperY(1, STEP_Y, DIR_Y);

// 多軸管理
AccelStepper* steppers[] = { &stepperX, &stepperY };
const int NUM_AXIS = 2;

void setup() {
    stepperX.setMaxSpeed(800);
    stepperX.setAcceleration(400);
    stepperY.setMaxSpeed(800);
    stepperY.setAcceleration(400);

    // 直線插補:同時移動到目標位置
    stepperX.moveTo(800);
    stepperY.moveTo(400);
}

void loop() {
    // 同時驅動所有軸(同步運動)
    bool running = false;
    for (int i = 0; i < NUM_AXIS; i++) {
        if (steppers[i]->distanceToGo() != 0) {
            steppers[i]->run();
            running = true;
        }
    }
    if (!running) {
        delay(1000);
        // 反向移動
        stepperX.moveTo(0);
        stepperY.moveTo(0);
    }
}

實務注意事項

  • 獨立電源:A4988 VMOT 需要 8-35V 獨立電源,不可從 ESP32 的 3.3V/5V 供電。NEMA 17 典型 2A/phase,需搭配 2A 以上電源
  • 大電容:A4988 電源端並聯 100μF 電解電容,吸收反電動勢
  • 散熱:A4988 在 1A 以上需要散熱片,超過 1.5A 建議加風扇
  • 共地:ESP32 GND 和 A4988 GND 必須連接
  • 電流設定:A4988 的 VREF 腳位透過可變電阻設定輸出電流:I_TripMax = VREF / (8 * R_Sense)
  • 共振:中速時可能發生機械共振,可嘗試改變微步進模式或加裝阻尼器

總結

ESP32 搭配 A4988 驅動器是控制步進馬達最簡潔可靠的方案。透過 STEP/DIR 介面和 AccelStepper 函式庫,可以在幾行程式碼內實現精確定位、加減速控制和多軸同步運動。

選擇指引:

  • 簡單旋轉或低精度定位:全步進 + delay() 控制
  • 一般 CNC/3D 列印:1/8 或 1/16 微步進 + AccelStepper 函式庫
  • 精密定位或低震動:1/16 或 1/32 微步進 + TMC2209/TMC5160 驅動器(取代 A4988)
  • 多軸協同:AccelStepper 多軸管理 + 定時器中斷
標籤: 教學
最後更新:2026 年 6 月 15 日

shi6a

這個人很懶,什麼都沒留下

點贊
< 上一篇
下一篇 >

文章評論

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回覆

COPYRIGHT © 2026 0x6A Logbook. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang