ImageVerifierCode 换一换
格式:DOC , 页数:12 ,大小:105KB ,
资源ID:10021728      下载积分:10 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.docduoduo.com/d-10021728.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录   微博登录 

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(CCITT CRC-16计算原理与实现.doc)为本站会员(精品资料)主动上传,道客多多仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知道客多多(发送邮件至docduoduo@163.com或直接QQ联系客服),我们立即给予删除!

CCITT CRC-16计算原理与实现.doc

1、CCITT CRC-16 计算原理与实现CRC 的全称为 Cyclic Redundancy Check,中文名称为循环冗余校验。它是一类重要的线性分组码,编码和解码方法简单,检错和纠错能力强,在通信领域广泛地用于实现差错控制。实际上,除数据通信外,CRC 在其它很多领域也是大有用武之地的。例如我们读软盘上的文件,以及解压一个 ZIP 文件时,偶尔会碰到“Bad CRC”错误,由此它在数据存储方面的应用可略见一斑。 差错控制理论是在代数理论基础上建立起来的。这里我们着眼于介绍 CRC 的算法与实现,对原理只能捎带说明一下。若需要进一步了解线性码、分组码、循环码、纠错编码等方面的原理,可以阅读有

2、关资料。 利用 CRC 进行检错的过程可简单描述为:在发送端根据要传送的 k 位二进制码序列,以一定的规则产生一个校验用的 r 位监督码(CRC 码),附在原始信息后边,构成一个新的二进制码序列数共 k+r 位,然后发送出去。在接收端,根据信息码和 CRC 码之间所遵循的规则进行检验,以确定传送中是否出错。这个规则,在差错控制理论中称为“生成多项式”。 1 代数学的一般性算法 在代数编码理论中,将一个码组表示为一个多项式,码组中各码元当作多项式的系数。例如 1100101 表示为 1x6+1x5+0x4+0x3+1x2+0x+1,即 x6+x5+x2+1。 设编码前的原始信息多项式为 P(x)

3、,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) x

4、6+x5 x - = - = - = (x3+x2+x) + - G(x) x3+x+1 x3+x+1 x3+x+1 即 R(x)=x。注意到 G(x)最高幂次 r=3,得出 CRC 为 010。 如果用竖式除法,计算过程为 1110 - 1011 /1100000 (1100 左移 3 位) 1011 - 1110 1011 - 1010 1011 - 0010 0000 - 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 无余式。

5、回头看一下上面的竖式除法,如果被除数是1100010,显然在商第三个 1 时,就能除尽。 上述推算过程,有助于我们理解 CRC 的概念。但直接编程来实现上面的算法,不仅繁琐,效率也不高。实际上在工程中不会直接这样去计算和验证 CRC。 下表中列出了一些见于标准的 CRC 资料: 名称 生成多项式 简记式* 应用举例 CRC-4 x4+x+1 ITU G.704 CRC-12 x12+x11+x3+x+1 CRC-16 x16+x12+x2+1 1005 IBM SDLC CRC-ITU* x16+x12+x5+1 1021 ISO HDLC, ITU X.25, V.34/V.41/V.42,

6、 PPP-FCS CRC-32 x32+x26+x23+.+x2+x+1 04C11DB7 ZIP, RAR, IEEE 802 LAN/FDDI, IEEE 1394, PPP-FCS CRC-32c x32+x28+x27+.+x8+x6+1 1EDC6F41 SCTP * 生成多项式的最高幂次项系数是固定的 1,故在简记式中,将最高的 1统一去掉了,如 04C11DB7 实际上是 104C11DB7。 * 前称 CRC-CCITT。ITU的前身是 CCITT。 4.CRC 算法的实现 - 要用程序实现 CRC 算法,考虑对第 2 节的长除法做一下变换,依然是 M = 11100110,G

7、 = 1011, 其系数 r 为 3。 11001100 - 1011 )11100110000 1011. -. 1010 1011 - 1110. 1011. -. 1010 1011 - 100 1 110 0110000 011 101 0110000 101第一位为 1,移位且计算 1 010 110000 011 001 110000001第一位第二位均为 0,移位 2 次 00 111 0000111第一位为 1,移位且计算 1 110 000 011 101 000101 第一位为 1,移位且计算 1 010 00 011 001 00移位 2 次得 100 用 CRC16-C

