项目介绍
本项目选用来自ADI的板卡(TMC4361A-BOB&TMC2160-BOB板卡)连接步进电机,使用树莓派Pico实现电机定速旋转、指定角度旋转、指定圈数旋转、正反转切换功能。在电机控制过程中,TMC4361A是电机运行状态控制芯片,TMC2160是电机驱动芯片,树莓派Pico用于配置两种芯片功能,并处理用户的输入。
方案设计
使用状态机实现电机的定速旋转、指定角度旋转、指定圈数旋转、以及正反转切换功能。
硬件连接
Pico与TMC4361的连接:
通过SPI1(CS=Pin13, SCK=Pin14, MOSI=Pin15, MISO=Pin12)连接到TMC4361的(CSN, SCK, SDI, SDO),通过Pin16连接到CLK端口。
Pico与TMC2160的连接:
通过SPI0(CS=Pin5, SCK=Pin2, MOSI=Pin3, MISO=Pin4)连接到TMC4361的(CSN, SCK, SDI, SDO)。
TMC4361与TMC2160的连接:
TMC4361的STPOUT和DIROUT连接到TMC2160的STEP和DIR。
TMC2160与电机的连接:
(A1, A2), (B1, B2) 分别连接到两相四线电机的两相端口。
电源连接:
电脑USB提供三个板卡的逻辑电源。TMC2160的VS,GND连接到12V1.5A的电源。

