STM32 定时器编码器接口实战:正交解码测转速,电机闭环第一步

做电机控制,第一步往往是「知道转子转了没有、转多快、往哪转」。你在轴上贴个增量编码器,出来 A、B 两路相位差 90 度的方波。手动去读两个 IO 的电平变化、数边沿、判方向,中断能给你炸到怀疑人生,还容易漏脉冲。

STM32 的定时器自带编码器接口(Encoder Mode),硬件帮你数脉冲、判方向,CPU 只需要在想看的时候读一下计数器。这篇文章把正交解码原理、4 倍频、用定时器数脉冲算转速讲清楚,顺带把最常踩的坑列出来。

正交编码到底在算什么

增量编码器 A、B 两路方波,相位差 90 度。正转时 A 领先 B 90 度,反转时 B 领先 A 90 度。只看两路电平的跳变顺序,就能判断方向;数跳变次数,就能知道转了多少。

定时器编码器模式的逻辑是:把 A、B 两路接到同一个定时器的两个通道(TI1、TI2),在 A 的上升沿、下降沿、B 的上升沿、下降沿都计数。这样一个机械脉冲周期里数到 4 次边沿,叫4 倍频,分辨率直接翻四倍。

计数器是带符号的:正转递增,反转递减。溢出回绕也无所谓,读出来的值就是相对位移,减一下就知道这段时间转了多少。

CubeMX 与代码

CubeMX 里把对应定时器(TIM2~TIM5 多数支持)的 Combined Channels 选成 Encoder Mode。两个通道映射到 TI1、TI2,极性一般选 TI1FP1 和 TI2FP2(或都不反向,看编码器相位)。计数器周期设成足够大(比如 16 位就 65535,32 位定时器更大),避免短时间溢出。

c 复制代码
// 启动编码器接口
HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL);

// 主循环里读取
int32_t cnt = (int16_t)__HAL_TIM_GET_COUNTER(&htim2);  // 16位带符号

如果定时器是 32 位(如 TIM2、TIM5 部分型号),计数器直接当 int32_t 读,溢出周期更长,适合高速长时间累积。

怎么算转速

编码器的脉冲数对应机械角度。比如编码器每圈 1000 线,4 倍频后每圈 4000 个计数。测速就是「单位时间内的计数变化量 ÷ 每圈计数 ÷ 时间」:

c 复制代码
static int32_t last_cnt = 0;
static uint32_t last_tick = 0;

void measure_speed(void)
{
    int32_t cnt = (int32_t)__HAL_TIM_GET_COUNTER(&htim2);
    uint32_t now = HAL_GetTick();
    float dt = (now - last_tick) / 1000.0f;        // 秒
    int32_t delta = cnt - last_cnt;                 // 这段时间计数的变化
    float rpm = (delta / 4000.0f) / dt * 60.0f;     // 每圈4000计数

    last_cnt = cnt;
    last_tick = now;
    // rpm 就是当前转速
}

关键点:delta 要用带符号的减法。正转和反转的计数器是连续增减的,直接减就能得到净位移,不用分别数正负。用定时中断(比如每 10ms 调一次)周期性算,就得到平稳的转速反馈,这正是 FOC 电流环之外的速度环输入。

十个坑,测速乱基本都在这

  1. 两个通道接到同一个定时器。A、B 必须进同一个 TIM 的 CH1/CH2,用两个不同定时器各自数一路是数不出方向和 4 倍频的。

  2. 极性配反导致方向反。正转读出来是负、反转是正。这不是错,是编码器接线和极性设置的问题。把 TI1、TI2 极性都翻转,或者直接对读数取负,让正转对应正数即可。

  3. 计数器溢出没处理。16 位计数器从 65535 回 0 或 0 回 65535,直接减 delta 会算出巨大负值或正值。用带符号类型(int16_t 读再转 int32_t),回绕减法仍正确;或者定时清零、用增量累计。

  4. 每圈计数算错。编码器标 1000 线,你当 1000 计数算转速,漏了 4 倍频,转速算出来只有实际四分之一。标称线数 × 4 才是每圈计数,除非你特意关掉倍频。

  5. 测速周期和电机响应不匹配。10ms 测一次和 1 秒测一次,得到的转速噪声和延迟完全不同。慢速用长周期平滑,快速用短周期跟手,别一刀切。

  6. delta 用了无符号类型。cnt 是无符号读出来,相减结果被当成无符号,反转时溢出成大正数,转速符号全错。读出来先转成有符号再减。

  7. 编码器电源和地没共。编码器和 MCU 不共地,A、B 信号参考点漂移,电平识别错,计数乱跳。编码器 GND 必须和板子 GND 连起来。

  8. 长线传输没做差分或缓冲。编码器线拉几米,普通推挽信号受干扰,边沿抖动多计脉冲。距离远用 RS422 差分接收,或者至少加滤波和施密特触发。

  9. Z 相(零位)没利用做绝对归零。增量编码器只能数相对位移,上电不知道绝对角度。接 Z 相到定时器外部触发或 IO,转一圈对齐一次零位,解决累计漂移。

  10. 高速时计数溢出丢脉冲。电机转太快,单位时间脉冲数超过定时器计数能力或 MCU 读取太慢,漏数。提高定时器位数、缩短读取间隔,或评估编码器最高响应频率是否超 MCU 支持。

把这件事收一下

编码器接口是电机闭环的入口:硬件数脉冲判方向,4 倍频提分辨率,定时读计数器算转速。CPU 几乎不参与计数,只在测量周期去读一下差值。真正的麻烦不在配置,在方向极性、溢出回绕、还有每圈计数到底乘没乘 4。把这几点钉死,转速反馈就稳了,速度环才有靠谱的输入。

正反转只看 A、B 谁领先 90 度,4 倍频把分辨率翻四倍。读计数器用带符号减法吃溢出,每圈计数别忘乘 4,编码器接地要共,测速才不飘。

相关推荐
Jason_zhao_MR4 小时前
Linux与实时控制如何兼得
linux·嵌入式硬件·机器人·工业控制
BSD_CGQ5 小时前
FSR传感器STM32 DMA高速采样工程实现(高精度、低CPU占用)
stm32·单片机·嵌入式硬件·压力传感器·源头工厂·柔性薄膜压力传感器·可变电阻压力传感器
芯岭技术郦8 小时前
32 位 ARM® Cortex®-M0+ 内核MCU普冉MS32C001-C
单片机·嵌入式硬件
骑着毛驴数星星8 小时前
STM32 CAN波特率与采样点计算,基于HAL库
stm32·单片机·嵌入式硬件
zhangrelay9 小时前
Arduino-MEGA-ESP单片机理论课笔记02-硬件-2026
笔记·单片机·嵌入式硬件
艾芯微科技9 小时前
钰泰 ETA5055V330DD1E|SOT-223 3.3V LDO,低压差、大电流线性稳压选型分享
网络·单片机·嵌入式硬件·集成测试·51单片机
新晨单片机设计10 小时前
S023A-基于STM32单片机智能插座【Proteus仿真+Keil程序+原理图】
stm32·单片机·proteus·单片机智能插座
威嵌神州10 小时前
恩智浦 T1022 性能怎么样?QorIQ 架构中端工业嵌入式优势解析
嵌入式硬件
weixin_6906547411 小时前
龙迅#LT9611EX 现MIPI转HDMI1.4功能主推型号,分辨率高达4K30HZ,IC内置I2C无需外部12C控制。
嵌入式硬件·音视频·信号处理
EatFans11 小时前
全栈自造 Status Deck(四):硬件终于到了,从点亮屏幕到跑通第一个 Demo
单片机·物联网