4、绝对式编码器原理:单圈与多圈、SPI通信协议、数据帧解析、CRC校验
绝对式编码器,说白了就是「一上电就知道位置」的传感器。增量式编码器需要你转一圈去找零位,绝对式不用。这一点在FOC控制里太重要了——电机一启动,转子在哪儿,我立刻就知道,不需要「找零」这个过程。
我个人习惯把绝对式编码器分成两类:单圈和多圈。咱们先把这个概念理清楚。
4.1 单圈 vs 多圈:你到底需要多少圈?
单圈绝对式编码器,顾名思义,只能告诉你「在这一圈里的位置」。比如一个12位的单圈编码器,一圈有4096个位置。但如果你让电机转了两圈,它分不清现在是第二圈还是第一圈——因为位置值又回到0了。
多圈编码器就不一样了。它内部多了一个「圈数计数器」,可以记录你转了多少圈。比如12位单圈 + 12位多圈,总共24位数据,能记录4096圈内的绝对位置。
我在项目里遇到过一个问题:一个机械臂关节用了单圈编码器,每次上电后必须回零。后来换成多圈的,上电直接干活,省了回零这一步。你想想看,如果你的系统不允许「上电找零」(比如某些医疗设备),多圈就是刚需。
| 类型 | 数据范围 | 上电行为 | 典型应用 |
|---|---|---|---|
| 单圈绝对式 | 0 ~ (2^N - 1) | 直接读取位置 | 伺服电机、云台 |
| 多圈绝对式 | 圈数 × 单圈分辨率 | 直接读取位置 | 机械臂、AGV |
关键点:多圈编码器内部通常靠「齿轮传动」或「磁计数」来记录圈数。但注意,多圈计数是有上限的——超过最大圈数,计数器会溢出。选型时一定要算清楚你的应用会不会超圈。
4.2 SPI通信协议:绝对式编码器的「语言」
大多数绝对式编码器都用SPI通信。为什么?因为SPI是全双工、速度快、时序简单。你想想看,编码器要实时反馈位置,SPI的几MHz时钟完全够用。
SPI有四根线:SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。对于编码器来说,MCU是主机,编码器是从机。主机发一个命令帧,编码器回一个数据帧。
我常用的SPI时序是这样的:
// 伪代码:读取绝对式编码器位置
uint16_t read_encoder_position(void) {
uint16_t rx_data = 0;
// 拉低CS,开始通信
CS_LOW();
// 发送读取命令(比如0xFFFF),同时接收数据
rx_data = spi_transfer16(0xFFFF);
// 拉高CS,结束通信
CS_HIGH();
return rx_data;
}
嗯,这里要注意:不同厂家的编码器,命令格式不一样。有的需要先发一个「读位置」指令,有的直接发任意数据就能读到位置。我建议你仔细看数据手册,别想当然。
我的经验:SPI时钟频率别拉太高。虽然编码器标称能跑10MHz,但实际线缆长了、干扰大了,容易丢数据。我一般用2~5MHz,稳定第一。
4.3 数据帧解析:从原始数据到角度值
SPI读回来的是一串二进制数,你得把它解析成角度。不同编码器的数据帧格式不同,但大体结构类似。
以某款14位单圈绝对式编码器为例,它的数据帧是16位:
| 位 | 15 | 14 | 13 | 12 ~ 1 | 0 |
|---|---|---|---|---|---|
| 含义 | 奇偶校验 | 数据有效标志 | 错误标志 | 位置数据(12位) | 保留 |
解析步骤很简单:
- 检查错误标志位,如果置位,说明编码器内部故障,数据不可用。
- 检查数据有效标志,确保数据是新鲜的。
- 提取位置数据位(bit 12 ~ bit 1),得到一个0~4095的值。
- 换算成角度:角度 = (位置值 / 4096) × 360°。
// 解析14位编码器数据
float parse_encoder_frame(uint16_t raw) {
// 检查错误标志 (bit 13)
if (raw & (1 << 13)) {
// 编码器报错,返回上次有效值或报错
return last_valid_angle;
}
// 提取位置数据 (bit 12 ~ bit 1)
uint16_t position = (raw >> 1) & 0x0FFF;
// 换算成角度
float angle = (float)position / 4096.0f * 360.0f;
last_valid_angle = angle;
return angle;
}
我曾经踩过的坑:有一款编码器的数据位是MSB对齐的,另一款是LSB对齐的。没仔细看手册,直接移位,结果角度乱跳。后来用逻辑分析仪抓波形,才发现问题。记住:先看数据手册的位定义图,再写代码。
4.4 CRC校验:数据可靠性的最后一道防线
工业现场干扰多,SPI通信偶尔会出错。CRC校验就是用来检测数据有没有被「篡改」的。
很多绝对式编码器会在数据帧末尾附加一个CRC校验码。MCU收到数据后,用同样的多项式算一遍CRC,对比一下。如果一致,数据可信;不一致,扔掉重读。
常见的CRC多项式有:
- CRC-8:多项式 0x31(x^8 + x^5 + x^4 + 1),常用于短数据帧。
- CRC-16:多项式 0x8005(x^16 + x^15 + x^2 + 1),用于长数据帧。
我一般用查表法实现CRC,速度快,适合实时控制:
// CRC-8 查表法实现
static const uint8_t crc8_table[256] = {
0x00, 0x31, 0x62, 0x53, 0xC4, 0xF5, 0xA6, 0x97,
// ... 省略中间数据,实际使用时需要完整表
};
uint8_t calc_crc8(uint8_t *data, uint8_t len) {
uint8_t crc = 0x00;
for (uint8_t i = 0; i < len; i++) {
crc = crc8_table[crc ^ data[i]];
}
return crc;
}
// 使用示例
uint8_t check_encoder_frame(uint16_t raw) {
uint8_t *bytes = (uint8_t *)&raw;
uint8_t received_crc = bytes[1] & 0x0F; // 假设CRC在低4位
uint8_t calc_crc = calc_crc8(bytes, 1); // 只对高字节计算
return (received_crc == calc_crc);
}
我的建议:CRC校验虽然好,但别过度依赖。如果连续3次CRC校验失败,我建议你直接报错,而不是一直重试。因为大概率是硬件连接有问题,重试也白搭。
4.5 知识体系总览
下面这张图把绝对式编码器的核心知识点串起来了。你可以把它当作一个「速查地图」:
这张图把单圈/多圈、SPI通信、数据帧解析、CRC校验和应用串在了一起。你写代码的时候,可以对照这张图,看看自己卡在哪一步。