树莓派RP2350 - 步进电机驱动
本文介绍了树莓派 RP2350
开发板实现步进电机驱动的项目设计,主要包括旋转角度的精确控制、串口发送实现自定义角度旋转、OLED
显示旋转状态三部分。
扩展板PCB工程详见:RP2350扩展板 -
立创开源硬件平台
.
项目介绍
包括步进电机原理、该项目使用的 28BYJ-48 步进电机,及其驱动器——ULN2003
驱动模块介绍。
步进电机原理
步进电机(Stepper
Motor)是一种将电脉冲信号转换为精确角度位移的执行器件,属于开环控制电机。
核心特点:每接收一个脉冲,转子就转动一个固定的角度(称为“步距角”),无需反馈传感器即可实现位置控制。
-
结构组成
-
:绕有线圈的磁极,分为多相(常见2相、4相、5相)。
:永磁体(永磁式)或齿状铁芯(反应式/混合式)。
28BYJ-48 步进电机
28BYJ-48 是一款常见的低成本、小扭矩 5 线单极步进电机,可使用 ULN2003
控制器和单片机实现旋转控制,广泛用于打印机、扫描仪、摄像机云台、空调、家电、玩具、消费电子等领域。
参数
28BYJ-48 是一款适应性强的 5V DC步进电机,设计紧凑,适用于各种应用。
它具有四个相位,速度变化比为1/64,步距角为5.625°/64步,允许精确控制。
电机在100Hz频率下工作,25°C 时的直流电阻为 50Ω ±7% .
它的空载牵引频率大于600Hz,空载脱离频率超过1000Hz,确保在不同场景下的可靠性。
28BYJ-48 在 120Hz 时的自定位转矩和牵引转矩均超过
34.3mN.m,提供强劲性能。
其摩擦转矩范围为600到1200 gf.cm,而拉入转矩为300 gf.cm。
实际输出轴步距角为 5.625°/64 ≈ 0.0879°,转一圈理论上需要
64×64=4096 步,实际可能存在误差。
详见:
28BYJ-48 数据手册
.
ULN2003 驱动器
ULN2003
是一款常用的达林顿晶体管阵列芯片,专为驱动高电流负载(如继电器、步进电机、LED阵列等)设计。其作用是将 MCU
输出的弱电流信号转换为大电流输出,是控制 28BYJ-48 步进电机的核心驱动芯片。
原理图
使用时需要将 28BYJ-48 步进电机的5线快接插头与 ULN2003 模块对应接口连接,并将模块的 4
个控制引脚(信号输入端,丝印 IN1、IN2、IN3、IN4)与单片机对应引脚相连,实现控制信号输入。
详见:
ULN2003A 数据手册 - Texas
Instruments
.
项目方案
具体执行方案和工程测试流程如下
-
1.步进电机原理
-
2.旋转角度的精确控制
-
3.串口发送实现自定义角度旋转
-
4. OLED 显示旋转状态
#1 旋转指定角度
本节介绍并实现了指定角度的步进电机旋转控制。
硬件连接
- GP1 ---- IN2 (ULN2003)
- GP18 ---- IN3 (ULN2003)
- GP19 ---- IN4 (ULN2003)
代码
'''
Name: Stepper Motor driven by
ULN2003
Version: v1.0
Date: 2025.05
Author: ljl
Other: Rotate stepper motor (28byj-48) for custom
angle.
Hardware connect:
0 ---- IN1 (ULN2003)
1 ---- IN2 (ULN2003)
18 ---- IN3 (ULN2003)
19 ---- IN4 (ULN2003)
Ref:
https://pico.nxez.com/2023/11/24/how-to-use-the-stepper-motors-on-raspberry-pi-pico.html
'''
from
machine import Pin
import
utime
# 电机控制引脚
coils
= [
Pin
(0, Pin.OUT),
# A相 (IN1)
Pin
(1, Pin.OUT),
# B相 (IN2)
Pin
(18, Pin.OUT),
# C相 (IN3)
Pin
(19, Pin.OUT)
# D相 (IN4)
]
# 四相八拍步进电机的顺序值
STEP_SEQ
= [
[1
, 0, 0, 1],
# AB'
[1
, 0, 0, 0],
# A
[1
, 1, 0, 0],
# AB
[0
, 1, 0, 0],
# B
[0
, 1, 1, 0],
# BC
[0
, 0, 1, 0],
# C
[0
, 0, 1, 1],
# CD
[0
, 0, 0, 1]
# D
]
'''
驱动电机旋转指定步数
:param steps: 正数=顺时针,负数=逆时针
:param delay_ms: 步间延时(ms),控制转速
'''
def
step_motor(steps,
delay_ms=1):
direction
= 1 if steps
>=0 else
-1
for
_ in
range(abs(steps)):
for
phase in
range(8)[::direction]:
# 方向控制
for
coil, state in
zip(coils,
STEP_SEQ[phase]):
coil
.value(state)
utime
.sleep_ms(delay_ms)
# 旋转角度控制
def
rotate_angle(angle):
steps_per_rev
= 509
steps
= int(angle
* (steps_per_rev /
360))
step_motor
(steps)
# 释放电机扭矩
def
release():
for
coil in coils:
coil
.value(0)
while
True:
#rotate_angle(1) #
以单步方式持续转动
rotate_angle
(180) # 逆时针
release
()
utime
.sleep_ms(2000)
rotate_angle
(-90) # 顺时针
release
()
utime
.sleep_ms(2000)
由供电处的电压-电流计量工具可知,步进电机旋转工作时的功率约为 1W
#2 串口自定义角度
在实现步进电机旋转驱动的基础上,进一步实现串口发送自定义角度并旋转的功能设计方案。
硬件连接
- GP1 ---- IN2 (ULN2003)
- GP4 ---- IN3 (ULN2003)
- GP5 ---- IN4 (ULN2003)
- GP8 ---- RXD (CH340)
- GP9 ---- TXD (CH340)
代码
'''
Name: Stepper Motor rotate custom angle from
serial
Version: v1.0
Date: 2025.05
Author: ljl
Other: Rotate stepper motor (28byj-48) for custom
angle from UART.
Hardware connect:
0 ---- IN1 (ULN2003)
1 ---- IN2 (ULN2003)
4 ---- IN3 (ULN2003)
5 ---- IN4 (ULN2003)
8 ---- RXD (CH340)
9 ---- TXD (CH340)
'''
from
machine import Pin,
UART
import
utime
import
ujson
# 电机控制引脚
coils
= [
Pin
(0, Pin.OUT),
# A相 (IN1)
Pin
(1, Pin.OUT),
# B相 (IN2)
Pin
(4, Pin.OUT),
# C相 (IN3)
Pin
(5, Pin.OUT)
# D相 (IN4)
]
# 四相八拍步进电机的相序
STEP_SEQ
= [
[1
, 0, 0, 1],
# AB'
[1
, 0, 0, 0],
# A
[1
, 1, 0, 0],
# AB
[0
, 1, 0, 0],
# B
[0
, 1, 1, 0],
# BC
[0
, 0, 1, 0],
# C
[0
, 0, 1, 1],
# CD
[0
, 0, 0, 1]
# D
]
# 驱动电机旋转指定步数;delay_ms
步间延时(ms),控制转速
def
step_motor(steps,
delay_ms=1):
direction
= 1 if steps
>=0 else
-1
for
_ in
range(abs(steps)):
for
phase in
range(8)[::direction]:
# 方向控制
for
coil, state in
zip(coils,
STEP_SEQ[phase]):
coil
.value(state)
utime
.sleep_ms(delay_ms)
# 角度控制
def
rotate_angle(angle):
steps_per_rev
= 509
steps
= int(angle
* (steps_per_rev /
360))
step_motor
(steps)
# 释放电机扭矩
def
release():
for
coil in coils:
coil
.value(0)
# 串口控制旋转角度
def
uart_control():
uart
=
machine.UART(1,
baudrate=9600,
tx=Pin(8),
rx=Pin(9))
while
True:
if
uart.any():
cmd
= uart.read()
try
:
data
=
ujson.loads(cmd)
rotate_angle
(int(data['angle']))
release
()
except
:
uart
.write('Invalid command\r\n')
release
()
else
:
release
()
utime
.sleep_ms(100)
# main loop
while
True:
uart_control
()
这里为了节能并提高效率,仅在串口发送正确指令时旋转,其他情况均释放步进电机扭矩,此时电流约为 0
.
效果
由于调用了 ujson 库,因此串口发送指令需符合 json 格式,如
{"angle":40}
.
若串口发送 json 消息的格式错误,则反馈指令无效的提示。
#3 OLED 显示旋转状态
在前面实现步进电机旋转驱动、串口自定义角度控制的基础上,进一步实现串口发送角度、旋转、OLED
状态显示的功能设计方案。
硬件连接
- GP1 ---- IN2 (ULN2003)
- GP18 ---- IN3 (ULN2003)
- GP19 ---- IN4 (ULN2003)
- GP8 ---- RXD (CH340)
- GP9 ---- TXD (CH340)
- GP4 ---- SDA (OLED_SSD1306)
- GP5 ---- SCL (OLED_SSD1306)
流程图
代码
'''
Name: Stepper Motor rotate custom angle from serial
and OLED display
Version: v1.0
Date: 2025.05
Author: ljl
Other: Rotate stepper motor (28byj-48) for custom
angle from UART, and OLED display the motor state in moving or
steady.
Hardware connect:
0 ---- IN1 (ULN2003)
1 ---- IN2 (ULN2003)
18 ---- IN3 (ULN2003)
19 ---- IN4 (ULN2003)
8 ---- RXD (CH340)
9 ---- TXD (CH340)
4 ---- SDA (OLED_SSD1306)
5 ---- SCL (OLED_SSD1306)
Serial send style: {"angle": 40}
'''
from
machine import Pin,
UART, SoftI2C
import
ssd1306 # OLED
import
ujson # read uart string
import
utime
# ==== Initialized IIC OLED ====
i2c
=
SoftI2C(scl=Pin(5),
sda=Pin(4))
oled_width
= 128
oled_height
= 64
oled
=
ssd1306.SSD1306_I2C(oled_width,
oled_height, i2c)
# display the motor state
def
display_motor(angle,state):
oled
.fill(0) #
清屏
oled
.text("Rotate Angle: ",
0, 0)
oled
.text("{:.1f}
deg".format(angle),
20, 15)
oled
.text("State: ", 0,
35)
if
state == 1:
oled
.text("Rotating ...", 20,
50)
elif
state == 0:
oled
.text("Reset", 20,
50)
else
:
oled
.text("Error", 20,
50)
oled
.show()
# 电机控制引脚
coils
= [
Pin
(0, Pin.OUT),
# A相 (IN1)
Pin
(1, Pin.OUT),
# B相 (IN2)
Pin
(18, Pin.OUT),
# C相 (IN3)
Pin
(19, Pin.OUT)
# D相 (IN4)
]
# 四相八拍步进电机的相序
STEP_SEQ
= [
[1
, 0, 0, 1],
# AB'
[1
, 0, 0, 0],
# A
[1
, 1, 0, 0],
# AB
[0
, 1, 0, 0],
# B
[0
, 1, 1, 0],
# BC
[0
, 0, 1, 0],
# C
[0
, 0, 1, 1],
# CD
[0
, 0, 0, 1]
# D
]
# 驱动电机旋转指定步数;delay_ms
步间延时(ms),控制转速
def
step_motor(steps,
delay_ms=1):
direction
= 1 if steps
>=0 else
-1
for
_ in
range(abs(steps)):
for
phase in
range(8)[::direction]:
# 方向控制
for
coil, state in
zip(coils,
STEP_SEQ[phase]):
coil
.value(state)
utime
.sleep_ms(delay_ms)
# 角度控制
def
rotate_angle(angle):
steps_per_rev
= 509 # 64步/拍
× 8拍 × 8相位
steps
= int(angle
* (steps_per_rev /
360))
step_motor
(steps)
# 释放电机扭矩
def
release():
for
coil in coils:
coil
.value(0)
# 串口控制旋转角度
def
uart_control():
uart
=
machine.UART(1,
baudrate=9600,
tx=Pin(8),
rx=Pin(9))
while
True:
if
uart.any():
cmd
= uart.read()
try
:
data
=
ujson.loads(cmd)
ra
=
float(data['angle']) #
rotate angle
display_motor
(ra,1)
rotate_angle
(ra)
release
()
display_motor
(ra,0)
except
:
uart
.write('Invalid command\r\n')
release
()
else
:
release
()
#display_motor(0,0)
utime
.sleep_ms(100)
# main loop
display_motor
(0,0) # initialize OLED
display
while
True:
uart_control
()
效果
总结
本文介绍了 RP2350
开发板实现步进电机驱动的项目设计,包括旋转角度的精确控制、串口发送实现自定义角度旋转、OLED 显示旋转状态等,为 RP2350
的开发、设计和应用提供了参考。
树莓派RP2350实现步进电机精确控制
树莓派RP2350 - 步进电机驱动
本文介绍了树莓派 RP2350 开发板实现步进电机驱动的项目设计,主要包括旋转角度的精确控制、串口发送实现自定义角度旋转、OLED 显示旋转状态三部分。
扩展板PCB工程详见:RP2350扩展板 - 立创开源硬件平台
.
项目介绍
包括步进电机原理、该项目使用的 28BYJ-48 步进电机,及其驱动器——ULN2003 驱动模块介绍。
步进电机原理
步进电机(Stepper Motor)是一种将电脉冲信号转换为精确角度位移的执行器件,属于开环控制电机。
核心特点:每接收一个脉冲,转子就转动一个固定的角度(称为“步距角”),无需反馈传感器即可实现位置控制。
结构组成
定子
:绕有线圈的磁极,分为多相(常见2相、4相、5相)。
转子
:永磁体(永磁式)或齿状铁芯(反应式/混合式)。
定子绕组按特定顺序通电,产生旋转磁场,吸引转子逐步转动。
工作过程
通过控制器(如单片机)发送脉冲信号,驱动电路按顺序切换定子绕组的电流方向。
每切换一次,转子转动一个步距角,连续脉冲使电机连续旋转。
28BYJ-48 步进电机
28BYJ-48 是一款常见的低成本、小扭矩 5 线单极步进电机,可使用 ULN2003 控制器和单片机实现旋转控制,广泛用于打印机、扫描仪、摄像机云台、空调、家电、玩具、消费电子等领域。
参数
28BYJ-48 是一款适应性强的 5V DC步进电机,设计紧凑,适用于各种应用。
它具有四个相位,速度变化比为1/64,步距角为5.625°/64步,允许精确控制。
电机在100Hz频率下工作,25°C 时的直流电阻为 50Ω ±7% .
它的空载牵引频率大于600Hz,空载脱离频率超过1000Hz,确保在不同场景下的可靠性。
28BYJ-48 在 120Hz 时的自定位转矩和牵引转矩均超过 34.3mN.m,提供强劲性能。
其摩擦转矩范围为600到1200 gf.cm,而拉入转矩为300 gf.cm。
详见:
28BYJ-48 数据手册
.
ULN2003 驱动器
ULN2003 是一款常用的达林顿晶体管阵列芯片,专为驱动高电流负载(如继电器、步进电机、LED阵列等)设计。其作用是将 MCU 输出的弱电流信号转换为大电流输出,是控制 28BYJ-48 步进电机的核心驱动芯片。
原理图
使用时需要将 28BYJ-48 步进电机的5线快接插头与 ULN2003 模块对应接口连接,并将模块的 4 个控制引脚(信号输入端,丝印 IN1、IN2、IN3、IN4)与单片机对应引脚相连,实现控制信号输入。
详见:
ULN2003A 数据手册 - Texas Instruments
.
项目方案
具体执行方案和工程测试流程如下
1.步进电机原理
2.旋转角度的精确控制
3.串口发送实现自定义角度旋转
4. OLED 显示旋转状态
#1 旋转指定角度
本节介绍并实现了指定角度的步进电机旋转控制。
硬件连接
代码
'''
Name: Stepper Motor driven by ULN2003
Version: v1.0
Date: 2025.05
Author: ljl
Other: Rotate stepper motor (28byj-48) for custom angle.
Hardware connect:
0 ---- IN1 (ULN2003)
1 ---- IN2 (ULN2003)
18 ---- IN3 (ULN2003)
19 ---- IN4 (ULN2003)
Ref: https://pico.nxez.com/2023/11/24/how-to-use-the-stepper-motors-on-raspberry-pi-pico.html
'''
from
machine import Pin
importutime
# 电机控制引脚
coils
= [
Pin(0, Pin.OUT), # A相 (IN1)
Pin(1, Pin.OUT), # B相 (IN2)
Pin(18, Pin.OUT), # C相 (IN3)
Pin(19, Pin.OUT) # D相 (IN4)
]# 四相八拍步进电机的顺序值
STEP_SEQ
= [
[1, 0, 0, 1], # AB'
[1, 0, 0, 0], # A
[1, 1, 0, 0], # AB
[0, 1, 0, 0], # B
[0, 1, 1, 0], # BC
[0, 0, 1, 0], # C
[0, 0, 1, 1], # CD
[0, 0, 0, 1] # D
]'''
驱动电机旋转指定步数
:param steps: 正数=顺时针,负数=逆时针
:param delay_ms: 步间延时(ms),控制转速
'''
def
step_motor(steps, delay_ms=1):
direction= 1 if steps >=0 else -1
for_ in range(abs(steps)):
forphase in range(8)[::direction]: # 方向控制
forcoil, state in zip(coils, STEP_SEQ[phase]):
coil.value(state)
utime.sleep_ms(delay_ms)
# 旋转角度控制
def
rotate_angle(angle):
steps_per_rev= 509
steps= int(angle * (steps_per_rev / 360))
step_motor(steps)
# 释放电机扭矩
def
release():
forcoil in coils:
coil.value(0)
while
True:
#rotate_angle(1) # 以单步方式持续转动rotate_angle
(180) # 逆时针
release()
utime.sleep_ms(2000)
rotate_angle(-90) # 顺时针
release()
utime.sleep_ms(2000)
由供电处的电压-电流计量工具可知,步进电机旋转工作时的功率约为 1W
#2 串口自定义角度
在实现步进电机旋转驱动的基础上,进一步实现串口发送自定义角度并旋转的功能设计方案。
硬件连接
代码
'''
Name: Stepper Motor rotate custom angle from serial
Version: v1.0
Date: 2025.05
Author: ljl
Other: Rotate stepper motor (28byj-48) for custom angle from UART.
Hardware connect:
0 ---- IN1 (ULN2003)
1 ---- IN2 (ULN2003)
4 ---- IN3 (ULN2003)
5 ---- IN4 (ULN2003)
8 ---- RXD (CH340)
9 ---- TXD (CH340)
'''
from
machine import Pin, UART
importutime
importujson
# 电机控制引脚
coils
= [
Pin(0, Pin.OUT), # A相 (IN1)
Pin(1, Pin.OUT), # B相 (IN2)
Pin(4, Pin.OUT), # C相 (IN3)
Pin(5, Pin.OUT) # D相 (IN4)
]# 四相八拍步进电机的相序
STEP_SEQ
= [
[1, 0, 0, 1], # AB'
[1, 0, 0, 0], # A
[1, 1, 0, 0], # AB
[0, 1, 0, 0], # B
[0, 1, 1, 0], # BC
[0, 0, 1, 0], # C
[0, 0, 1, 1], # CD
[0, 0, 0, 1] # D
]# 驱动电机旋转指定步数;delay_ms 步间延时(ms),控制转速
def
step_motor(steps, delay_ms=1):
direction= 1 if steps >=0 else -1
for_ in range(abs(steps)):
forphase in range(8)[::direction]: # 方向控制
forcoil, state in zip(coils, STEP_SEQ[phase]):
coil.value(state)
utime.sleep_ms(delay_ms)
# 角度控制
def
rotate_angle(angle):
steps_per_rev= 509
steps= int(angle * (steps_per_rev / 360))
step_motor(steps)
# 释放电机扭矩
def
release():
forcoil in coils:
coil.value(0)
# 串口控制旋转角度
def
uart_control():
uart= machine.UART(1, baudrate=9600, tx=Pin(8), rx=Pin(9))
whileTrue:
ifuart.any():
cmd= uart.read()
try:
data= ujson.loads(cmd)
rotate_angle(int(data['angle']))
release()
except:
uart.write('Invalid command\r\n')
release()
else:
release()
utime.sleep_ms(100)
# main loop
while
True:
uart_control()
这里为了节能并提高效率,仅在串口发送正确指令时旋转,其他情况均释放步进电机扭矩,此时电流约为 0 .
效果
由于调用了 ujson 库,因此串口发送指令需符合 json 格式,如
{"angle":40}
.
若串口发送 json 消息的格式错误,则反馈指令无效的提示。
#3 OLED 显示旋转状态
在前面实现步进电机旋转驱动、串口自定义角度控制的基础上,进一步实现串口发送角度、旋转、OLED 状态显示的功能设计方案。
硬件连接
流程图
代码
'''
Name: Stepper Motor rotate custom angle from serial and OLED display
Version: v1.0
Date: 2025.05
Author: ljl
Other: Rotate stepper motor (28byj-48) for custom angle from UART, and OLED display the motor state in moving or steady.
Hardware connect:
0 ---- IN1 (ULN2003)
1 ---- IN2 (ULN2003)
18 ---- IN3 (ULN2003)
19 ---- IN4 (ULN2003)
8 ---- RXD (CH340)
9 ---- TXD (CH340)
4 ---- SDA (OLED_SSD1306)
5 ---- SCL (OLED_SSD1306)
Serial send style: {"angle": 40}
'''
from
machine import Pin, UART, SoftI2C
importssd1306 # OLED
importujson # read uart string
importutime
# ==== Initialized IIC OLED ====
i2c
= SoftI2C(scl=Pin(5), sda=Pin(4))
oled_width= 128
oled_height= 64
oled= ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)
# display the motor state
def
display_motor(angle,state):
oled.fill(0) # 清屏
oled.text("Rotate Angle: ", 0, 0)
oled.text("{:.1f} deg".format(angle), 20, 15)
oled.text("State: ", 0, 35)
ifstate == 1:
oled.text("Rotating ...", 20, 50)
elifstate == 0:
oled.text("Reset", 20, 50)
else:
oled.text("Error", 20, 50)
oled.show()
# 电机控制引脚
coils
= [
Pin(0, Pin.OUT), # A相 (IN1)
Pin(1, Pin.OUT), # B相 (IN2)
Pin(18, Pin.OUT), # C相 (IN3)
Pin(19, Pin.OUT) # D相 (IN4)
]# 四相八拍步进电机的相序
STEP_SEQ
= [
[1, 0, 0, 1], # AB'
[1, 0, 0, 0], # A
[1, 1, 0, 0], # AB
[0, 1, 0, 0], # B
[0, 1, 1, 0], # BC
[0, 0, 1, 0], # C
[0, 0, 1, 1], # CD
[0, 0, 0, 1] # D
]# 驱动电机旋转指定步数;delay_ms 步间延时(ms),控制转速
def
step_motor(steps, delay_ms=1):
direction= 1 if steps >=0 else -1
for_ in range(abs(steps)):
forphase in range(8)[::direction]: # 方向控制
forcoil, state in zip(coils, STEP_SEQ[phase]):
coil.value(state)
utime.sleep_ms(delay_ms)
# 角度控制
def
rotate_angle(angle):
steps_per_rev= 509 # 64步/拍 × 8拍 × 8相位
steps= int(angle * (steps_per_rev / 360))
step_motor(steps)
# 释放电机扭矩
def
release():
forcoil in coils:
coil.value(0)
# 串口控制旋转角度
def
uart_control():
uart= machine.UART(1, baudrate=9600, tx=Pin(8), rx=Pin(9))
whileTrue:
ifuart.any():
cmd= uart.read()
try:
data= ujson.loads(cmd)
ra= float(data['angle']) # rotate angle
display_motor(ra,1)
rotate_angle(ra)
release()
display_motor(ra,0)
except:
uart.write('Invalid command\r\n')
release()
else:
release()
#display_motor(0,0)utime
.sleep_ms(100)
# main loop
display_motor
(0,0) # initialize OLED display
whileTrue:
uart_control()
效果
总结
本文介绍了 RP2350 开发板实现步进电机驱动的项目设计,包括旋转角度的精确控制、串口发送实现自定义角度旋转、OLED 显示旋转状态等,为 RP2350 的开发、设计和应用提供了参考。