什么是CRC校验: http://www.51hei.com/bbs/dpj-47736-1.html
https://wenku.baidu.com/view/0b9f0dd4360cba1aa811daf5.html?rec_flag=default&sxts=1532740998346
CRC-16校验码计算方法:
常用查表法和计算法。计算方法一般都是:
(1)、预置1个16位的寄存器为十六进制FFFF(即全为1),称此寄存器为CRC寄存器;
(2)、把第一个8位二进制数据(既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器,高八位数据不变;
(3)、把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位;
(4)、如果移出位为0:重复第3步(再次右移一位);如果移出位为1,CRC寄存器与多项式A001(1000 0000 0000 0101)进行异或;(modbus多项式为x16+x15+x2+1 = 8005,A001是8005按位颠倒后的结果)
(5)、重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
(6)、重复步骤2到步骤5,进行通讯信息帧下一个字节的处理;
(7)、将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换;
(8)、最后得到的CRC寄存器内容即为:CRC码。
所以要写一个CRC校验首先你得搞清楚这些:
一、确定CRC-8还是CRC-16校验,从而确定一帧数据结尾附加的字节数。
二、确定生成多项式。(我是根据modbus协议写的。)
三、确定是正序检验还是反序检验。正序检验采用正序简记式,反序检验采用反转简记式。
四、判断CRC是否正确的两种方法:
1.算前七个字节的CRC算出来与最后一个字节相等,则正确。(一般用于发送端计算CRC值)
2.算8个字节的CRC,算出来等于0则正确。(一般用于接收端进行检测)(我一般用这个)
也就是说假如我是发送端,我要发送一串数据,当然了屁股后头还得跟着几个字节的CRC(刚刚说了有CRC8和CRC16还有CRC32之分),那么这几个字节的CRC就是根据你要发送的这串数据(不包含CRC位)来算。算好了,发出去。再假设下我现在是在接收端,接收端我接收到了主机发送过来的一串数据,这个时候我咋知道数据发过来有没有出错呢(没出错就做出相应的响应,出错就抛弃这帧数据)?将接收到的数据去除CRC位,我再算一次CRC。假如算出来的跟他发送过来的CRC一样,哎呦,这串数据没出错。响应吧。你的响应被主机接收到,主机也是像之前一样算CRC,然后比较发送过来的CRC是否一样。然后照此循环。看懂了吗?没看懂?那附上我学长教我时写的小教程(其实就是一张图而已。。。)
下面是程序实现(这个程序就是实现算CRC哒):
小细节:在VS中:int(16bit) short(16bit) char(8bit)
#include"stdio.h"
int main ()
{
int len = 0;
int i, j;
unsigned short ax1, axh1, axl1 ;
unsigned char axh, axl;
unsigned short ax = 0xffff;
unsigned char data[8] = {};
while(1) //动态录入数据回车结束。
{
scanf("%d", &data[len]);
len++;
if(getchar() == '\n')
break;
}
printf("我爱灌汤包\n");
for(j = 0; j < len; j++) //上述计算步骤(6) //calculate ax (计算ax)
{
ax ^= (unsigned short)data[j];
for(i = 0; i < 8; i++)//上述计算步骤(5)
{
if(ax & 1)//若最高位为1则
{
ax = (ax >> 1);
ax ^= 0xa001;
}
else
{
ax = (ax >> 1);
}
}
}
ax1 = ax;
axl = (ax1>>8); // ax的高低位分开显示
axh = ax1;
axl1=(ax1 >> 8); // ax的高低位合并显示
axh1 = (ax1 << 8);
ax = axh1 | axl1;
printf("%02x %02x %02x\n", axh, axl, ax);
getchar();
return 0;
}
以上我是用数组写的,回头再贴上用指针写的。
查表法是将移位异或的计算结果做成了一个表,就是将0~256放入一个长度为16位的寄存器中的低八位,高八位填充0,然后将该寄存器与多项式0XA001按照上述3、4步骤,直到八位全部移出,最后寄存器中的值就是表格中的数据,高八位、低八位分别单独一个表。(后续再补充吧)