第2章 CRC数学原理:多项式除法、模2运算
2.1 从一次调试经历说起
几年前我做一批QSPI Flash固件升级模块,通信偶尔丢包。加了CRC校验后丢包率降了不少,但有一个特定数据模式总报错。我排查了半天,最后发现是CRC的数学实现出了岔子——模2除法的余数没对齐,直接把错位的数据当成了有效帧。
那次之后我彻底想明白一件事:CRC的可靠性,根子在数学原理上。多项式除法和模2运算看着像纸上谈兵,但哪一步理解不到位,工程上就会踩坑。这章我们就把它彻底掰开揉碎。
2.2 模2运算:CRC的"加减乘除"
模2运算说白了就是不带进位/借位的二进制运算。你想想看,普通加法里1+1=2要进位,模2加法里1+1=0,不进位。它只在乎"异或"的结果。
| 运算类型 | 规则 | 与普通运算的区别 |
|---|---|---|
| 模2加法 | 0+0=0, 0+1=1, 1+0=1, 1+1=0 | 无进位,等价于 XOR |
| 模2减法 | 0-0=0, 0-1=1, 1-0=1, 1-1=0 | 无借位,与加法完全相同 |
| 模2乘法 | 与普通二进制乘法步骤一致 | 中间结果相加时使用模2加法 |
| 模2除法 | 用XOR逐位相减,够除就上1,不够上0 | 每一步都是异或,不比较大小 |
我个人习惯把模2运算记成"XOR全家桶"。加法是XOR,减法也是XOR,除法里的每一步还是XOR。你只要记住这一个操作,整套运算就通了。
2.3 多项式表示:二进制与代数的桥梁
为什么CRC要把二进制数写成多项式?因为多项式的"次数"天然对应了数据的位权,而多项式除法恰好能生成一个紧凑的校验余数。
映射规则极简单:二进制数的每一位,就是多项式对应次数的系数。系数只能是0或1。
| 二进制 | 多项式表示 | 说明 |
|---|---|---|
| 1011 | x³ + x + 1 | 最高位x³,最低位x⁰=1 |
| 1101 | x³ + x² + 1 | x¹项系数为0,省略 |
| 10011 | x⁴ + x + 1 | 常用的CRC-4生成多项式 |
| 1 0000 0111 | x⁸ + x² + x + 1 | CRC-8 常见多项式之一 |
我在项目中见过有人直接把多项式当整数做除法,结果余数全错。记住:多项式除法的"次数比较"代替了整数除法的"大小比较",这是关键区别。
2.4 多项式除法:CRC计算的核心
算CRC的过程,本质上就是一次多项式除法。我们拿一个具体例子走一遍。
已知:
- 原始数据:1101(多项式:x³ + x² + 1)
- 生成多项式:1011(x³ + x + 1),记为G(x),次数n=3
计算CRC的步骤:
- 原始数据左移n位(补n个0):1101 000
- 用生成多项式1011,对1101000做模2除法
- 余数就是CRC值(取n位)
除法过程如下(每一步都是XOR):
1011
________
1011 | 1101000
1011
----
1100 ← 第1次XOR结果
1011
----
1110 ← 第2次XOR结果
1011
----
101 ← 余数(3位)
余数是 101,这就是CRC-3校验值。把它附加到原始数据后面,得到编码结果:1101 101。
2.5 CRC编码完整流程
上面这个例子,其实包含了CRC编码的全部数学环节。下面这张图把整个流程串起来,你一看就明白。
流程很清晰:原始数据先左移,腾出n位空间放CRC;然后用生成多项式做模2除法,算出余数;最后把余数拼回去。接收方用同样的多项式再做一次除法,余数为0则数据无误。
2.6 工程避坑指南
数学原理搞懂了,但工程实现时还有几个细节容易翻车。我把自己踩过的坑列出来,你遇到时心里有数。
生成多项式最高位和最低位必须为1。最高位为1决定了余数的位数,最低位为1保证了能检测出奇数个错误。有些芯片手册给的多项式省略了最高位1,你补上才完整。
教科书上的CRC是"原始模2除法",但工程标准(如CRC-32)还加了初始值预设和结果异或。数学原理是基础,协议标准是变体,两者不矛盾。
前面说过,余数不足n位要补前导0。我在一个项目里忘记补0,CRC从8位变成了6位,两个错误码撞在了一起,排查了一整天才发现。
嗯,这章内容就到这。数学原理是CRC的根基,模2运算和多项式除法看似简单,但每一步都有细节。你拿纸笔手动算一次,比光看代码印象深得多。