CRC校验原理及代码实现
目录背景原理模2除法多项式计算流程代码实现()c语言实现c语言测试结果labview实现labview测试结果目录
背景
在进行数据传输时,为了避免数据传输发生错误,需要对数据进行校验,从而产生了一些校验方法。CRC校验便是其中之一。
校验流程如下:
1:数据发送方按照一定的计算方法得到校验码,附在数据串末尾。
2:数据接收方在接受到数据后,按照同样的方法对数据进行校验,如果得到的校验码和收到的校验码相等,则说明传输数据未发生错误。。
以上存在一个问题,如何确定收到数据哪部分是校验码,哪部分是数据串部分,这里需要事先约定好,例如将收到数据最后一个字节约定为校验码。
原理
采用模2除法,数据串除以多项式。
模2除法
校验码的计算采用的是模2除法,所谓模2除法,即每一位除的结果不影响其它位。如下图所示:
更通俗的理解就是二者异或
多项式
多项式决定模2除法中的被除数,可表示为𝐺(x)=∑2_(𝑖=1)^𝑗▒〖𝐶_𝑖 𝑥^𝑖+1〗,𝐶_𝑖 为系数,影响到被除数,如𝐺(x) = 𝑥^16+ 𝑥^15+ 𝑥^2+1
可得被除数为1 1000 0000 0000 0101
计算流程
设传输数据串为1100 1100
按照模2除法操作,在操作之前要在后面添加j个0,此例为16个0,则除数为:
1100 1100 0000 0000 0000 0000 0000
最后剩下计算即可
代码实现()
用代码实现,需要明确几个量:
多项式:决定校验码的长度
初始值:CRC码初始值
结果异或值:计算结果异或
输入值反转:将取出的一个字节按位反转
输出值反转:计算结果按位反转
上图是crc不同算法情况,只需要按照以下方法,对照上图,即可用代码实现。这里以以CRC-16/IBM为例,其他与此基本相同,实现思路如下:
**第一步:**设置一个CRC16位变量,赋值初始值为0x0000(右表可查)
**第二步:**取出要传输数据的第一个字节,将该字节按位反转
**第三步:**将取出的字节数与CRC变量高八位异或,结果放置于CRC变量,注意,CRC的低八位数据保持不变。
**第四步:**判断CRC变量左移1位,低位补0,如果移出位为1,则异或上CRC多项式0x8005,结果存放于CRC变量,否则,不处理。
**第五步:**重复第四步操作,直到8位数据全部进行处理。
**第六步:**重复第二步到第五步,进行通讯帧下一个字节的处理。
**第七步:**按位反转,然后异或上 结果异或值0x0000 ,得到CRC校验码
c语言实现
#include<stdio.h>unsigned char u8_reverse(unsigned char U8_Data){unsigned char num = 0;for(int i = 0; i < 8; i++){num |= (U8_Data & 0x01) << (7 - i) ;U8_Data = U8_Data >> 1;}return num;}unsigned short u16_reverse(unsigned short U16_Data){unsigned short num = 0;for(int i = 0; i < 16; i++){num |= (U16_Data & 0x01) << (15 - i) ;U16_Data = U16_Data >> 1;}return num;}unsigned short CRC_16_IBM(unsigned char *Data,int Len){unsigned short CRC = 0x0000;unsigned char data;for(int i = 0;i < Len; i++){data = u8_reverse(*Data++);CRC = CRC ^ (data << 8);for(int j = 0; j < 8; j++){if((CRC & 0x8000) != 0){CRC = (CRC << 1) ^ 0x8005;}else{CRC = (CRC << 1);}}}CRC = u16_reverse(CRC);return CRC;}int main(){printf("please input data to caculate CRC\n");char Data_Buf[8] = {0};scanf("%s",Data_Buf);printf("the CRC is : \n");printf("%x\n",CRC_16_IBM(Data_Buf,2));return 0;}
c语言测试结果
待传输数据:0x31 0x32
CRC计算值:0x4594
labview实现
labview测试结果
传输数据:0x1024666666661024
CRC计算结果:0x8c97