文章转自 循环冗余校验(CRC)算法入门引导 - Ivan 的专栏 - 博客频道 - CSDN.NET
web
http://blog.csdn.net/liyuanbhu/article/details/7882789算法
1、原理部分编程
CRC 算法的基本思想是将传输的数据当作一个位数很长的数,将这个数除以另外一个数,获得的余数做为校验数据附加到原数据后面。除法采用正常的多项式乘除法,而加减法都采用模2运算。模2运算就是结果除以2后取余数,如3 mod 2 = 1,在计算机中就是异或运算:app
例如:ide
要传输的数据为:1101011011函数
除数设为:10011oop
在计算前先将原始数据后面填上4个0:11010110110000,之因此要补0,补0的个数就是获得的余数位数。大数据
采用了模2的加减法后,不须要考虑借位的问题。最后获得的余数就是CRC 校验字。为了进行CRC运算,也就是这种特殊的除法运算,必需要指定个被除数,在CRC算法中,这个被除数有一个专有名称叫作“生成多项式”。文献中提到的生成多项式常常会说到多项式的位宽(Width,简记为W),这个位宽不是多项式对应的二进制数的位数,而是位数减1。好比CRC8中用到的位宽为8的生成多项式,其实对应得二进制数有九位:100110001。ui
2、编程实现编码
假设咱们的生成多项式为:100110001(简记为0x31),也就是CRC-8
则计算步骤以下:
(1) 将CRC寄存器(8-bits,比生成多项式少1bit)赋初值0
(2) 在待传输信息流后面加入8个0
(3) While (数据未处理完)
(4) Begin
(5) If (CRC寄存器首位是1)
(6) reg = reg XOR 0x31
(7) CRC寄存器左移一位,读入一个新的数据于CRC寄存器的0 bit的位置。
(8) End
(9) CRC寄存器就是咱们所要求的余数。
实际上,真正的CRC 计算一般与上面描述的还有些出入。这是由于这种最基本的CRC除法有个很明显的缺陷,就是数据流的开头添加一些0并不影响最后校验字的结果。所以真正应用的CRC 算法基本都在原始的CRC算法的基础上作了些小的改动。
所谓的改动,也就是增长了两个概念,第一个是“余数初始值”,第二个是“结果异或值”。
所谓的“余数初始值”就是在计算CRC值的开始,给CRC寄存器一个初始值。“结果异或值”是在其他计算完成后将CRC寄存器的值在与这个值进行一下异或操做做为最后的校验值。
常见的三种CRC 标准用到个各个参数以下表。
|
CCITT |
CRC16 |
CRC32 |
校验和位宽W |
16 |
16 |
32 |
生成多项式 |
x16+x12+x5+1 |
x16+x15+x2+1 |
x32+x26+x23+x22+x16+ x12+x11+x10+x8+x7+x5+ x4+x2+x1+1 |
除数(多项式) |
0x1021 |
0x8005 |
0x04C11DB7 |
余数初始值 |
0xFFFF |
0x0000 |
0xFFFFFFFF |
结果异或值 |
0x0000 |
0x0000 |
0xFFFFFFFF |
加入这些变形后,常见的算法描述形式就成了这个样子了:
(1) 设置CRC寄存器,并给其赋值为“余数初始值”。
while(数据未处理完)
begin(8_bit)
(2) 将数据的第一个8-bit字符与CRC寄存器进行异或,并把结果存入CRC寄存器。
(3) CRC寄存器向右移一位,MSB补零,移出并检查LSB。
(4) 若是LSB为0,重复第三步;若LSB为1,CRC寄存器与0x31相异或。
(5) 重复第3与第4步直到8次移位所有完成。此时一个8-bit数据处理完毕。
end(8-bit)
(6) 重复第2至第5步直到全部数据所有处理完成。
(7) 最终CRC寄存器的内容与“结果异或值”进行或非操做后即为CRC值。
示例性的C代码以下所示,由于效率很低,项目中如对计算时间有要求应该避免采用这样的代码。这个代码有一个crc的参数,能够将上次计算的crc结果传入函数中做为此次计算的初始值,这对大数据块的CRC计算是颇有用的,不须要一次将全部数据读入内存,而是读一部分算一次,全读完后就计算完了。这对内存受限系统仍是颇有用的。
上面的算法对数据流逐位进行计算,效率很低。实际上仔细分析CRC计算的数学性质后咱们能够多位多位计算,最经常使用的是一种按字节查表的快速算法。该算法基于这样一个事实:计算本字节后的CRC码,等于上一字节余式CRC码的低8位左移8位,加上上一字节CRC右移 8位和本字节之和后所求得的CRC码。若是咱们把8位二进制序列数的CRC(共256个)所有计算出来,放在一个表里,编码时只要从表中查找对应的值进行处理便可。
按照这个方法,能够有以下的代码(这个代码来自Micbael Barr的书“Programming Embedded Systems in C and C++” ):
上面代码中crcInit() 函数用来计算crcTable,所以在调用 crcCompute 前必须先调用 crcInit()。