CRC校验算法Word格式.docx

上传人:b****5 文档编号:18571017 上传时间:2022-12-28 格式:DOCX 页数:8 大小:17.96KB
下载 相关 举报
CRC校验算法Word格式.docx_第1页
第1页 / 共8页
CRC校验算法Word格式.docx_第2页
第2页 / 共8页
CRC校验算法Word格式.docx_第3页
第3页 / 共8页
CRC校验算法Word格式.docx_第4页
第4页 / 共8页
CRC校验算法Word格式.docx_第5页
第5页 / 共8页
点击查看更多>>
下载资源
资源描述

CRC校验算法Word格式.docx

《CRC校验算法Word格式.docx》由会员分享,可在线阅读,更多相关《CRC校验算法Word格式.docx(8页珍藏版)》请在冰豆网上搜索。

CRC校验算法Word格式.docx

8)+B3),比如数字是0x01,0x02,0x03,那么对应的数字就是0x10203;

依次类推。

如果字节数很多,那么对应的数就非常非常大,不过幸好CRC只需要得到余数,而不需要得到商。

从上面介绍的原理我们可以大致知道CRC校验的准确率,在CRC8中出现了误码但没发现的概率是1/256,CRC16的概率是1/65536,而CRC32的概率则是1/2^32,那已经是非常小了,所以一般在数据不多的情况下用CRC16校验就可以了,而在整个文件的校验中一般用CRC32校验。

这里还有个问题,如果被除数比除数小,那么余数就是被除数本身,比如说只要传一个字节,那么它的CRC就是它自己,为避免这种情况,在做除法之前先将它移位,使它大于除数,那么移多少位呢?

这就与所选的固定除数有关了,左移位数比除数的位数少1,下面是常用标准中的除数:

CRC8:

多项式是X8+X5+X4+1,对应的数字是0x131,左移8位

CRC12:

多项式是X12+X11+X3+X2+1,对应的数字是0x180D,左移12位

CCITTCRC16:

多项式是X16+X12+X5+1,对应的数字是0x11021,左移16位

ANSICRC16:

多项式是X16+X15+X2+1,对应的数字是0x18005,左移16位

CRC32:

多项式是X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+1,对应数字是0x104C11DB7,左移32

因此,在得到字节串对应的数字后,再将数字左移M位(比如ANSI-CRC16是左移16位),就得到了被除数。

好了,现在被除数和除数都有了,那么就要开始做除法求CRC校验码了。

CRC除法的计算过程与我们笔算除法类似,首先是被除数与除数高位对齐后,被除数减去除数,得到了差,除数再与差的最高位对齐,进行减法,然后再对齐再减,直到差比除数小,这个差就是余数。

不过和普通减法有差别的是,CRC的加(减)法是不进(借)位的,比如10减01,它的结果是11,而不是借位减法得到的01,因此,实际上CRC的加法和减法所得的结果是一样的,比如10加01的结果是11,10减01的结果也是11,这其实就是异或操作。

虽然说了这么多也不一定能说清楚,我们还是看一段CRC除法求余程序吧:

/*这段程序是求数据0x880000除以0x11021的余数*/

/*这段程序其实也就是求字节0x88的CRC16校验码,因为0x88左移16位是0x880000*/

unsignedshortcrc16_div()

{

unsignedlongdata=0x880000;

unsignedlongccitt16=0x11021;

/*这是比较值,被除数与它比较看是否需要减去除数

注意,这里只需要与0x10000比较就可以了,而不需要与除数0x18005比较,这样可以少很多计算

而且余数的范围就在0-0xFFFF之间,而不是0-0x18004之间了*/

unsignedlongcmp_value=0x10000;

inti;

ccitt16<

=7;

/*左移7位,与被除数最高位对齐*/

cmp_value<

while(cmp_value>

=0x10000)/*循环直到差数比cmp_value小*/

{

if((data&

cmp_value)!

=0)/*最高位为1,则减去除数*/

data^=ccitt16;

/*做CRC的减法,就是异或操作*/

}

else/*最高位为0,不够减*/

/*不作任何操作,只执行后面的移位操作*/

/*得到了差,右移一位,与被除数下一位对齐*/

ccitt16>

>

=1;

cmp_value>

/*现在data的最低两个字节就是余数,也就是CRC校验码*/

return(data&

0xFFFF);

}

好了,现在我们已经会计算0x88的CRC校验码了,它只是对0x880000做除法运算求余数而已,不过这只是求单字节的CRC校验码,那如果有十多个字节怎么办?

我们的计算机也存不下那么大的数呀,看来我们还要对程序进行些改进,使它能对大数求除法了。

unsignedshortcrc16_div_2()

/*这段程序也是求数据0x88的CRC校验码,与上一个程序crc16_div所得结果相同*/

/*这里只需要直接传数据就可以,而不需要再事先移位*/

