Modbus CRC16校验详解与实战应用 Modbus 里的 CRC 是检错码发送方对前面的数据算出一个 16 位校验值附在帧尾接收方用同样算法再算一遍或者把整帧含 CRC 一起算结果应为 0。1. Modbus CRC 的固定参数Modbus RTU 用的是CRC-16/MODBUS参数固定宽度16 位初始值0xFFFF多项式正常写法0x8005实际字节算法里用反转后的0xA001输入反转是输出反转是结果异或0x0000发送顺序低字节在前高字节在后所以你会看到很多代码里写0xA001它来自0x8005 1000 0000 0000 0101 反转 1010 0000 0000 0001 0xA0012. 最常用的计算算法在CRC计算时只用8个数据位起始位及停止位如有奇偶校验位也包括奇偶校验位都不参与CRC计算。CRC计算方法是1、预置1个16位的寄存器为十六进制FFFF全1此寄存器为CRC寄存器2、把第一个8位二进制数据即通讯信息帧的第一个字节与16位的CRC寄存器的低八位相异或把结果存放于CRC寄存器。3、把CRC寄存器的内容右移一位朝低位用0填补最高位并检测右移后的移出位。4、如果移出位为零则重复第三步再次右移一位如果移出位为1CRC寄存器与多项式A001进行异或。5、重复步骤3和4直到右移8次这样整个8位数据全部进行了处理。6、重复步骤2和5进行通讯信息帧下一个字节的处理。7、将该通讯信息帧所有字节按上述步骤计算完成后得到的16位CRC寄存器的高、低字节进行交换8、最后得到的CRC寄存器内容即为CRC校验码。伪代码crc 0xFFFF for 每个字节 b in 数据: crc crc XOR b 重复 8 次: if crc 最低位是 1: crc (crc 1) XOR 0xA001 else: crc crc 1 最后得到的 crc 就是 CRC 值注意计算 CRC 时只算 CRC 前面的数据不算 CRC 本身。3. 举个例子1. 要计算的数据假设要发送的原始数据是01 03 00 00 00 01含义01 从站地址 03 功能码读保持寄存器 00 00 起始地址 00 01 读取数量1 个寄存器Modbus RTU 需要在这 6 个字节后面加上 2 个字节 CRC。使用的 CRC 算法是CRC-16/MODBUS初始值0xFFFF 多项式反转值0xA001 每次处理一个字节再循环 8 次 如果最低位是 1则crc (crc 1) ^ 0xA001 如果最低位是 0则crc crc 12. 第一个字节0x01的详细计算初始 CRCcrc 0xFFFF处理第一个字节0x01crc crc ^ 0x01 0xFFFF ^ 0x01 0xFFFE然后对0xFFFE循环 8 次。第几次当前 CRC最低位操作计算后 CRC初始0xFFFE0xFFFE10xFFFE0右移1位0x7FFF20x7FFF1右移后异或0xA0010x9FFE30x9FFE0右移0x4FFF40x4FFF1右移后异或0xA0010x87FE50x87FE0右移0x43FF60x43FF1右移后异或0xA0010x81FE70x81FE0右移0x40FF80x40FF1右移后异或0xA0010x807E具体某一步举例第 2 步当前 CRC 0x7FFF 最低位是 1 先右移0x7FFF 1 0x3FFF 再异或0x3FFF ^ 0xA001 0x9FFE所以处理完第一个字节0x01后crc 0x807E3. 后续字节的汇总计算接下来依次处理03 00 00 00 01每个字节的处理方式都一样crc crc ^ 当前字节 然后循环 8 次 if crc 1: crc (crc 1) ^ 0xA001 else: crc crc 1汇总如下处理的字节异或后的 CRC8 次循环后的 CRC初始0xFFFF0x010xFFFF ^ 0x01 0xFFFE0x807E0x030x807E ^ 0x03 0x807D0x21400x000x2140 ^ 0x00 0x21400xF0200x000xF020 ^ 0x00 0xF0200xD8F10x000xD8F1 ^ 0x00 0xD8F10x84190x010x8419 ^ 0x01 0x84180x0A84所以最终 CRC 值是crc 0x0A844. 最终发送的完整帧Modbus RTU 规定 CRC 发送时低字节在前 高字节在后0x0A84的低字节和高字节是低字节0x84 高字节0x0A所以完整帧是01 03 00 00 00 01 84 0A其中01 03 00 00 00 01 原始数据 84 0A CRC 校验注意不是01 03 00 00 00 01 0A 84 ← 这是错的因为 Modbus 要求低字节先发。5. 接收方如何校验接收方收到完整帧01 03 00 00 00 01 84 0A然后把整帧 8 个字节一起做同样的 CRC 计算。如果计算正确最终结果应该是0x0000因为 CRC 算法有一个性质原始数据 正确 CRC 一起再算一遍余数为 0所以接收方通常这样判断计算整帧 CRC 如果结果 0x0000则校验通过 否则校验失败4. C 语言示例#includestdint.huint16_tmodbus_crc16(constuint8_t*buf,uint16_tlen){uint16_tcrc0xFFFF;for(uint16_ti0;ilen;i){crc^buf[i];for(intj0;j8;j){if(crc0x0001){crc(crc1)^0xA001;}else{crc1;}}}returncrc;}发送时这样追加uint16_tcrcmodbus_crc16(frame,len);frame[len]crc0xFF;// 低字节先发frame[len1](crc8)0xFF;// 高字节后发校验时通常把收到的整帧包括最后两个 CRC 字节一起再算uint16_tcrcmodbus_crc16(frame,len2);if(crc0){// CRC 正确}5.labview中的crc校验表示步骤1先将字符串强制转换成整型数组2跟FFFF异或3右移一位如果进位输出最低位是1那么与A001异或。4右移8次5交换字节并且强制转换成字符串6整体7结果测试