CRC算法原理

您所在的位置:网站首页 crc校验生成多项式发送数据 CRC算法原理

CRC算法原理

2024-07-14 09:13| 来源: 网络整理| 查看: 265

一、    通讯校检

    在一个p位二进制数据序列之后附加一个r位二进制校检码,构成一个总长为p+r的二进制序列。附加在数据序列之后的这个校检码与p位二进制序列之间存在一个特定的关系,如果因干扰等原因使得数据序列中的一些位发生错误,这种特性的关系就会破坏。因此,可以通过检查该关系,实现对接收到的数据正确性的检验。

根据校检码与p位二进制序列之间的关系,可以将通讯校检方式分为:

a. 奇偶校检:每个字节的校检码与该字节(包括校检码)中1的个数对应;

b.  累加和校检:每个数据包的校检码为该数据包中所有数据忽略进位的累加和;

c.  CRC-xx校检:每个二进制序列的校检码为该序列与所选择的GF(2)多项式模2除法的余数。

奇偶校验检测错误概率大约为50%,简单但传输效率低。奇偶校验多用于低速度数据通讯,如RS232。

累加和校验检测错误概率大概为1/256,实现简单,也被广泛的采用。

CRC校检,只要选择的除数GF(2)多项式位数足够多,检测错误的概率几乎不存在。

二、    CRC算法背景

1.  几个基本的概念

1)  帧检测序列FCS(Frame CheckSequence):为进行差错检验而添加的冗余码。

2)  多项式模2除法:不考虑进位、错位的二进制加减法;

3)  生成多项式:当进行CRC检验时,发送方和接受方事先约定一个除数,即生成多项式G(x),常用的CRC码的生成多项式为:

CRC8=X8+X5+X4+1

CRC-CCITT=X16+X12+X5+1

CRC16=X16+X15+X5+1

CRC12=X12+X11+X3+X2+1

CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+1

每一个生成二项式与一个二进制序列对应,如CC8对应的二进制序列为:100110001。

2.  CRC校检码的计算

设信息字段为K位,校验字段为R位,则码字长度为N(N=K+R)。设双方事先约定了一个R次多项式g(x),则CRC码:

V(x)=A(x)g(x)=xRm(x)+r(x)

其中:   m(x)为K次信息多项式, r(x)为R-1次校验多项式。

这里r(x)对应的代码即为冗余码,加在原信息字段后即形成CRC码。

r(x)的计算方法为:在K位信息字段的后面添加R个0,再除以g(x)对应的代码序列,得到的余数即为r(x)对应的代码(应为R-1位;若不足,而在高位补0)。

计算示例:

设需要发送的信息为M = 1010001101,产生多项式对应的代码为P = 110101,R=5。在M后加5个0,然后对P做模2除法运算,得余数r(x)对应的代码:01110。故实际需要发送的数据是101000110101110。

当接收方收到数据后,用收到的数据对P(事先约定的)进行模2除法,若余数为0,则认为数据传输无差错;若余数不为0,则认为数据传输出现了错误,由于不知道错误发生在什么地方,因而不能进行自动纠正,一般的做法是丢弃接收的数据。

3. 数学推理

    设欲传输的信息有K位,如下图所示,首先将欲传输的数据序列m(x)乘以 XR , 其中R为g(x)的最高次冥。将得到的多项式XR m(x)除以约定的多项式g(x),忽略除法结果的“商”,取出其余数,并与XRm(x)相加,形成K+R位的发送序列,即:m’(x) = XRm(x) +r(x)。

CRC编码过程如下:

设待校验的信息码有k位,即:m = (mk-1、mk-2、mk-3……m1、m0), 多项式m(x)可表示为

m(x) = mk-1xk-1+ mk-2xk-2 +……m1x1+ m0x0   --------式(1)

用多项式g(x)的最高次幂R对应的XR 乘以m(x),将得到式(2)

XR m(x) = mk-1xk+R-1+mk-2xk+R-2 +……m1x1+R+ m0x0+R -- 式(2)

将XR m(x) 模2除以g(x),得到多项式商为A(x),余数为r(x),即:

A(x)g(x) = XR m(x) +r(x) -----------------------------式(3)

余数多项式r(x)可表示为

r(x) = rR-1xR-1+rR-2xR-2 +……r1x1+ r0x0 -------------式(4)

将式(2)和式(4)代入式(3)得

A(x)g(x) = mk-1xk+R-1+mk-2xk+R-2 +……m1x1+R+ m0x0+R  + rR-1xR-1+rR-2xR-2 +……r1x1+ r0x0   -----------------------式(5)

式(5)对应的码组为K+R位,即:

N = (mk-1+ mk-2 +……m1+ m0  + rR-1+rR-2 +……r1+ r0)-式(6)

从M到N就是CRC的编码过程mk-1+ mk-2 +……m1+ m0  为k位信息码;rR-1+ rR-2 +……r1+ r0为R位校验码。

   在信息接收端,将接受到的K+R位码除以相同的多项式g(x),根据式(3)所产生的余数为0,则接受到的数据信息正确无误,否则则认为信息在传输过程中产生的误码。

    根据式(1)~式(6),CRC编码必须进行模2除运算,CRC的校验位就是模2除得到的余数,如果余数用寄存器的存数表示,模2除用异或门表示,那么通用的CRC串行电路就可以同下图所示的电路来实现。

