1. 选型这件事:为什么我不选 DRV8825,而用 DRV8818 + STM32F412RE
1.1 DRV8818PWPR 到底解决什么问题
先交代一下背景。我这两年一直在做小型工业机械臂和自动化设备的关节运动控制,核心动作就是控制双极步进电机。早期图省事,直接买现成的步进驱动模块,A4988、DRV8825、TMC2209 都上过。这些模块写个 STEP/DIR 就能转,但等你真的把电机装到机器上,开始调低速平稳性、带负载能力、长时间温升、故障恢复这些指标时,就会发现现成模块能改的东西太少。
DRV8818PWPR 这颗料是我在对比了几轮之后固定下来的主力方案。它是一颗带电流斩波的双 H 桥步进电机驱动器,供电范围 8.2V 到 45V,单 H 桥连续电流 1.5A、峰值 2.5A,PWP 后缀代表 HTSSOP-16 封装,带 PowerPAD 散热焊盘。这个电压和电流范围覆盖了绝大多数中小型工业设备的实际需求:24V 系统下带 57 系列步进电机(2 相、额定 1.5A 左右)非常合适,36V 系统也能跑,峰值 2.5A 给了短时堵转和加速阶段足够的余量。
最关键的一点是:DRV8818 内部没有微步进索引器。DRV8825、TMC2209 这类芯片内部有查表逻辑,MCU 只需要发固定数量的 STEP 脉冲,芯片自己会把电流按正弦波形切出来。DRV8818 不是这样,它只负责"按你给的时序切换 H 桥方向 + 用内部斩波器限制电流",至于电流波形长什么样、每个微步应该落到哪一档,全要 MCU 自己算好之后通过 VREF 引脚喂给它。
很多人一听"没有索引器"就觉得这颗料麻烦,但我恰恰是冲着这点选的。没有索引器意味着电流波形完全由我控制,16 细分、32 细分、任意非标准细分、甚至低速时的三角波电流剖面,都做得出来。这对机器人关节的意义很大:关节在不同姿态下负载不一样,需要在线调整电流来兼顾力矩和发热;某些场合要求电机的振动噪声达到极低水平,这靠芯片固化的细分数表是调不出来的。
1.2 与集成索引器芯片的方案对比
为了说清楚为什么选 DRV8818,我把当时纠结过的几个方案放在一起做过对比,这张表基本反映了它们在实际使用中的差别:
| 项目 | DRV8825 | A4988 | TMC2209 | DRV8818 |
|---|---|---|---|---|
| 内部微步索引器 | 有,固定 1/32 细分 | 有,固定 1/16 细分 | 有,固定 1/256 细分 | 无,MCU 自定义波形 |
| 供电电压 | 8.2V~45V | 8V~35V | 4.75V~29V | 8.2V~45V |
| 连续/峰值电流 | 1.5A / 2.5A | 1A / 2A | 1.4A / 2A | 1.5A / 2.5A |
| 电流波形可编程性 | 低 | 低 | 中(有 StealthChop) | 高 |
| 接口 | STEP/DIR | STEP/DIR | STEP/DIR + UART | STEP/DIR 或 PHASE/EN |
| 封装 | HTSSOP-28/QFN | QFN-8 | QFN-28 | HTSSOP-16(PWPR) |
DRV8825 的优势是简单,MCU 给它一个 STEP 脉冲它就前进一步,内部自动把两相电流切成微步正弦波形,适合快速出活。缺点也很明确:细分数被锁死在 1/32,电流剖面是固定的,想调波形只能通过外部衰减模式或者改电机,可玩空间小。TMC2209 的 StealthChop 确实安静,但它的最大供电电压只有 29V,做 24V 系统勉强够,做 36V 就危险了,而且芯片内部算法对电机电感和电压比较敏感,调不好反而会出共振。
DRV8818 的定位恰恰相反。它把"怎么切电流"这个决策权完全交给了 MCU。你可以理解为:DRV8825 是自动挡,DRV8818 是手动挡。自动挡省心,但手动挡在特殊工况下的细腻程度是自动挡没办法比的。而且 PWPR 封装只有 16 脚,布板面积小,对于我这种需要把驱动电路集成到机械臂关节板上的场景非常友好。
1.3 为什么 MCU 非得是 STM32F412RE
有人会问:既然驱动芯片已经这么讲究了,MCU 用个 STM32F103 不够吗?还真不够。我在开发过程中把主控从 F103 换成了 STM32F412RE,原因很具体。
F412RE 是 Cortex-M4F 内核,100MHz 主频,带硬件浮点单元,512KB Flash,128KB SRAM。对步进电机控制来说,硬件 FPU 的直接价值就是我可以放心地在运动控制中断里做加减速曲线运算,不用担心浮点运算吃掉太多周期。F103 是 M3 内核,没有 FPU,做 S 曲线时只能靠定点近似,精度和开发效率都会打折。
更重要的是 F412 有两个 12 位 DAC 通道。DRV8818 实现微步进需要给 VREF 引脚送一个随微步位置变化的正弦阶梯电压,最省事、最干净的方式就是直接用 DAC 输出。F103 系列绝大多数型号没有 DAC,只能退而用 PWM + RC 滤波方案,性能和纹波表现都有差距。F412 的 DAC 刚好解决了这个痛点,一个通道控制 A 相 VREF,另一个通道控制 B 相 VREF,做单轴驱动几乎是为这个场景量身定做的。
还有定时器资源。F412 的高级定时器 TIM1/TIM8 可以输出带死区控制的 PWM,通用定时器 TIM2/TIM5 是 32 位计数器,做步数计数和速度周期换算非常顺手。机器人项目中往往还要跑 CAN 总线、RS485、编码器接口,F412 这些外设齐全,一颗芯片搞定整个关节控制板,不需要再外挂其他芯片。
2. 硬件设计:45V/2A 级别的功率级要扎扎实实
2.1 电源架构:VM、逻辑电源和地线怎么处理
DRV8818 的供电分为两部分:VM 是电机电源,负责给 H 桥和电机提供能量;逻辑电源负责驱动芯片内部的控制逻辑。工业场景下最常用的电机电源是 24V,我建议从开关电源出来之后先经过一级 π 型滤波再接 VM 引脚。
具体做法:VM 引脚旁边放一个 100μF 电解电容加一个 100nF 陶瓷电容,电解电容选低 ESR 的固态电容,陶瓷电容要紧贴芯片引脚,用来吸收高频开关噪声。为什么要求这么高?因为步进电机在换相瞬间电流变化率非常大,如果 VM 引脚上的电源阻抗太高,电流冲击会直接把电压拉下去。我之前在实验板上偷懒,只在电源入口放了一个 10μF 电容,一跑 1A 以上的电流就发现芯片过流保护误触发,示波器一量 VM 在换相瞬间跌了将近 3V,后面换成 100μF + 100nF 的组合才稳定下来。
逻辑电源和电机电源必须分开。我是用 24V 转 5V 再转 3.3V 给 STM32F412RE 和芯片逻辑供电,3.3V 电源域和 VM 电源域之间通过 0Ω 电阻单点连接。这个做法的目的是避免电机大电流在 PCB 地线上造成的电压差跑进 MCU 的地参考。机器人线缆长、干扰大,共地处理不好会出各种诡异问题,后面第五节我会详细讲一个真实案例。
VREF、采样电阻和芯片 GND 的走线要用开尔文接法。也就是说,电流采样电阻的两端要分别走两根线:一根走大电流主干,另一根单独接到芯片的采样输入引脚,不能让采样线上的电压降混进主电流路径。这个问题很多工程师第一次画板时不注意,结果电流门槛不准,偏差能到 20% 以上。
2.2 PWPR 封装的散热焊盘:决定芯片能否长时间输出
这是 PWPR 后缀最容易被忽略的地方。DRV8818 表面是 HTSSOP-16 封装,但底部有一块裸露的散热焊盘(PowerPAD),这个焊盘从电气上看是接地,从热学上看是芯片唯一的有效散热路径。
我测过这个差异:第一版板子没有给散热焊盘做正规处理,只是随便在 PCB 上开了一个窗口焊上芯片,下面没有过孔、没有铺铜。结果电机电流 0.8A 跑半小时后,芯片表面温度摸上去烫手,用热电偶实测约 90°C,长时间运行总担心热保护跳掉。第二版我把散热焊盘用锡膏充分焊接后,焊盘下方打了一排过孔,过孔连接到内层和底层的整块铜皮,同样条件下表面温度降到约 55°C。
具体做法:PCB 上对应 PowerPAD 的位置画一块连续的铜皮,铜皮大小尽量延伸到芯片四周的铺铜区域,然后均匀打 9 到 16 个 0.3mm 过孔,过孔不要用绿油盖住,要让锡膏能流进去形成导热通道。芯片焊接时一定要保证焊盘和 PCB 铜皮之间没有空洞,最好的办法是钢网开孔和回流焊,手工焊接的话要仔细检查底部是否完全贴合。
散热计算也要心里有数。DRV8818 的功率损耗主要来自 MOSFET 导通损耗,RDS(on) 在 0.5Ω 量级。单桥持续 1A 电流时,功率大约是 1² × 0.5 = 0.5W,两个桥同时工作就接近 1W。这个热量对 Pin 脚本身来说很小,但对封装来说如果全部靠空气对流散掉,热阻大约在 30°C/W 到 40°C/W,意味着芯片温度比环境高 30°C 到 40°C。工业环境如果有密闭机箱,环境温度本身就有 50°C,芯片温度很容易逼近 125°C 的极限。所以散热焊盘不是可选项,是必须项。
2.3 电流采样电阻与 VREF 设定的实际计算
DRV8818 的电流斩波原理是:芯片内部有一个比较器,把采样电阻上的电压和 VREF 引脚电压做比较,超过阈值就关断当前桥臂,让电流衰减。这样 VREF 电压就决定了电机的峰值电流。工程上这个关系可以写成:
ITRIP = VREF / (K × RSENSE)
其中 K 是芯片内部电流检测放大器的增益系数,具体数值在你手上那颗料的数据手册里查。不同批次、不同厂家的版本可能略有差异,不要拿网上随随便便的公式直接套。
举个实际例子。我常用的采样电阻是 0.1Ω,封装 2512,功率 1W,精度 1%。电机额定电流 1.5A,我想让峰值电流限制在 1.2A 留出安全裕量。假设手册给出的 K 值为 5,那 VREF 就是 1.2 × 5 × 0.1 = 0.6V。F412 的 DAC 满量程是 3.3V,0.6V 只用了不到 20% 的 DAC 范围,分辨率上完全没有问题。如果你需要的电流比较大,可以把 VREF 调高,但要确认不能超过数据手册规定的上限。
采样电阻的功率也不能忽略。持续 1.5A 电流流过 0.1Ω 电阻,产热是 1.5² × 0.1 = 0.225W,考虑到微步进时电流不是恒定的,峰值功率会更高。2512 封装加适当铺铜可以扛住,如果选 0805 封装,长时间运行就会烫得离谱,阻值漂移直接导致电流门槛不准。
2.4 保护与吸收:急停、泵升和输出振铃
步进电机的急停和堵转会带来一个工业场景特有的问题:反电动势泵升。电机在高速旋转时突然被切断电源,电机本身的惯性会继续推动转子旋转,把动能转换成电能回灌到 VM 母线,导致 VM 电压瞬间升高。如果电源系统没有吸收能力,电压可能超过 45V 的绝对最大值,直接击穿芯片。
我在这方面的做法是:VM 引脚上除了电解电容,再并联一片 TVS 瞬态抑制二极管,击穿电压选在 45V 左右、或比最高工作电压高 20% 的位置。这样即使急停,多余的泵升能量会被 TVS 泄放掉,芯片不会看到超过耐压的电压。实验中发现,24V 系统、1.5A 电流下急停,VM 电压实测能冲到 32V,不加 TVS 的话离 45V 极限已经不远,如果系统用的是 36V 电源,那就非常危险。
输出端 OUT1±、OUT2± 到电机之间有长线时,建议并联一个小电容加电阻的 RC 吸收网络,通常取 10Ω + 1nF 或者 22Ω + 470pF。这个网络的目的是吸收 PWM 斩波在线上产生的高频振铃,减小辐射 EMI。电容取大了会影响电流控制波形,取小了没效果,可以从 470pF 起步实测。
ENBL 引脚也别裸奔。上电复位瞬间 MCU 的引脚处于高阻态,如果 ENBL 悬空且逻辑上是高电平使能,电机会在 MCU 初始化之前就开始有电流,这在工业设备上非常危险。我给 ENBL 加了 10kΩ 下拉电阻,并让 MCU 在完成初始化后才拉高,保证"上电后电机默认锁定,程序确认后才释放"。
3. 微步进波形生成:芯片不管细分,MCU 就得全包
3.1 整步、半步和微步进的关系
双极步进电机的本质是两相绕组,交替改变两相电流的方向,转子就会一步一步转动。1.8° 步距角的电机,200 个整步转一圈。整步工作的问题是共振:转子每走一步都会在惯性作用下过冲,然后在平衡位置附近振荡,如果输入的步进频率恰好和电机的机械共振频率接近,电机会剧烈抖动甚至丢步。半步进和微步进的核心思想是让电流不是简单地两个方向开关切换,而是按照近似正弦的方式在 A、B 两相之间连续过渡,转子每一步只走整步的一部分,运动自然平滑得多。
DRV8818 没有索引器,它内部的 H 桥仍然只是按开关表切换方向。你给一个 STEP 脉冲,它就执行一次换相;给得越多,电机走得越快。要让电流正弦化,唯一的办法是同时调整 VREF 引脚上的电压。经典实现是:MCU 把每一微步对应的正弦电流比例算好,塞进一张查找表,每来一个 STEP 脉冲,就更新一次 VREF,然后再给 STEP 脉冲。VREF 电压决定当前相的目标电流,STEP 脉冲决定当前换相状态,两者合在一起,电机的相电流才会形成平滑的正弦波形。
这里有个容易混淆的点。DRV8818 的 STEP/DIR 模式本质上是把 4 个换相状态做成内部状态机,每个 STEP 脉冲推进一个状态。配合 VREF 正弦变化,每一个微步实际上等于"换相状态不变或切一个状态 + 电流目标按正弦升降一档"。如果你把 STEP 给得非常快、VREF 却不更新,那就退化成了整步或者半步工作;如果 VREF 更新了但没有对应的 STEP 脉冲推进,电流变化也不会作用在转子上。两者必须同步。
3.2 方案 A:DAC 直接驱动 VREF
最干净的方案就是用 F412RE 的 DAC 直接输出 VREF 电压。12 位 DAC 的分辨率是 4096 级,把它映射到一个周期的正弦波上,做 16 细分时每个微步有 256 个电压等级,远远够用。
我把整个实现拆成三个部分:
第一,准备正弦查找表。不需要存整个 360° 的波形,只需要存 0° 到 90°的四分之一正弦,然后利用对称性生成其余象限。这样即使细分做到 64,表的大小也很小,完全放在 Flash 里。每个微步的相位值是一个 16 位数,高两位决定象限,低 14 位反正切插值。
第二,把相位值换算成 DAC 值。正弦值乘以当前设定的峰值电流对应的 DAC 满兹值,再加上中点偏置,得到一个 12 位的代码直接写入 DAC 寄存器。注意 VREF 不需要覆盖整个 0 到 3.3V,因为峰值电流一般只用到 1.5A 左右,对应的 VREF 可能只有零点几伏,所以正弦表的范围要做归一化,把 DAC 的全程利用起来,保证低电流时也有足够的分辨率。具体做法是在软件里做标定:先把 DAC 输出从 0 扫到 0.8V,用万用表实测电机电流,得到一条 DAC 值到电流的校准曲线,然后固件里用查表插值反算。
第三,触发节奏。我的做法是让 TIM1 或 TIM6 产生步进时钟中断,在中断里先更新 DAC,再翻转/输出 STEP 脉冲信号。顺序很重要:先更新 VREF,再送 STEP,这样换相瞬间电流目标已经是新的,不会在换相时突然跳变。如果用先 STEP 再 VREF 的顺序,一个微步周期刚开始时电流还是上一档的旧值,波形会产生明显的台阶感。
实际测试中,DAC 方案的表现相当好。16 细分、转速 60rpm 时,用电流探头看 A 相电流波形,是干净的正弦波,几乎没有可见的阶梯。低速不抖动,声音也小很多。缺点是 DAC 通道只有两个,F412RE 正好够单轴用;如果要做双轴,就需要 PWM 方案了。
3.3 方案 B:PWM + RC 滤波,多轴时的低成本选择
F412RE 只有两个 DAC 输出通道,多轴驱动时不够用。并且 DAC 方案的主要问题是它占用了模拟通道,如果需要用 ADC 采样电机电流做闭环,通道就不够分配了。这种情况下可以用高级定时器的 PWM 输出加二阶 RC 低通滤波,把 PWM 波形平滑成和 DAC 等效的直流电压,再送到 VREF。
我的具体做法:把定时器的 PWM 频率设在 50kHz,占空比最大 100%,经一阶 RC 截止频率约 1kHz 的低通滤波后,纹波已经衰减到可以接受的水平。实际用了两级 RC:第一级截止频率 2kHz,第二级 500Hz,得到 3.3V 以内的可调电压。PWM 分辨率用 12 位,即 100MHz 定时器时钟、50kHz 频率、对应计数周期 2000,和 DAC 的 4096 级相差不大。
用 PWM 方案时最需要注意的问题是纹波。VREF 上的纹波会直接调制到电流斩波比较器上,表现为电机电流产生高频抖动,听感上就是一种毛刺声。解决的办法是把滤波做重一点,但滤波太重会导致 VREF 的响应变慢,微步切换时电压跟不上,波形会失真。我的经验是 PWM 频率尽量高于 50kHz,RC 时间常数取在 0.5ms 到 1ms,这刚好能满足 2000 步/秒的微步更新率。
多轴的资源分配可以这样规划:第一轴用 DAC 输出,保证关键关节波形质量;第二轴、第三轴用 PWM 通道输出。F412RE 的高级定时器输出通道多,完全够用。
3.4 波表、方向处理和更新时序
不管用 DAC 还是 PWM,波表和方向处理都是共通的。我这里给一个简化的伪代码框架,大家可以照着移植:
#define MICROSTEPS_PER_STEP 16 #define TABLE_SIZE 64 // 一整个正弦周期的微步细分数 uint16_t phase_accumulator = 0; const uint16_t cos_table[TABLE_SIZE] = { ... }; // 余弦波表,A相 const uint16_t sin_table[TABLE_SIZE] = { ... }; // 正弦波表,B相 void StepTimerISR(void) { // 1. 先根据当前位置更新 VREF DAC_SetValue(0, cos_table[phase_accumulator]); DAC_SetValue(1, sin_table[phase_accumulator]); // 2. 再输出 STEP 脉冲(实际由定时器硬件自动触发,这里只是示例) STEP_PIN = 1; delay_us(3); STEP_PIN = 0; // 3. 推进相位 if (direction == FORWARD) { phase_accumulator = (phase_accumulator + 1) % TABLE_SIZE; } else { phase_accumulator = (phase_accumulator + TABLE_SIZE - 1) % TABLE_SIZE; } }方向处理有两种方式。一种是用 DRV8818 的 DIR 引脚,MCU 只改 DIR 电平,电机内部换相方向自动反转;另一种是 MCU 不改 DIR,而是反向扫描波表。第二种方式在这个方案里更可取,因为 VREF 波形和 DIR 引脚如果不同步,会在换向瞬间出现电流方向冲突。我用的是"波表反向扫描 + DIR 引脚按需切换",保证在任何时刻波表方向和实际换相状态一致。
更新时序上,STEP 脉冲和 VREF 更新的间隔要固定。我建议 STEP 高电平宽度至少 2μs,VREF 更新必须提前 STEP 至少 5μs 完成,这样斩波比较器有足够时间响应新的电压。这个时间参数是我在示波器上一步步测出来的,太小了波形有毛刺,太大了会拖慢最大微步频率。
4. 加减速与位置平滑:从"能转"到"转得好看"
4.1 为什么直接发匀速脉冲一定会出事
很多刚接触步进电机的人有一个误区:只要频率对得上,电机就能转。实际上,如果你直接以 10000 PPS(脉冲每秒)的频率启动电机,它几乎必丢步。原因是步进电机的力矩-速度特性是一个下降的曲线:转速越高,输出力矩越小。而启动瞬间电机处于静止状态,必须克服静摩擦和转子的惯性才能进入同步状态,这个启动瞬间需要的力矩往往比匀速运行时大得多。
匀速运行在某个速度下没问题,不代表能从静止直接跳到这个速度。所以必须做加减速:启动时频率低、力矩大,随着转速上升逐步提高频率、让电机在力矩曲线允许的范围内跟随目标速度。没有加减速的后果不只是丢步,还有机械冲击。机器人关节减速器如果每次都受到脉冲性的冲击扭矩,齿轮寿命会明显缩短,这是工业设备不能接受的。
4.2 梯形加减速的最小可用实现
最简单也最可靠的加减速曲线是梯形:加速段以恒定加速度 a 升高频率,达到目标速度 vmax 后匀速,最后以同样的负加速度减速到零。这个曲线的优点是参数少、计算直观、容易在 MCU 中实现,对于大多数定位应用已经足够。
核心公式只有两个。一个是速度、加速度和步数的关系:加速段走过的步数 Sa = vmax² / (2 × a)。另一个是频率和周期的转换:周期 T = 1 / v,或者说定时器装载值 = 定时器时钟频率 / v。
实现时逐毫秒更新速度。比如定时器每 1ms 产生一个时基中断,在中断里:
if (state == ACCEL) { current_speed += accel_per_tick; if (current_speed >= vmax) { current_speed = vmax; state = RUN; } } else if (state == DECEL) { current_speed -= decel_per_tick; if (current_speed <= 0) { current_speed = 0; state = STOP; } } // 把 speed 换算成周期,装载进步进定时器 period = TIMER_CLOCK / current_speed;这里有一个很隐蔽的坑:如果每毫秒只改一次定时器周期,那么在这 1ms 内电机频率是恒定的,从宏观上看是梯形加减速,但微观上每个 1ms 段的起点和终点速度是跳变的,这种跳变在某些负载下依然会引起微小的冲击和丢步。工程上把加速段分成 100 到 200 个速度档,每一档之间的速度变化控制在 5% 以内,实测下来冲击可以忽略。千万不要用 50 档以下的粗粒度加速,除非负载特别轻。
梯形加减速的另一个注意点是减速点的计算。想准确停在目标位置,必须在正确的位置开始减速。简单的做法是:计算总共需要的步数 N,减速步数 Sd 和加速步数 Sa 相等(在不考虑静摩擦差异的理想情况下),那么当剩余步数小于等于 Sd 时就开始减速。我在代码里用一个剩余步数计数器,每走一步减一,当剩余步数等于 Sd 时切换状态到减速。
4.3 S 曲线在 F412 上的落地方式
梯形曲线的短板是加加速度(jerk)不连续。加速度从 0 突然跳到 a 再跳回 0,会导致关节末端的振动,尤其在机器人长悬臂结构上,这种振动的余振非常明显。S 曲线通过让加速度本身连续变化来消除这个问题:加速度先增后减,速度曲线呈 S 形,位置轨迹更加平滑。
S 曲线的完整实现要用到加加速度参数 j:加速度从 0 增加到 a_max 的时间由 j 决定,然后再从 a_max 减小到 0,加速段实际上由两段抛物线对接而成。每次步进中断里都要做实时数值积分,计算量比较大。
在 F412RE 上,我利用 FPU 做了简化版 S 曲线。思路是预先离线计算一张"速度档位表",把从静止加速到 vmax 的过程中所有需要输出的频率档位一一列出来,大约 200 到 500 个档位,每个档位对应速度和步数。运行时 MCU 不需要做浮点积分,只需要查表加一个 32 位计数器。这样 S 曲线的计算量在中断里只占几十个周期,100MHz 主频完全吃得下。
具体实现时,速度档位表的生成放在上位机或启动时一次性计算。公式是:第 n 档的时间点 t_n,对应的加速度 a(t_n) 由 S 曲线方程给出,然后速度 v(t_n) = ∫ a dt,步数累计 S(t_n) = ∫ v dt。表中的每一项记录三个值:步数累计值、当前速度、下一步速度。运行时每走一步就检查累计步数是否到达当前档位的终点,到了就切换频率到下一步速度。这个查表法有个额外的好处:即使中途收到新的目标位置,也可以直接在表中切换加减速状态,不会出现计算跟不上中断的卡顿。
4.4 与编码器闭环的衔接思路
DRV8818 加 F412 这套方案,最自然的扩展就是加编码器做位置闭环。虽然驱动器的电流环已经被芯片内部斩波器处理掉了,但位置环和速度环还是在 MCU 里软件实现的。
我的做法是:编码器用定时器编码器接口(比如 TIM3 或 TIM4 的编码器模式)直接读取,位置环 1kHz 更新。每个控制周期里,把目标位置和实际位置做差得到位置误差,经过一个简单的 PID 控制器计算目标速度,然后把目标速度通过上面提到的 S 曲线速度档位表折算成当前的微步频率,再通过定时器输出 STEP 脉冲。PID 的输出不要直接驱动频率,而是先经过一个限幅器限制速度变化率,防止控制器启动瞬间给出过大的加速度请求,导致电机再次丢步。
没有编码器时的堵转检测也可以做。电机的反电动势在堵转时会消失,导致相电流突然上升。虽然斩波器会限制电流不超过 ITRIP,但在接近 ITRIP 的状态下运行会持续发热。一个实用的检测手段是:通过 ADC 采样 VM 母线电流或者直接采样采样电阻上的平均电压,当发现连续若干毫秒电流值都超过正常运转的阈值,就可以判断发生了堵转,然后让 MCU 控制 ENBL 拉低,停止输出,避免电机长时间过热。这个方法不需要额外硬件,只消耗一个 ADC 通道,非常适合作为安全兜底。
5. 上机实测:那些只有电机转起来才会暴露的问题
5.1 低速嗡鸣和轴端抖动的完整排查
项目进行到整机联调时,我遇到了一个非常典型的问题:电机在低速(大约 20rpm)运行时,轴端有明显的抖动,同时伴随一种周期性嗡鸣声。这个现象在实验室里桌面运行时已经存在,装到机械臂上之后变得更明显,因为机械臂的固有频率放大了振动。
我按下面的顺序排查:
第一步,检查 STEP 信号。用示波器挂在驱动板输入端的 STEP 引脚上,看波形边沿是否干净。结果是 3.3V 方波,边沿没有明显的振铃和毛刺,可以排除 MCU 输出问题。
第二步,测量 VREF 波形。这是最关键的检查点。示波器直接测 DAC 输出到 VREF 引脚的那根线,发现上面叠加了一个周期性纹波,频率刚好等于 STEP 频率的两倍。这说明什么问题呢?我的波表在 16 细分时只生成了 16 个点,每个点更新后 DAC 输出立即跳到下一个值,但是 STEP 脉冲触发后,电流还没有完全跟上,下一档电压就到了,造成电流波形上明显的台阶感和过冲。
第三步,改进波表密度。把正弦波表从 16 点扩展到 64 点,DAC 每次更新只改变四分之一的原始台阶,波形平滑度显著提升。同时把 DAC 中断优先级提到 STEP 输出之前,确保换相瞬间电压已经稳定。改完之后抖动明显减轻,但嗡鸣还在。
第四步,怀疑斩波频率。DRV8818 的斩波频率是固定的还是可调的,取决于具体配置。我在数据手册的斩波章节摸索之后发现,可以通过外部电容调整振荡器频率,把斩波频率从默认值稍微调高,让它和机械共振频率错开。实测把斩波频点移开后,嗡鸣几乎听不到了。这个问题的本质是斩波纹波激励了电机的机械共振,单靠软件波形优化解决不了,必须从频率上错开。
整个排查花了一个下午,最终的结论是:低速抖动主要原因是 VREF 更新粒度太粗,嗡鸣主要原因是斩波频率巧合地与机械共振频率重合。两者都解决之后,低速平稳性达到了我预期的水平。
5.2 芯片发热:热保护导致突然停转
另一个让我印象深刻的问题是芯片热保护。某一次长时间低温测试,电机转了大约 40 分钟后突然停住,MCU 那边没有收到任何丢步报告。查了半天才发现是 DRV8818 触发了过温保护(OTSD),芯片自动关断了输出。
这个案例暴露的问题有两个层面。第一层是散热焊盘焊接质量不行。前面说过,如果 PowerPAD 下面没有完整的铺铜和过孔,芯片热阻会非常大,在环境温度 40°C、电机 1.2A 电流下,芯片温度突破保护阈值是必然的。第二层是电流设置欠思考。我为了追求大力矩,把 ITRIP 设得偏高,但实际工况中负载根本用不到那么大的电流,白白转化成热。
解决办法:把散热焊盘重新做扎实,同时在固件里加了一档"低速高力矩、高速低电流"的自动怠速减流功能。当电机静止或速度低于某个阈值时,VREF 自动降低到运行电流的 50%,既保证了静止保持力矩,又减少了长时间通电发热。这个功能在机器人关节上尤其重要,因为机械臂在等待指令时电机是长时间通电的,如果一直满电流,机柜里的温度迟早会失控。
5.3 丢步问题:从现象到根因的定位流程
机器人设备最怕的就是丢步,因为开环状态下丢步意味着位置误差不可察觉,直到最后对位才发现偏差。我遇到过一次非常隐蔽的丢步:机械臂末端到位精度差了大约 1.2°,也就是大约 27 个整步,而且不是每次都丢,偶尔丢,非常难复现。
排查时我做了几个假设:第一个假设是加速度太大。我把梯形加速的 a 从 100 rps² 降到 50 rps²,丢步概率从 10% 降到 8%,没有本质改善。说明不是加速度的问题,至少不是主要原因。
第二个假设是电源在加速瞬间压降。我用示波器同时监控 VM 电压和 STEP 脉冲,发现每到大电流加速段,VM 电压会从 24V 掉到 21V 左右,到了大约 18V 的瞬间,STEP 信号上出现了一个毛刺,导致少走了一个脉冲。这个毛刺是怎么来的?STEP 信号线离功率走线太近,功率开关的 dv/dt 通过寄生电容耦合到信号线上,干扰了 MCU 的定时器输出。虽然 MCU 输出本身是好的,但线路上的电容耦合把它污染了。
解决方法是把 STEP 信号线加 33Ω 串联电阻加 100pF 电容对地滤波,同时重新布局,让信号线和功率走线之间拉开距离。改动后丢步彻底消失。这个案例的意义在于:很多时候丢步不是电机力矩不够,而是信号完整性出了问题,排查时不要只盯着软件,要舍得花时间在示波器上抓实际信号。
后来又出现过一次丢步,这次是 nFAULT 触发了过流保护,芯片主动断开输出。原因是电机堵转瞬间电流尖峰触发了过流阈值,处理方案是软件里加了堵转降速策略:检测到 nFAULT 信号后,不是立即停机,而是先尝试降速、减小加速度,连续几次都触发才真正报警停机。这样既可以避免误报,也能在真正堵转时保护电机和驱动。
5.4 机器人线缆下的电磁干扰防护
把电机装到旋转关节上之后,驱动板和控制板之间要用一根几米长的线缆连接,这时候干扰问题开始变得突出。步进电机的相线是 PWM 斩波的高压脉冲,dv/dt 很大,会向空间辐射噪声;线缆又长,相当于一根天线,噪声会耦合到 STEP、DIR、ENBL 这些控制信号上。
我最后采用的防护方案是:所有控制信号都做差分传输,STEP 和 DIR 分别用一对差分线,在接收端用 RS422 接收器恢复成单端信号。步进电机控制信号频率不高,但要求可靠的边沿,差分传输几乎可以完全消除共模干扰。线缆选双绞屏蔽线,屏蔽层在驱动板一端单点接地,避免地环路。
如果不用差分方案,至少也要做到:信号线在 PCB 上用包地处理,线缆远离电机相线,STEP 高电平和低电平都要加滤波电容,防止边沿附近的毛刺被当成有效脉冲。在调速精度不高的场合,还可以在 MCU 端做输入滤波,只有持续超过 1μs 的电平才认为是一个有效步骤,这样大多数噪声脉冲会被滤掉。
6. 从开发板方案到工业产品:还差这最后几步
6.1 供电、急停和上电时序
工业设备不是实验室里的面包板,供电、急停、上电时序都得规范化。我的做法是:24V 电源进入设备后,先经过一个缓启动电路,用 NTC 热敏电阻加继电器旁路,避免上电瞬间电容充电电流过大;然后分配一路给电机驱动,一路通过 DCDC 给逻辑电路供电。
有一个特别容易出问题的时序:MCU 还没通电时,电机驱动芯片的 ENBL 引脚如果出于外部原因被拉高,电机会立刻通电,即使 MCU 完全没参与也会锁死转子。这在工业设备上会造成危险的上电姿态不确定。所以前面提到的 ENBL 下拉电阻是硬性要求。另外,急停按钮应该直接切断电机电源,而不是依赖软件下发停止指令。机械开关的可靠性远高于软件执行链路。
掉电瞬间的处理也需要考虑。如果主电源断电,VM 电压跌落的过程里,电机相电流可能因为 H 桥进入未知状态而产生反向电流冲击。我给 DRV8818 加了一个简单的掉电检测:用电阻分压器监控 VM 电压,送入 F412RE 的 ADC,当电压低于设定值(比如 20V)时,MCU 立即把 ENBL 拉低,并在 1ms 内完成所有轴的使能关闭。这个动作比完全依赖电源自身掉电要可靠得多。
6.2 故障上报:让每一颗芯片的异常都可追踪
工业现场最重要的一件事是可诊断性。电机转得好好的突然停了,维护人员要知道是因为什么停的。DRV8818 的 nFAULT 引脚输出过流、过温等异常状态,我把它接到了 F412RE 的一个外部中断引脚上,同时在 MCU 里维护一个故障寄存器,记录故障类型、发生时刻、故障前的速度档位和电流设定值。
每次 nFAULT 触发,中断服务程序第一件事是读取芯片状态,把信息写进 SRAM 缓存,然后通过 CAN 总线或者 RS485 上报给上位机,上位机可以显示故障码和现场参数。这样即使设备在车间无人运行,故障发生后维护人员也能通过历史记录判断是偶发堵转还是持续过流,而不至于盲目地换件调试。
注意 nFAULT 是开漏输出,需要外部上拉电阻。上拉电阻接到逻辑电源。我在这个引脚上并联了一个 10nF 滤波电容,避免了开关噪声导致的假故障触发,前提是确认故障信号不是快速脉冲信号,步进电机的过流故障持续时间通常有几百微秒,滤波不会影响有效检测。
6.3 多轴扩展与总线同步
一个机械臂往往需要多个关节,每个关节一个电机,我不可能每轴都用一片 STM32F412RE 加一片 DRV8818 的设计,成本太高。更合理的架构是:一块主控板(F412RE)同时控制多轴,电机驱动芯片分布在各个关节附近的功率板上,主控板通过总线把 STEP/DIR 或者位置指令发给各轴。
F412RE 的定时器资源可以支持 2 到 3 轴电机的直接脉冲输出:TIM1 输出两路互补的 PWM 作为轴 1 的 STEP 和 DIR,TIM8 输出轴 2 的 STEP/DIR,TIM2 和 TIM3 分别做两轴的位置计数。VREF 方面,轴 1 用 DAC 通道 0,轴 2 用 DAC 通道 1,第三轴就只能走 PWM 滤波方案。这样单主控最多带三轴,对于小型桌面机械臂够用了,五轴、六轴的机型还是用多主控加 CAN 总线组网更合理。
总线上同步也是一个细节。多轴协同运动时,每个轴的动作必须同时开始才能保证末端轨迹不偏离。我在 CAN 总线上定义了同步指令:主控发送一个同步帧,所有关节板收到后不是立即执行,而是等到下一个 1ms 时基中断的时刻才统一启动速度曲线。这样可以把轴间启动时间差控制在 1ms 以内,对于大多数点到点定位应用足够。
6.4 这套方案适合什么,不适合什么
DRV8818 加 STM32F412RE 这套组合,最适合的场景是中小功率、需要精细电流控制的工业设备:小型机械臂关节、自动化定位平台、医疗设备运动模块、精密送料机构。它的最大优势是灵活性和可控性,电流波形、细分策略、加减速曲线全部在软件里,出问题可以调,不用频繁改板。
它的边界也很明显:连续电流超过 2A 的电机就不适合了,这时候要么换更大的驱动芯片,要么加散热强制风冷;120V 或者 220V 供电的伺服系统更是完全不是它的领域。另外,如果项目对开发速度要求极高、没有什么特殊波形需求,用 DRV8825 确实更快,没必要为了可编程性付出额外开发时间。
如果重新再做一遍这套设计,我会在布板阶段就把故障诊断做得更细,比如每个采样电阻旁边预留电流电压的测试点,方便产线校准。电流闭环虽然芯片内部已经完成了,但外部做一次系统级的电流标定会大幅提升批量生产的一致性。这个可以留到下一版硬件里迭代。