共计 2845 个字符,预计需要花费 8 分钟才能阅读完成。
背景痛点
在电机控制系统中,位置和速度的精确检测是核心需求。AB 双相霍尔编码器因其结构简单、成本低、抗污染能力强等优点被广泛应用,但在实际开发中常遇到以下问题:

- 信号抖动 :霍尔元件受磁场干扰或机械振动影响,导致输出信号出现毛刺
- 转速计算误差 :低速时脉冲间隔大,高速时易丢失脉冲,影响转速测量精度
- 方向误判 :AB 相时序判断错误会导致位置累计误差越来越大
与光电编码器相比,霍尔编码器的优缺点非常明显:
- 优点 :
- 无需精密光栅,结构更坚固
- 对灰尘、油污不敏感
-
工作温度范围更宽(-40℃~150℃)
-
缺点 :
- 分辨率通常较低(每转几十到几百个脉冲)
- 磁铁易受外部磁场干扰
- 需要更严格的机械安装公差
硬件设计
STM32 定时器配置
使用 STM32 的编码器接口模式是最佳选择,以 TIM3 为例配置步骤:
- 配置 GPIO 为浮空输入模式(GPIO_MODE_INPUT)
- 设置 TIMx_CCMR1 寄存器为编码器模式 3(TIM_ENCODERMODE_TI12)
- 配置输入滤波器(TIM_IC_FILTER)根据信号质量设置 4 - 8 个时钟周期
- 开启计数溢出中断(TIM_IT_UPDATE)
硬件滤波设计
推荐使用二阶 RC 滤波电路:
A 相 → 1kΩ → 100nF → MCU
↓
100nF
↓
GND
截止频率计算:
fc = 1/(2π√(R1R2C1C2)) ≈ 1.6kHz
抗干扰布线
- 使用双绞线传输 AB 相信号
- 编码器电源与 MCU 电源共地
- 信号线远离电机驱动线至少 3cm
- 在连接器处放置 TVS 二极管(如 SMBJ5.0CA)
核心实现
四倍频状态机
通过状态机实现 4 倍频解码的典型状态转移:
stateDiagram
[*] --> State00
State00 --> State01: A↑
State00 --> State10: B↑
State01 --> State11: B↑ (正向)
State01 --> State00: A↓
State11 --> State10: A↓ (正向)
State11 --> State01: B↓
State10 --> State00: B↓ (正向)
State10 --> State11: A↑
中断服务函数示例
void EXTI9_5_IRQHandler(void) {
static uint8_t last_state = 0;
uint8_t current_state = (GPIOB->IDR >> 6) & 0x03; // PB6,PB7
// 状态转移判断
switch(last_state << 2 | current_state) {
case 0b0001: case 0b0111: case 0b1110: case 0b1000:
position++;
break;
case 0b0010: case 0b1011: case 0b1101: case 0b0100:
position--;
break;
}
// 软件消抖(3 次采样表决)static uint8_t filter_cnt = 0;
if(current_state == last_state) {filter_cnt = 0;} else if(++filter_cnt >= 3) {
last_state = current_state;
filter_cnt = 0;
}
EXTI->PR = EXTI_PR_PR6 | EXTI_PR_PR7; // 清除中断标志
}
转速计算优化
采用移动平均滤波的微分算法:
#define SAMPLE_NUM 5
int32_t speed_calculate(int32_t positions[]) {
static uint8_t idx = 0;
positions[idx] = position;
idx = (idx + 1) % SAMPLE_NUM;
// 计算差分时处理计数器溢出
int32_t diff = positions[idx] - positions[(idx+1)%SAMPLE_NUM];
if(diff > 0x7FFFFFFF) diff -= 0xFFFFFFFF;
else if(diff < -0x7FFFFFFF) diff += 0xFFFFFFFF;
return diff * 1000 / (SAMPLE_NUM * control_period_ms);
}
性能测试
脉冲丢失率测试
- 使用可编程电机驱动器设定固定转速
- 记录 10 秒内编码器计数值 M1
- 读取驱动器反馈的实际转数 M2
- 计算丢失率:
丢失率 = |(M1/PPR) - (M2* 传动比)| / (M2* 传动比) × 100%
逻辑分析仪验证
推荐使用 Saleae Logic Pro 8:
- 连接 AB 相和 Z 相信号
- 设置采样率≥10MHz
- 添加协议分析器→正交编码器
- 检查:
- 相位差是否为 90°±10°
- 上升 / 下降时间是否 <1μs
- 有无振铃现象
避坑指南
常见故障排查
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 计数方向随机变化 | 1.AB 相序接反 2. 磁极安装偏移 |
1. 交换 A / B 接线 2. 调整磁铁居中 |
| 高速时丢脉冲 | 1. 滤波器截止频率过低 2. 中断优先级不够 |
1. 减小 RC 值 2. 提升中断优先级 |
| 低速时计数跳变 | 1. 电源噪声大 2. 磁铁剩磁不足 |
1. 增加 LC 滤波 2. 更换 N52 钕磁铁 |
电源噪声处理
- 在编码器供电端并联 100μF 电解电容 +100nF 陶瓷电容
- 使用 LDO 而非开关电源供电
- 对于长线传输,采用 RS422 差分传输
温度补偿
在 -20℃以下时:
- 降低采样频率(延长滤波器时间)
- 增加霍尔元件偏置电压(通过 DAC 调节)
- 采用温度查表法补偿转速计算系数
完整代码示例
基于 STM32CubeIDE 的 HAL 库实现:
/**
* @brief 编码器初始化
* @param htim: 定时器句柄(需配置为 Encoder Mode)* @retval None
*/
void Encoder_Init(TIM_HandleTypeDef *htim) {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;
// 相同配置复制到 IC2...
HAL_TIM_Encoder_Init(htim, &sConfig);
HAL_TIM_Encoder_Start(htim, TIM_CHANNEL_ALL);
}
// 通过 DMA 读取计数值
void Encoder_StartDMA(TIM_HandleTypeDef *htim, uint32_t *pData) {HAL_TIM_Encoder_Start_DMA(htim, TIM_CHANNEL_1, pData, 1);
}
延伸思考
多编码器系统
- 使用 STM32 的多个定时器(如 TIM1+TIM8)
- 通过外部中断 +GPIO 扩展(需要软件解码)
- 专用芯片方案(如 LS7366R)
FOC 控制特殊处理
在磁场定向控制中需注意:
- 机械角度与电角度的转换:
电角度 = (机械角度 × 极对数) % 360 - 换向时刻增加±5°的软件补偿
- 采用滑模观测器补偿低速非线性误差
正文完
