3. 常见CRC标准:CRC-8, CRC-16, CRC-32, CRC-CCITT

CRC 标准多了去了。你打开个芯片手册,光校验方式就能列七八种。说白了,不同标准就是不同多项式、不同初始值、不同输出异或的组合。选哪个?看你的通信场景和性能要求。

我做了十几年通信诊断,见过不少工程师随便挑个CRC标准就往上怼。结果呢?CRC 误判率高、或者计算太慢拖累吞吐。今天我把最常见的几个标准拆开讲,附带我自己踩过的坑。

3.1 标准速查表

先给你一个总表,心里有个底。后面再逐个细聊。

标准名称位宽常用多项式主要应用我的选择建议
CRC-88 位0x07(x⁸ + x² + x + 1)小数据块、传感器、1-Wire嵌入式内存紧张时首选
CRC-1616 位0x8005(x¹⁶ + x¹⁵ + x² + 1)Modbus、USB、PPP工业通信首推
CRC-3232 位0x04C11DB7(标准以太网)以太网、ZIP、文件校验大包传输,别犹豫
CRC-CCITT16 位0x1021(x¹⁶ + x¹² + x⁵ + 1)XMODEM、蓝牙、老旧协议兼容旧系统时的选择

注:多项式通常用倒序表示(比如 0x8005 实际是 0xA001 反转)。你算 CRC 时一定要和协议文档里的多项式表对上,否则全是错。

3.2 CRC-8:轻量级选手

CRC-8 只有 8 位。说白了,它占用资源最少,8 位微控制器都能轻松跑。

我在做无线传感器节点时用过它。电池供电,MCU 主频只有 16 MHz,每次发 20 个字节以内。CRC-8 误判率大约 1/256,够用了。但千万别拿它保护超过 256 字节的包——碰撞概率会飙高。

参数一览:

  • 多项式:0x07(标准),也有 0x9B(自动校验)
  • 初始值:0x00
  • 输出异或:0x00
  • 典型应用:1-Wire 协议、SMBus

3.3 CRC-16 双雄:标准 16 与 CCITT

CRC-16 有两个常见变体,你肯定碰到过。一个叫 CRC-16-IBM(0x8005),一个叫 CRC-16-CCITT(0x1021)。

我记得有一次排查 Modbus 通信失败,现场说“CRC 算出来不对”。我查了三天才发现——对端用的是 CCITT,我这头写了 IBM 标准。两个多项式不同,算出来当然驴唇不对马嘴。后来我在代码里统一用可配置的多项式表,再没出过这种低级错误。

特性CRC-16-IBMCRC-16-CCITT
多项式(标准)0x80050x1021
初始值0x00000x0000(或 0xFFFF)
输出异或0x00000x0000
常用领域Modbus RTU、USBXMODEM、蓝牙
误判率(16 位)约 1/65536约 1/65536

注意:CCITT 还有另一种变体用 0xFFFF 作为初始值。如果发现你的 CRC 计算结果总差固定值,多半是初始值没对上。

3.4 CRC-32:重型武器

CRC-32 是业界标杆。以太网、ZIP 文件、PNG 图片……几乎处处都有它。多项式 0x04C11DB7,32 位空间,误判率低至 1/4.3×10⁹。你想想看,现在网卡每天收发几百兆数据,靠的就是它。

我在调试某个电信设备的 VLAN 转发问题时,切出原始报文自己算 CRC。用 Wireshark 标了 CRC-32,核对多项式发现没问题。结果发现是硬件校验 enable 和 disable 逻辑反了……嗯,这是另一个故事了。

CRC-32 标准参数:

多项式:0x04C11DB7(正向)
初始值:0xFFFFFFFF
输出异或:0xFFFFFFFF
字节序:小端(LSB first)

3.5 核心参数对比表

挑选 CRC 标准时,我建议你盯着这四个参数看:多项式、宽度、初始值、输出异或。你只要把参数表按下面格式写清楚,移植起来非常简单。

标准宽度多项式(十六进制)初始值输出异或典型 poly(反转后)
CRC-880x070x000x000xE0
CRC-16-IBM160x80050x00000x00000xA001
CRC-16-CCITT160x10210x00000x00000x8408
CRC-32320x04C11DB70xFFFFFFFF0xFFFFFFFF0xEDB88320

一项个人小技巧:我习惯把多项式表放在 ROM 里预计算好,然后直接查表算 CRC。512 字节的表,速度比逐位计算快几十倍。特别是 CRC-32,没事别用逐位法——慢到崩溃。

3.6 选型思路与避坑

给你一个简单的判定树,帮我选了好多年不出错:

  • 包长 ≤ 64 字节、MCU 资源极少 → CRC-8
  • 工业总线、Modbus、串口通信 → CRC-16-IBM(0x8005)
  • 需要兼容老协议(XMODEM、蓝牙) → CRC-16-CCITT
  • 网络传输、文件校验、大包 → CRC-32

避坑指南——我曾经犯过的错:

  • 我曾经直接抄网上别人写的 CRC 表,结果多项式表是反转前还是反转后没分清。算出来的 CRC 永远和别人对不上。解决方案:先找个已知 test vector 验证。比如输入 "123456789" 看输出是不是标准值。
  • 我曾经用 CRC-32 保护一个只有 4 字节的短包。误判率反而比 CRC-16 还差?因为 32 位多项式用 4 字节数据算出来,有效检错范围根本发挥不出来。短包用小宽度就行了。
  • 注意端序问题。很多通信协议用 LSB first(小端),但有些嵌入式内部寄存器是 MSB first。如果你发现 CRC 一半对一半错,先检查字节序。

3.7 CRC 标准关系图

下面这张图帮你理清常见标准之间的层级。注意:不同标准共享相同的数学原理,只是参数不同。

常见 CRC 标准关系图 CRC 校验核心:多项式除法 8 位宽 16 位宽 32 位宽 CRC-8 (0x07) CRC-16-IBM CRC-16-CCITT CRC-32 (0x04C11DB7) 典型应用场景 • 传感器、1-Wire • Modbus、USB、PPP • XMODEM、蓝牙 • 以太网、ZIP、文件校验 注:小数据量用窄宽度,大包/高可靠性用 CRC-32

3.8 小结

选 CRC 标准,别盲目追求位宽大。我反而建议你根据数据包长度和平台资源先列三个候选,再用测试向量跑一遍。很多时候 CRC-16 就能满足需求,没必要上 CRC-32 拖累计算。