前言:1、想直接用CRC的可以直接看程序,想了解原理,或者写程序的原理的。可以看按顺序看整篇 2、模二除法没有深入研究,所以模二除法待验证,也不去验证了,我花了一个月的业余时间写。3、本文只进行了16位的验证。个人建议会用就行。

目录

什么是CRC

CRC的计算原理

异或计算和直观图:先看这个

模二计算方法:再理解这个

程序原理:

位处理型:按照异或计算和直观图视频里的原理

位处理程序补充:

字节处理型:

字节型处理程序补充:

多项式表


什么是CRC

CRC(Cyclic Redundancy Check),即循环冗余校核,是一种根据网络数据包或电脑文件等数据产生简短固定位数校核码的快速算法,主要用来检测或校核数据传输或者保存后可能出现的错误。CRC利用除法及余数的原理,实现错误侦测的功能,具有原理清晰、实现简单等优点。

个人理解:就是CRC校验就是保证传输的内容是不是错了,是不是收到干扰。

发送方:如传输的0x32.校验一次记为校验1,校验码一并传输;即传输为0x32 校验1。

最高位在传输的时候收到干扰变成了1,接收到的为0xB2 校验1;那么接下来接收方就判定产生错误

接收方:再次校验接收回来的数据0x32,记为校验2。如果接收的数据0x32正确,校验2与校验1一样,则传输正确,如果不一样,要么是校验1传输出问题要么是0x32出问题。此时判定不需要此帧数据

CRC的计算原理

异或计算和直观图:先看这个

[CRC校验]手算与直观演示_哔哩哔哩_bilibili

模二计算方法:再理解这个

除了以上的计算,还有就是用数据串右移多项式的位宽进行(记为数据串1)除去多项式,除到数据串1的最后一位。

如上图:现假设选择的 CRC生成多项式为 G( X) = X^4 + X^3 + 1,要求出二进制序列 10110011的 CRC校验码。下面是具体的计算过程 :
①将多项式转化为二进制序列,由 G( X) = X^4 + X^3 + 1可知二进制一种有五位,第4位、第三位和第零位分别为1,则序列为11001
②多项式的位数位5,则在数据帧的后面加上4位0,数据帧变为 101100110000,然后使用模2除法除以除数 11001,得到余数

③将计算出来的CRC校验码添加在原始帧的后面,真正的数据帧为101100110100,再把这个数据帧发送到接收端。
④接收端收到数据帧后,用上面选定的除数,用模2除法除去,验证余数是否为0,如果为0,则说明数据帧没有出错。

此处引用一个博主:CRC校验原理及步骤_erci_fc2336的博客-CSDN博客_crc校验

程序原理:

数据串都放进8位型数组u8 data[100],确定好多项式,并且去除最高位。

为啥去除最高位?因为方便运算,并且在程序处理的时候已经考虑最高位的处理。结合多项式表比如多项式为CRC16xmodem,二进制为1 0001 0000 0010 0001,省去最高位为0x1021。

省去的最高位在程序中补偿:因为是从数据串的首位异或二进制为1 0001 0000 0010 0001,如果数据串首位为1就异或1 0001 0000 0010 0001,此时数据串的首位1被异或清零相当于移除掉数据串首位,并且异或去掉多项式首位的效果;否则首位为0直接移除掉。

位处理型:按照异或计算和直观图视频里的原理

1、提取出数据串的位数与多项式省去最高位后一样(8 、16、32),记为datax,位数记为L

2、多项式省去最高位后记为ployint;

3、判断首位是否为1,为1就右移一位datax,从数据串中补上L=L+1的位,进行异或。不为1直接左移,再补上L=L+1。

4直到L为数据串的位长度,后再补ployint位宽长度的0;假设数据串为10字节,ployint为0x1021位宽是16,在10*8个L长度之后开始补0,直到L补到10*8+16结束所有运算,此时的异或结果就是校验值。

位处理程序补充:但是程序我写的是CRC16Xmodem多项式。

