本文介绍了 DFRobot Beetle RP2350 开发板实现步进电机驱动的项目设计,主要包括旋转角度的精确控制、串口发送实现自定义角度旋转、OLED 显示旋转状态三部分。
项目介绍
包括步进电机原理、该项目使用的 28BYJ-48 步进电机,及其驱动器——ULN2003 驱动模块介绍。
步进电机原理
步进电机(Stepper Motor)是一种将电脉冲信号转换为精确角度位移的执行器件,属于开环控制电机。
核心特点:每接收一个脉冲,转子就转动一个固定的角度(称为“步距角”),无需反馈传感器即可实现位置控制。
结构组成
·定子:绕有线圈的磁极,分为多相(常见2相、4相、5相)。
·转子:永磁体(永磁式)或齿状铁芯(反应式/混合式)。定子绕组按特定顺序通电,产生旋转磁场,吸引转子逐步转动。
工作过程
通过控制器(如单片机)发送脉冲信号,驱动电路按顺序切换定子绕组的电流方向。每切换一次,转子转动一个步距角,连续脉冲使电机连续旋转。
28BYJ-48 步进电机
28BYJ-48 是一款常见的低成本、小扭矩 5 线单极步进电机,可使用 ULN2003 控制器和单片机实现旋转控制,广泛用于打印机、扫描仪、摄像机云台、空调、家电、玩具、消费电子等领域。
参数 | 值/描述 |
电机类型 | 单极 4 相永磁式步进电机(5线制) |
步距角 | 5.625°(64 步/圈),配合减速齿轮后 0.0879°(实际输出轴 4096 步/圈) |
减速比 | 1:64(内部齿轮组减速) |
额定电压 | 5V 或 12V DC |
相电流 | 约 100mA(每相) |
保持扭矩 | 约 0.1 N·m(输出轴,受减速齿轮影响) |
绕组电阻 | 约 50Ω/相 |
实际输出轴步距角为 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 显示旋转状态
旋转指定角度
本节介绍并实现了指定角度的步进电机旋转控制。
硬件连接
GP0 ---- IN1 (ULN2003)
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 ... pberry-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
串口自定义角度
在实现步进电机旋转驱动的基础上,进一步实现串口发送自定义角度并旋转的功能设计方案。
硬件连接
GP0 ---- IN1 (ULN2003)
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 消息的格式错误,则反馈指令无效的提示。
OLED 显示旋转状态
在前面实现步进电机旋转驱动、串口自定义角度控制的基础上,进一步实现串口发送角度、旋转、OLED 状态显示的功能设计方案。
硬件连接
GP0 ---- IN1 (ULN2003)
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()
效果
动态
总结
本文介绍了 DFRobot Beetle RP2350 开发板实现步进电机驱动的项目设计,包括旋转角度的精确控制、串口发送实现自定义角度旋转、OLED 显示旋转状态等,为 Beetle-RP2350 的开发、设计和应用提供了参考。