本帖最后由 无垠的广袤 于 2025-5-3 04:35 编辑
本文介绍了 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 步,实际可能存在误差。
ULN2003 驱动器
ULN2003 是一款常用的达林顿晶体管阵列芯片,专为驱动高电流负载(如继电器、步进电机、LED阵列等)设计。其作用是将 MCU 输出的弱电流信号转换为大电流输出,是控制 28BYJ-48 步进电机的核心驱动芯片。
原理图
使用时需要将 28BYJ-48 步进电机的5线快接插头与 ULN2003 模块对应接口连接,并将模块的 4 个控制引脚(信号输入端,丝印 IN1、IN2、IN3、IN4)与单片机对应引脚相连,实现控制信号输入。
项目方案
具体执行方案和工程测试流程如下
步进电机原理 旋转角度的精确控制 串口发送实现自定义角度旋转 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 的开发、设计和应用提供了参考。
----------- 彩蛋 -------------
介绍了 Beetle RP2350 开发板驱动 WS2812B 实现流水灯的项目设计。
WS2812B 流水灯
使用 neopixel 库实现 WS2812B 驱动。
WS2812 简介
WS2812 是一款集成了控制电路和发光电路的智能外控 LED 光源,通常被称为 "NeoPixel"(由 Adafruit 推广)。采用单线通信协议,能够实现全彩控制,广泛应用于 LED 灯带、装饰照明、创意项目等领域。
特点 集成驱动芯片
单线控制(单总线协议)
24 位真彩色
响应速度快
低电压供电
级联能力
优势:仅需 1 个 I/O 即可实现彩色灯带效果。
代码
- '''
- Name: WS2812 flow light by using neopixel
- Version: v1.0
- Date: 2025.05
- Author: ljl
- Other: include 3 effects: blink, flow lights and full-color running light.
- URL1: https://electrocredible.com/neop ... ry-pi-pico-ws2812b/
- URL2: https://blog.csdn.net/jiangge12/article/details/128857863
- '''
-
- import neopixel
- from machine import Pin
- import time
-
- ws_pin = 27
- led_num = 8
- BRIGHTNESS = 0.05 # Adjust the brightness (0.0 - 1.0)
-
- neoRing = neopixel.NeoPixel(Pin(ws_pin), led_num)
-
- # 定义亮度
- def set_brightness(color):
- r, g, b = color
- r = int(r * BRIGHTNESS)
- g = int(g * BRIGHTNESS)
- b = int(b * BRIGHTNESS)
- return (r, g, b)
- # -------------------------------------
- # 流水灯函数
- def color_wipe(color, delay):
- for i in range(led_num):
- neoRing = set_brightness(color) # 设置当前 LED 的颜色
- neoRing.write() # 更新 LED 状态
- time.sleep(delay) # 延时
- for i in range(led_num):
- neoRing = (0, 0, 0) # 关闭当前 LED
- neoRing.write() # 更新 LED 状态
- time.sleep(delay) # 延时
- # 定义流水灯循环
- def loop_wipe():
- color_wipe((255, 0, 0), 0.1) # 红色流水灯
- color_wipe((0, 255, 0), 0.1) # 绿色流水灯
- color_wipe((0, 0, 255), 0.1) # 蓝色流水灯
- # -------------------------------------
- # 连续流水灯函数
- def color_continue(color, delay):
- for i in range(led_num):
- neoRing = set_brightness(color) # 设置当前 LED 的颜色
- neoRing.write() # 更新 LED 状态
- time.sleep(delay) # 延时
- # 定义连续流水灯循环
- def loop_continue():
- color_continue((255, 0, 0), 0.1) # 红色流水灯
- color_continue((0, 255, 0), 0.1) # 绿色流水灯
- color_continue((0, 0, 255), 0.1) # 蓝色流水灯
- # -------------------------------------
- # 定义闪灯循环
- def loop():
- # Display red
- color = (255, 0, 0) # Red color
- color = set_brightness(color)
- neoRing.fill(color)
- neoRing.write()
- time.sleep(0.5)
- # Display green
- color = (0, 255, 0) # Green color
- color = set_brightness(color)
- neoRing.fill(color)
- neoRing.write()
- time.sleep(0.5)
- # Display blue
- color = (0, 0, 255) # Blue color
- color = set_brightness(color)
- neoRing.fill(color)
- neoRing.write()
- time.sleep(0.5)
-
- while True:
- #loop()
- #loop_wipe()
- loop_continue()
复制代码
效果
RGB 三色流动点亮
全彩 RGB 流水灯设计,为后续项目增加美观的背景,突显赛博朋克风格。
|