void InvertUint8(unsigned char *DesBuf, unsigned char *SrcBuf)//字节取反
{int i;unsigned char temp = 0;for(i = 0; i < 8; i++){if(SrcBuf[0] & (1 << i)){temp |= 1<<(7-i);}}DesBuf[0] = temp;
}void InvertUint16(unsigned short *DesBuf, unsigned short *SrcBuf)//16位取反
{int i;unsigned short temp = 0;for(i = 0; i < 16; i++){if(SrcBuf[0] & (1 << i)){temp |= 1<<(15 - i);}}DesBuf[0] = temp;
}unsigned int wei_chuli(unsigned char *puchMsg, unsigned int usDataLen)
{unsigned short wCRCin = 0x0000;unsigned short wCPoly = 0x1021;unsigned short wChar = puchMsg[0]<<8|puchMsg[1];    //如果改成其他校验模式,改这三个的类型和值就行了。int i=0;unsigned char t=0;//记处理当前字节的位unsigned char temp=0;//记补位补0还是1unsigned char now_zijie_num=1;//记当前第几字节//for(i=0;i<usDataLen;i++)InvertUint8(puchMsg+i,puchMsg+i); //如果需要输入反转,应把数组每个字节不动位置,每个字节的位进行反转puchMsg+=1; //指针指向第二个字节wCRCin^=wChar;//开始输入异或while (now_zijie_num<=usDataLen)//直到字节数都处理完,当前字节数大于usDataLen{printf("开始处理第%d字符: \r\n",now_zijie_num);for(i = 0x80,t=0; i >0; i=i>>1,t++)      //用来提取当前字节的后第二位字节的位{   printf("处理第%d字符%d位: \r\n",now_zijie_num,t);if(wCRCin & 0x8000)                 //判断当前字节最高位{
//              printf("处理前  %x \r\n",wCRCin);
//              printf("异或值  %x \r\n",wCPoly);if(now_zijie_num<=usDataLen-sizeof(wCPoly))   //只要没到倒数第二个字节,就正常补位,到了只能补零。相当于数据串整体移位多项式位宽。{wCRCin=(wCRCin << 1)+(temp=*(puchMsg+1)&i?1:0);//公式内的左移是单目运算,实际的wCRCin已经移位。并且补上前字节的后第二位字节的位printf("当前在%d字节\r\n",now_zijie_num);printf("补后第二字节补后第二字节%x字节的%d位补了%d",*(puchMsg+1),t,temp);}else {wCRCin=(wCRCin << 1);      //处理完数据传只补零printf("当前在%d字节\r\n",now_zijie_num);printf("只补0后");}printf("处理前  %x \r\n",wCRCin);printf("异或值  %x \r\n",wCPoly);wCRCin = wCRCin^ wCPoly;printf("处理结果%x \r\n",wCRCin);}else{   wCRCin = wCRCin << 1;if(now_zijie_num<=usDataLen-sizeof(wCPoly)) //只要没到倒数第二个字节,就正常补位,到了只能补零。{             //wCRCin=wCRCin+(temp=*(puchMsg+1)&i?1:0);printf("当前在%d字节\r\n",now_zijie_num);printf("纯位移,补后第二字节%x字节的%d位补了%d",*(puchMsg+1),t,temp);}else { printf("当前在%d字节\r\n",now_zijie_num);printf("纯位移,只补0");}printf("单纯移位之后%x   \r\n",wCRCin);}printf("   \r\n",wCRCin);printf("   \r\n",wCRCin);}if(now_zijie_num<=usDataLen-sizeof(wCPoly)) //如果数据没完,每次补完8位,指针++puchMsg++;now_zijie_num++;}//InvertUint16(&wCRCin, &wCRCin);//如果输出需要反转return (wCRCin) ;   //输出需要异或可以在这里处理。
}

字节处理型:

PS:以下的加号都是异或

把按字节排列的数据流表示成数学多项式,设数据流为BYTE[n]BYTE[n-1]BYTE[n-2]、、、BYTE[1]BYTE[0],表示成数学表达式为BYTE[n]×256^n+BYTE[n-1]×256^(n-1)

+...+BYTE[1]*256+BYTE[0],在这里+表示为异或运算。设生成多项式为G17(17bit),CRC码为CRC16。

则,CRC16=(BYTE[n]×256^n+BYTE[n-1]×256^(n-1)+...+BYTE[1]×256+BYTE[0])×256^2/G17,即数据流左移16位,再除以生成多项式G17。

先变换BYTE[n-1]、BYTE[n-1]扩大后的形式,

CRC16

=BYTE[n]×256^n×256^2/G17+BYTE[n-1]256^(n-1)×256^2/G17+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

=(Z[n]+Y[n]/G17)×256^n+BYTE[n-1]×256^(n-1)×256^2/G17+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

