28BYJ-48配ULN2003接Arduino全攻略

2026-11-13 07:19:18 12阅读

几块钱一套的28BYJ-48步进电机加ULN2003驱动板,大概是全世界出货量最大的步进电机组合,打印机、扫描仪、空调摆叶里都能拆到同款。对刚碰步进电机的人来说,它便宜、慢、扭矩小,但接线、步序、库用法一样不缺,是把步进电机的门道吃透的最佳练手件。这篇把接线、单步半步全步的区别、Stepper和AccelStepper两个库的用法一次讲清,参数和代码都对照了Makerguides与DroneBot Workshop两篇教程原文,有据可查。

28BYJ-48步进电机、ULN2003驱动板与Arduino Uno的实物图

先认识28BYJ-48:小身板里的齿轮箱

28BYJ-48是一只5V单极性四相步进电机,线圈电阻约50欧姆,所以5V供电下单相电流大约100毫安,一只ULN2003达林顿管阵列就能轻松驱动,这也是它配ULN2003板子的原因。电机本体直径28毫米,轴径5毫米带扁位,方便装轮子或连杆。

它的内部结构是转子转32步一圈,再经过一组减速齿轮把扭矩放大、速度降低。标称减速比是1/64,但论坛上有人拆机数过齿轮齿数,实际是63.68395:1这个奇怪的数。所以输出轴全步模式一圈2048步,半步模式标称4096步,按真实齿轮比算其实是约4076步——如果你拿它做需要精确角度的事,这个差别就要算进去。

速度方面别抱期待:5V下最大转速大约每分钟10到15圈,再快就丢步。要圈数没圈数、要速度没速度,但换来的小扭矩在摆叶、云台微调、转盘这类应用上刚刚好,DroneBot那篇教程也提到电机加驱动板总价不到5美元。

把关键参数汇总成一张表,选购和写代码时都对着它来:

参数项数值
额定电压5V
线圈电阻约50欧姆
相数4相单极性
本体直径28毫米
轴径5毫米带扁位
标称减速比1/64(实测约63.68:1)
全步每圈步数2048
半步每圈步数标称4096,按实测齿轮比约4076
最大转速5V下约10到15rpm

买的时候留意一个细节:不同批次的齿轮比可能有出入,前面说的63.68:1不是所有电机都一样,对角度精度有要求就按自己的电机实测校准。另外别把它跟Adafruit那款同外形的小减速步进电机搞混,那款齿轮比约1/16,全步一圈只有513步,参数差得远。

接线:四根信号线加一路独立5V

ULN2003驱动板上有个白色插座,电机引线插上去就对,不会插反。剩下的接线只有六根,一张表列清楚:

ULN2003驱动板接到哪里
IN1Arduino数字脚8
IN2Arduino数字脚9
IN3Arduino数字脚10
IN4Arduino数字脚11
逻辑GNDArduino的GND
电源正负极外部5V电源(与Arduino共地)

整理成图就是下面这样:28BYJ-48与ULN2003驱动板接Arduino Uno的接线图,IN1至IN4对应数字脚8至11

这里有一条必须记住的红线:绝对不要拿Arduino板载的5V输出给电机供电。28BYJ-48电流虽小,但线圈通断会在电源线上制造噪声,轻则单片机重启乱跳,重则烧板。Makerguides和DroneBot两篇原文都把这条加粗强调过。正确做法是电机和驱动板用独立5V电源,Arduino自己走USB或电源插座供电,两边共地。驱动板电源旁边还有个跳线帽,拔掉就能断开电机供电,调试时很好用。Arduino与ULN2003驱动板、外部5V电源的接线示意,数字脚8至11对应IN1至IN4

这只电机便宜到可以一次买两只。下图是双电机方案:第一套照旧用脚8到11,第二套驱动板接脚4到7,两块驱动板共用一路外部5V,AccelStepper里建两个对象就能让两只电机同时各转各的。双电机版本的写法思路也简单:给两个AccelStepper对象分别设好最大速度、加速度和目标位置,loop里轮流调run(),用distanceToGo()判断到位没有,到了就把目标取反,两只电机就会一正一反来回加速减速。DroneBot的第二个示例正是这么写的,一只全步一只半步,看驱动板上的灯就能看出两种步序的点灯节奏不一样。两只28BYJ-48配两块ULN2003驱动板接Arduino的双电机接线图,第二套用数字脚4至7

通电后先别急着跑程序,驱动板上四颗LED就是步序指示灯,一会儿程序跑起来看灯的点亮顺序,比看电机直观得多。

单步、半步与全步:步序里的门道

28BYJ-48的四相线圈按特定顺序通电才会转。全步模式每次点亮两相,输出轴每步0.176度,一圈2048步;半步模式在两相和单相之间交替,每步0.0879度,一圈4096步,转动更平滑但控制频率翻倍。

