MODBUS协议中的CRC校验_RobotWoods的博客-CSDN博客_modbus crc
以下面这段收发数据为例:
发送的数据是工控机发送给plc的,他们的通信是modbus通信,前面的01。。。。。0f是实际使用的数据,具体意义可以查,后面的4位数8774,是前面这一串数字的校验码,这个校验码可以由下面这个生成器来生成。
CRC(循环冗余校验)在线计算_ip33.com
注意要选hex,这是一串16进制数,两两一组
参数模型有很多,不要去选自定义,直接选图片里那个,这个是最常用的
模型选定之后,下面的各种配置选项就已经自动的配置完成了,然后点击计算,就可以得到校验计算结果74 87,这是两个字节,一个字节是8位2进制数,或者2位十六进制数,这里的高位和低位调换一下顺序,得到的就是87 74
补充:
WIDTH:宽度,即CRC比特数。
这里就是你想得到的crc校验码的比特数,这里我们想得到的是16个2进制数,这里当然是选16,rtu协议里本来就是选用这个规则
POLY:生成项的简写,以16进制表示。例如:CRC-32即是0x04C11DB7,忽略了最高位的"1",即完整的生成项是0x104C11DB7。
将多项式转化为二进制序列,由G(X) = X4 + X3 + 1可知二进制一种有五位,第4位、第三位和第零位分别为1,则序列为11001
再举个例子:如果多项式是x3+x+1,可以写成:1*x3+0*x2+1*x+1*1 有幂次就为1 没有幂次就为0 首尾一定要是1 所以 1 0 1 1
再回到图中的例子中,x16 + x15 + x2 + 1对应的2进制数字是1 1000 0000 0000 0101,注意,在规则里,要把最高位的1去掉,所以就变为1000 0000 0000 0101,这个2进制数对应的16进制数就是8005
INIT:这是算法开始时寄存器(crc)的初始化预置值,十六进制表示。
REFIN:待测数据的每个字节是否按位反转,True或False。
REFOUT:在计算后之后,异或输出之前,整个数据是否按位反转,True或False。
XOROUT:计算结果与此参数异或后得到最终的CRC值。
关于crc校验码的具体的计算过程,我找到了一个写得很好的文章,链接如下:
CRC校验的计算过程-电子发烧友网
Width:指的CRC校验值的长度,通常有8bit,16bit,24bit,32bit等。
Poly:是多项式的值,以上面图中的CRC-8:x8+x2+x+1为例,它表示二进制为100000111,去掉最高位的1,十六进制表示就是0x07
Init: Init 的位数和Poly的位数相同,它的值为全0或者全F,当全为0时,在算法开始前对数据(这个数据是根据RefIn的值得到的)后面补上CRC位数个0后就可以进行后续计算了。当全为1时,表示在算法开始前对数据的前CRC位数(高位)先和对应位数个1进行异或(即:前CRC位数的值按位取反),再在后面补上CRC位数个0,才进行后续计算。
RefIn和Refout:它们要么全为False,要么全为True。
RefIn为False表示,输入的原始数据的每个字节的第7位作为最高有效位,第0位作为最低有效位,即正常计算即可
当RefIn为True时,输入的原始数据的每个字节需要做个逆序的处理,注意:针对的每个字节,而不是整个数据,以一个4字节的原始数据为例:
当Refout为False时,输出不做处理,当Refout为True,需要对输出数据做一次整个数据的逆序处理,注意:这里做的逆序和RefIn不同,它不是按字节逆序,而是整个逆序,以CRC-32为例来说明,最后的数据为32位,当Refout为True时,翻转如下:
XorOut:表示根据上面参数计算完后,和这个数再进行一次异或。
下面分析一下上面的结果0x79的由来:
1) 0x13 对应二进制为00010011
2)由于RefIn为False,所以0x13不做处理还是00010011
3) 因为Init为0x00,00010011后面加8个0即可,输入数据变为0001001100000000
4) 多项式为x8+x2+x+1 对应二进制100000111,将上述0001001100000000 除以该多项式对应的100000111
整个计算过程如下:
最后得到余数:01111001
5) 由于RefOuT为False,所以余数不变,还为01111001
6) 由于Xorout为0,表示不用再取反,所以最终的结果就是01111001,即十六进制0x79
算一个不过瘾,我们再来计算一个
这一次和上面唯一的不同是将初始值由原来的0x00换为了0xFF,这个例子就是给大家演示初始值到底什么意思.
下面分析一下上面的结果0x79的由来:
1) 0x13 对应二进制为00010011
2) 由于RefIn为False,所以0x13不做处理还是00010011
3) 因为Init为0xFF,00010011的高8位要先与0xFF异或,输入数据变为11101100,后面再加入8个0,变为 1110110000000000
4) 多项式为x8+x2+x+1 对应二进制100000111,将上述1110110000000000 除以该多项式对应的100000111,最后得到余数:10001010
5) 由于RefOuT为False,所以余数不变,还为10001010
6) 由于Xorout为0,表示不用再取反,所以最终的结果就是10001010,即十六进制0x8A
这个例子演示了初始值的含义,我们再看最后一个例子,这个例子演示了RefIn和RefOut为True的具体含义
1) 0x13 对应二进制为00010011
2) 由于RefIn为True,所以0x13需要逆序一下得到11001000
3) 因为Init为0x00,所以11001000后面直接添加4个0即可,得到110010000000
4) 多项式为x4+x+1 对应二进制10011,将上述110010000000 除以10011,最后得到余数:0010
5) 由于RefOuT为True,所以余数要逆序变为0100
6) 由于Xorout为0,表示不用再取反,所以最终的结果就是0100
CRC每种参数模型的检错能力,同时CRC也可以纠错,这需要专业的数学计算,这也超出了我的能力,这里也不介绍了。
看完这些大家应该都清楚了CRC的计算,有些 MCU本身集成了硬件CRC模块,你只需要配置寄存器,就可以算出CRC结果了,或者也可以通过软件来实现,