=Z[n]×256^n+{Y[n]×256/G17+BYTE[n-1]×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

=Z[n]×256^n+{(YH8[n]×256+YHL[n])×256/G17+BYTE[n-1]×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

=Z[n]×256^n+{YHL[n]×256/G17+(YH8[n]+BYTE[n-1])×256^2/G17}×256^(n-1)+...+BYTE[1]×256×256^2/G17+BYTE[0]×256^2/G17

这样就推导出,BYTE[n-1]字节的CRC校验码为{YHL[n]×256/G17+(YH8[n]+BYTE[n-1])×256^2/G17},即上一字节CRC校验码Y[n]的高8位(YH8[n])与本字节BYTE[n-1]异或,

该结果单独计算CRC校验码(即单字节的16位CRC校验码,对单字节可建立表格,预先生成对应的16位CRC校验码),所得的CRC校验码与上一字节CRC校验码Y[n]的低8位(YL8[n])

乘以256(即左移8位)异或。然后依次逐个字节求出CRC,直到BYTE[0]。

字节型算法的一般描述为:本字节的CRC码,等于上一字节CRC码的低8位左移8位,与上一字节CRC右移8位同本字节异或后所得的CRC码异或。

以上是引用的内容;但是我觉得紫色的没有完整,或者没有准确描述。

个人分析:BYTE[n-1]字节的CRC校验码为{YHL[n]×256/G17+(YH8[n]+BYTE[n-1])×256^2/G17}

可以再分解为{【YHL[n]+(YH8[n]+BYTE[n-1])×256】x256/G17}

结论:所以可以轻松发现:BYTE[n-1]字节的CRC校验码为上一个BYTE[n]字节校验码的高8位,异或BYTE[n-1]字节左移8,再异或上一个校验码的低八。也就是说上个字节校验码的高位异或BYTE[n-1]字节再进行异或处理,又得到了BYTE[n-1]校验值。

>>补充:关于z[n]的出现,可以考虑到模二除法,BYTE[n]=商*多项式+余数【PS余数就是该字节的CRC校验值】。所以z[n]=商*多项式,还留着z[n]是为了保证等式的完整性。

 为什么会找以上理论呢?因为每个人都只发程序文章,而程序为什么这样写,没有人提到,理论和程序联系存在部分断层。接下来就是程序补充了。

字节型处理程序补充:使用的是CRC16-Xmodem算法,可以看下面的多项式表。

unsigned short CRC16_XMODEM(unsigned char *puchMsg, unsigned int usDataLen)
{unsigned short wCRCin = 0x0000;unsigned short wCPoly = 0x1021;unsigned char wChar = 0;int i,t=0;while (usDataLen--){wChar = *(puchMsg++);t++;printf("第%d个数:  %x \r\n",t,wChar);
/*********************
为什么要用每个字节的校验码异或下一个字节,这就需要刚才的字节型处理理论依据了
*********************************/wCRCin ^= (wChar << 8);/******* 这个哦******/if(t==3)printf("%x \r\n",wCRCin);for(i = 0; i < 8; i++){    printf("处理第%d字符%d位: \r\n",t,i);if(wCRCin & 0x8000){printf("处理前  %x \r\n",wCRCin);printf("异或值  %x \r\n",wCPoly);wCRCin = (wCRCin << 1) ^ wCPoly;printf("处理结果%x \r\n",wCRCin);}else{wCRCin = wCRCin << 1;printf("单纯移位之后%x   \r\n",wCRCin);}printf("   \r\n",wCRCin);printf("   \r\n",wCRCin);}}return (wCRCin) ;
}

根据以上程序可以提供一个直接表观察数据处理:如二进制处理测试数据表1可以不用看除了多项式表以下的都不用看,因为需要增加学习量了,有兴趣可以看,研究就可以动手写一下,试一下看一下如下下下面的

此处引用了百度:CRC校验字节型算法查表法解读 - 百度文库

多项式表

此表有引用:

C# 实现CRC校验(循环冗余校验)CRC-8位/16位/32位等参数模型_猿长大人的博客-CSDN博客_c# crc校验

二进制处理测试数据表1

描述此表的目的:·观察数据变化,单字节处理和多字节处理的变化。

之前思考一个问题,就是单字节处理与多项式处理8次,但是双字节也会处理8次,而且后面第二个字节也会参与处理,所以观察单字节处理完结果和双字节处理第一个字节完是否一样?

表左边使用的是0x32,表右边是0x32 0x03;单字节处理和双字节处理。

观察第七位也就是第一个字节最后一位处理完成。

第1个数:  0011 0010

处理第1字符0位:

单纯  0110 0100 0000 0000

处理第1字符1位:

单纯  1100 1000 0000 0000

处理第1字符2位:

处理前1100 1000 0000 0000

异或值0001 0000 0010 0001

处结果1000 0000 0010 0001

处理第1字符3位:

处理前1000 0000 0010 0001

异或值0001 0000 0010 0001

处结果0001 0000 0110 0011

处理第1字符4位:

单纯  0010 0000 1100 0110

处理第1字符5位:

单纯  0100 0001 1000 1100

处理第1字符6位:

单纯  1000 0011 0001 1000

处理第1字符7位:

处理前1000 0011 0001 1000

异或值0001 0000 0010 0001

处理值0001 0110 0001 0001

校验值为0001 0110 0001 0001

可以观察这里

第1个数:  0011 0010 0000 0011

处理第1字符0位:

纯移0110 0100 0000 0110 0000 0000 0000 0000

处理第1字符1位:

纯移1100 1000 0000 1100 0000 0000 0000 0000

处理第1字符2位:

处理前1100 1000 0000 1100 0000 0000 0000 0000

异或值0001 0000 0010 00010000 0000 0000 0000

处结果1000 0000 0011 1001 0000 0000 0000 0000

处理第1字符3位:

处理前1000 0000 0011 1001 0000 0000 0000 0000

异或值0001 0000 0010 0001 0000 0000 0000 0000

处结果0001 0000 0101 0011 0000 0000 0000 0000

处理第1字符4位:

纯移0010 0000 1010 0110 0000 0000 0000 0000

处理第1字符5位:

纯移0100 0001 0100 1100 0000 0000 0000 0000

处理第1字符6位:

纯移1000 0010 1001 1000 0000 0000 0000 0000

处理第1字符7位:

处理前1000 0010 1001 1000 0000 0000 0000 0000

异或值0001 0000 0010 0001 0000 0000 0000 0000

处结果0001 0101 0001 0001 0000 0000 0000 0000

校验值为0001 010 0001 0001

处理第2字符8位:

纯移0010 1010 0010 0010 0000 0000 0000 0000

处理第2字符9位:

纯移0101 0100 0100 0100 0000 0000 0000 0000

处理第2字符10位:

纯移1010 1000 1000 1000 0000 0000 0000 0000

处理第2字符11位:

处理前1010 1000 1000 1000 0000 0000 0000 0000

异或值0001 0000 0010 0001 0000 0000 0000 0000

处结果0100 0001 0011 0001 0000 0000 0000 0000

处理第2字符12位:

纯移1000 0010 0110 0010 0000 0000 0000 0000

处理第2字符13位:

处理前1000 0010 0110 0010 0000 0000 0000 0000

异或值0001 0000 0010 0001 0000 0000 0000 0000

处结果0001 0100 1110 0101 0000 0000 0000 0000

处理第2字符14位:

纯移0010 1001 1100 1010 0000 0000 0000 0000

处理第2字符15位:

纯移101 0011 1001 0100 0000 0000 0000 0000

最终结果101 0011 1001 0100 0000 0000 0000 0000

如上表的测试是用VC2010程序测试出来的,附带程序。

主程序:

int main()
{  int z=0;unsigned char a[10]={0xe2, 0x03 ,0x97 ,0x01}; //e2 03 97 01unsigned char a1[10]={0x32, 0x03 ,0x08 ,0x81};//32 03 08 81//z=CRC16_XMODEM(a1, 2);//printf("校验值: %x",z);//z=CRC16_XMODEM_test(0x3203, 1);//CRC_16_desplay_2jinzhi(a1,1);     //表左边用的CRC_16_desplay_2jinzhi_2(0x3203,  1);//表右边用的printf("TEST_校验值: %x",z);
}

表左用的程序

int CRC_16_desplay_2jinzhi(unsigned char *puchMsg, unsigned int usDataLen)
{unsigned short wCRCin = 0x0000;unsigned short wCPoly = 0x1021;unsigned char wChar = 0;int i,t=0;char buff[50]={0};//itoa(x,buff,2);while (usDataLen--){wChar = *(puchMsg++);t++;itoa(wChar,buff,2);printf("第%d个数:  %s \r\n",t,buff);wCRCin ^= (wChar << 8);if(t==3){itoa(wCRCin,buff,2);printf("%s \r\n",buff);}for(i = 0; i < 8; i++){    printf("处理第%d字符%d位: \r\n",t,i);if(wCRCin & 0x8000){itoa(wCRCin,buff,2);printf("处理前。。。。%s \r\n",buff);itoa(wCPoly,buff,2);printf("异或值。。。  000%s \r\n",buff);wCRCin = (wCRCin << 1) ^ wCPoly;itoa(wCRCin,buff,2);printf("处理结果。    %s \r\n",buff);}else{wCRCin = wCRCin << 1;itoa(wCRCin,buff,2);printf("单纯移位之后  %s   \r\n",buff);}printf("   \r\n",wCRCin);printf("   \r\n",wCRCin);}}itoa(wCRCin,buff,2);printf("最终结果%s   \r\n\r\n",buff);return (wCRCin) ;}

表右用的程序

int CRC_16_desplay_2jinzhi_2(unsigned short puchMsg, unsigned int usDataLen)
{unsigned int wCRCin = 0x00000000;unsigned int wCPoly = 0x10210000;unsigned int wChar = 0;int i,t=0;char buff[50]={0};//itoa(x,buff,2);while (usDataLen--){wChar =puchMsg;t++;itoa(wChar,buff,2);printf("第%d个数:  %s \r\n",t,buff);wCRCin ^= (wChar << 16);if(t==3){itoa(wCRCin,buff,2);printf("%s \r\n",buff);}for(i = 0; i < 16; i++){    printf("处理第%d字符%d位: \r\n",t,i);if(wCRCin & 0x80000000){itoa(wCRCin,buff,2);printf("处理前%s \r\n",buff);itoa(wCPoly,buff,2);printf("异或值000%s \r\n",buff);wCRCin = (wCRCin << 1) ^ wCPoly;itoa(wCRCin,buff,2);printf("处结果%s \r\n",buff);}else{wCRCin = wCRCin << 1;itoa(wCRCin,buff,2);printf("纯移%s   \r\n",buff);}printf("   \r\n",wCRCin);printf("   \r\n",wCRCin);}}itoa(wCRCin,buff,2);printf("最终结果%s\r\n\r\n",buff);return (wCRCin) ;}

字节处理型型和位处理型对比验证

可以先通过网上的校验计算做对比:CRC(循环冗余校验)在线计算_ip33.com

本人使用VC2010学习版做的验证程序如下,也可以用在单片机上。

#include<stdio.h>
#include<stdlib.h>
unsigned short CRC16_XMODEM(unsigned char *puchMsg, unsigned int usDataLen);
unsigned short CRC16_XMODEM_test(unsigned short puchMsg, unsigned int usDataLen);
int CRC_16_desplay_2jinzhi(unsigned char *puchMsg, unsigned int usDataLen);
int CRC_16_desplay_2jinzhi_2(unsigned short puchMsg, unsigned int usDataLen);
unsigned int wei_chuli(unsigned char *puchMsg, unsigned int usDataLen);
int main()
{  int z=0,z1=0;unsigned char a[10]={0xe2, 0x03 ,0x97 ,0x01}; //e2 03 97 01unsigned char a1[10]={0x32, 0x03 ,0x08 ,0x81,0x32,0x99,0x01,0x12};//32 03 08 81 32 99 01 12z1=CRC16_XMODEM(a1, 4);//z=CRC16_XMODEM_test(0x3203, 1);//CRC_16_desplay_2jinzhi(a1,1);//CRC_16_desplay_2jinzhi_2(0x3203,  1);z=wei_chuli(a1,4 );printf("校验值: %x",z1);printf("TEST_校验值: %x",z);
}unsigned short CRC16_XMODEM(unsigned char *puchMsg, unsigned int usDataLen)
{unsigned short wCRCin = 0x0000;unsigned short wCPoly = 0x1021;unsigned char wChar = 0;int i,t=0;while (usDataLen--){wChar = *(puchMsg++);t++;printf("第%d个数:  %x \r\n",t,wChar);wCRCin ^= (wChar << 8);if(t==3)printf("%x \r\n",wCRCin);for(i = 0; i < 8; i++){    printf("处理第%d字符%d位: \r\n",t,i);if(wCRCin & 0x8000){printf("处理前  %x \r\n",wCRCin);printf("异或值  %x \r\n",wCPoly);wCRCin = (wCRCin << 1) ^ wCPoly;printf("处理结果%x \r\n",wCRCin);}else{wCRCin = wCRCin << 1;printf("单纯移位之后%x   \r\n",wCRCin);}printf("   \r\n",wCRCin);printf("   \r\n",wCRCin);}}return (wCRCin) ;
}unsigned int wei_chuli(unsigned char *puchMsg, unsigned int usDataLen)
{unsigned short wCRCin = 0x0000;unsigned short wCPoly = 0x1021;unsigned short wChar = puchMsg[0]<<8|puchMsg[1];    //如果改成其他校验模式,改这三个的类型和值就行了。int i=0;unsigned char t=0;//记处理当前字节的位unsigned char temp=0;//记补位补0还是1unsigned char now_zijie_num=1;//记当前第几字节//for(i=0;i<usDataLen;i++)InvertUint8(puchMsg+i,puchMsg+i); //如果需要输入反转,应把数组每个字节不动位置,每个字节的位进行反转puchMsg+=1; //指针指向第二个字节wCRCin^=wChar;//开始输入异或while (now_zijie_num<=usDataLen)//直到字节数都处理完,当前字节数大于usDataLen{printf("开始处理第%d字符: \r\n",now_zijie_num);for(i = 0x80,t=0; i >0; i=i>>1,t++)      //用来提取当前字节的后第二位字节的位{   printf("处理第%d字符%d位: \r\n",now_zijie_num,t);if(wCRCin & 0x8000)                 //判断当前字节最高位{
//              printf("处理前  %x \r\n",wCRCin);
//              printf("异或值  %x \r\n",wCPoly);if(now_zijie_num<=usDataLen-sizeof(wCPoly))   //只要没到倒数第二个字节,就正常补位,到了只能补零。相当于数据串整体移位多项式位宽。{wCRCin=(wCRCin << 1)+(temp=*(puchMsg+1)&i?1:0);//公式内的左移是单目运算,实际的wCRCin已经移位。并且补上前字节的后第二位字节的位printf("当前在%d字节\r\n",now_zijie_num);printf("补后第二字节补后第二字节%x字节的%d位补了%d",*(puchMsg+1),t,temp);}else {wCRCin=(wCRCin << 1);      //处理完数据传只补零printf("当前在%d字节\r\n",now_zijie_num);printf("只补0后");}printf("处理前  %x \r\n",wCRCin);printf("异或值  %x \r\n",wCPoly);wCRCin = wCRCin^ wCPoly;printf("处理结果%x \r\n",wCRCin);}else{   wCRCin = wCRCin << 1;if(now_zijie_num<=usDataLen-sizeof(wCPoly)) //只要没到倒数第二个字节,就正常补位,到了只能补零。{             //wCRCin=wCRCin+(temp=*(puchMsg+1)&i?1:0);printf("当前在%d字节\r\n",now_zijie_num);printf("纯位移,补后第二字节%x字节的%d位补了%d",*(puchMsg+1),t,temp);}else { printf("当前在%d字节\r\n",now_zijie_num);printf("纯位移,只补0");}printf("单纯移位之后%x   \r\n",wCRCin);}printf("   \r\n",wCRCin);printf("   \r\n",wCRCin);}if(now_zijie_num<=usDataLen-sizeof(wCPoly)) //如果数据没完,每次补完8位,指针++puchMsg++;now_zijie_num++;}//InvertUint16(&wCRCin, &wCRCin);//如果输出需要反转return (wCRCin) ;   //输出需要异或可以在这里处理。
}

 得到比较表:

左边为z1=CRC16_XMODEM(a1, 4);字节型处理

右边为z=wei_chuli(a1,4 );位型处理,位处理可以进行手算进行对比

第1个数:  32

处理第1字符0位:

单纯移位之后6400

处理第1字符1位:

单纯移位之后c800

处理第1字符2位:

处理前  c800

异或值  1021

处理结果8021

处理第1字符3位:

处理前  8021

异或值  1021

处理结果1063

处理第1字符4位:

单纯移位之后20c6

处理第1字符5位:

单纯移位之后418c

处理第1字符6位:

单纯移位之后8318

处理第1字符7位:

处理前  8318

异或值  1021

处理结果1611

第2个数:  3

处理第2字符0位:

单纯移位之后2a22

处理第2字符1位:

单纯移位之后5444

处理第2字符2位:

单纯移位之后a888

处理第2字符3位:

处理前  a888

异或值  1021

处理结果4131

处理第2字符4位:

单纯移位之后8262

处理第2字符5位:

处理前  8262

异或值  1021

处理结果14e5

处理第2字符6位:

单纯移位之后29ca

处理第2字符7位:

单纯移位之后5394

第3个数:  8

5b94

处理第3字符0位:

单纯移位之后b728

处理第3字符1位:

处理前  b728

异或值  1021

处理结果7e71

处理第3字符2位:

单纯移位之后fce2

处理第3字符3位:

处理前  fce2

异或值  1021

处理结果e9e5

处理第3字符4位:

处理前  e9e5

异或值  1021

处理结果c3eb

处理第3字符5位:

处理前  c3eb

异或值  1021

处理结果97f7

处理第3字符6位:

处理前  97f7

异或值  1021

处理结果3fcf

处理第3字符7位:

单纯移位之后7f9e

第4个数:  81

处理第4字符0位:

处理前  fe9e

异或值  1021

处理结果ed1d

处理第4字符1位:

处理前  ed1d

异或值  1021

处理结果ca1b

处理第4字符2位:

处理前  ca1b

异或值  1021

处理结果8417

处理第4字符3位:

处理前  8417

异或值  1021

处理结果180f

处理第4字符4位:

单纯移位之后301e

处理第4字符5位:

单纯移位之后603c

处理第4字符6位:

单纯移位之后c078

处理第4字符7位:

处理前  c078

异或值  1021

处理结果90d1

校验值: 90d1

开始处理第1字符:

处理第1字符0位:

当前在1字节

纯位移,补后第二字节8字节的0位补了0单纯移位之后6406

处理第1字符1位:

当前在1字节

纯位移,补后第二字节8字节的1位补了0单纯移位之后c80c

处理第1字符2位:

当前在1字节

补后第二字节补后第二字节8字节的2位补了0处理前  9018

异或值  1021

处理结果8039

处理第1字符3位:

当前在1字节

补后第二字节补后第二字节8字节的3位补了0处理前  72

异或值  1021

处理结果1053

处理第1字符4位:

当前在1字节

纯位移,补后第二字节8字节的4位补了1单纯移位之后20a7

处理第1字符5位:

当前在1字节

纯位移,补后第二字节8字节的5位补了0单纯移位之后414e

处理第1字符6位:

当前在1字节

纯位移,补后第二字节8字节的6位补了0单纯移位之后829c

处理第1字符7位:

当前在1字节

补后第二字节补后第二字节8字节的7位补了0处理前  538

异或值  1021

处理结果1519

开始处理第2字符:

处理第2字符0位:

当前在2字节

纯位移,补后第二字节81字节的0位补了1单纯移位之后2a33

处理第2字符1位:

当前在2字节

纯位移,补后第二字节81字节的1位补了0单纯移位之后5466

处理第2字符2位:

当前在2字节

纯位移,补后第二字节81字节的2位补了0单纯移位之后a8cc

处理第2字符3位:

当前在2字节

补后第二字节补后第二字节81字节的3位补了0处理前  5198

异或值  1021

处理结果41b9

处理第2字符4位:

当前在2字节

纯位移,补后第二字节81字节的4位补了0单纯移位之后8372

处理第2字符5位:

当前在2字节

补后第二字节补后第二字节81字节的5位补了0处理前  6e4

异或值  1021

处理结果16c5

处理第2字符6位:

当前在2字节

纯位移,补后第二字节81字节的6位补了0单纯移位之后2d8a

处理第2字符7位:

当前在2字节

纯位移,补后第二字节81字节的7位补了1单纯移位之后5b15

开始处理第3字符:

处理第3字符0位:

当前在3字节

纯位移,只补0单纯移位之后b62a

处理第3字符1位:

当前在3字节

只补0后处理前  6c54

异或值  1021

处理结果7c75

处理第3字符2位:

当前在3字节

纯位移,只补0单纯移位之后f8ea

处理第3字符3位:

当前在3字节

只补0后处理前  f1d4

异或值  1021

处理结果e1f5

处理第3字符4位:

当前在3字节

只补0后处理前  c3ea

异或值  1021

处理结果d3cb

处理第3字符5位:

当前在3字节

只补0后处理前  a796

异或值  1021

处理结果b7b7

处理第3字符6位:

当前在3字节

只补0后处理前  6f6e

异或值  1021

处理结果7f4f

处理第3字符7位:

当前在3字节

纯位移,只补0单纯移位之后fe9e

开始处理第4字符:

处理第4字符0位:

当前在4字节

只补0后处理前  fd3c

异或值  1021

处理结果ed1d

处理第4字符1位:

当前在4字节

只补0后处理前  da3a

异或值  1021

处理结果ca1b

处理第4字符2位:

当前在4字节

只补0后处理前  9436

异或值  1021

处理结果8417

处理第4字符3位:

当前在4字节

只补0后处理前  82e

异或值  1021

处理结果180f

处理第4字符4位:

当前在4字节

纯位移,只补0单纯移位之后301e

处理第4字符5位:

当前在4字节

纯位移,只补0单纯移位之后603c

处理第4字符6位:

当前在4字节

纯位移,只补0单纯移位之后c078

处理第4字符7位:

当前在4字节

只补0后处理前  80f0

异或值  1021

处理结果90d1

这是手算表:手算时多项式0x1021在前面最高位要加1即1 0001 0000 0010 0001

数据串为0x32 0x03 0x08 0x81 并且添加多项式位宽个0,即加16个0.

手算的校验结果为0x90d1

CRC校验原理的完整学习相关推荐

  1. 【个人学习总结】CRC校验原理及实现

    [个人学习总结]CRC校验原理及实现 一.CRC校验原理[理论篇] 1.硬核视频讲解[重点看,非常非常好!!!] 2.基础文章[略看] 3.深入文章!!![代码.查表法有点看不懂,跨越有点大] 理解重 ...

  2. 简单易懂的CRC校验原理阐述

    不要跑,CRC没这么难!(简单易懂的CRC原理阐述) 网上大多的教材都是面向大佬的很多细节原理都没有讲清楚,对于我们这些新萌菜鸟们实在太不友好了.于是我写一篇相对轻松易懂的博客,希望能对学习CRC的朋 ...

  3. CRC校验原理及STM32 IAP在线升级程序

    CRC校验原理: 什么是CRC校验? CRC即循环冗余校验码:是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定.循环冗余检查(CRC)是一种数据传输检错功能,对数据 ...

  4. CRC校验原理及CRC-8简单校验函数设计

    CRC校验原理及CRC-8简单校验函数设计 CRC为循环冗余校验码,是一种常用的.具有检错.纠错能力的校验码.通常发送方在发送的数据之后,附上其CRC校验码.接收方收到数据后,也做同样的CRC校验,得 ...

  5. CRC校验原理和推导过程及Verilog实现(一文讲透)

    目录 一.CRC简介 1.1 CRC可检测的错误 1.2 CRC需要知道的基本名称 1.2.1 多项式公式 1.2.2 多项式简记式 1.2.3 数据宽度 1.2.4 初始值与结果异或值 1.2.5 ...

  6. CRC校验原理及步骤

    什么是CRC校验? CRC即循环冗余校验码:是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定.循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并 ...

  7. CRC校验原理及两种代码实现方法(c语言和labview实现)

    CRC校验原理及代码实现 目录 背景 原理 模2除法 多项式 计算流程 代码实现() c语言实现 c语言测试结果 labview实现 labview测试结果 目录 背景 在进行数据传输时,为了避免数据 ...

  8. CRC校验原理及代码

    参考:CRC校验原理及步骤https://blog.csdn.net/d_leo/article/details/73572373 什么是CRC校验? CRC即循环冗余校验码:是数据通信领域中最常用的 ...

  9. 【RE】3 CRC校验原理及实现

    0 简介 循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可 ...

最新文章

  1. 笔记本右侧手滑板Synaptics
  2. linux string split,linux下awk内置函数的使用(split/substr/length)
  3. spring-data-redis 使用
  4. ios 跳转到某 app 的评价区域、由某应用跳转到其他应用
  5. 使用logrotate分割tomcat日志
  6. JS实现上下左右对称的九九乘法表
  7. Android OpenGL Cannot create GL program: 0 GL error: 1282
  8. .net MVC之表单的使用
  9. unity3d 资源打包加密
  10. 设计模式(五)学习----装饰模式
  11. mysql的分类有哪些_MYSQL查询所有的分类,以及每个分类下面所有的文章?
  12. 【Discuz系列教程2】论坛入口forum.php
  13. css3中的过度transition与动画animation以及字体@font-face
  14. 20200714每日一句
  15. 最终,我决定将代码迁出x86架构!
  16. Latex:字体设置
  17. [Mac]图像处理JPEG工具箱jpegtbx_1.4的MATLAB编译及使用
  18. jq正则过滤html style,Jqgrid利用正则匹配表达式正确移除html标签
  19. 证券教父阚治东出手:UU跑腿获2亿元B轮融资
  20. 软件质量管理体系 type:pdf_昆明医疗器械软件注册流程,软件评估_上海峦灵

热门文章

  1. 2019DevFest | 从互联网前端到2B交付型前端-探索面向交付的实用前端技术栈
  2. In-memory Computing with SAP HANA读书笔记 - 第二章:SAP HANA overview
  3. 【C++】C++数组初始化方法
  4. SSL握手过程实例抓包分析
  5. 流量分析实战(1⃣️)_2014_11_16
  6. 【Unity】加载时 Newtonsoft.Json 提示 Metadata file `Newtonsoft.Json.dll` does not contain valid metadata
  7. 淘宝卖家如何设置公益宝贝
  8. 汇编语言基础之七- 框架指针的省略(FPO)
  9. 你是人间的四月天---林徽因
  10. python3+scrapy+selenium爬取英雄联盟英雄资料