四线步进电机(28BYJ-48,A+ A- B+ B-)驱动思路

四线步进电机(28BYJ-48,A+ A- B+ B-)驱动思路

四线 = 两相四线步进电机,两相绕组:A相(A+,A-)、B相(B+,😎,没有公共端,典型就是28BYJ-48。 驱动芯片:ULN2003 最常用,也可以用三极管/MOS管搭H桥。 驱动方式:4拍(单拍) / 8拍(半步,细分,更顺滑)

一、绕组逻辑

  • A相:A+、A- 一组线圈;B相:B+、B- 另一组线圈
  • 线圈通电原理:电流方向决定磁极。A+高A-低 与 A-高A+低,磁极相反。
  • 两相四线没有中心抽头,不能像五线28BYJ那样用公共端,必须H桥,每相正反换向。

两种驱动节拍表

1)4拍(全步,单绕组通电,扭矩一般,震动大)

顺序:A → B → /A → /B

拍号 A+ A- B+ B-
0 1 0 0 0
1 0 0 1 0
2 0 1 0 0
3 0 0 0 1
循环 0→1→2→3 正转;反向 3→2→1→0 反转

2)8拍(半步模式,力矩平稳、抖动小,角度精度高)

单拍+双拍混合,就是半步驱动

拍号 A+ A- B+ B-
0 1 0 0 0
1 1 0 1 0
2 0 0 1 0
3 0 1 1 0
4 0 1 0 0
5 0 1 0 1
6 0 0 0 1
7 1 0 0 1
0~7 正转;7→0 反向循环

28BYJ-48 减速后:8拍模式一圈需要4096拍

二、硬件引脚定义

A+ → GPIO2
A- → GPIO3
B+ → GPIO4
B- → GPIO5

ULN2003:单片机IO输出高电平,ULN输出低电平,节拍表电平要反过来!这点非常容易踩坑! 简单记:

  • 如果你直接MOS管H桥:代码用上面节拍表

  • ULN2003驱动28BYJ:IO输出取反,表格1写成0,0写成1

三、设计思路

  1. 建立节拍数组,存放8拍的A+ A- B+ B-电平
  2. 维护一个全局变量 step_index,记录当前在哪一拍
  3. 每一次步进:修改4个IO口电平 → step_index++,超过7归零;反转就 step_index--
  4. 延时控制转速:延时越大越慢;不要太短,否则丢步
  5. 原点限位逻辑:
    • 上电:电机持续向零点方向走,检测到限位信号,停止,重置角度计数器=0
    • 之后每旋转目标角度,计算需要多少拍,循环输出节拍

四、ESP32 示例代码(两相四线,8拍,A+A-B+B-)

# MicroPython 版本,ESP32
from machine import Pin
import time

# 定义引脚 A+ A- B+ B-
A_plus = Pin(2, Pin.OUT)
A_minus = Pin(3, Pin.OUT)
B_plus = Pin(4, Pin.OUT)
B_minus = Pin(5, Pin.OUT)

# 8拍半步节拍表 H桥驱动(MOS管方案,高电平导通线圈)
# [A+, A-, B+, B-]
step_table = [
    [1,0,0,0],
    [1,0,1,0],
    [0,0,1,0],
    [0,1,1,0],
    [0,1,0,0],
    [0,1,0,1],
    [0,0,0,1],
    [1,0,0,1],
]

step_idx = 0

def set_step(idx):
    """输出对应节拍电平"""
    A_plus.value(step_table[idx][0])
    A_minus.value(step_table[idx][1])
    B_plus.value(step_table[idx][2])
    B_minus.value(step_table[idx][3])

def step_motor(step_num, delay_ms=3):
    """
    转动电机
    step_num >0 正转,<0反转
    delay_ms: 每拍间隔,越小越快,过小丢步
    """
    global step_idx
    dir = 1
    if step_num < 0:
        dir = -1
        step_num = -step_num
    for _ in range(step_num):
        set_step(step_idx)
        time.sleep_ms(delay_ms)
        step_idx += dir
        if step_idx >= 8:
            step_idx = 0
        elif step_idx <0:
            step_idx =7
    # 可选:转动完成,全部线圈断电,省电减少发热
    A_plus.off()
    A_minus.off()
    B_plus.off()
    B_minus.off()