寄存器配置
1. TMC4361A寄存器配置
1.1. Register 0x31 – External Clock Frequency (fCLK)
- 配置值:
self._clock_freq(外部时钟频率,25位无符号整数) - 描述:
- 功能:该寄存器配置外部时钟频率,
fCLK是一个 25 位的无符号整数。 - 作用:该寄存器用于设置芯片的外部时钟频率,用于驱动芯片时序的同步。时钟频率会影响芯片的所有计时器和控制机制。
- 默认值:无默认值,取决于外部时钟输入。
- 功能:该寄存器配置外部时钟频率,
- 备注:确保外部时钟输入正确,影响芯片所有的计时操作。
1.2. Register 0x10 – Output Timings (STP_LENGTH_ADD & DIR_SETUP_TIME)
- 配置值:
STP_LENGTH_ADD(bit 15:0,默认值:0x0000)DIR_SETUP_TIME(bit 31:16,默认值:0x0000)
- 描述:
- STP_LENGTH_ADD:设置在步进信号 (
STPOUT) 活动期间,为有效输出步进,所需要的附加时钟周期数。 - DIR_SETUP_TIME:设置方向输出 (
DIROUT) 和步进输出 (STPOUT) 电压变化之间的延迟时间,单位为时钟周期数。
- STP_LENGTH_ADD:设置在步进信号 (
- 作用:
- STP_LENGTH_ADD:定义输出步进信号所需的额外时钟周期。
- DIR_SETUP_TIME:控制方向信号与步进信号之间的时间间隔,确保信号之间的同步,避免时序冲突。
- 默认值:
0x0000。
该配置确保了步进信号和方向信号之间的同步,减少因时序问题引起的控制错误。
1.3. Register 0x0C – Event Protection Configuration (EVENT_CLEAR_CONF)
- 配置值:
0xFFFFFFFF - 描述:
- 功能:该寄存器用于配置事件保护机制。其值设置为
0xFFFFFFFF时,表示所有事件位都会被保护,防止自动清除。 - 作用:在读取 EVENTS 寄存器(0x0E)时,选定的事件位(在 EVENTS 寄存器中)不会被清除,直到显式清除。
- 功能:该寄存器用于配置事件保护机制。其值设置为
- 默认值:
0x00000000。 - 备注:
- 保护机制:该配置用于防止读取 EVENTS 寄存器时,事件位被自动清除。设置为
0xFFFFFFFF表示保护所有事件。 - 使用此配置时,必须手动清除事件,否则这些事件会保持激活。
- 保护机制:该配置用于防止读取 EVENTS 寄存器时,事件位被自动清除。设置为
1.4. Register 0x0E – Status Event Register (EVENTS)
- 配置值:
0xFFFFFFFF - 描述:
- 功能:该寄存器用于存储当前的状态事件信息。
- 作用:此寄存器包含所有的状态事件标志,表示芯片的工作状态。事件包括驱动器错误、超时、位置错误等。
- 默认值:无默认值。
- 备注:
- 该寄存器用于指示当前的状态事件,通常需要结合 EVENT_CLEAR_CONF 配置,保护重要事件不被自动清除。
- 必须通过软件读取和清除事件标志来管理系统的状态。
1.5. Register 0x20 – RAMPMODE
RAMPMODE寄存器用于设置请求的运动曲线和操作模式,包含3个位用于指定不同的操作模式和运动曲线配置。
- 操作模式 (Operation Mode):
- Bit 2:
- 1: 定位模式 (Positioning Mode):在此模式下,
XTARGET(目标位置)为速度变化的主要参考。 - 0: 速度模式 (Velocity Mode):在此模式下,
VMAX(目标速度)为速度变化的主要参考。
- 1: 定位模式 (Positioning Mode):在此模式下,
- 运动曲线 (Motion Profile):
- Bits 1:0:
- 00: 无加速曲线 (No Ramp):
VACTUAL(实际速度)仅跟随VMAX,即采用矩形速度曲线。 - 01: 梯形加速曲线 (Trapezoidal Ramp):考虑加速和减速值,在生成
VACTUAL时不调整加速度。 - 10: S型加速曲线 (S-shaped Ramp):考虑所有加速、减速以及弯曲值,用于生成平滑的
VACTUAL速度曲线。
- 00: 无加速曲线 (No Ramp):
- 默认值:
0x0,表示无加速曲线,速度直接跟随VMAX。
1.6. Register 0x24 – VMAX
VMAX寄存器用于设置最大允许的速度,具有符号表示,采用32位格式(24位整数部分和8位小数部分)。设置电机的最大速度或目标速度,依据所选运动模式(定位模式或速度模式)进行调整。在位置模式下,VMAX限制了位置变化的最大速度;而在速度模式下,VMAX是电机运行的目标速度。
- 格式:32位数据,包含24位整数部分和8位小数部分,范围为
4 mpps ≤ |VMAX [pps]| ≤ CLK_FREQ • ½ pulses。 - 范围:例如,如果时钟频率
fCLK为16 MHz,则最大速度|VMAX|≤ 8 Mpps(百万脉冲每秒)。
- 范围:例如,如果时钟频率
- 默认值:未指定具体默认值。根据应用需求,用户需自行设置适合的速度值。
1.7. Register 0x37 – XTARGET
XTARGET寄存器用于设置目标位置,具有符号表示,采用32位格式。
- 格式:32位数据,表示目标位置值。
- 默认值:未指定具体默认值,需自行设置所需的目标位置。
2. TMC2160寄存器配置
2.1. Register 0x00 – GCONF (Global Configuration Flags)
- 配置值:
0x00000008 - 解析:二进制为
0000 0000 0000 1000,即 bit[3] = 1。 - 作用:
- bit3 – multistep_filt = 1
启用步进信号滤波器,用于 StealthChop 优化,在外部 STEP 源时开启(默认=1)。
- bit3 – multistep_filt = 1
- 其他位:保持默认值。
2.2. Register 0x10 – IHOLD_IRUN (Driver Current Control)
- 配置值:
0x000A0806 - 解析:
- 二进制分解:
- IHOLD (bits 4..0) = 0x06 = 6
→ 电机静止电流:6/32 ≈ 19% 额定电流。 - IRUN (bits 12..8) = 0x10 = 16
→ 电机运行电流:16/32 = 50% 额定电流。 - IHOLDDELAY (bits 19..16) = 0x0A = 10
→ 电机进入静止电流的延时控制 = 10 × 2^18 个时钟周期。
- IHOLD (bits 4..0) = 0x06 = 6
- 作用:
- 在运行时提供 50% 额定电流,保证转矩和稳定性;
- 静止时电流降低至 19%,减少发热;
- 延时机制避免了突然降流带来的电机抖动。
2.3. Register 0x6C – CHOPCONF (Chopper Configuration)
- 配置值:
0x010100C3 - 解析:二进制展开如下:0x010100C3 = 0000 0001 0000 0001 0000 0000 1100 0011
- 关键位说明:
- toff (bits 3..0) = 0x3 = 3
→ Chopper off-time = 24 + 32×3 = 120 clocks。驱动器有效(toff ≠ 0)。 - hstrt (bits 6..4) = 0x1 = 1
→ Hysteresis start 值。 - hend (bits 10..7) = 0x0 = 0
→ Hysteresis end 值。 - tbl (bits 16..15) = 0x2 = 2
→ Comparator blank time = 36 clocks。 - mres (bits 27..24) = 0x0 = 256 microsteps
→ 原生 256 微步分辨率。 - intpol (bit 28) = 1
→ 启用插值至 256 微步,保证最平滑的运动。 - dedge (bit 29) = 0
→ 不启用双沿触发。 - diss2g/diss2vs (bits 31..30) = 0
→ 短路保护功能开启(默认安全)。
- toff (bits 3..0) = 0x3 = 3
- 作用:
- 选择 SpreadCycle 模式(chm=0)
- 微步分辨率设置为 256 microsteps,并启用插值,保证低速平滑运行;
- 设置合适的 TOFF 与 blank time,确保稳定的电流斩波控制。
状态机设计
可以将电机的控制分为以下几种状态:
- 待机状态:初始状态,等待命令输入。
- 定速旋转状态:电机以一定速度旋转。
- 指定角度旋转状态:电机旋转至指定角度后停止。
- 指定圈数旋转状态:电机旋转指定圈数后停止。
- 正转状态:电机向一个方向旋转。
- 反转状态:电机向另一个方向旋转。
每当接收到一个特定的命令后,状态机将切换到相应的状态。
输入命令,输入将通过字母和回车来触发状态转换:
- 'S':定速旋转
- 'A':指定角度旋转
- 'C':指定圈数旋转
- 'R':切换正转或反转
TMC4361需提供一个输入频率才可以正常运行,该频率用pico的PWM输出即可。
pico两个spi分别输出到TMC4361和TMC2160,分别用于配置寄存器。
程序设计
程序流程图

核心代码
1. 异步任务启动与状态共享
位于 main 异步函数中,是整个程序的入口和调度中心。它首先定义了一个名为 ctx 的共享上下文词典,用于在不同的并发任务之间安全地传递和共享数据(如速度、方向、当前位置等)。使用 uasyncio.create_task() 启动了两个核心的并发任务:monitor_status(状态监控)和 handle_input(用户输入处理),让它们并行运行。
async def main():
ctx = {
'round': 360 / 1.8 * 128,
'speed': int(360 / 1.8 * 128),
'direction': 1,
'current_position': 0
}
tmc.set_accelerations(ctx['round'], ctx['round'], 0, 0)
tmc.stop()
uasyncio.create_task(monitor_status(tmc, ctx))
uasyncio.create_task(handle_input(tmc, ctx))
while True:
await uasyncio.sleep(1)
2. 电机状态持续监控
monitor_status 函数是一个在后台持续运行的协程。它的核心功能是通过 while True 循环,每隔100毫秒调用 `tmc.get_current_tmc.get_current_position() 从硬件读取电机当前所处的精确位置。然后,它将这个实时位置数据更新到共享的 ctx 词典中。这确保了其他任务在需要时总能获取到最新的电机状态,为精确的角度和圈数控制提供了数据基础。
async def monitor_status(tmc, ctx):
while True:
current_position = tmc.get_current_position()
ctx['current_position'] = current_position
await uasyncio.sleep_ms(100)
3. 异步监听用户输入
handle_input 函数同样是一个协程,专门负责处理用户的键盘输入。它通过 uasyncio.StreamReader 异步地等待来自标准输入(sys.stdin)的数据。关键在于 await sreader.readline(),它会暂停此任务的执行,直到用户输入一行字符并按下回车。在此等待期间,CPU可以去执行其他任务(如 monitor_status),实现了非阻塞式的输入处理,提高了系统效率。
async def handle_input(tmc, ctx):
sreader = uasyncio.StreamReader(sys.stdin)
while True:
res = await sreader.readline()
user_input = res.decode().strip()
parts = user_input.split(':')
command = parts[0].upper()
4. 指令解析
'S' 指令:定速旋转
当检测到命令为 'S' 时,程序会将TMC4361运动控制器设置为 速度模式 (VELOCITY_MODE)。然后,它会调用 `tmc.set_max_tmc.set_max_speed() 函数,将用户设定的速度值发送给控制器。这会使电机以指定的速度持续旋转,直到接收到新的指令。
'A' 和 'C' 指令:精确定位
这两个指令分支处理的是基于位置的旋转。它们首先将控制器切换到 位置模式 (POSITIONING_MODE)。核心逻辑是计算出目标位置 `targettarget_pos。这个计算基于从 ctx 中读取的当前位置,加上用户指定的角度或圈数转换成的步数,再乘以方向系数。最后,通过 tmc.set_target_position() 命令电机运动到这个绝对位置后自动停止。
'R' 指令:切换方向
处理 'R' 指令的代码非常简洁。它不直接与电机硬件通信,而是修改共享状态 ctx 中的 direction 变量,将其值在 1 和 -1 之间切换。这个 direction 变量会在之后处理 'A' 和 'C' 指令计算目标位置时被用作乘数,从而轻松地实现正转和反转的切换。
if command == 'S': # Set Speed
speed = int(parts[1])
ctx['speed'] = speed # Update shared speed value
tmc.set_ramp_mode(TMC4361.VELOCITY_MODE, TMC4361.TRAPEZOIDAL_RAMP)
tmc.set_max_speed(speed)
print("Speed set to:", speed)
elif command == 'A': # Rotate by Angle
angle = float(parts[1])
tmc.set_ramp_mode(TMC4361.POSITIONING_MODE, TMC4361.TRAPEZOIDAL_RAMP)
tmc.set_max_speed(ctx['speed'])
# Read current position from the shared context
target_pos = int(ctx['current_position'] + ctx['round'] * angle / 360 * ctx['direction'])
tmc.set_target_position(target_pos)
print("Rotating by angle:", angle)
elif command == 'C': # Rotate by Cycles/Revolutions
revolutions = int(parts[1])
tmc.set_ramp_mode(TMC4361.POSITIONING_MODE, TMC4361.TRAPEZOIDAL_RAMP)
tmc.set_max_speed(ctx['speed'])
# Read current position from the shared context
target_pos = int(ctx['current_position'] + ctx['round'] * revolutions * ctx['direction'])
tmc.set_target_position(target_pos)
print("Rotating by revolutions:", revolutions)
elif command == 'R': # Reverse direction
ctx['direction'] *= -1
print("Direction switched, current direction:", "lockwise" if ctx['direction']==1 else "counterclockwise")
else:
print("Error: Unknown command")
5. TMC2160驱动器配置
配置TMC2160的GCONF寄存器启用外部STEP/DIR接口,设置IHOLD_IRUN电流参数为0x000A0806,配置CHOPCONF寄存器为0x010100C3实现128微步控制,设置斩波器空载时间和迟滞值。
tmc2160_configs = [
(0x00, 0x00000008),
(0x10, 0x000A0806),
(0x6C, 0x010100C3)
]
tmc2160 = TMC2160(spi, cs_pin=5)
tmc2160.configure_registers(tmc2160_configs)
6. TMC4361基础初始化
初始化TMC4361时钟频率为8MHz,设置步进脉冲宽度和方向信号建立时间各5ns,配置事件寄存器禁止自动清除事件标志。
tmc = TMC4361(spi, cs_pin=13, clock_freq=8000000)
tmc.write_register(TMC4361.CLK_FREQ_REGISTER, 8000000)
tmc.set_output_timings(5, 5)
tmc.write_register(TMC4361.EVENT_CLEAR_CONF_REGISTER, 0xFFFFFFFF)
实物演示
- 定速旋转

- 指定角度旋转

- 指定圈数旋转

- 正反转切换

完整的动态演示效果请观看演示视频。
总结
本项目的难点主要在于对TMC4361和TMC2160这两款芯片的寄存器功能配置的深入理解。由于这两款芯片功能复杂,开发过程中需要花费大量时间仔细阅读芯片的数据手册,并在其中找到关键寄存器的配置细节。只有准确配置这些寄存器,才能确保系统能够稳定运行。
本项目的目标是实现对用户输入的处理,并为电机提供简单的开环控制功能。通过对寄存器的正确配置,能够有效控制电机的转动,同时保证系统的响应速度和稳定性,满足基本的控制需求。


