通信校验CRC15使用过程示例
一、先明确:CAN CRC15 标准参数
- 多项式:0x4599
- 初始值:0x0000
- 输入不反转、输出不反转
- 最终异或:0x0000
- 结果只取低 15 位:
crc & 0x7FFF
二、示例数据(模拟 CAN 一段数据)
用最简单的 1 字节数据演示,方便手算:待计算数据:0x11
三、手动计算完整过程(逐行详解)
初始
crc = 0x0000
第一步:异或 + 移位
CAN CRC15 处理一个字节时:crc = crc ^ (data << 7)
0x11 << 7 = 0x880
所以:crc = 0x0000 ^ 0x880 =0x880
第二步:循环 8 次,逐位处理
规则:
- 若 crc最高位(第 15 位,0x4000)= 1→
crc = (crc << 1) ^ 0x4599 - 否则→
crc = crc << 1
当前 crc =0x880(二进制:0000100010000000)最高位 0x4000? →否
开始 8 轮:
- 第 1 次:0x880 << 1 =0x1100
- 第 2 次:0x1100 << 1 =0x2200
- 第 3 次:0x2200 << 1 =0x4400现在最高位 0x4000 = 1→ 0x4400 <<1 = 0x8800 ^ 0x4599 =0xCD99
- 第 4 次:最高位 = 1→ 0xCD99<<1=0x9B32 ^ 0x4599 =0xDECB
- 第 5 次:最高位 = 1→ 0xDECB<<1=0xBD96 ^ 0x4599 =0xF80F
- 第 6 次:最高位 = 1→ 0xF80F<<1=0xF01E ^ 0x4599 =0xB587
- 第 7 次:最高位 = 1→ 0xB587<<1=0x6B0E ^ 0x4599 =0x2E97
- 第 8 次:最高位 = 0→ 0x2E97 <<1 =0x5D2E
四、最终 CRC15
crc = 0x5D2E只取 15 位:CRC15 = 0x5D2E & 0x7FFF = 0x5D2E
五、C 代码验证(工程版)
#include <stdint.h> uint16_t CAN_CRC15(uint8_t *data, uint32_t len) { uint16_t crc = 0x0000; while (len--) { crc ^= (uint16_t)*data++ << 7; for (int i = 0; i < 8; i++) { if (crc & 0x4000) crc = (crc << 1) ^ 0x4599; else crc <<= 1; } } return crc & 0x7FFF; } // 测试 #include <stdio.h> int main() { uint8_t data[] = {0x11}; uint16_t crc = CAN_CRC15(data, 1); printf("CAN CRC15 = 0x%04X\n", crc); return 0; }运行结果:
CAN CRC15 = 0x5D2E和手算完全一致 ✅
六、这个示例在 CAN 里的真实意义
- 0x11 可以是 CAN 帧里的1 字节数据段
- 0x5D2E 就是会被放到CRC 场的校验码
- 接收方收到后,用同样算法再算一遍 → 结果一样 = 数据无错