对写代码的人真正要紧的是引脚顺序:这只电机的步序是1-3-2-4,也就是说代码里构造Stepper对象时,引脚必须按8、10、9、11的顺序填,而不是按接线顺序8、9、10、11直接填。这是新手最容易踩的坑——接完线电机只会抖不转,九成是这个原因。

ULN2003本身不产生步序,它只是功率放大:四个输入脚各控制一路达林顿管,把Arduino的弱信号放大成能灌进线圈的电流。步序全靠软件排,所以换库、换单片机都不影响硬件。

用自带Stepper库让电机转起来

Arduino IDE自带的Stepper库就能驱动它,不用装任何东西。下面这段示例让电机正转一圈、停半秒、反转一圈,循环往复:

/* 
  Example sketch to control a 28BYJ-48 stepper motor 
  with ULN2003 driver board and Arduino UNO. 
  More info: https://www.makerguides.com 
*/

// Include the Arduino Stepper.h library:
#include "Stepper.h"

// Define number of steps per rotation:
const int stepsPerRevolution = 2048;

// Wiring:
// Pin 8 to IN1 on the ULN2003 driver
// Pin 9 to IN2 on the ULN2003 driver
// Pin 10 to IN3 on the ULN2003 driver
// Pin 11 to IN4 on the ULN2003 driver

// Create stepper object called 'myStepper', note the pin order:
Stepper myStepper = Stepper(stepsPerRevolution, 8, 10, 9, 11);

void setup() {
  // Set the speed to 5 rpm:
  myStepper.setSpeed(5);
  
  // Begin Serial communication at a baud rate of 9600:
  Serial.begin(9600);
}

void loop() {
  // Step one revolution in one direction:
  Serial.println("clockwise");
  myStepper.step(stepsPerRevolution);
  delay(500);
  
  // Step one revolution in the other direction:
  Serial.println("counterclockwise");
  myStepper.step(-stepsPerRevolution);
  delay(500);
}

看构造函数那行,引脚顺序正是前面说的8、10、9、11。setSpeed的单位是转每分钟,5rpm对这只电机是个稳妥值。想观察步序,可以把步数改成4、速度改成1,慢慢看驱动板上的灯逐个点亮。setup()里什么都不用设,Stepper库构造时已经自动把四个脚配成输出,这是DroneBot原文里专门交代过的一点。

AccelStepper:想要平滑和精确就换它

Stepper库的step()是阻塞式的,转完才执行下一行,还不能加减速。进阶玩法用AccelStepper库,在库管理器里搜AccelStepper安装即可。它的接口类型参数填8代表四线半步模式,填4代表全步;引脚同样按IN1-IN3-IN2-IN4的顺序传。第一段是恒速连续旋转:

/* 
  Example sketch to control a 28BYJ-48 stepper motor 
  with ULN2003 driver board, AccelStepper and Arduino UNO: 
  continuous rotation. More info: https://www.makerguides.com 
*/

// Include the AccelStepper library:
#include "AccelStepper.h"

// Motor pin definitions:
#define motorPin1  8      // IN1 on the ULN2003 driver
#define motorPin2  9      // IN2 on the ULN2003 driver
#define motorPin3  10     // IN3 on the ULN2003 driver
#define motorPin4  11     // IN4 on the ULN2003 driver

// Define the AccelStepper interface type: 4 wire motor in half step mode:
#define MotorInterfaceType 8

// Initialize with pin sequence IN1-IN3-IN2-IN4
AccelStepper stepper = AccelStepper(MotorInterfaceType, motorPin1, motorPin3, motorPin2, motorPin4);

void setup() {
  // Set the maximum steps per second:
  stepper.setMaxSpeed(1000);
}

void loop() {
  // Set the speed of the motor in steps per second:
  stepper.setSpeed(500);
  // Step the motor with constant speed as set by setSpeed():
  stepper.runSpeed();
}

setSpeed的单位是每秒步数,半步模式一圈4096步,500步每秒约等于7rpm。实测超过1000步每秒就不可靠了,这也符合它10到15rpm的物理上限。把setSpeed填负数就反转。

跑这段代码要注意:runSpeed()必须放在loop里不停地被调用,它每被叫一次才走一步,调用得不够勤电机就走走停停。这跟Stepper库的step()是两种哲学——step()阻塞式的写法简单粗暴,转完才执行下一行;AccelStepper的run()系是非阻塞的,一次只推一小步,主循环里还能顺便干别的事,比如读传感器、刷新显示。代价是loop里不能塞delay,一塞整个节奏就乱了。

第二段示例用setCurrentPosition清零加循环判断,精确控制转几圈:正转一圈、反转一圈、再正转两圈,每段之间停一秒:

/* Example sketch to control a 28BYJ-48 stepper motor with 
  ULN2003 driver board, AccelStepper and Arduino UNO
  More info: https://www.makerguides.com */

#include "AccelStepper.h"

// Motor pin definitions:
#define motorPin1  8      // IN1 on the ULN2003 driver
#define motorPin2  9      // IN2 on the ULN2003 driver
#define motorPin3  10     // IN3 on the ULN2003 driver
#define motorPin4  11     // IN4 on the ULN2003 driver

