CRC校验.docx
《CRC校验.docx》由会员分享,可在线阅读,更多相关《CRC校验.docx(10页珍藏版)》请在冰豆网上搜索。
CRC校验
CRC校验
CRC即循环冗余校验码(CyclicRedundancyCheck):
是数据通信领域中最常用的一种差错校验码,其特征是信息字段和校验字段的长度可以任意选定。
生成CRC码的基本原理:
任意一个由二进制位串组成的代码都可以和一个系数仅为‘0’和‘1’取值的多项式一一对应。
例如:
代码1010111对应的多项式为x6+x4+x2+x+1,而多项式为x5+x3+x2+x+1对应的代码101111。
CRC码集选择的原则:
若设码字长度为N,信息字段为K位,校验字段为R位(N=K+R),则对于CRC码集中的任一码字,存在且仅存在一个R次多项式g(x),使得
V(x)=A(x)g(x)=xRm(x)+r(x);
其中:
m(x)为K-1次信息多项式,r(x)为R-1次校验多项式,
g(x)称为生成多项式:
g(x)=g0+g1x1+g2x2+...+g(R-1)x(R-1)+gRxR
发送方通过指定的g(x)产生CRC码字,接收方则通过该g(x)来验证收到的CRC码字。
CRC校验码软件生成方法:
借助于多项式除法,其余数为校验字段。
例如:
信息字段代码为:
1011001;对应m(x)=x6+x4+x3+1
假设生成多项式为:
g(x)=x4+x3+1;则对应g(x)的代码为:
11001
x4m(x)=x10+x8+x7+x4对应的代码记为:
10110010000;
采用多项式除法:
得余数为:
1010(即校验字段为:
1010)
发送方:
发出的传输字段为:
10110011010
信息字段校验字段
接收方:
使用相同的生成码进行校验:
接收到的字段/生成码(二进制除法)
如果能够除尽,则正确,
给出余数(1010)的计算步骤:
除法没有数学上的含义,而是采用计算机的模二除法,即,除数和被除数做异或运算。
进行异或运算时除数和被除数最高位对齐,按位异或,左移一位,最高位是1继续异或,为0则继续左移。
10110010000
-11001
--------------------------
=01111010000
1111010000
-11001
-------------------------
=0011110000
11110000
-11001
--------------------------
=00111000
111000
-11001
-------------------
=001010
利用CRC进行检错的过程可简单描述为:
在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在原始信息后边,构成一个新的二进制码序列数共k+r位,然后发送出去。
在接收端,根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。
这个规则,在差错控制理论中称为“生成多项式”。
在代数编码理论中,将一个码组表示为一个多项式,码组中各码元当作多项式的系数。
例如1100101表示为1·x6+1·x5+0·x4+0·x3+1·x2+0·x+1,即x6+x5+x2+1。
设编码前的原始信息多项式为P(x),P(x)的最高幂次加1等于k;生成多项式为G(x),G(x)的最高幂次等于r;CRC多项式为R(x);编码后的带CRC的信息多项式为T(x)。
发送方编码方法:
将P(x)乘以xr(即对应的二进制码序列左移r位),再除以G(x),所得余式即为R(x)。
用公式表示为T(x)=xrP(x)+R(x)
接收方解码方法:
将T(x)除以G(x),如果余数为0,则说明传输中无错误发生,否则说明传输有误。
举例来说,设信息码为1100,生成多项式为1011,即P(x)=x3+x2,G(x)=x3+x+1,计算CRC的过程为
xrP(x)x3(x3+x2)x6+x5x--------=----------=--------=(x3+x2+x)+--------G(x)x3+x+1x3+x+1x3+x+1即R(x)=x。
注意到G(x)最高幂次r=3,得出CRC为010。
如果用竖式除法,计算过程为
1110-------1011/1100000(1100左移3位)1011----11101011-----10101011-----00100000----010因此,T(x)=(x6+x5)+(x)=x6+x5+x,即1100000+010=1100010
如果传输无误,
T(x)x6+x5+x------=---------=x3+x2+x,G(x)x3+x+1无余式。
回头看一下上面的竖式除法,如果被除数是1100010,显然在商第三个1时,就能除尽。
上述推算过程,有助于我们理解CRC的概念。
但直接编程来实现上面的算法,不仅繁琐,效率也不高。
实际上在工程中不会直接这样去计算和验证CRC。
发送方:
发出的传输字段为:
1011001 1010
信息字段 校验字段
看一下下面的生成码、解码的过程:
发送的数据为“12”这是字符对应的16进制为3132H
接收方:
使用相同的生成码进行校验:
接收到的字段/生成码(二进制除法)如果能够除尽,则正确)。
下面的这个程序就是获取一块数据(以字节为单位)的CRC校验码,将所有的数据视作连接在一起的0、1,当然实际存储也是这样,我们计算是从第一个字节的第7位到最后一个字节的第0位。
如何理解这一长串的0、1对生成码的除法是用程序实现的关键。
这里的加减为异或,这一串0、1是左移16位的数据,所以,一直算到序列的最后一位也是可以被除的。
除法思想借鉴如下:
当按位计算CRC时,例如计算二进制序列为1001101010101111时,将二进制序列数左移16位,即为1001101010101111(0000000000000000),实际上该二进制序列可拆分为1000000000000000(0000000000000000)+000000000000000(0000000000000000)+00000000000000(0000000000000000)+1000000000000(0000000000000000)+……现在开始分析运算:
<1>对第一个二进制分序列求余数,竖式除法即为0x10000^0x11021运算,后面的0位保留;<2>接着对第二个二进制分序列求余数,将第一步运算的余数*2后再和第二个二进制分序列一起对0x11021求余,这一步理解应该没什么问题。
如果该分序列为0,无需计算。
在按个10进制的数说明一下例如54321除以10,我们可以50000%10*10+4000%10*10+300%10*10........注意我们只是为了说明上面的思想,这里的加为异或。
uintcal_crc(uchar*ptr,ucharlen){//len为数据的字节长度
{
unsignedintcrc=0;
unsignedchari;
unsignedchar*ptr=test;
while(len--)
{
for(i=0x80;i!
=0;i=i>>1)
{
if((crc&0x8000)!
=0)
{
crc=crc<<1;
crc=crc^0x1021;
}
else
{
crc=crc<<1;
}
if((*ptr&i)!
=0)
{
crc=crc^0x1021;
}
}
ptr++;
}
return(crc);
}
unsignedcharcrc8(unsignedchar*ptr,unsignedcharlen)
{
unsignedchari;
unsignedcharcrc=0;
while(len--!
=0)
{
for(i=1;i!
=0;i*=2)
{
if((crc&1)!
=0){crc/=2;crc^=0x8C;}
elsecrc/=2;
if((*ptr&i)!
=0)crc^=0x8C;
}
ptr++;
}
return(crc);
}
CRC校验
随着数据采集系统的功能日益强大,以及微型计算机的普及,在现代工业中,利用微机进行数据通讯的工业控制应用得也越来越广泛。
特别是在大规模高精度数据采集系统中,对数据进行分析和计算将占用很大一部分单片机的资源,可以将采集到的数据通过串行通讯方式传送给PC机,由PC机来完成数据的处理工作。
但是由于传输距离、现场状况等诸多可能出现的因素的影响,计算机与受控设备之间的通讯数据常会发生无法预测的错误。
为了防止错误所带来的影响,在数据的接收端必须进行差错校验。
虽然差错校验也可以完全由硬件来承担,但由于单片机和PC都具有很强的软件编程能力,这就为实施软件的差错校验提供了前提条件,而软件的差错校验有经济实用并且不增加硬件开销的优点。
本文就是基于多功能应变测试系统而编写的主机和单片机之间的RS-485通讯系统,介绍了一种软件差错校验方案循环冗余差错校验法。
1CRC法的原理
传统的差错检验法有:
奇偶校验法,校验和法,行列冗余校验法等。
这些方法都是在数据后面加一定数量的冗余位同时发送出去,例如在单片机的通讯方式2和3中,TB8就可以作为奇偶校验位同数据一起发送出去,在数据的接收端通过对数据信息进行比较、判别或简单的求和运算,然后将所得和接收到的冗余位进行比较,若相等就认为数据接收正确,否则就认为数据传送过程中出现错误。
但是冗余位只能反映数据行或列的奇偶情况,所以这类检验方法对数据行或列的偶数个错误不敏感,漏判的概率很高。
因此,此种方法的可靠性就差。
循环冗余码校验英文名称为CyclicalRedundancyCheck,简称CRC。
它是利用除法及余数的原理来作错误侦测(ErrorDetecting)的。
实际应用时,发送装置计算出CRC值并随数据一同发送给接收装置,接收装置对收到的数据重新计算CRC并与收到的CRC相比较,若两个CRC值不同,则说明数据通讯出现错误。
由于这种方法取得校验码的方式具有很强的信息覆盖能力,所以它是一种效率极高的错误校验法。
错误的概率几乎为零。
在很多的仪器设备中都采用这种冗余校验的通讯规约。
根据应用环境与习惯的不同,CRC又可分为以下几种标准:
①CRC-12码;②CRC-16码;
③CRC-CCITT码;④CRC-32码。
CRC-12码通常用来传送6-bit字符串。
CRC-16及CRC-CCITT码则是用来传送8-bit字符,其中CRC-16为美国采用,而CRC-CCITT为欧洲国家所采用。
CRC-32码大都被采用在一种称为Point-to-Point的同步传输中。
2CRC校验码的生成过程
我们以最常用的CRC-16码作为例子进行说明。
冗余循环码包括2个字节,即16位二进制数。
先预置16位寄存器全部为1,再逐步把每8位的数据信息进行处理。
在进行CRC计算时只用8位数据位,起始位和停止位,如有奇偶校验位的话也包括奇偶校验位,都不参与CRC计算。
在计算CRC码时,8位数据与寄存器的数据相异或,得到的数据向低位移一位,用0填补最高位,再检查最低位。
如果最低位为1,把寄存器的内容与预置数相异或;若最低位为0,则不进行异或计算。
这个过程一直重复8次,第8次移位后,下一个8位数据再与现在寄存器中的内容相异或,这个过程和以上一样重复8次。
当所有的信息处理完后,最后寄存器中的内容即为CRC码。
这个CRC码将由发送设备跟在数据的最后一起发送。
计算CRC的步骤为:
(1)预置16位寄存器位十六进制数FFFF(即全为1)。
称此寄存器位CRC寄存器。
(2)把第一个8位数据与16位寄存器的低位相异或,将结果放于CRC寄存器中;
(3)把寄存器的内容右移一位(朝低位),用0填补最高位,检查最低位;
(4)如果最低位为0,重复第三步(再次移位);
如果最低位为1,CRC寄存器与多项式码进行异或;
(5)重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
(6)重复步骤2到5,进行下一个8位数据的处理;
(7)最后得到的CRC寄存器即为CRC码。
3CRC软件实现
/*************************************************
函数功能:
求CRC16校验值程函数
修改日期:
2006.7.4
待修改:
OK
参数:
*str指向txbuf,待发送数组;
num为报文字节数
最后计算结果为2字节数。
MODBUS传输时,CRC低位在前,crc%256求低位;
高位在后,crc/256求高位。
*************************************************/
uintcrc16(uchar*str,uintnum)//CRC计算子程序,
{
uchari;
//uintcrc;
crc=0xffff;
for(i=0;i{
arc=(str[i]^crc)&0x00ff;
crc=_irol_(crc,8); //整形循环右移指令
crc=crc&0x00ff;
crc=crc^crctable[arc];
}
return(crc);
}
/**************************************************************************
函数功能:
CRC校验程函数
修改日期:
2006.7.4
待修改:
OK
参数:
N为报文字节数,rxbuf[]为接收报文区
如果最后计算结果CRC==0,说明报文在传输过程中正确
**************************************************************************/
voidcrc_verify(ucharN)//CRC校验程序
{
uchari;
crc=0xFFFF;//modbus_crc初值
for(i=0;i<=7;i++)//CRC校验方式可以做一个子程序来处理
{
arc=(rxbuf[i]^crc)&0x00FF;//xor
crc=_irol_(crc,8);//整形循环右移指令
crc=crc&0x00FF;
crc=crc^crctable[arc];//xor
_nop_();
}
}
uintcodecrctable[]={//CRC计算用表
0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
};