unsignedshortdata=0x88;

/*这里只需要2个字节0x1021,而不是0x11021,为什么不再需要最高位的1,看看代码就清楚了*/

unsignedshortccitt16=0x1021;

data<

=8;

for(i=0;

i<

8;

i++)

if(data&

0x8000)/*最高位为1,减去除数*/

/*将最高位的1移出,剩下的数与0x1021(而不是0x11021)异或,这是因为最高位的1与0x11021的最高位1异或后为0*/

else/*最高位为0,不需要减去除数*/

/*直接移位*/

returndata;

现在对单字节0x88求CRC16,我们只需要两字节short型的整数就行了,而不需要象以前必须用long型0x880000,其实不管多少字节,只用short型就能够计算它的CRC16。

下面说说怎么求多字节的样验码:

当我们求得一个字节(比如0x88)的CRC校验码后,如果这时又有一个字节(比如0x23)加入,需要求校验码,该怎么办呢?

以前得到的是0x880000除以0x11021的余数,但现在需要得到的是0x除以0x11021的余数,以前求得的校验码是不是白费了?

不是的,因为当我们得到0x880000除以0x11021的余数(这里余数是0x1080)后,需要求0x除以0x11021的余数,只要将原来的余数0x1080左移8位除以0x11021就得到了0x除以0x11021的余数(想一想为什么),再加上0x230000除以0x11021的余数。

这其实就是求0x108000+0x230000除以0x11021的余数.。

因此根据这个方法,我们就可以写出求多个字节的CRC算法:

/*这段代码是求ccitt-crc16的算法

参数:

data:

字节数据

crc:

原来数据求得的crc校验码

返回值:

数据的ccitt-crc16校验码

*/

unsignedshortcrc16_ccitt(unsignedchardata,unsignedshortcrc)

crc^=(data<

8);

/*新的数据与将原来的余数(就是crc)相加(加法就是异或操作)*/

/*求数据的CRC校验码*/

if(crc&

crc<

crc^=ccitt16;

returncrc;

/*这是个主程序,表示如何计算5个字节的CRC*/

voidmain()

unsignedshortcrc;

chardata[5]={0x71,0x88,0x93,0xa5,0x13};

/*计算这5个数据的CRC校验码*/

crc=0;

5;

crc=crc16_ccitt(data[i],crc);

printf("

crcis%x"

crc);

好了,讲到这里CRC算法已经全部介绍完了。

什么,讲完了?

不对呀,我怎么记得CRC程序都有个数组叫CRC表什么的,你这里怎么没有?

呵呵,其实使用CRC表是为了节省一些运算时间,事先将算好的CRC保存在数组里,省得临时再计算,它保存的是0到0xff的CRC码,下面我们来自己生成一个CRC表:

unsignedshortCRC16_CCITT_TABLE[256];

voidinit_crc16_ccitt_table()

256;

CRC16_CCITT_TABLE[i]=crc16_ccitt(i,0);

上面只是一个字节的CRC表,那多个字节的CRC如何计算呢?

与前面求多字节的CRC方法差不多,它的代码如下:

/*这段代码是查表求ccitt-crc16的算法,它与前面的程序crc16_ccitt所得到的结果一样

unsignedshortcrc16_ccitt_2(unsignedchardata,unsignedshortcrc)

unsignedcharc;

c=crc>

8;

/*c的值为crc的高8位*/

/*crc现在的值变为低8位左移8位*/

crc^=CRC16_CCITT_TABLE[data^c];

最后要说的是CRC的正序和反转问题,比如前面ccitt-crc16的正序是0x1021,如果是反转就是0x8408(就是将0x1021倒过来低位变高位)为什么要反转?

这是因为数据传输可能是先传低位再传高位(比如串口就是低位在前高位在后)。

反转的CRC算法与正序类似,只是需要注意移位的方向相反。

/*这段代码是求ccitt-crc16的反转算法

原来数据求得的crc反转校验码

数据的ccitt-crc16反转校验码

unsignedshortcrc16_ccitt_r(unsignedchardata,unsignedshortcrc)

unsignedshortccitt16=0x8408;

crc^=data;

1)/*最低位为1,减去除数*/

crc>

else/*最低位为0,不需要减去除数*/

/*这段代码是查表求反转ccitt-crc16的算法,它与前面的程序crc16_ccitt_r所得到的结果一样

unsignedshortcrc16_ccitt_r2(unsignedchardata,unsignedshortcrc)

c=crc&

0xff;

crc^=CRC16_CCITT_R_TABLE[data^c];

本来随这篇Blog我写了两个C程序,一个是这篇文章的全部源程序的例子,一个是crc16的CRC表及查表程序,程序在TC下测试通过。

不过我不知道怎么添加附件,所以就没附程序了。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 生产经营管理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1