# ========== 测试 ==========
# 转一圈 4096步(8拍模式)
step_motor(4096, 3)
time.sleep(1)
# 反转半圈
step_motor(-2048,3)

五、ULN2003注意事项

ULN2003是灌电流驱动,IO输出高,ULN输出低,线圈通电。 节拍表电平全部取反:1→0,0→1

step_table_uln = [
    [0,1,1,1],
    [0,1,0,1],
    [1,1,0,1],
    [1,0,0,1],
    [1,0,1,1],
    [1,0,1,0],
    [1,1,1,0],
    [0,1,1,0],
]

六、限位原点集成思路

# 霍尔限位接GPIO14
hall = Pin(14, Pin.IN, Pin.PULL_UP)

def home():
    """上电回零函数"""
    global step_idx
    print("寻找原点...")
    while hall.value() == 1: # 没检测到磁铁
        set_step(step_idx)
        time.sleep_ms(4)
        step_idx +=1
        if step_idx >=8:
            step_idx=0
    # 碰到原点,停止,清零步数计数
    A_plus.off()
    A_minus.off()
    B_plus.off()
    B_minus.off()
    print("原点找到!")

七、设计要点总结

  1. 四线两相,A+/A- 控制A相磁场方向;B+/B-控制B相
  2. 优先8拍半步,云台更顺滑
  3. 开环靠脉冲计数,必须上电回零(霍尔/限位)消除丢步误差
  4. 每拍之间必须延时,不能无限快
  5. 运动结束可以关闭所有绕组,降低发热

八、正反转控制逻辑

step_table = [
    [1,0,0,0], # 0
    [1,0,1,0], # 1
    [0,0,1,0], # 2
    [0,1,1,0], # 3
    [0,1,0,0], # 4
    [0,1,0,1], # 5
    [0,0,0,1], # 6
    [1,0,0,1], # 7
]
  • 正转:0 →1 →2 →3 →4 →5 →6 →7 →0(数组下标递增)
  • 反转:0 →7 →6 →5 →4 →3 →2 →1 →0(数组下标递减)
dir = 1    # +1 下标递增
dir = -1   # -1 下标递减
step_idx = step_idx + dir
step_idx 越界后做边界处理

九、角度与速度控制

step_num 作用

step_num = 需要执行多少个节拍。

  • step_num = 2048:电机一共走2048拍,然后停下
  • step_num = -2048:走2048拍,反向转动

28BYJ-48 8拍模式:4096拍 = 完整一圈360° 所以 step_num=1024 → 转90°,step_num=2048 → 180°

step_motor(step_num, delay_ms=3)
# step_num:总步数(角度)
# delay_ms:每一拍的间隔时间(速度)

速度由谁控制?

delay_ms:每一拍之间等待多久

  • delay_ms = 5:每拍等5ms → 慢
  • delay_ms = 2:每拍等2ms → 更快
  • 太小(比如<1ms):来不及建立磁场,直接丢步,电机不转

转速公式: 每秒拍数 = 1000 / delay_ms 例:delay_ms=3 → 1000/3 ≈ 333拍/秒

示例代码

def step_motor(step_num, delay_ms=3):
    dir = 1 if step_num>0 else -1
    step_num = abs(step_num)
    for _ in range(step_num):   # 循环执行 step_num 次
        set_step(step_idx)
        time.sleep_ms(delay_ms) # 控制速度
        step_idx += dir

for _ in range(step_num):循环多少次,就走多少步。

step_motor(1024, 5) # 走1024拍,慢速度
step_motor(1024, 2) # 同样1024拍(同样角度),速度更快
step_motor(4096, 3) # 走更多步数(一圈),中等速度
posted @ 2026-09-19 09:18  Q&25  阅读(46)  评论(0)    收藏  举报