步進馬達與 A4988 驅動器
ESP32 步進馬達控制在 CNC、3D 列印、機器手臂等精密定位場景中扮演核心角色。步進馬達將電脈衝轉換為精確的機械角度位移,每個脈衝對應一個固定的步進角(通常 1.8°),無需編碼器回授即可實現開迴路定位。
A4988 是 Allegro 推出的 DMOS 微步進驅動器,內建自動電流衰減、過熱關斷和交叉電流保護,只需 STEP/DIR 兩條訊號線即可控制步進馬達。

STEP/DIR 控制時序
A4988 使用最簡潔的 STEP/DIR 介面:
- STEP:每個上升緣觸發一次步進(或微步進)
- DIR:邏輯電平決定旋轉方向(HIGH = 順時針,LOW = 逆時針)
- ENABLE:低電位啟用驅動器輸出
- MS1/MS2/MS3:微步進模式選擇
關鍵時序要求:
- 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° |
微步進透過在 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 多軸管理 + 定時器中斷
文章評論