共计 2764 个字符,预计需要花费 7 分钟才能阅读完成。
背景痛点:为什么选择霍尔编码器?
在电机控制和位置检测领域,传统电位器或单相编码器存在明显不足:

- 电位器有机械磨损,寿命短且精度随使用下降
- 单相编码器无法判断旋转方向,应用场景受限
- 光电编码器虽然精度高,但对灰尘敏感且成本较高
AB 双相霍尔编码器的优势突显:
- 无接触式检测,理论寿命无限长
- 双相信号可精确判断方向和位置
- 成本仅为光电编码器的 1 /3~1/2
- 典型精度可达 12-14 位(4096-16384CPR)
技术核心:正交编码原理深度解析
信号特征图解
A 相: __|¯¯|__|¯¯|__|¯¯
B 相: ¯¯|__|¯¯|__|¯¯|__
↑ 每个方波周期包含 4 个可检测边沿
- A/ B 相保持 90°相位差(正交)
- 顺时针旋转时 A 相领先,逆时针时 B 相领先
4 倍频计数实现
- 检测 A 相上升沿时检查 B 相电平(计数 +1)
- 检测 A 相下降沿时检查 B 相电平(计数 +1)
- 检测 B 相上升沿时检查 A 相电平(计数 +1)
- 检测 B 相下降沿时检查 A 相电平(计数 +1)
霍尔 vs 光电编码器对比
| 特性 | 霍尔编码器 | 光电编码器 |
|---|---|---|
| 分辨率 | 中(1000-5000CPR) | 高(>10000CPR) |
| 抗污染性 | 强(IP67) | 弱(需密封) |
| 响应速度 | 快(<1μs) | 较快(10μs) |
| 温度范围 | -40~125℃ | 0~70℃ |
Arduino 实战:从接线到代码实现
硬件连接示意图
编码器 Arduino
A 相 -----> D2(中断 0)
B 相 -----> D3(中断 1)
VCC -----> 5V
GND -----> GND
完整示例代码
volatile long pulseCount = 0;
int lastEncoded = 0;
void setup() {pinMode(2, INPUT_PULLUP); // A 相
pinMode(3, INPUT_PULLUP); // B 相
attachInterrupt(0, updateEncoder, CHANGE); // D2 中断
attachInterrupt(1, updateEncoder, CHANGE); // D3 中断
Serial.begin(115200);
}
void updateEncoder() {int MSB = digitalRead(2); // A 相当前状态
int LSB = digitalRead(3); // B 相当前状态
int encoded = (MSB << 1) | LSB; // 组合成 2bit 状态
int sum = (lastEncoded << 2) | encoded; // 拼接上次状态
// 状态机判断方向(灰色码顺序)if(sum == 0b1101 || sum == 0b0100 ||
sum == 0b0010 || sum == 0b1011) pulseCount++;
if(sum == 0b1110 || sum == 0b0111 ||
sum == 0b0001 || sum == 0b1000) pulseCount--;
lastEncoded = encoded;
}
void loop() {
// 转换为角度(假设 1000 线编码器)float angle = (pulseCount % 4000) * 0.09;
Serial.print("Position:");
Serial.println(angle);
delay(100);
}
代码关键点说明:
- 使用
CHANGE中断捕获所有边沿变化 - 采用状态机消除抖动(灰色码顺序检测)
- 每转脉冲数 = 线数×4(1000 线→4000 脉冲 / 转)
工业级应用方案
EMI 防护电路设计
编码器输出 ----[10Ω]----+----[TVS DIODE]----GND
|
C
|
GND
- TVS 管选型要点:
- 钳位电压 <MCU 耐压值(如 SMBJ5.0CA)
- 响应时间 <1ns
- 结电容 <50pF
STM32 硬件编码器模式
// 使用 TIM3 的编码器接口模式
void Encoder_Init(void) {TIM_Encoder_InitTypeDef sConfig = {0};
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 65535;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
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(&htim3, &sConfig);
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
}
高频问题排查指南
计数异常排查流程
- 示波器检查 A / B 相信号质量
- 确认幅值(通常 3.3V/5V)
- 观察相位差是否稳定 90°
- 检查电源噪声
- 编码器供电建议加 LC 滤波
- 验证 MCU 中断响应时间
- 确保能捕获最高转速信号
转速与采样频率关系
最大转速(rpm) = (MCU 采样频率 × 60) / (编码器线数 × 4)
例如:
– 1000 线编码器
– STM32 中断响应频率 100kHz
– 理论最大转速 = (100000×60)/(1000×4) = 1500rpm
进阶应用:从位置检测到运动控制
PID 闭环控制实现框架
- 编码器反馈当前位置
- 计算与目标位置的偏差
- PID 控制器输出 PWM 占空比
- 驱动电机减小位置误差
ROS 集成示例
#!/usr/bin/env python
import rospy
from std_msgs.msg import Int32
class EncoderNode:
def __init__(self):
self.pub = rospy.Publisher('encoder_counts', Int32, queue_size=10)
self.count = 0
def update_encoder(self, delta):
self.count += delta
self.pub.publish(self.count)
if __name__ == '__main__':
rospy.init_node('encoder_driver')
node = EncoderNode()
# 此处接入实际硬件读取代码
rospy.spin()
经验总结
经过多个机器人项目的实践验证,AB 相霍尔编码器在满足以下条件时表现最佳:
- 信号线使用双绞线 + 屏蔽层
- 供电电压稳定(波动 <5%)
- 机械安装同心度偏差 <0.1mm
- 在高速应用时启用硬件滤波
建议开发过程中先用示波器验证信号质量,再逐步增加功能复杂度。对于首次使用者,可从 1000 线编码器开始实践,再根据实际需求升级更高分辨率型号。
正文完
