有个做小型机械臂的朋友前阵子找我,说他的两相双极步进电机在低速时稳稳当当,一加速到 200 RPM 就开始丢步,抓取位置每次差个一两度,改程序改到怀疑人生。他用的方案是 TB67S531FTG 配 STM32L073RZ——这套组合在工业设备和小型机器人里其实相当常见:TB67S531FTG 负责功率级、电流斩波和各种保护,STM32L073RZ 负责脉冲时序、加减速规划和状态管理,分工清楚、成本可控。但大部分人卡在同一个地方:把线接上、让电机转起来,就急着做整机,结果一上负载全是问题。步进电机控制这件事,难的不是"让它转",而是"让它每次都在同一个位置停住"。这篇就把这套组合从选型逻辑、电流控制原理、硬件布局、固件时序到故障排查的完整链路拆开讲,你照着能直接落地。
1. 先把分工想清楚:TB67S531FTG 与 STM32L073RZ 各自负责什么
很多人做方案时习惯把驱动器当成"黑盒功放",MCU 给脉冲它就转。这个理解没错,但不够用。真正的问题几乎都出在两边的交界处——什么时候该由硬件兜底,什么时候必须由固件介入。把这层边界划清楚,后面 80% 的坑都能提前避开。
1.1 驱动器侧的边界:功率、斩波与保护
TB67S531FTG 属于东芝 TB67S 系列的两相双极步进电机驱动 IC,采用 PWM 恒流斩波控制,内部集成完整的 H 桥功率级。它对外暴露的接口很"硬件化":一路时钟输入决定步进节奏,几路模式引脚决定细分档位和衰减方式,一路参考电压(VREF)决定线圈电流幅值。也就是说,MCU 只负责"走多快",驱动器自己负责"给多大电流"。
这个分工带来的好处是实时性:电流环由驱动器内部的比较器和斩波逻辑完成,响应速度在微秒级,MCU 完全不用管。如果换成 MCU 自己用 ADC 采样再软件调电流,中断延迟加上 ADC 转换时间,几十微秒就过去了,高速下根本追不上。所以选这颗芯片的核心价值,不是"它能驱动电机",而是"它把最吃实时性的那一环从 MCU 手里拿走了"。
同时它内部还带了过流保护、过热保护和欠压锁定。这几种保护在工业场景里不是可选项——电机堵转、线缆短路、电源掉电都会瞬间产生极端工况。这些保护触发后会通过故障引脚通知 MCU,固件必须能识别并安全停机,而不是继续傻发脉冲。
注意:TB67S 系列内部型号不少,电压电流等级、细分档位数、电流设定公式的系数在不同型号间会变。下面所有的计算我都会给出公式和方法,但落到你手上那颗具体的芯片时,务必对着最新数据手册核对一遍系数和引脚定义。
1.2 MCU 侧的边界:时序、规划与状态
STM32L073RZ 是 STM32L0 系列里的高配型号,Cortex-M0+ 内核,主频 32MHz,Flash 192KB、RAM 20KB,外设里带多个通用定时器、USART、SPI、I2C、ADC 和 DAC,还带段码 LCD 控制器。有人会问:驱动步进电机,为什么要用超低功耗的 L0 系列,而不是 F4 或者 G0?
答案在场景里。工业现场很多设备是"间歇工作"的——机械臂抓一次、等两秒、再抓一次;或者电池供电的巡检小车,一天动几次。L0 系列在停止模式下的功耗是微安级,唤醒时间也短,配合前面那颗驱动器的待机功能,整机静态功耗能做得很低。而步进电机控制对算力的需求其实很低:真正的负载是定时器中断,不是浮点运算。所以 L0 的性能完全够,省下来的功耗和成本才是真正的收益。
固件这边要负责的具体是这些事:产生精确稳定的步进脉冲、实现加减速曲线避免冲击、管理运行状态机、处理驱动器故障信号、必要时做位置闭环。其中脉冲的稳定性是第一要务——任何一次抖动都会被电机直接"翻译"成速度波动甚至失步。
1.3 一个常见误区:把驱动器的模式引脚当成"随便接"
我见过不止一次,有人把细分模式引脚直接拉到固定电平就完事,理由是"我就用整步,够了"。整步确实简单,但两相双极电机在整步驱动下,每走一步转子都要在两个稳定位置之间做一次大幅摆动,低速时顿挫感非常明显,噪声大。更重要的是,整步时的转矩波动最大,机械结构会受到周期性的冲击。
正确做法是把模式引脚接到 MCU 的 GPIO 上,虽然运行中一般不改,但上电时留出可配置的余地,调试阶段可以随时切换细分档位对比效果。另外,模式引脚的上电时序也有讲究——如果 VREF 还没建立、电源还没稳定,驱动器就进入了某个细分模式,可能会在初始化瞬间输出一个异常电流尖峰。稳妥的做法是:先让 MCU 把模式引脚拉到确定电平、拉低使能,等电源稳定几百毫秒后再拉高使能。
2. 两相双极步进电机的电流是怎么被"压住"的
要理解为什么会有失步、发热、噪声这些问题,绕不开一个核心:步进电机的转矩来自线圈电流,而线圈是感性负载,电流不能突变。整个控制系统的本质,就是在"想让电流快速建立"和"电感不让它快速建立"之间做权衡。
2.1 H 桥与线圈:为什么必须做恒流斩波
两相双极步进电机有四根线,每相一组线圈,由驱动器内部的 H 桥双向驱动。"双极"的意思就是电流能在同一相里正反两个方向流动。
现在想象一下:如果直接用 24V 电源接上线圈(假设相电阻 1.2Ω,相电感 3mH),稳态电流会达到 20A,线圈当场冒烟。所以必须限流。最土的办法是串一个功率电阻,但那样电阻上会白白烧掉大量功率,效率极低,而且电阻发热又会带来温漂。
TB67S531FTG 用的是开关式恒流斩波:H 桥的管子以几十 kHz 的频率开关,当线圈电流上升到设定值时关断,电流通过续流回路缓慢下降;降到某个下限附近再打开。这样电流就被"压"在一个窄带内波动,平均值等于我们设定的目标值。整个过程能量损耗主要在管子的导通电阻和开关损耗上,效率远高于串电阻。
这里有个关键认知:斩波频率越高,电流纹波越小,但开关损耗越大。驱动器内部已经选好了一个折中点,通常不用调。但如果你在低速时听到刺耳的啸叫,很可能就是这个斩波频率落在了可听范围内,属于正常的物理现象,不是故障。
2.2 采样电阻、VREF 与电流设定的完整计算
电流设定是这套方案里唯一一个必须精确计算的参数,算错了要么力矩不足,要么烧电机。
TB67S 系列一般通过一个外部采样电阻(R_RS)把线圈电流转换成电压,再和 VREF 比较。手册里通常给出类似这样的关系:
I_out = V_REF / (k × R_RS)其中 k 是芯片内部固定的比例系数(不同型号不同,常见量级在 3 到 5 之间)。
举一个完整的例子。假设你的电机额定相电流是 1.5A,我们先用 R_RS = 0.1Ω 来算:
I_out = V_REF / (5 × 0.1) = V_REF / 0.5 要让 I_out = 1.5A,则 V_REF = 1.5 × 0.5 = 0.75V0.75V 是个很舒服的参考电压,用 MCU 的 DAC 输出或者一个电阻分压都能做。接下来验证采样电阻的功耗:
P_RS = I² × R_RS = 1.5² × 0.1 = 0.225W接近 1/4W 的极限了,长期工作会很烫。两个方案:换用 0.05Ω 的采样电阻(此时 VREF 要相应降到 0.375V),或者用两颗 0.22Ω 并联。我更倾向后者,因为 0.05Ω 的阻值太小,采样电压只有几十毫伏,噪声和失调的影响会明显放大。
用 STM32L073RZ 的 DAC 输出 VREF 有个额外好处:你可以在运行中动态调整电流。低速重载时给满 1.5A,高速轻载时降到 1.0A,静止保持时降到 0.6A。这一招对降低整机发热非常有效,后面第 6 节还会展开。
2.3 衰减模式:慢衰减、快衰减与混合衰减的取舍
这是最容易被忽略、但对性能影响极大的一个设置。
斩波关断后,线圈电流不是立刻消失的,它会通过 H 桥的下管或者体二极管续流。根据续流路径不同,分为慢衰减(电流缓慢下降)、快衰减(电流快速下降)和混合衰减(先快后慢)。
为什么要在意这个?因为电流上升和下降的速度决定了电机能达到的最高转速。慢衰减时电流下降慢,在高速步进时线圈电流还没降下来,下一步的导通就已经开始,导致电流"积压",波形失真;快衰减虽然干净,但电流纹波大,低速时噪声和发热都会增加。
实践中的经验是:低速段用慢衰减或混合衰减,电流波形平滑、噪声小;高速段(大概超过 500 到 800 PPS 之后)切到快衰减或提高快衰减占比,能明显改善高速转矩。TB67S531FTG 一般提供衰减模式的引脚或寄存器配置,如果跑起来发现高速段力矩突然塌下去,第一件事就是去调这个。
2.4 细分档位不是越高越好
细分(microstepping)的原理是把一整个步距角再细分成若干小步,通过让两相电流按正弦/余弦规律变化,使合成磁场矢量平滑旋转。
细分带来的好处很直观:运行更平滑、低速共振更小、定位分辨率更高。但它的代价很多人没算清楚:
细分后,每一步的力矩是按正弦分布的,微步位置上的保持力矩会低于整步位置。理论上整步位置的保持力矩是额定值,而两个整步之间的中间位置,单步保持力矩可能只有额定的 70% 左右。如果你的负载有较大的静态扭矩,细分档位太高反而容易被"推回来"。
另外,细分越高,同样的转速需要的脉冲频率越高。1.8° 的电机,整步 200 步/圈,用 1/16 细分就是 3200 脉冲/圈。跑到 300 RPM 时:
脉冲频率 = 3200 × (300 / 60) = 3200 × 5 = 16000 Hz = 16kHz16kHz 对 MCU 来说毫无压力,但要注意脉冲输出的驱动能力和走线的信号完整性。我一般建议工业定位场景从 1/8 或 1/16 起步,超过 1/32 之后收益递减,反而增加 CPU 中断负担。
3. 硬件落地:从电源倒灌到散热焊盘的实操细节
原理清楚之后,真正决定成败的是硬件。步进驱动板的故障里,超过一半来自布局和外围电路,而不是芯片本身。这一节讲的全是我在实际板子上踩过的具体问题。
3.1 VM 电源与去耦:被低估的电容布局
电机驱动器最怕的不是电流不够,而是电压尖峰。电机是感性负载,每次斩波关断、每次减速制动,线圈里的能量都会往电源线上倒灌。
必备的是两颗电容:一颗大容量的电解电容做能量缓冲,一颗小容量的陶瓷电容做高频去耦。经验值是大电解按每安培输出电流配 100μF 左右(1.5A 电机配 220μF 到 470μF 比较稳妥),陶瓷电容用 100nF 加 1μF 组合,必须紧贴驱动器的 VM 引脚和 GND 引脚放置,走线长度控制在几毫米内。
我见过一个经典错误:陶瓷电容放在了板子另一头,离芯片 3 厘米。结果就是斩波时电源线上有几十伏的振铃,芯片的欠压保护频繁误触发。把电容挪到芯片旁边,问题当场消失。这不是玄学,是高频电流回路的面积问题——回路面积越小,寄生电感越小,振铃越弱。
3.2 采样电阻的开尔文接法与滤波
采样电阻上只有几十到一两百毫伏的电压,任何一点点寄生电阻都会污染测量结果。所以采样电阻必须用开尔文四线接法:大电流从电阻焊盘的两端走,采样信号从焊盘内侧的两个独立点引出,走差分对回到芯片的采样引脚。
如果做不到严格四线,至少保证采样走线从电阻焊盘的内边缘引出,不要从大电流路径上"分叉"。另外,这对差分线要并行走、等长、尽量靠近,中间不要被其他信号穿过。
滤波方面,芯片的采样输入一般内部已经有消隐时间(blanking time)来避开开关瞬间的尖峰,但外部再加一级 RC 会稳妥得多。取值上要注意时间常数不能太大,否则会吃掉电流环的响应速度。我一般用 100Ω 加 1nF,时间常数 100ns 量级,既能滤掉尖峰又不影响环路。
3.3 散热焊盘、过孔阵列与温升估算
TB67S531FTG 这类驱动器基本都是带裸露散热焊盘的 QFN 或类似封装,散热能力几乎完全取决于 PCB。
先说损耗来源。驱动器内部主要有三块:导通损耗、开关损耗、静态损耗。导通损耗占大头:
P_cond = I² × R_DS(on)_total假设高边加低边总的导通电阻是 0.3Ω(注意手册标的是 25°C 的值,结温升高后要乘 1.3 到 1.5 倍做裕量,这里按 0.45Ω 估):
单桥 P_cond = 1.5² × 0.45 = 1.01W 两相合计 ≈ 2.0W再看热阻。一个四层板、散热焊盘下面打 9 到 16 个 0.3mm 过孔、焊盘面积足够大的情况下,结到环境的热阻 θJA 大概能压到 35°C/W 左右:
温升 = 2.0W × 35°C/W = 70°C环境温度 40°C 时结温到 110°C,已经接近很多芯片的过热保护阈值了。所以过孔阵列和铜箔面积不是可选项:过孔要尽量多、尽量短,直接连到内层或底层的完整地平面;如果做不了多层板,就用双面大面积覆铜,正反面通过过孔缝合。
如果结温还是太高,最有效的办法不是加散热片(QFN 贴散热片效果有限),而是降低保持电流和动态调整电流,从源头减少损耗。
3.4 保护与反电动势:减速时电流往哪走
这里必须讲一个很多人忽略的物理过程。电机高速旋转时突然减速或者急停,转子带着机械惯性继续转,此时它变成一个发电机,把动能转换成电能往驱动器里灌。如果驱动器没有吸收路径,这股能量会把 VM 电压顶到很高,轻则触发过压保护,重则击穿管子。
两个应对手段:一是在 VM 和 GND 之间加 TVS 管做钳位,选型时钳位电压要低于驱动器的最大耐压并留足够裕量;二是靠前面那颗大电解电容吸收能量,所以电容容量别抠。另外,固件里要做减速规划,不要允许急停,从控制层面把能量冲击降下来,这比任何保护器件都有效。
还有一个细节:电机线如果比较长(超过 30cm),建议在驱动器输出侧加共模电感和对地小电容,抑制线缆辐射和反射。
4. STM32L073RZ 固件:脉冲发生、加减速曲线与状态机
硬件搭好之后,固件决定电机的"性格"。同样是转 10 圈,不同的加减速策略给人的感觉完全不一样,机械寿命也差很多。
4.1 定时器选型与脉冲输出的两种做法
STM32L073RZ 有多个通用定时器可以用。产生步进脉冲有两种主流做法。
第一种是用定时器的 PWM 输出模式。把 ARR 设成脉冲周期,CCR 设成周期的一半,输出就是占空比 50% 的方波,非常干净。改变速度就是改 ARR。缺点是每次改 ARR 都要注意预装载寄存器的更新时机,避免出现一个畸形的宽脉冲。
第二种是用输出比较翻转模式(toggle on compare)。每次比较匹配时引脚翻转一次,同时产生中断,在中断里重装载下一个周期值。这种方式对中断的实时性要求更高,但灵活性更强,可以方便地实现非均匀的脉冲间隔——这正是加减速曲线的需要。
我一般用第二种,因为加减速本质上就是让脉冲间隔不断变化,翻转模式配合预装载寄存器(ARR 的 preload 使能)最顺手。
/* 用 TIM2 的通道 1 产生步进脉冲,翻转模式 */ static void step_pulse_init(uint32_t arr) { /* 使能 TIM2 时钟(RCC 配置略) */ TIM2->PSC = 0; /* 计数时钟 32MHz,够用 */ TIM2->ARR = arr; /* 第一个脉冲周期 */ TIM2->CCR1 = arr; /* 比较值等于 ARR,匹配即翻转 */ TIM2->CCMR1 = (0x3U << 0); /* OC1M = toggle mode */ TIM2->CCER |= TIM_CCER_CC1E;/* 使能输出 */ TIM2->CR1 |= TIM_CR1_ARPE; /* 使能 ARR 预装载 */ TIM2->EGR |= TIM_EGR_UG; /* 立即更新影子寄存器 */ }中断服务程序里更新下一个周期:
void TIM2_IRQHandler(void) { if (TIM2->SR & TIM_SR_CC1IF) { TIM2->SR = ~TIM_SR_CC1IF; TIM2->ARR = ramp_next(&g_ramp); /* 取下一段的周期值 */ g_ramp.steps_done++; } }有一点必须注意:ARR 的预装载使能在切换周期时很关键。如果没开,写 ARR 会立刻生效,可能在当前计数已经超过新 ARR 的时候造成一次异常长的或短的周期,反映到电机上就是"咯噔"一下。
4.2 从定时器计数到转速:一份可直接套用的换算
这套参数换算我建议写死在代码里,别每次手算。
设电机步距角 1.8°,整步 200 步/圈;细分设为 m;目标转速 n(RPM)。则每秒需要的脉冲数:
f_step = 200 × m × n / 60定时器计数时钟为 32MHz,则 ARR 值:
ARR = 32_000_000 / f_step - 1反过来说,已知 ARR 求转速:
n = 32_000_000 × 60 / ((ARR + 1) × 200 × m)举个具体值:细分 16,目标 300 RPM:
f_step = 200 × 16 × 300 / 60 = 16000 Hz ARR = 32_000_000 / 16000 - 1 = 1999非常整,说明这个配置下定时器资源很宽裕。但如果细分提到 1/128,同样的转速需要 128kHz,ARR 只有 249,此时 32MHz 时钟的量化误差已经开始影响速度精度了。所以高细分高速场景要么提高定时器时钟,要么换用带更高主频的型号。这个边界值得提前算一遍。
4.3 加减速曲线的实现与表格化
步进电机不能瞬间从静止跳到目标速度,因为转子有惯性,频率跳变太大就会失步。必须走一条加速曲线。
最简单的做法是线性加速:每一步的间隔按固定增量递减。缺点是加速到目标速度时加速度是突变的,机械上会有冲击,容易激发共振。
稍微好一点的是梯形速度曲线:加速度恒定,段与段之间有过渡。再讲究一点是 S 曲线,加速度本身也是渐变的,启停最柔和。
工程上最实用的做法是预先算表。经典的步进加速表公式(来自长期被引用的步进控制应用笔记):
C_n = C_0 × (√(n+1) − √(n))其中 C_n 是第 n 步的定时器计数值,C_0 = √(2α/a),α 是每步对应的角度(弧度),a 是角加速度。
这个公式的好处是不用开循环做浮点运算,可以事先算好一张表放进数组,运行时查表。但要注意表的大小——加速段几百步就够,太长会浪费 Flash。
/* 预先算好的加速表,从静止到目标速度 */ static const uint16_t g_accel_table[ACCEL_STEPS] = { /* ... */ }; typedef enum { ST_IDLE = 0, ST_ACCEL, ST_RUN, ST_DECEL, ST_FAULT } step_state_t; typedef struct { uint32_t steps_left; /* 本次运动剩余步数 */ uint16_t idx; /* 当前加速表索引 */ step_state_t state; uint32_t target_arr; /* 目标速度对应的 ARR */ } ramp_t; static uint32_t ramp_next(ramp_t *r) { switch (r->state) { case ST_ACCEL: r->idx++; if (r->idx >= ACCEL_STEPS) { r->state = ST_RUN; return r->target_arr; } return g_accel_table[r->idx]; case ST_RUN: /* 提前判断剩余步数,进入减速段 */ if (r->steps_left <= ACCEL_STEPS) { r->state = ST_DECEL; r->idx = ACCEL_STEPS - r->steps_left; } return r->target_arr; case ST_DECEL: r->idx--; if (r->idx == 0) { r->state = ST_IDLE; /* 停止定时器 */ } return g_accel_table[r->idx]; default: return r->target_arr; } }这段代码的核心思路是:减速段直接用加速表倒着走。因为减速就是加速的逆过程,用同一张表既省 Flash 又保证对称性。但前提是每次运动的步数足够长,至少要走完一次完整的加速和减速。如果只走几十步,就得用一张压缩过的短表,或者干脆限制最高速度。
实践心得:加减速的步数规划最好在运动开始前就算好。我见过有人在运行时才发现剩余步数不够减速,只能硬停,结果就是丢步。这个必须在状态机里提前判断,留足减速距离。
4.4 状态机与故障处理
步进控制看起来很线性,其实状态不少:待机、使能、加速、匀速、减速、保持、故障。用状态机组织是最清晰的。
故障处理这块几个要点。驱动器的故障引脚一般是有源低电平的开漏输出,需要外部上拉,接到 MCU 的外部中断引脚。故障触发时要立即停止脉冲输出、拉低使能,然后根据故障类型决定能否自动恢复。过流和短路必须人工排查后复位,欠压和过热可以考虑延时自动重试。
还有一个细节:上电初始化的顺序。正确顺序是先配置好 GPIO 状态(使能拉低、模式引脚拉到确定值),再初始化定时器(先不启动),再等待电源稳定,最后拉高使能、启动定时器。反过来做,很可能在初始化过程中就发出一串不受控的脉冲,机械结构直接撞限位。
5. 失步、发热、噪声:一套可复现的排查链路
这一节是我最想写的部分,因为实际工作中遇到问题的概率远大于从零设计。下面这套排查顺序,是我踩过足够多坑之后总结出来的,按这个顺序走基本能定位到根因。
5.1 先分清是"脉冲没发出去"还是"发了但电机没跟上"
失步的现象都一样——位置对不上,但原因完全不同。第一件事是分叉判断。
拿示波器(或者逻辑分析仪)直接夹在驱动器的脉冲输入引脚上,看波形。如果脉冲数量是对的,那问题在驱动器或电机侧;如果脉冲本身就是乱的、少的、有毛刺的,那问题在 MCU 侧。
MCU 侧最常见的原因是中断被抢占。STM32L073RZ 主频 32MHz,如果定时器中断里做了耗时操作(比如浮点运算、串口打印),下一次中断就会延迟,脉冲间隔就抖动了。我的做法是:定时器中断里只做最少的整数运算和寄存器写入,其他事情全部丢给主循环或者用 DMA 搬运。用volatile变量在主循环和中断之间传递状态,而不是在中断里做逻辑判断。
还有一类是电平问题。如果驱动器输入是光耦隔离的,需要一定的驱动电流,MCU 的 GPIO 直驱可能不够,波形上升沿会变缓。这时候要加一级三极管或者专用驱动。
5.2 用示波器和 ADC 把问题定位到具体环节
确认脉冲没问题之后,下一步是看电流波形。最直接的办法是在采样电阻两端(注意用差分探头或者隔离)看电压波形,它直接反映线圈电流。
正常的高速波形应该是接近正弦的、幅值稳定的曲线。如果看到波形顶部被削平或者幅值随速度升高明显下降,那就是电流环没跟上,多半是衰减模式设置不对,或者是 VM 电压不够——高速时反电动势加上电感压降,需要的电源电压比低速时高得多。
关于电源电压的选择,有个粗略的经验公式:为了让电流在一步时间内建立起来,电源电压至少要满足
V_M > I × R + L × dI/dt其中 dI/dt 由步进频率和电流变化幅度决定。举个数值:电机相电阻 1.2Ω、相电感 3mH,工作电流 1.5A,在 16kHz 的脉冲频率下,一步时间内电流要变化 1.5A:
V_M > 1.5 × 1.2 + 0.003 × 1.5 / (1/16000) = 1.8 + 72 = 73.8V这个估算过于保守(实际电流不是每步都从零变到满),但它说明了一个重要事实:高速下需要的电源电压远高于低速。很多人的 24V 方案在 300 RPM 就上不去了,原因就在这里。24V 大概能舒服地跑到 200 到 400 RPM(取决于电机电感),再高就得考虑 36V 或 48V 供电——前提是驱动器耐压允许。
5.3 三个高频坑:地线、模式引脚上电时序、保持电流
这三个坑我几乎每次调试新板子都会遇到至少一个。
第一个是地线。功率地和信号地如果处理不当,大电流在地线上产生的压降会串进采样回路,导致电流设定完全不准。正确做法是在驱动器芯片的 GND 引脚附近单点汇合,让大电流回路的电流不流过采样信号的参考路径。如果实在分不开,至少保证采样电阻的接地端直接回到芯片的 GND 引脚,不要经过任何其他负载。
第二个是模式引脚的上电时序。前面提过一次,这里补充一个更隐蔽的情况:如果模式引脚通过电阻上拉到 VDD,而 VDD 和 VM 的上电速度不一样(比如 VM 是大电容需要慢慢充),就可能出现芯片已经上电但模式引脚电平还没建立的情况,此时驱动器可能进入一个未定义的模式,输出异常电流。解决办法是模式引脚由 MCU 主动驱动,MCU 由上电复位电路保证在电源稳定前保持输出低电平。
第三个是保持电流。电机停在某个位置时,如果保持电流设成满值,线圈会持续发热,几分钟就能到烫手的程度,长期下来绝缘老化、电阻漂移,最终导致失步。正确做法是电机停止后延时一段时间(比如 200ms),把 VREF 降到额定的 50% 到 70%,用一个 DMA 或者定时器更新 DAC 输出就行,代码量很小,效果很明显。
6. 放进机器人和工业设备里:闭环、多轴与长期可靠性
单轴调试通过只是及格,真正上设备还有几个层面的考量。
6.1 开环不够用的时候:编码器闭环怎么加
步进电机开环控制的优点是简单、成本低、静止时不需要反馈也能保持位置。但它有个无法回避的缺点:一旦失步,系统自己不知道。工业设备里这很危险,机械臂抓偏一点可能就撞到工装。
解决方案有两个层次。低成本方案是用驱动器的电流反馈做堵转检测:STM32L073RZ 的 ADC 可以采样采样电阻上的电压,正常运行时电流波形是规律的,如果电机被卡住,电流波形会明显异常。但这个方案受斩波纹波干扰大,需要同步采样或者做较重的滤波,实际效果一般。
更可靠的方案是加装编码器做半闭环。用增量式编码器接在电机轴上,每次运动完成后比对目标步数和实际脉冲数,偏差超过阈值就报警或者自动补偿。这样既能发现失步,又能在一定范围内纠正。STM32L073RZ 的定时器支持编码器模式,硬件解码,几乎不占 CPU。
值得注意的是,闭环不一定要做成完整的 PID 位置环。对步进电机来说,**"位置校验 + 重试"**这种粗粒度闭环往往性价比最高:平时照常开环走,走完对一下数,不对就退回原点重新定位。实现简单,鲁棒性也好。
6.2 保持电流与发热的平衡
工业设备往往要求长时间连续工作,热设计就成了硬约束。我一般按这个策略分档:
| 工况 | 电流设定 | 目的 |
|---|---|---|
| 加速/重载运行 | 100% 额定 | 保证不失步 |
| 匀速轻载 | 70% ~ 80% | 降耗、降噪 |
| 停止保持(短时) | 50% ~ 70% | 维持位置同时降温 |
| 停止保持(长时) | 20% ~ 30% 或断电 | 靠机械自锁或抱闸维持 |
这里有个判断依据:如果机械结构本身有自锁特性(比如丝杆、蜗轮蜗杆),长时间停止时可以直接把电流降到零甚至关断使能,位置不会丢。只有直驱或者皮带传动这类没有自锁的场合,才需要保持电流。这一点在设计初期就要和机械方案一起确认,能省掉不少散热设计。
6.3 多轴系统的实时性安排
一个三轴或四轴系统,每轴一个定时器独立跑脉冲,看起来简单,实际上有几个资源冲突点。
第一是中断优先级。每个轴的定时器中断都在高频触发(16kHz 以上),如果优先级配得一样,会出现中断嵌套和延迟抖动。正确做法是只给最高优先级,其他轴用硬件 PWM 或者 DMA 方式产生脉冲,尽量减少中断数量。STM32L073RZ 的定时器数量有限,如果轴数多,就要考虑用外部脉冲发生芯片或者换更多定时器的型号。
第二是运动规划的同步。多轴联动时,各轴的速度曲线要协调,比如直线插补要求各轴同时到达终点。这就需要一个统一的时间基准,把所有轴的运动参数在同一个节拍里更新。我一般用一个低速的系统定时器(比如 1kHz)作为规划节拍,在这个节拍里计算各轴下一个时间段的速度,然后更新各自的定时器 ARR。规划频率低、脉冲发生频率高,这样分层就避免了高频中断里的复杂计算。
第三是电源分配。多个电机同时加速时,瞬时电流可能是额定值的两三倍。电源和前面的大电容都要按"所有轴同时加速"这个最坏情况来设计,否则会出现电压跌落导致某个轴失步。
我在实际项目里最深刻的体会是:步进系统的稳定性,八成取决于机械和电源,两成才是控制算法。调不出来的时候先别急着改代码,去看看电源纹波、机械装配的同轴度、联轴器的间隙,往往问题就在那里。TB67S531FTG 加 STM32L073RZ 这套组合本身的性能是够用的,真正决定成败的是你有没有把每一个细节都想到——采样电阻的功耗算过没有,散热焊盘下面打了几个过孔,加速表在剩余步数不足时会不会出错,这些看起来琐碎的地方,才是把电机从"能转"做到"可靠"的分界线。