共计 1373 个字符,预计需要花费 4 分钟才能阅读完成。
AB 编码器作为电机控制和位置检测的核心传感器,其精准度直接影响闭环系统的性能表现。今天我们就来聊聊如何在 STM32 上稳定高效地读取 AB 编码器信号。

一、新手常见三大痛点
- 信号抖动导致计数跳变 :机械振动或电磁干扰会使 AB 相产生毛刺,导致计数器错误增减
- 高速旋转时丢失脉冲 :GPIO 轮询方式在电机高速运转时无法及时捕获所有边沿
- 正反转判断错误 :相位关系解析不当会造成方向误判,累计误差越来越大
二、硬件连接与模式选择
- 上拉电阻配置 :
- 推荐使用 1kΩ~4.7kΩ 上拉电阻(具体值根据编码器输出特性调整)
-
并联 100nF 滤波电容可有效抑制高频干扰
-
接口方案对比 :
| 方式 | 优点 | 缺点 |
|—————–|———————–|———————–|
| GPIO 轮询 | 实现简单 | 占用 CPU 资源,易丢脉冲 |
| 定时器编码器模式 | 硬件自动计数,零开销 | 需要特定定时器支持 |
三、定时器编码器模式详解
- 4 倍频原理 :
- 同时捕获 AB 相的上升沿和下降沿
-
每转脉冲数 = 编码器 PPR × 4
-
关键寄存器配置 (以 TIM3 为例):
// CubeMX 配置示例 htim3.Init.Period = 0xFFFF; // ARR 最大值 htim3.EncoderMode = TIM_ENCODERMODE_TI12; // 双通道计数模式 sConfig.ICPolarity = TIM_ICPOLARITY_RISING; // 上升沿触发 sConfig.ICSelection = TIM_ICSELECTION_DIRECTTI; // 直连输入
四、抗干扰软件策略
-
计数器溢出处理 :
int32_t Get_EncoderDelta(void) { static uint16_t last_cnt = 0; uint16_t curr_cnt = TIM3->CNT; int16_t delta = (int16_t)(curr_cnt - last_cnt); last_cnt = curr_cnt; return delta; // 自动处理 16 位溢出 } -
移动平均滤波 :
#define FILTER_WINDOW 5 float speed_filter_buf[FILTER_WINDOW]; float Get_FilteredSpeed(void) { static uint8_t idx = 0; speed_filter_buf[idx++] = Get_EncoderDelta(); if(idx >= FILTER_WINDOW) idx = 0; float sum = 0; for(uint8_t i=0; i<FILTER_WINDOW; i++) {sum += speed_filter_buf[i]; } return sum/FILTER_WINDOW; }
五、实测数据与优化建议
-
采样周期计算公式 :
最大转速 (rpm) × PPR × 4 ÷ 60 = 最大计数频率 (Hz) 建议采样频率 > 2 × 最大计数频率 -
中断优先级设置 :
- 编码器接口中断应高于运动控制周期中断
- 但低于紧急停止等安全中断
六、扩展思考
当系统需要同时读取多个编码器时,可以考虑:
1. 使用多个定时器的编码器模式
2. 通过 DMA 批量采集计数寄存器值
3. 采用 FPGA 做高速信号预处理
经过实际测试,在 1000RPM 转速下,采用本文方案的位置检测误差 <0.1%,完全满足大多数工业应用场景。希望这篇指南能帮你绕过那些我当年踩过的坑!
正文完
