⚙️ ESP32 28BYJ-48 步进电机实战:精准角度控制从入门到应用
📅 2026-05-27 · 📂 硬件编程 · ⏱ 阅读约 6 分钟
📺 B站推荐视频:ESP32控制步进电机 | ESP32 control stepper motor
📖 概述
28BYJ-48 是嵌入式开发中最常见的四相五线步进电机,搭配 ULN2003 驱动板使用。它每步转动约 5.625°(64步/圈),内部通过减速齿轮将精度提升到 2048 步/圈(约 0.18°/步),非常适合需要精准角度控制的场景。
相比之前学的 SG90 舵机(0~180° 范围限制),步进电机可以360° 连续旋转且保持扭矩,是相机云台、3D打印机、自动窗帘、机器人关节的核心部件。
🛒 物料清单
| 物料 | 型号/参数 | 参考价格 |
| 开发板 | ESP32 / ESP32-S3 | ¥15~30 |
| 步进电机 | 28BYJ-48(5V,4相5线) | ¥5~8 |
| 驱动板 | ULN2003 步进电机驱动模块 | ¥3~5 |
| 电源 | 5V 外接电源(推荐独立供电) | ¥5~10 |
| 杜邦线 | 公对母 × 6 | ¥1 |
⚠️ 供电警告:28BYJ-48 工作时电流约 200~300mA,不要用 ESP32 的 5V 引脚直接供电!电压不稳会导致电机丢步或 ESP32 重启。建议使用独立 5V 电源,或至少给 ESP32 用合格的 USB 供电。
🔌 接线图
ULN2003 驱动板是步进电机的标准搭档——它内部集成 7 个达林顿晶体管,将 ESP32 的 3.3V 弱信号放大为电机所需的 5V 驱动电流。
28BYJ-48 电机 ──── ULN2003 驱动板 ──── ESP32
蓝色线 → IN1 → GPIO 16
粉色线 → IN2 → GPIO 17
黄色线 → IN3 → GPIO 18
橙色线 → IN4 → GPIO 19
红色线 → VCC(+) → 5V 外接电源 (+)
— → GND(-) → ESP32 GND + 电源 GND(共地!)
💡 引脚可以换:GPIO 16~19 是推荐配置,你可以换成任意 GPIO。只需同步修改代码中的 IN1~IN4 引脚定义即可。
💻 基础代码:让电机转起来
步进电机的核心是按顺序激励线圈。我们使用 4 步(全步模式)或 8 步(半步模式)的序列来驱动。以下代码实现正转一圈 → 停1秒 → 反转一圈的循环:
// 28BYJ-48 基础驱动 — 全步模式
const int IN1 = 16;
const int IN2 = 17;
const int IN3 = 18;
const int IN4 = 19;
// 全步励磁序列(4步)
const int steps_full[4][4] = {
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}
};
// 半步励磁序列(8步,更平滑)
const int steps_half[8][4] = {
{1, 0, 0, 0},
{1, 1, 0, 0},
{0, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 1, 0},
{0, 0, 1, 1},
{0, 0, 0, 1},
{1, 0, 0, 1}
};
int pins[4] = {IN1, IN2, IN3, IN4};
void setup() {
for (int i = 0; i < 4; i++) {
pinMode(pins[i], OUTPUT);
digitalWrite(pins[i], LOW);
}
Serial.begin(115200);
Serial.println("28BYJ-48 Stepper Ready!");
}
void stepMotor(int dir, int total_steps, int delay_ms) {
for (int i = 0; i < total_steps; i++) {
int idx = dir == 1 ? (i % 8) : (7 - (i % 8));
for (int j = 0; j < 4; j++) {
digitalWrite(pins[j], steps_half[idx][j]);
}
delay(delay_ms);
}
}
void loop() {
Serial.println("正转 1 圈...");
stepMotor(1, 4096, 2); // 半步模式 4096 步 = 1 圈
delay(1000);
Serial.println("反转 1 圈...");
stepMotor(-1, 4096, 2);
delay(1000);
}
💡 步数计算:28BYJ-48 减速比 1:64,全步模式 64×64=4096 步/圈,半步模式 64×64×2=4096 步/圈(半步每步角度减半但数量翻倍)。如果觉得 4096 步太多,可以用全步模式(2048 步/圈),但振动稍大。
🚀 进阶应用
1. 精准角度控制函数
很多场景不需要转整圈,而是精确转某个角度(比如相机云台转 45°)。封装一个「转角度」函数让代码更语义化:
// 转动指定角度(支持小数)
void rotateAngle(float degrees, int dir) {
int steps = (int)(degrees / 360.0 * 4096);
stepMotor(dir, steps, 2);
}
// 使用示例:正转 90°
rotateAngle(90, 1);
2. 加减速控制(梯形速度曲线)
步进电机在高速启动时容易失步(丢步)。专业做法是使用梯形加减速:启动时逐步减小 delay,停止前逐步增大 delay。Arduino 平台可以使用 AccelStepper 库轻松实现:
// 使用 AccelStepper 库(PlatformIO: AccelStepper)
#include <AccelStepper.h>
AccelStepper stepper(AccelStepper::HALF4WIRE, 16, 18, 17, 19);
void setup() {
stepper.setMaxSpeed(1000); // 最大速度(步/秒)
stepper.setAcceleration(500); // 加速度(步/秒²)
}
void loop() {
stepper.moveTo(4096); // 目标位置:正转 1 圈
while (stepper.distanceToGo() != 0) {
stepper.run();
}
delay(1000);
stepper.moveTo(0); // 回到原点
while (stepper.distanceToGo() != 0) {
stepper.run();
}
delay(1000);
}
💡 AccelStepper 引脚顺序注意:构造函数中的引脚顺序是 IN1, IN3, IN2, IN4(交叉排列),不是 IN1, IN2, IN3, IN4。这是库的内部约定,写错会导致电机不转或抖动。
🔧 实战场景
场景一:自动窗帘控制器
需求:每天早晨 7:00 自动拉开窗帘 180°,晚上 19:00 自动关闭。
物料组合:ESP32 + 28BYJ-48 + ULN2003 + DHT22(温湿度联动)+ OLED 显示屏
联动思路:利用之前学的 DHT22 温湿度传感器 检测室内温度——温度超过 28°C 时自动关闭窗帘遮阳。用 OLED SSD1306 显示当前窗帘状态和温度。结合 WiFi NTP 对时(参考 WiFi 连接教程),实现精准定时。
场景二:简易 CNC 绘图仪 X/Y 轴
需求:用两个步进电机搭建一个 XY 平面绘图仪,能画简单图形。
物料组合:ESP32 + 2×28BYJ-48 + 2×ULN2003 + 激光头或笔架
联动思路:两个步进电机分别控制 X 轴和 Y 轴,配合 AccelStepper 的 MultiStepper 实现多轴联动。接收上位机通过 MQTT 发来的 G-code 指令,解析后执行绘图动作。
❓ 常见问题
❌ 电机抖动但不转
这是最常见的"失步"现象。原因有三:① delay 太小(速度过快),尝试将 delay 从 2ms 增大到 5~8ms;② 供电不足,务必用独立 5V 电源;③ ULN2003 的 VCC 跳线帽未插好。排查顺序:先降速 → 再查供电 → 最后查接线。
❌ 转动角度不准(多转或少转)
28BYJ-48 的减速比是 1:63.68395(不是精确的 1:64),所以 4096 步实际略少于一圈。如果需要高精度角度控制,建议增加归零限位开关——在初始位置装一个微动开关,每次启动先回零。
❌ ESP32 不断重启
步进电机启动瞬间的电流冲击可达 500mA+,远超 ESP32 板载 LDO 的承受能力。解决方案:① 使用独立 5V/2A 电源给 ULN2003 供电;② 在 ULN2003 的 VCC-GND 两端并联 100μF 电解电容,吸收电流尖峰;③ 电机和 ESP32 务必共地(GND 相连)。
❌ AccelStepper 引脚顺序写错
HALF4WIRE 模式下,AccelStepper 构造函数引脚顺序是 IN1, IN3, IN2, IN4(不是 1-2-3-4)。写错顺序最常见的症状是电机完全不动或随机抖动。建议先用本文的基础代码(不用库)验证接线正确后,再切换 AccelStepper。