8、CITT 的生成多项式 0x1021,其 C 代码(本文所有代码假定系统为 32位,且都在 VC6 上编译通过)如下: unsigned short do_crc(unsigned char *message, unsigned int len) int i, j; unsigned short crc_reg; crc_reg = (message0 (7 - i) 0x1021; else crc_reg = (crc_reg (7 - i); else for (j = 0; j 1) 0x8408; 14. else 15. crc_reg = 1; 16. current = 1;

9、17. 18. 19. return crc_reg; 20. 该算法使用了两层循环,对消息逐位进行处理,这样效率是很低的。为了提高时间效率,通常的思想是以空间换时间。考虑到内循环只与当前的消息字节和crc_reg 的低字节有关,对该算法做以下等效转换: Java 代码 1. unsigned short do_crc(unsigned char *message, unsigned int len)2. 3. int i, j; 4. unsigned short crc_reg = 0; 5. unsigned char index; 6. unsigned short to_xor; 7

10、. 8. for (i = 0; i 1) 0x8408; 16. else 17. to_xor = 1; 18. 19. crc_reg = (crc_reg 8) to_xor; 20. 21. return crc_reg; 22. 现在内循环只与 index 相关了,可以事先以数组形式生成一个表crc16_ccitt_table,使得 to_xor = crc16_ccitt_tableindex,于是可以简化为: Java 代码 1. unsigned short do_crc(unsigned char *message, unsigned int len)2. 3. unsig

11、ned short crc_reg = 0; 4. 5. while (len-) 6. crc_reg = (crc_reg 8) crc16_ccitt_table(crc_reg *message+) 7. 8. return crc_reg; 9. crc16_ccitt_table 通过以下代码生成: Java 代码 1. int main() 2. 3. unsigned char index = 0; 4. unsigned short to_xor; 5. int i; 6. 7. printf(“unsigned short crc16_ccitt_table256 =n“)

12、; 8. while (1) 9. 10. if (!(index % 8) 11. printf(“n“); 12. 13. to_xor = index; 14. for (i = 0; i 1) 0x8408; 18. else 19. to_xor = 1; 20. 21. printf(“0x%04x“, to_xor); 22. 23. if (index = 255) 24. 25. printf(“n“); 26. break; 27. 28. else 29. 30. printf(“, “); 31. index+; 32. 33. 34. printf(“;“); 35.

13、 return 0; 36. 37. 38.生成的表如下: 39. 40.unsigned short crc16_ccitt_table256 = 41. 42.0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 43.0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 44.0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 45.0x9cc9, 0x8d40, 0

14、xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 46.0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 47.0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 48.0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 49.0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0

15、xd8fd, 0xc974, 50.0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 51.0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 52.0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 53.0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 54.0x6306, 0x728f

16、, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 55.0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 56.0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 57.0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 58.0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5

17、, 0xe13e, 0xf0b7, 59.0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 60.0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 61.0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 62.0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 63.0x2942, 0x3

18、8cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 64.0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 65.0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 66.0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 67.0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1

19、de9, 0x2f72, 0x3efb, 68.0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 69.0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 70.0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 71.0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 72.0xf78f,

20、0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 73.0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 74.; 这样对于消息 unsigned char messagelen,校验码为: unsigned short code = do_crc(message, len); 并且按以下方式发送出去: messagelen = code messagelen + 1 = (code 接收端对收到的 len + 2 字节执行 do_crc,如果没有差错发生则

21、结果应为 0。 在一些传输协议中,发送端并不指出消息长度,而是采用结束标志,考虑以下几种差错: 1)在消息之前,增加 1 个或多个 0 字节; 2)消息以 1 个或多个连续的 0 字节开始,丢掉 1 个或多个 0; 3)在消息(包括校验码)之后,增加 1 个或多个 0 字节; 4)消息(包括校验码)以 1 个或多个连续的 0 字节结尾,丢掉 1 个或多个0; 显然,这几种差错都检测不出来,其原因就是如果寄存器值为 0,处理 0 消息字节(或位),寄存器值不变。为了解决前 2 个问题,只需寄存器的初值非 0 即可,对 do_crc 作以下改进: Java 代码 1. unsigned short

22、 do_crc(unsigned short reg_init, unsigned char *message, unsigned int len) 2. 3. unsigned short crc_reg = reg_init; 4. 5. while (len-) 6. crc_reg = (crc_reg 8) crc16_ccitt_table(crc_reg *message+) 7. 8. return crc_reg; 9. 在 CRC16-CCITT 标准中 reg_init = 0xffff,为了解决后 2 个问题,在 CRC16-CCITT 标准中将计算出的校验码与 0xf

23、fff 进行异或,即: unsigned short code = do_crc(0xffff, message, len); code = 0xffff; messagelen = code messagelen + 1 = (code 显然,现在接收端对收到的所有字节执行 do_crc,如果没有差错发生则结果应为某一常值 GOOD_CRC。其满足以下关系: unsigned char p= 0xff, 0xff; GOOD_CRC = do_crc(0, p, 2); 其结果为 GOOD_CRC = 0xf0b8。 在同一程序中验证如下(放在 main 函数中可试验): Java 代码 1

24、. unsigned char p= 0xa0,0xb0,0xff, 0xff; 2. unsigned short crc; 3. crc= do_crc(0xffff, p, 2); /计算前两位的 CRC 码 4. crc=0xffff; /对其取反 5. p2=crc /将计算的 CRC 码加到信息序列后面 6. p3=crc8 7. printf(“p2=%x,p3=%xn“,p2,p3); 8. crc=do_crc(0xffff,p,4); /对信息码CRC 码共同计算得出CRC=0xf0b8 9. printf(“crc is %xn“,crc); 假设发送的信息是 p0,p1;低位先发,对其计算的 CRC 加到信息码后面 然后对信息码CRC 码共同计算 CRC 值,此时应该是常数 0xf0b8。不管信息码如何变化,内容和长度都可变,只要把计算的 CRC 码加进去一起计算 CRC,就应该是得该常数 GOOD_CRC。

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报