前阵子由于“摸鱼”需要,笔者学习了crc16校验这一小小的通信领域知识。也就有了这篇博客。在此笔者不求甚解(通信大佬可以自行略过),有错漏的地方还望指出\(^o^)/~♪(・ω・)ノ
在此笔者借鉴了这位大佬的博客https://blog.csdn.net/qq_37591637/article/details/83376006
目录
python实现crc16校验
正题
伪代码
举例
python代码 (附上注释)
为什么会有crc校验?
在数据传输过程中,无论传输系统的设计再怎么完美,差错总会存在,这种差错可能会导致在链路上传输的一个或者多个帧被破坏,从而接受方接收到错误的数据。为尽量提高接受方收到数据的正确率,在接收方接收数据之前需要对数据进行差错检测,当且仅当检测的结果为正确时接收方才真正收下数据。
检测的方式有多种,常见的有奇偶校验、因特网校验和循环冗余校验等。
在计算机网络通信中运用crc校验,相对于其他校验方法就有一定的优势。CRC可以高比例的纠正信息传输过程中的错误,可以在极短的时间内完成数据校验码的计算,并迅速完成纠错过程, CRC 算法检验的检错能力极强,检测成本较低,是计算机信息通信领域最为普遍的校验方式。
一下是笔者在网上找到的crc16的校验方法:
(1)、预置1个16位的寄存器为十六进制FFFF(即全为1),称此寄存器为CRC寄存器;
(2)、把第一个8位二进制数据(既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器,高八位数据不变;
(3)、把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位;
(4)、如果移出位为0:重复第3步(再次右移一位);如果移出位为1,CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;
(5)、重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
(6)、重复步骤2到步骤5,进行通讯信息帧下一个字节的处理;
(7)、将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换;
(8)、最后得到的CRC寄存器内容即为:CRC码。
通过上述方法,我们不妨将它翻译成伪代码:
crc=0xFFFF;
crc=0xFFFF^data(我们将需要校验的数据赋值给data)
for( i=0;i<8; i++ )
{
if(第0位是1){
crc=crc >> 1
crc=crc ^ 0xA001
}
else{
crc=crc >>1
}
}
在此笔者不求甚解,以 2D 为例,如有错漏,还请不吝赐教\(^o^)/~
另外,各位感兴趣可以到http://www.ip33.com/crc.html这个网站进行验证
(注:请选择CRC-16/MODBUS算法)
下面是python实现效果
# -*-coding:utf8-*- ls=input().split() # 这样你可以input数据,用空格隔开,.split在此是用来分割字符串的 datas=list(ls) print(datas) # 输入数据后,打印一下列表 crc16=0xFFFF poly=0xA001 for data in datas: # 表示将datas列表中的每一个变量赋值给data, # 在此你可以自由输入数据,校验的次数是由你输入的数据的多少决定的 a=int(data,16) # print(a) crc16 = a ^ crc16 #^ 异或运算:如果两个位为“异”(值不同),则该位结果为1,否则为0。 for i in range(8): # 对于每一个data,都需要右移8次,可以简单理解为对每一位都完成了校验 if 1&(crc16) == 1: # crc16与上1 的结果(16位二进制)只有第0位是1或0,其他位都是0 # & 与运算:都是1才是1,否则为0 crc16 = crc16 >> 1 # >>表示右移,即从高位向低位移出,最高位补0 crc16 = crc16^poly else: crc16 = crc16 >> 1 # print(crc16)#得到的结果还是10进制 crc16=hex(int(crc16))# 将10进制转换成16进制 # print(crc16) crc16=crc16[2:].upper() # [2:]的作用是将4位16进制的0x消除 # .upper()可以让字母变成大写,只是为了格式好看而已,并不影响校验结果 print(crc16) length = len(crc16) high=crc16[0:length-2].zfill(2) high=str(high) # [0:length]是将得到的4位16进制切片成两个校验码而已 # 一些结果以0开头,会自动把0给吞掉 .zfill(2)可以让结果以两位二进制的形式出现 low=crc16[length-2:length].zfill(2) low=str(low) # print(type(low)) print("校验码低位:"+low.upper()) print("校验码高位:"+high.upper())