1、校验原理1、循环校验码(CRC 码):是数据通信领域中最常用的一种差错校验码,其特征是信息字段和校验字段的长度可以任意选定。2、生成 CRC 码的基本原理:任意一个由二进制位串组成的代码都可以和一个系数仅为0和 1取值的多项式一一对应。例如:代码 1010111 对应的多项式为x6+x4+x2+x+1,而多项式为 x5+x3+x2+x+1 对应的代码 101111。3、CRC 码集选择的原则:若设码字长度为 N,信息字段为 K 位,校验字段为R 位(N=K+R),则对于 CRC 码集中的任一码字,存在且仅存在一个 R 次多项式g(x),使得V(x)=A(x)g(x)=xRm(x)+r(x);其
2、中: m(x)为 K 次信息多项式, r(x)为 R-1 次校验多项式,g(x)称为生成多项式:g(x)=g0+g1x+ g2x2+.+g(R-1)x(R-1)+gRxR发送方通过指定的 g(x)产生 CRC 码字,接收方则通过该 g(x)来验证收到的 CRC码字。 4、CRC 校验码软件生成方法:借助于多项式除法,其余数为校验字段。例如:信息字段代码为: 1011001;对应 m(x)=x6+x4+x3+1 假设生成多项式为:g(x)=x 4+x3+1;则对应 g(x)的代码为: 11001x4m(x)=x10+x8+x7+x4 对应的代码记为:10110010000;采用多项式除法: 得余
3、数为: 1010 (即校验字段为:1010)发送方:发出的传输字段为: 1 0 1 1 0 0 1 1 0 10信息字段 校验字段接收方:使用相同的生成码进行校验:接收到的字段 /生成码(二进制除法)如果能够除尽,则正确,CRC 校验源码分析这两天做项目,需要用到 CRC 校验。以前没搞过这东东,以为挺简单的。结果看看别人提供的汇编源程序,居然看不懂。花了两天时间研究了一下 CRC 校验,希望我写的这点东西能够帮助和我有同样困惑的朋友节省点时间。 先是在网上下了一堆乱七八遭的资料下来,感觉都是一个模样,全都是从 CRC 的数学原理开始,一长串的表达式看的我头晕。第一次接触还真难以理解。这些东西
4、不想在这里讲,随便找一下都是一大把。我想根据源代码来分析会比较好懂一些。 费了老大功夫,才搞清楚 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 以下的源程序全部以 CCITT 为例。其实本质都是一样,搞明白一种,其他的都是小菜。 图 1,图 2 说明了 CRC 校验中 CRC 值
5、是如何计算出来的,体现的多项式正是 X16+X12+X5+1。 Serial Data 即是需要校验的数据。从把数据移位开始计算,将数据位(从最低的数据位开始)逐位移入反向耦合移位寄存器(这个名词我也不懂,觉得蛮酷的,就这样写了,嘿)。当所有数据位都这样操作后,计算结束。此时,16 位移位寄存器中的内容就是 CRC 码。图中进行 XOR 运算的位与多项式的表达相对应。 X5 代表 Bit5,X12 代表 Bit12,1 自然是代表 Bit0,X16 比较特别,是指移位寄存器移出的数据,即图中的 DATA OUT。可以这样理解,与数据位做XOR 运算的是上次 CRC 值的 Bit15。 根据以上
6、说明,可以依葫芦画瓢的写出以下程序。(程序都是在 keil C 7.10 下调试的) typedef unsigned char uchar; typedef unsigned int uint; code uchar crcbuff = 0x00,0x00,0x00,0x00,0x06,0x0d,0xd2,0xe3; uint crc; / CRC 码 void main(void) uchar *ptr; crc = 0; / CRC 初值 ptr = crcbuff; / 指向第一个 Byte 数据 crc = crc16l(ptr,8); while(1); uint crc16l(u
7、char *ptr,uchar len) / ptr 为数据指针, len 为数据长度 uchar i; while(len-) for(i=0x80; i!=0; i=1) if(crc crc = 0x8408; else crc = 1; if(*ptr ptr+; return(crc); 0x8408 就是 CCITT 的反转多项式。 套用别人资料上的话 “反转多项式是指在数据通讯时,信息字节先传送或接收低位字节,如重新排位影响 CRC 计算速度,故设反转多项式。” 如 code uchar crcbuff = 0x00,0x00,0x00,0x00,0x06,0x0d,0xd2,0
8、xe3; 反过来就是 code uchar crcbuff_fan = 0xe3,0xd2,0x0d,0x06,0x00,0x00,0x00,0x00; crc = 0; ptr = crcbuff_fan; crc = crc16r(ptr,8); 执行结果 crc = 0x5f1d; 如想验证是否正确,可改 code uchar crcbuff_fan_result = 0xe3,0xd2,0x0d,0x06,0x00,0x00,0x00,0x00,0x1d,0x5f; ptr = crcbuff_fan_result; crc = crc16r(ptr,10); 执行结果 crc = 0
9、; 符合 CRC 校验的原理。 请注意 0x5f1d 在数组中的排列中低位在前,正是反相运算的特点。不过当时是把我搞的晕头转向。 在用半字节查表法进行反相运算要特别注意一点,因为是右移,所以 CRC 移出的 4Bit 与数据 XOR 的操作是在 CRC 的高位端。因此余式表的产生是要以下列数组通过修改函数 crc16r 产生。 code uchar ban_fan= 0,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0;得出余式表 code uint fan_yushi16= 0x0000, 0
10、x1081, 0x2102, 0x3183, 0x4204, 0x5285, 0x6306, 0x7387, 0x8408, 0x9489, 0xa50a, 0xb58b, 0xc60c, 0xd68d, 0xe70e, 0xf78f ; uint ban_fan_crc(uchar *ptr,uchar len) uchar da; while(len-!=0) da = (uchar)(crc crc = 4; crc = fan_yushi da(*ptr da = (uchar)(crc crc = 4; crc = fan_yushi da(*ptr/16); ptr+; retur
11、n(crc); 主程序中 crc = 0; ptr = crcbuff_fan; crc = ban_fan_crc(ptr,8); 执行结果 crc = 0x5f1d; 反相运算的算法简单实现 crc 校验前一段时间做协议转换器的时间用到 CRC-16 校验,查了不少资料发现都不理想。查表法要建表太麻烦,而计算法觉得那些例子太罗嗦。最后只好自己写了,最后发现原来挺简单嘛:) 两个子程序搞定。这里用的多项式为: CRC-16 = X16 + X12 + X5 + X0 = 20+25+212+216=0x11021 因最高位一定为“1”,故略去计算只采用 0x1021 即可 CRC_Byte:计算单字节的 CRC 值 CRC_Data:计算一帧数据的 CRC 值 CRC_High CRC_Low:存放单字节 CRC 值 CRC16_High CRC16_Low:存放帧数据 CRC 值 ;- ; Function: CRC one byte ; Input: CRCByte
Copyright © 2018-2021 Wenke99.com All rights reserved
工信部备案号:浙ICP备20026746号-2
公安局备案号:浙公网安备33038302330469号
本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。