共计 1492 个字符,预计需要花费 4 分钟才能阅读完成。
一、电机编码器基础认知
增量式编码器通过 A / B 两相 90°相位差的脉冲信号记录电机转动信息。STM32 的 TIMx 定时器自带 正交解码器 硬件功能,可自动识别 A / B 相边缘变化并统计脉冲数,相比外部中断方案节省 CPU 资源。

- A/ B 相波形特征:正转时 A 相领先 B 相 90°,反转时滞后
- 4 倍频计数原理:STM32 可在每个脉冲的上升 / 下降沿计数,实现 4 倍精度提升
- 典型 520 电机参数:500 线编码器旋转一周产生 2000 个计数脉冲(500×4)
二、CubeMX 实战配置
2.1 定时器模式设置
- 打开 CubeMX 选择对应 TIMx(推荐 TIM2/TIM3/TIM4)
- 在 ”Combined Channels” 选择 Encoder Mode
- 配置通道 1 / 2 为 Input Capture direct/indirect(与硬件接线对应)
// 自动生成的 HAL 初始化代码片段
TIM_Encoder_InitTypeDef sConfig = {0};
sConfig.EncoderMode = TIM_ENCODERMODE_TI12; // 双通道模式
sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
sConfig.IC1Filter = 6; // 推荐滤波值
2.2 计数器参数调整
- AutoReload 值:设为 65535(16 位计数器最大值)
- ClockSource:禁用内部时钟(重要!)
- NVIC 设置:启用定时器中断处理溢出
三、核心代码实现
// 带溢出处理的读数函数
int32_t Get_Encoder_Value(TIM_HandleTypeDef *htim) {
static uint16_t last_cnt = 0;
static int32_t total_pulse = 0;
uint16_t current_cnt = __HAL_TIM_GET_COUNTER(htim);
int16_t delta = (int16_t)(current_cnt - last_cnt);
// 处理计数器溢出(0xFFFF ↔ 0x0000 跳变)if(delta > 32767) delta -= 65536;
else if(delta < -32767) delta += 65536;
total_pulse += delta;
last_cnt = current_cnt;
return total_pulse;
}
四、硬件设计黄金法则
4.1 信号滤波电路
- RC 低通滤波:在 A / B 相输入脚接 100Ω 电阻 +100pF 电容
- 施密特触发器:推荐使用 74HC14 对信号整形
4.2 电源处理
- 电机与 MCU 使用独立 LDO 供电
- 编码器电源线串接磁珠(如 BLM18PG221SN1)
4.3 机械安装
- 编码器与电机轴同心度偏差需 <0.1mm
- 使用柔性联轴器补偿微小错位
五、生产环境避坑指南
- 中断优先级冲突
- 编码器 TIM 中断优先级应高于 PWM TIM
-
避免在中断内进行浮点运算
-
计数器溢出陷阱
- 每次读取间隔不超过计数器半周期(推荐 <10ms)
-
使用 int32_t 类型存储累计脉冲数
-
转速计算隐患
- 采用 64 位整数进行转速运算
- 添加速度变化率限制(防突变)
六、进阶思考题
- 如何利用 TIMx 的 Capture 功能实现单圈零点校准?
- 在电池供电场景下,怎样优化编码器功耗?
- 当电机转速超过编码器最大响应频率时,有哪些补救方案?
实践心得
实际测试中发现,使用优质屏蔽线可使信号抖动减少 70%。建议在 PCB 布局时将编码器接口靠近 MCU 放置,过长的飞线会引入干扰。遇到数据跳变时,首先检查电源质量而非盲目调整代码参数。
正文完
