python实现crc16校验
? ? ? ? 前阵子由于“摸鱼”需要,笔者学习了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实现效果
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())
|