// Define the AccelStepper interface type; 4 wire motor in half step mode:
#define MotorInterfaceType 8

// Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper library with 28BYJ-48 stepper motor:
AccelStepper stepper = AccelStepper(MotorInterfaceType, motorPin1, motorPin3, motorPin2, motorPin4);

void setup() {
  // Set the maximum steps per second:
  stepper.setMaxSpeed(1000);
}

void loop() {
  // Set the current position to 0:
  stepper.setCurrentPosition(0);

  // Run the motor forward at 500 steps/second until the motor reaches 4096 steps (1 revolution):
  while (stepper.currentPosition() != 4096) {
    stepper.setSpeed(500);
    stepper.runSpeed();
  }
  delay(1000);

  // Reset the position to 0:
  stepper.setCurrentPosition(0);

  // Run the motor backwards at 1000 steps/second until the motor reaches -4096 steps (1 revolution):
  while (stepper.currentPosition() != -4096) {
    stepper.setSpeed(-1000);
    stepper.runSpeed();
  }

  delay(1000);

  // Reset the position to 0:
  stepper.setCurrentPosition(0);
  // Run the motor forward at 1000 steps/second until the motor reaches 8192 steps (2 revolutions):
  while (stepper.currentPosition() != 8192) {
    stepper.setSpeed(1000);
    stepper.runSpeed();
  }

  delay(3000);
}

第三段加上加减速,setAcceleration的单位是步每秒平方,moveTo设目标位置,runToPosition会自动加速巡航再减速停准,来回各两圈:

/* 
  Example sketch to control a 28BYJ-48 stepper motor with ULN2003 driver board, 
  AccelStepper and Arduino UNO: acceleration and deceleration. 
  More info: https://www.makerguides.com 
*/

#include "AccelStepper.h"

// Motor pin definitions:
#define motorPin1  8      // IN1 on the ULN2003 driver
#define motorPin2  9      // IN2 on the ULN2003 driver
#define motorPin3  10     // IN3 on the ULN2003 driver
#define motorPin4  11     // IN4 on the ULN2003 driver

// Define the AccelStepper interface type; 4 wire motor in half step mode:
#define MotorInterfaceType 8

// Initialize with pin sequence IN1-IN3-IN2-IN4
AccelStepper stepper = AccelStepper(MotorInterfaceType, motorPin1, motorPin3, motorPin2, motorPin4);

void setup() {
  // Set the maximum steps per second:
  stepper.setMaxSpeed(1000);
  // Set the maximum acceleration in steps per second^2:
  stepper.setAcceleration(200);
}

void loop() {
  // Set target position:
  stepper.moveTo(8192);
  // Run to position with set speed and acceleration:
  stepper.runToPosition();
  
  delay(1000);
  
  // Move back to original position:
  stepper.moveTo(0);
  // Run to position with set speed and acceleration:
  stepper.runToPosition();
  
  delay(1000);
}

加减速的价值在于速度突变时不容易丢步,这一点对扭矩本就不富裕的28BYJ-48尤其重要。

几个避坑提醒

第一,供电永远走外部5V,共地不共电源。第二,电机只抖不转先查引脚顺序,8、10、9、11这个1-3-2-4步序是硬规矩。第三,每台电机的齿轮比可能有出入,DroneBot原文特意提醒有些批次不是64:1,按4076步一圈校准更准。第四,ULN2003方案只能驱动这只5V单极性电机,换双极性电机或12V电机就得换A4988、L298N这类驱动,别硬套。

这套组合的天花板确实低,但作为步进电机教学件几乎完美:接错会抖、跑快丢步、齿轮比有彩蛋,步进电机的所有典型脾气它都能让你亲眼见到。玩透它再上A4988加NEMA17,很多概念就直接迁移了。


作者:舵机老炮
链接:https://www.aiddithome.com/p/b8cdbfcc92f4f.html
本作版权归作者所有,未经允许请勿转载。若存在违规行为,您可以点击 “举报”。


登录 后发表评论
4条评论
电烙铁爱好者
1楼 · 31分钟前

去年买套件送了两只这个电机一直吃灰,看完才知道当初接线没问题,是代码里引脚顺序直接按8、9、10、11填的,怪不得只会嗡嗡抖不转。8、10、9、11这个1-3-2-4步序算是刻进脑子里了。另外那组实测63.68395:1的齿轮比真有意思,回头拿它做个时钟秒针盘校准玩玩。

阿强焊点总飞
2楼 · 31分钟前

上手第一只步进电机就是它,至今家里空调摆叶还是这方案,便宜是真便宜,丢步也是真容易丢。

刷着刷着入坑了
3楼 · 31分钟前

外部供电那条深有体会,当年图省事直接接Arduino的5V,板子动不动重启,换了独立电源立马老实。

隔壁工位的好奇宝
4楼 · 31分钟前

AccelStepper这个setAcceleration确实好用,加了减速之后丢步少太多了,就是loop里千万别手滑塞delay。