4.  “余数初始值”和“结果异或值”

“余数初始值”就是在计算CRC值的开始,给CRC寄存器一个初始值。“结果异或值”是在其余计算完成后将CRC寄存器的值在与这个值进行一下异或操作作为最后的校验值。

三、    CRC的参数模型

CRC32 的参数模型是:Name : "CRC-32"Width : 32Poly : 04C11DB7Init : FFFFFFFFRefIn : TrueRefOut : TrueXorOut : FFFFFFFFCheck : CBF43926

NAME名称WIDTH宽度, 即 CRC 比特数POLY   生成项的简写。以 16 进制表示, 即是 0x04C11DB7。 忽略了最高位的"1",即完整的生成项是0x104C11DB7。   重要的一点是,这是“未颠倒”的生成项! 前面说过,“颠倒的” 生成项是 0xEDB88320。INIT   这是算法开始时寄存器的初始化预置值,十六进制表示。这个值可以直接赋值给“直驱查表法” 算法中的寄存器, 作为寄存器的初始值!REFIN   这个值是真 TRUE 或假 FALSE。如果这个值是 FALSE, 表示待测数据的每个字节都不用“颠倒”, 即 BIT7 仍是作为最高位, BIT0作为最低位。  如果这个值是 TRUE,表示待测数据的每个字节都要先“颠倒”, 即 BIT7 作为最低位, BIT0作为最高位。REFOUT   这个值是真 TRUE 或假 FALSE。如果这个值是 FALSE, 表示计算结束后, 寄存器中的值直接进入 XOROUT 处理即可。如果这个值是 TRUE, 表示计算结束后, 寄存器中的值要先“颠倒”, 再进入 XOROUT 处理。注意,这是将整个寄存器的值颠倒, 因为寄存器的各个字节合起来表达了一个值, 如果只是对各个字节各自颠倒, 那结果值就错误了。XOROUT   这是 W 位长的 16 进制数值。这个值与经REFOUT 后的寄存器的值相 XOR, 得到的值就是最终正式的 CRC 值!CHECK这不是定义值的一部分,这只是字串 "123456789"用这个 CRC 参数模型计算后得到的 CRC 值, 作为参考。   我们发现, CRC32 模型的 Init=0xFFFFFFFF, 就是说寄存器要用 0xFFFFFFFF 进行初始化,而不是 0。为什么? 因为待测数据的内容和长度是随机的, 如果寄存器初始值为 0,那么, 待测字节是 1 字节的0x00, 与待测字节是 N 字节的 0x00, 计算出来的CRC32 值都是 0, 那 CRC 值就没有意义了!所以寄存器用0xFFFFFFFF 进行初始化, 就可以避免这个问题了!RefIn=True,表示输入数据的每个字节需要“颠倒”! 为什么要“颠倒”, 因为很多硬件在发送时是先发送最低位 LSB 的! 比如 UART 等。    字节顺序不用颠倒, 只是每个字节内部的比特进行颠倒。例如待测的字串是"1234",这时也是一样先处理"1",再处理"2",一直到处理"4"。处理字符"1"时, 它是 0x31, 即 0011 0001, 需要先将它颠倒, 变成低位在前, 即 1000 1100,即 0x8C, 再进行处理。

也就是说, 待处理的数据是0x31 32 33 34, 颠倒后就变成 0x8C 4C CC 2C, 再进行 CRC 计算。RefOut=True, 表示计算完成后, 要将寄存器中的值再颠倒。注意, 这是将整个寄存器的值颠倒, 即如果寄存器中的值是 0x31 32 33 34, 颠倒后就变成 0x2C CC 4C 8C!XorOut=FFFFFFFF, 表示还需要将结果值与 0xffffffff 进行 XOR,这样就得到最终的 CRC32 值了!

不同的通讯方式采用不同的CRC模型,更多CRC模型:

http://reveng.sourceforge.net/crc-catalogue/

常见的三种CRC 标准用到个各个参数如下表。

四、    CRC算法的编程实现

1.  直接计算法

假设有一个4 bits的寄存器,通过反复的移位和进行CRC的除法,最终该寄存器中的值就是我们所要求的余数。

最最简单的算法:

把register中的值置0.

把原始的数据后添加w个0.

While (还有剩余没有处理的数据)

Begin

把register中的值左移一位,读入一个新的数据并置于register最低位的位置。

If (如果上一步的左移操作中的移出的一位是1)

register = register XOR Poly.

End

/****************************************************************

* 函数名             : CalcCrcDirectly

* 函数描述       : 直接计算法计算CRC-32校验码

* 输入参数     : data-待计算数据块的首地址

               size-待计算数据块的32字数量                   

* 输出结果     : 无

* 返回值       : 无

****************************************************************/

u32 CalcCrcDirectly (u32* data, u32size)

{

   u32 i,j,temp,crc = 0xFFFFFFFF;

   for(i=0; i



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3