【let's do|2026年第1期】 静音步进电机控制实践
2 过程帖 (测试元件及环境)

一 硬件环境:
1.主控板

2.步进驱动扩展版

3.转接板

4.42步进电机

5.电池

二 导线连接
1 硬件连接描述
步骤1:ESP32 → 扩展板
STEP → GPIO 21
DIR → GPIO 15
EN → GPIO 25
VIO → 3.3V
GND → 信号地
步骤2:扩展板 → 转接板
要注意2209驱动板的引脚与4988的不同,需转接板桥接一下,安装时需注意,可以根据VMOT引脚位置来定
步骤3:电池 → 扩展板
电池正极(+) → 扩展板 VMOT
电池负极(-) → 扩展板 GND
步骤4:步进电机 → 扩展板
步进电机 A1 → 扩展板 A1
步进电机 B1 → 扩展板 B1
步进电机 A2 → 扩展板 A2
步进电机 B2 → 扩展板 B2
步骤5:转接板 → TMC2209
TMC2209驱动模块直接插在转接板上。
2 实物连接
以下是实物连接图

二 软件环境:
1.thonny
2.esp32固件
https://micropython.org/download/ESP32_GENERIC/
三 测试程序:
1.运行测试
from machine import Pin import utime step = Pin(21, Pin.OUT) dir_pin = Pin(15, Pin.OUT) en = Pin(25, Pin.OUT) en.value(0) # 启用电机 dir_pin.value(0) # 设置顺时针 # 顺时针转 10000 步 for _ in range(10000): step.value(1) utime.sleep_us(1000) step.value(0) utime.sleep_us(1000) en.value(1) # 禁用电机
2.角度测试
import machine
import utime
# ==================== 引脚定义 ====================
motor_dir = machine.Pin(15, machine.Pin.OUT)
motor_step = machine.Pin(21, machine.Pin.OUT)
motor_en = machine.Pin(25, machine.Pin.OUT)
# ==================== 参数设置 ====================
MICRO_STEP_MODE = "1/8" # 细分:1/8, 1/16, 1/32, 1/64
STEP_ANGLE = 1.8
FULL_STEP_PULSES = int(360 / STEP_ANGLE) # = 200
MICRO_STEP_MAP = {"1/8":8, "1/16":16, "1/32":32, "1/64":64}
multiplier = MICRO_STEP_MAP[MICRO_STEP_MODE]
PULSES_PER_REV = FULL_STEP_PULSES * multiplier
def rotate(angle, rpm=30, direction="CW"):
"""
旋转指定角度
angle: 角度(0-360,支持小数)
rpm: 转速(转/分钟)
direction: 方向 "CW"(顺时针) 或 "CCW"(逆时针)
"""
# 计算需要的脉冲数
pulses_needed = int((angle / 360) * PULSES_PER_REV)
if pulses_needed == 0:
print("角度太小,无需转动")
return
# 计算脉冲延时
pulse_delay_us = int(30_000_000 / (rpm * PULSES_PER_REV))
# 设置方向
dir_value = 0 if direction == "CW" else 1
motor_dir.value(dir_value)
# 使能电机
motor_en.value(0)
# 发送脉冲
for i in range(pulses_needed):
motor_step.value(1)
utime.sleep_us(pulse_delay_us)
motor_step.value(0)
utime.sleep_us(pulse_delay_us)
# 关闭电机
motor_en.value(1)
print(f"旋转 {angle}° 完成 (脉冲数: {pulses_needed})")
# ==================== 使用示例 ====================
# 旋转90度
rotate(90, rpm=30, direction="CW")
utime.sleep(1)
# 旋转180度,逆时针,转速20rpm
rotate(180, rpm=20, direction="CCW")
utime.sleep(1)
# 旋转45度
rotate(45)3.速度测试
import machine
import utime
# ==================== 引脚定义 ====================
motor_dir = machine.Pin(15, machine.Pin.OUT)
motor_step = machine.Pin(21, machine.Pin.OUT)
motor_en = machine.Pin(25, machine.Pin.OUT)
# ==================== 用户设置 ====================
MICRO_STEP_MODE = "1/8" # 细分:1/8, 1/16, 1/32, 1/64
CURRENT_DIRECTION = "CW" # 方向:CW(顺时针), CCW(逆时针)
TARGET_RPM = 30 # 转速:30转/分钟
# ==================== 转速范围参考 ====================
"""
【推荐转速范围】
低速精密定位: 5-30 RPM ← 力矩大,不失步
中速运行: 30-120 RPM ← 常用范围
高速运行: 120-300 RPM ← 需加减速,力矩下降
极限转速: 300-600 RPM ← 力矩很小,容易失步
"""
# ==================== PULSES_PER_REV 计算 ====================
"""
【一圈需要多少个脉冲?】
第1步:电机步距角 = 1.8°
意思是:驱动器每收到1个脉冲,电机转1.8°
第2步:整步一圈需要多少脉冲?
360° ÷ 1.8° = 200 个脉冲
第3步:设置细分倍数
1/8细分 = 把1个整步分成8个微步
所以脉冲数变成原来的8倍
第4步:一圈脉冲数 = 200 × 细分倍数
举例:200 × 8 = 1600 个脉冲/圈
"""
STEP_ANGLE = 1.8
FULL_STEP_PULSES = int(360 / STEP_ANGLE) # = 200
MICRO_STEP_MAP = {"1/8":8, "1/16":16, "1/32":32, "1/64":64}
multiplier = MICRO_STEP_MAP[MICRO_STEP_MODE]
PULSES_PER_REV = FULL_STEP_PULSES * multiplier
# ==================== pulse_delay_us 计算 ====================
"""
【脉冲延时需要多少微秒?】
已知:
转速 = 30 转/分钟
一圈脉冲 = 1600 脉冲
第1步:转速换算成 转/秒
30 转/分钟 ÷ 60 = 0.5 转/秒
第2步:每秒需要多少个脉冲?
0.5 转/秒 × 1600 脉冲/圈 = 800 脉冲/秒 (即 800 Hz)
第3步:每个脉冲的周期是多少?
周期 = 1 ÷ 频率 = 1 ÷ 800 = 0.00125 秒 = 1250 微秒
第4步:每个脉冲需要高电平和低电平,各占一半时间
脉冲延时 = 周期 ÷ 2 = 1250 ÷ 2 = 625 微秒
【合并成一条公式】
脉冲延时(us) = 30,000,000 ÷ (转速 × 一圈脉冲数)
30,000,000 怎么来的?
60(分钟→秒) × 1,000,000(秒→微秒) ÷ 2(高低电平各一半)
= 60 × 1,000,000 ÷ 2 = 30,000,000
代入验证:30,000,000 ÷ (30 × 1600) = 30,000,000 ÷ 48,000 = 625 ✅
"""
pulse_delay_us = int(30_000_000 / (TARGET_RPM * PULSES_PER_REV))
# ==================== 方向设置 ====================
dir_value = 0 if CURRENT_DIRECTION == "CW" else 1
# ==================== 执行旋转 ====================
motor_en.value(0)
motor_dir.value(dir_value)
for i in range(PULSES_PER_REV):
motor_step.value(1)
utime.sleep_us(pulse_delay_us)
motor_step.value(0)
utime.sleep_us(pulse_delay_us)
motor_en.value(1)
print("转动一圈完成")4.距离测试
import machine
import utime
# ==================== 引脚定义 ====================
motor_dir = machine.Pin(15, machine.Pin.OUT)
motor_step = machine.Pin(21, machine.Pin.OUT)
motor_en = machine.Pin(25, machine.Pin.OUT)
# ==================== 固定参数 ====================
STEP_ANGLE = 1.8 # 步距角:电机每收到1个脉冲转动的角度
LEAD = 2 # 导程:丝杆转一圈,滑台移动的距离(mm)
MICRO_STEP = 8 # 细分:1/8细分
# ==================== 计算公式 ====================
"""
【导程与距离的计算公式】
1. 一圈脉冲数 = (360° ÷ 步距角) × 细分倍数
示例:360 ÷ 1.8 = 200个整步,200 × 8细分 = 1600脉冲/圈
2. 每毫米脉冲数 = 一圈脉冲数 ÷ 导程
示例:1600脉冲 ÷ 2mm = 800脉冲/mm
3. 目标距离脉冲数 = 距离(mm) × 每毫米脉冲数
示例:20mm × 800 = 16000脉冲
4. 脉冲延时(us) = 1,000,000 ÷ (速度 × 每毫米脉冲数 × 2)
示例:20mm/s → 1,000,000 ÷ (20 × 800 × 2) = 31us
"""
PULSES_PER_REV = int(360 / STEP_ANGLE) * MICRO_STEP # 一圈脉冲数 = 1600
PULSES_PER_MM = PULSES_PER_REV / LEAD # 每毫米脉冲数 = 800
# ==================== 方向映射 ====================
DIR = {"UP": 0, "DOWN": 1} # 方向:UP上升,DOWN下降(反了交换0和1)
# ==================== 移动函数 ====================
def move(direction, distance, speed):
"""
移动函数
参数:
direction: 方向 ("UP" 或 "DOWN")
distance: 距离 (mm)
speed: 速度 (mm/s)
计算过程:
脉冲数 = 距离 × 每毫米脉冲数
延时(us) = 1,000,000 ÷ (速度 × 每毫米脉冲数 × 2)
"""
if distance == 0:
return
# 根据速度和距离计算脉冲参数
delay_us = int(1_000_000 / (speed * PULSES_PER_MM * 2)) # 脉冲延时
pulses = int(distance * PULSES_PER_MM) # 所需脉冲数
# 设置方向
motor_dir.value(DIR[direction])
# 打印计算过程
print(f"\n【{direction}移动计算】")
print(f" 目标: {direction} {distance}mm, 速度{speed}mm/s")
print(f" 计算: {distance}mm × {PULSES_PER_MM:.0f}脉冲/mm = {pulses}脉冲")
print(f" 计算: 1,000,000 ÷ ({speed} × {PULSES_PER_MM:.0f} × 2) = {delay_us}us")
print(f" 结果: 延时{delay_us}us, 脉冲{pulses}")
# 发送脉冲
for _ in range(pulses):
motor_step.value(1)
utime.sleep_us(delay_us)
motor_step.value(0)
utime.sleep_us(delay_us)
utime.sleep(0.5) # 移动完成后停顿0.5秒
# ==================== 执行移动 ====================
motor_en.value(0) # 使能电机(0=使能,1=释放)
# 高速上升20mm,低速下降20mm
move("UP", 20, 10) # 上升20mm,速度20mm/s(高速)
move("DOWN", 20, 5) # 下降20mm,速度5mm/s(低速)
motor_en.value(1) # 释放电机
print("\n完成!")四 演示视频:
我要赚赏金
