资讯动态

STM32编码器测速实战:从脉冲到速度的完整链路拆解

发布时间:2026/10/27 9:17:25 来源:尧图企业网站定制
1. 从脉冲到速度编码器测速的完整工程链路拆解编码器读到的到底是什么这个问题看似基础但我在带新人和做技术评审的时候发现能把这条链路从头到尾讲清楚的人并不多。很多人拿到一个带编码器的电机第一反应是接上STM32的定时器开编码器模式读CNT寄存器然后除以线数乘以时间得到一个转速值觉得完事了。但实际跑起来之后低速抖得厉害、高速方向偶尔反、脉冲数对不上、换了个电机参数全乱——这些问题的根因几乎都出在对“脉冲到速度”这条链路的某个环节理解不到位。这篇文章面向的是正在用STM32做电机控制、编码器测速的嵌入式开发者尤其是那些已经能跑通基本功能、但被精度、稳定性、方向判断等问题困扰的朋友。我会从编码器的物理本质讲起把脉冲信号怎么变成可用的速度值这条链路完整拆开包括硬件接口、定时器配置、测速算法选型、参数计算、常见故障排查以及我在实际项目中踩过的坑和总结出来的经验。涉及的核心关键词包括编码器、脉冲、速度、PWM、STM32这些概念会贯穿全文但我会尽量用工程视角而不是教科书视角来讲。先给一个全局认知编码器输出的本质是位置增量信息它告诉你“转了多少”而不是“转多快”。速度是你通过对位置增量做时间微分算出来的。这个微分怎么算就是测速算法的核心。而STM32的定时器编码器模式本质上是一个硬件级的正交解码器加计数器它帮你把A/B两相的边沿变成方向相关的计数值。理解了这个你就知道为什么有些问题必须在硬件层面解决有些可以在软件层面补偿。注意编码器测速的精度和稳定性80%取决于你对信号链路的理解20%才取决于算法调参。方向搞反了再好的滤波器也救不回来。2. 编码器的物理本质与信号特征2.1 增量式编码器到底输出什么增量式编码器Incremental Encoder最核心的输出就是A相和B相两路方波信号它们频率相同但相位差90度。这个90度的相位差是方向判断的物理基础A相超前B相90度表示正转B相超前A相90度表示反转。除此之外大多数编码器还有一个Z相Index信号每转一圈输出一个脉冲用来做零位校准或圈数计数。这里有个容易被忽略的点编码器的“线数”和“脉冲数”不是一回事。假设一个编码器标称500线500 PPRPulses Per Revolution它指的是每转A相或B相各自输出500个脉冲。但如果你用STM32定时器的编码器模式配置成对A/B两相的上升沿和下降沿都计数4倍频那么每转的计数值就是500×42000。这个倍频关系直接决定了你的速度分辨率配错了就会导致速度值差2倍或4倍。我在一个项目里遇到过这样的情况客户反馈说电机实际转速和显示值差了整整4倍查了半天以为是算法问题最后发现是编码器模式配置成了双边沿计数但速度计算时用的还是单相脉冲数。这种问题在数据手册里写得很清楚但实际配置时很容易漏看。2.2 正交解码的硬件实现原理STM32的定时器编码器模式本质上是用硬件实现了一个正交解码器。它通过检测A/B两相的边沿组合来判断方向和计数。具体来说当A相和B相的电平组合按照00→01→11→10的顺序变化时计数器加1按照相反顺序变化时计数器减1。这个过程完全由硬件完成不需要CPU干预所以即使在高转速下也不会丢脉冲。但这里有个硬件层面的坑编码器模式下的计数器是16位或32位的存在溢出问题。16位定时器在4倍频、2000脉冲/转的配置下每转一圈计数值变化2000那么每32768/2000≈16.4圈就会溢出一次。如果你用简单的CNT差值来算速度溢出瞬间就会得到一个巨大的错误值。解决办法有两种一是用32位定时器如STM32F4系列的TIM2/TIM5二是定期读取并累加到软件计数器里。2.3 信号质量对测速的影响编码器输出的是方波但实际信号往往不是理想的方波。我在示波器上见过各种畸变上升沿有振铃、占空比不是50%、A/B相位差不是精确的90度、甚至偶尔有毛刺。这些问题在低速时影响不大但在高速时会导致误计数。信号质量问题的根源通常有三个一是编码器本身的输出驱动能力不足长线传输时边沿变缓二是电源噪声耦合到信号线上三是地线回路处理不当。我的一般处理原则是如果编码器输出是集电极开路OC或推挽输出优先用推挽如果传输距离超过30cm考虑加施密特触发器整形如果环境噪声大用双绞线加屏蔽层屏蔽层单端接地。提示不要小看编码器信号线上的一个小毛刺在4倍频模式下一个毛刺可能被计成4个脉冲直接导致速度值跳变。3. STM32定时器编码器模式配置实战3.1 硬件连接与引脚选择以STM32F103为例编码器接口通常使用TIM1、TIM2、TIM3、TIM4等高级或通用定时器的CH1和CH2通道。具体引脚需要查数据手册的复用功能表。比如TIM3的CH1是PA6CH2是PA7TIM2的CH1是PA0CH2是PA1。接线时A相接CH1B相接CH2Z相可以接一个外部中断引脚用于零位检测。这里有个实操细节STM32的编码器模式只使用CH1和CH2CH3和CH4可以独立用作PWM输出或其他功能。这意味着你可以在同一个定时器上同时实现编码器读取和PWM输出但要注意PWM频率和编码器计数不要互相干扰。我一般建议编码器和PWM用不同的定时器避免配置冲突。3.2 定时器初始化代码详解下面是一段基于STM32 HAL库的编码器模式初始化代码以TIM3为例TIM_HandleTypeDef htim3; TIM_Encoder_InitTypeDef sConfig {0}; htim3.Instance TIM3; htim3.Init.Prescaler 0; // 不分频编码器模式不需要预分频 htim3.Init.CounterMode TIM_COUNTERMODE_UP; htim3.Init.Period 65535; // 16位定时器最大值 htim3.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; htim3.Init.AutoReloadPreload TIM_AUTORELOAD_PRELOAD_DISABLE; sConfig.EncoderMode TIM_ENCODERMODE_TI12; // A/B两相都计数4倍频 sConfig.IC1Polarity TIM_ICPOLARITY_RISING; sConfig.IC1Selection TIM_ICSELECTION_DIRECTTI; sConfig.IC1Prescaler TIM_ICPSC_DIV1; sConfig.IC1Filter 10; // 输入滤波器根据信号质量调整 sConfig.IC2Polarity TIM_ICPOLARITY_RISING; sConfig.IC2Selection TIM_ICSELECTION_DIRECTTI; sConfig.IC2Prescaler TIM_ICPSC_DIV1; sConfig.IC2Filter 10; HAL_TIM_Encoder_Init(htim3, sConfig); HAL_TIM_Encoder_Start(htim3, TIM_CHANNEL_ALL);这段代码里有几个关键参数需要解释。EncoderMode设置为TIM_ENCODERMODE_TI12表示对TI1和TI2的边沿都计数也就是4倍频。如果只需要2倍频可以设置为TIM_ENCODERMODE_TI1或TIM_ENCODERMODE_TI2。IC1Filter和IC2Filter是输入滤波器取值范围0-15值越大滤波越强但会引入延迟。我一般从10开始试如果信号质量好可以降到4-6如果毛刺多就加到12-15。3.3 读取计数值与方向判断读取编码器计数值很简单调用__HAL_TIM_GET_COUNTER(htim3)即可。但方向判断需要一点技巧STM32的编码器模式会自动根据A/B相位关系增减计数器所以你可以通过连续两次读取的差值来判断方向。差值为正表示正转为负表示反转。但这里有个陷阱如果计数器溢出差值会突变。比如从65535跳到0差值算出来是-65535但实际上只转了1个脉冲。解决办法是使用带符号的32位变量来累加int32_t encoder_total 0; int16_t encoder_last 0; void update_encoder(void) { int16_t current (int16_t)__HAL_TIM_GET_COUNTER(htim3); int16_t diff current - encoder_last; encoder_total diff; encoder_last current; }这段代码利用16位有符号数的溢出特性自动处理了计数器回绕问题。diff在溢出时仍然正确因为C语言的有符号数溢出是定义良好的在大多数编译器上。这个技巧我在多个项目中用过非常稳定。4. 从脉冲到速度测速算法的选型与实现4.1 三种主流测速方法的对比测速算法本质上是在“测频率”和“测周期”之间做选择。常见的方法有三种方法原理适用场景优缺点M法频率法固定时间内计脉冲数高速高速精度高低速精度差T法周期法测量两个脉冲之间的时间低速低速精度高高速误差大M/T法结合两者同时测脉冲数和时间全速段精度高实现复杂M法的速度计算公式是速度 (脉冲数 / 线数) / 采样时间。比如1000线编码器4倍频后4000脉冲/转10ms采样时间内读到400个脉冲那么速度 (400/4000)/0.01 10转/秒 600 RPM。这个方法的精度取决于采样时间内能读到多少脉冲低速时脉冲数少量化误差就大。T法的速度计算公式是速度 1 / (脉冲周期 × 线数)。比如测得两个脉冲之间间隔500us1000线编码器那么速度 1/(0.0005×1000) 2转/秒 120 RPM。这个方法在低速时精度很高但高速时脉冲周期很短定时器分辨率不够会导致误差。4.2 M/T法混合测速的实现细节M/T法的核心思想是用一个定时器产生固定的采样周期比如10ms在这个周期内同时记录编码器脉冲数和一个高频时钟的计数值。低速时脉冲数少但高频时钟计数值大用时钟值来算周期高速时脉冲数多用脉冲数来算频率。这样在全速段都能保证精度。具体实现时我用TIM2做编码器接口TIM4做1MHz的高频计数TIM5做10ms的采样定时。每10ms中断一次读取编码器差值和高频计数值然后根据脉冲数是否超过阈值来选择计算公式。阈值一般设为10-20个脉冲低于这个值用T法高于用M法。注意M/T法的关键是高频时钟的频率要足够高一般至少是编码器最高输出频率的10倍以上。如果编码器最高输出100kHz高频时钟至少1MHz。4.3 速度计算的参数标定与验证算出来的速度值准不准需要用外部基准验证。我常用的方法是用示波器测编码器A相频率然后和程序算出的速度值对比。比如A相频率是10kHz1000线编码器那么转速 10000/1000 10转/秒 600 RPM。如果程序显示的不是这个值就要检查倍频系数、采样时间、线数参数是否匹配。还有一个容易忽略的点机械减速比。如果电机后面接了减速箱编码器装在电机轴上那么输出轴的实际转速要除以减速比。这个参数一定要在代码里体现否则显示值和实际值会差一个减速比的倍数。5. 常见问题排查与实战经验5.1 速度值抖动、跳变的排查思路速度值抖动是最常见的问题。排查时按以下顺序检查信号质量用示波器看A/B相波形是否有毛刺、振铃、边沿变缓。如果有先解决硬件问题。滤波器参数IC1Filter和IC2Filter是否合适。信号好就降低滤波信号差就提高滤波。采样周期采样周期太短会导致脉冲数少量化误差大。一般10ms-50ms比较合适。软件滤波在速度值上做一阶低通滤波或滑动平均但要注意相位延迟。电源噪声编码器供电是否干净是否和电机共用电源。建议编码器单独用LDO供电。我在一个项目里遇到过速度值每隔几秒跳一次的问题查了两天发现是编码器电源和电机驱动共用了一个开关电源电机换向时产生的噪声耦合到了编码器电源上。后来给编码器单独加了一个5V LDO问题立刻消失。5.2 方向判断错误的几种原因方向反了通常有三个原因一是A/B相接反了交换一下即可二是编码器模式配置成了单相计数导致方向判断失效三是机械安装方向和你预期的相反。前两个是软件问题第三个是机械问题。我一般先在软件里加一个方向取反的宏方便调试时快速切换。5.3 高速时丢脉冲的解决方案高速丢脉冲的表现是速度值在某个转速以上就不再增加或者增加变缓。原因通常是编码器输出频率超过了STM32定时器的最大计数频率。STM32的定时器编码器模式最高计数频率一般是系统时钟的一半比如72MHz系统时钟最高36MHz。如果编码器输出频率超过这个值就会丢脉冲。解决办法一是降低倍频系数从4倍频改成2倍频或1倍频二是换用更高主频的STM32三是用外部硬件正交解码芯片。我一般优先考虑降低倍频系数因为改一行配置就行不需要改硬件。5.4 常见问题速查表现象可能原因排查方法解决方案速度值始终为0编码器未供电、接线错误、定时器未启动万用表测编码器电源示波器看A/B相检查供电和接线确认HAL_TIM_Encoder_Start已调用速度值方向相反A/B相接反、方向配置错误交换A/B相测试交换接线或在软件中取反速度值差2倍或4倍倍频系数与计算参数不匹配检查EncoderMode和线数参数统一倍频系数和计算公式低速时速度值为0M法量化误差、采样周期太短增加采样周期或改用T法改用M/T法或增加采样时间高速时速度值饱和定时器计数频率不足计算编码器最高输出频率降低倍频系数或换更高主频MCU速度值周期性跳变计数器溢出、电源噪声检查溢出处理、示波器看电源用32位累加器、单独供电6. 从速度到控制PWM调速的闭环实现6.1 速度环PID的基本结构有了准确的速度反馈就可以做闭环控制了。速度环PID的输入是目标速度和实际速度的差值输出是PWM占空比。基本结构是每10ms执行一次PID计算更新PWM比较值。PID参数整定时先调P让系统有响应但不振荡再加I消除稳态误差D一般不用因为速度信号噪声大微分会放大噪声。我在实际项目中的经验是速度环的采样周期要和测速周期一致否则会出现采样不同步导致的振荡。另外PWM频率一般选10kHz-20kHz太低会有 audible noise太高会增加开关损耗。6.2 PWM输出配置与注意事项STM32的PWM输出用另一个定时器实现比如TIM1的CH1。配置时注意PWM频率 定时器时钟 / (预分频1) / (自动重载值1)。比如72MHz时钟预分频72-1自动重载1000-1PWM频率 72MHz/72/1000 1kHz。这个频率有点低电机可能会有啸叫建议改成10kHz以上。还有一个细节PWM输出和编码器读取最好用不同的定时器避免配置冲突。如果资源紧张必须共用要仔细检查引脚复用和中断优先级。6.3 闭环调试的实操步骤调试闭环时我一般按以下步骤开环测试固定PWM占空比观察电机是否正常转动速度反馈是否合理。P参数整定从小往大调直到速度能跟上目标值但略有超调。I参数整定从0慢慢加直到稳态误差消除但不要加到振荡。阶跃响应测试突然改变目标速度观察响应时间和超调量。负载测试加负载看速度是否稳定如果掉速严重说明P太小或I不够。提示调试时一定要用示波器或串口实时输出速度曲线光看数字很难判断振荡和超调。7. 编码器选型与硬件设计建议7.1 增量式 vs 绝对式编码器的选择增量式编码器便宜、接口简单但断电后位置丢失需要回零。绝对式编码器如AS5047P磁编码器断电后位置不丢但价格贵、接口复杂SPI或I2C。我一般根据应用场景选如果只需要测速增量式足够如果需要位置控制且不能回零选绝对式。AS5047P是我用过比较多的一款磁编码器14位分辨率SPI接口最高支持28krpm。它的优点是体积小、非接触、寿命长缺点是安装精度要求高磁铁和芯片的距离要控制在0.5-2mm之间。7.2 电源与信号完整性设计编码器供电要干净尤其是磁编码器和光电编码器。我一般用独立的LDO给编码器供电地和电机驱动地单点连接。信号线上如果走线较长加100Ω串联电阻和100pF电容做RC滤波。如果是差分输出的编码器如RS422用差分接收器转成单端再进STM32。还有一个容易忽略的点编码器电缆的屏蔽层要单端接地接在控制器一侧不要两端都接否则会形成地环路引入更多噪声。7.3 实际项目中的选型案例在一个机器人关节项目中我需要测速范围0-3000 RPM精度要求1%。我选了一款1000线的光电编码器4倍频后4000脉冲/转用STM32F407的TIM232位做编码器接口TIM5做10ms采样定时M/T法测速。实测下来全速段速度波动小于0.5%满足要求。成本方面编码器约80元STM32F407约30元整体方案性价比很高。8. 进阶话题从编码器数据中挖掘更多信息8.1 位置、速度、加速度的联合估计编码器不仅能测速还能通过差分得到加速度。加速度信息在振动分析、碰撞检测、负载估计中很有用。但加速度是速度的微分噪声会被放大所以一般需要先对速度做低通滤波再做差分。我一般用二阶巴特沃斯滤波器截止频率设为速度环带宽的2-3倍。8.2 编码器故障检测与容错编码器故障的典型表现是信号丢失、脉冲数异常、方向突变。检测方法有监测脉冲频率是否在合理范围、监测A/B相相位关系是否正常、监测Z相是否定期出现。如果检测到故障可以切换到无传感器控制或降级运行。我在一个项目中实现了简单的故障检测如果连续3个采样周期速度值为0但PWM输出不为0就判定编码器故障触发报警。8.3 与无传感器控制的融合在一些低成本应用中可以用编码器做低速段控制高速段切换到无传感器控制如反电动势观测器。这样既能保证低速精度又能省掉高速时的编码器依赖。融合的关键是切换点的选择和过渡过程的平滑处理。我一般用速度加权的方式做平滑过渡避免切换时的转矩突变。注意编码器和无传感器控制的融合需要仔细标定切换点选不好会导致系统振荡。9. 我在编码器测速项目中的几点体会做了这么多年的电机控制编码器测速这件事看起来简单但真正做好并不容易。我的体会是硬件是基础算法是手段标定是关键。硬件信号不干净再好的算法也白搭算法选型不对低速高速总有一段不好用标定不准确显示值和实际值对不上闭环控制就会出问题。另外不要迷信高线数编码器。线数越高脉冲频率越高对STM32的计数频率要求也越高。我见过有人用5000线编码器配STM32F103结果高速时丢脉冲换成1000线反而稳定了。选型时要算清楚最高转速下的脉冲频率留足余量。最后分享一个小技巧在调试初期可以用一个电位器模拟编码器信号手动改变频率和相位验证测速算法的正确性。这个方法比直接上电机调试更安全、更可控。等算法验证通过了再接到实际编码器上能省很多排查时间。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