Modbus CRC16 算法(举例)

1. Modbus CRC16 算法规范

Modbus 用的 CRC 算法标准称为 "Modbus CRC-16"​ 或 "CRC-16-IBM",也叫 CRC-16-ANSI,多项式为:

多项式 = x 16 + x 15 + x 2 + 1 多项式=x^{16} + x^{15} + x^{2} + 1 多项式=x16+x15+x2+1

用 16 进制表示时,多项式是 0x8005(但注意,Modbus 是高位在前运算,这里 Modbus 采用的是位逆序后的 0xA001​ 进行右移计算)。

算法初始值和结果异或:
初始 CRC 值 = 0xFFFF

实际上,在 Modbus RTU 中,计算时每个字节先与 CRC 低字节异或,然后 CRC 右移 1 位,如果移出位是 1 则与多项式 0xA001 异或(这是 0x8005 的位逆序多项式)。计算完所有字节后,得到的 CRC 值在传输时是低字节在前(Little-endian 字节顺序)附加在帧末尾。

简单概括
取当前数据的 1 位,与 CRC 的低位(bit 0)异或,结果记为 xorBit,然后 CRC 右移 1 位,如果 xorBit为 0,继续取数据的下一位;如果 xorBit为 1,则 CRC 与多项式 0xA001 异或。

2. 对 01 03 00 00 00 01进行 CRC 计算

用这个算法来算。

字节 0x01:

crc = 0xFFFF ^ 0x01 = 0xFFFE (1111 1111 1111 1110)

循环 8 次(一次一位):

位 0:crc & 1 = 0 → 右移 1 位:0x7FFF

位 1:0x7FFF & 1 = 1 → 右移 1 位得 0x3FFF,然后异或 0xA001:

0x3FFF ^ 0xA001 = 0x9FFE

位 2:0x9FFE & 1 = 0 → 0x4FFF

位 3:0x4FFF & 1 = 1 → 右移:0x27FF ^ 0xA001 = 0x87FE

位 4:0x87FE & 1 = 0 → 0x43FF

位 5:0x43FF & 1 = 1 → 右移:0x21FF ^ 0xA001 = 0x81FE

位 6:0x81FE & 1 = 0 → 0x40FF

位 7:0x40FF & 1 = 1 → 右移:0x207F ^ 0xA001 = 0x807E

处理完字节 0x01 后,CRC = 0x807E。

字节 0x03:

crc ^= 0x03 → 0x807E ^ 0x03 = 0x807D

循环 8 次:

0x807D & 1 = 1 → 右移:0x403E ^ 0xA001 = 0xE03F

0xE03F & 1 = 1 → 右移:0x701F ^ 0xA001 = 0xD01E

0xD01E & 1 = 0 → 0x680F

0x680F & 1 = 1 → 右移:0x3407 ^ 0xA001 = 0x9406

0x9406 & 1 = 0 → 0x4A03

0x4A03 & 1 = 1 → 右移:0x2501 ^ 0xA001 = 0x8500

0x8500 & 1 = 0 → 0x4280

0x4280 & 1 = 0 → 0x2140

CRC = 0x2140

字节 0x00: (跟0异或结果是本身)

crc ^= 0x00 = 0x2140

循环 8 次(每次 crc & 1 都是 0,因为 0x2140 二进制 0010 0001 0100 0000,最低位是 0,但右移过程中最低位会变化,我们仔细算):

0x2140 & 1 = 0 → 0x10A0

0x10A0 & 1 = 0 → 0x0850

0x0850 & 1 = 0 → 0x0428

0x0428 & 1 = 0 → 0x0214

0x0214 & 1 = 0 → 0x010A

0x010A & 1 = 0 → 0x0085

0x0085 & 1 = 1 → 右移:0x0042 ^ 0xA001 = 0xA043

0xA043 & 1 = 1 → 右移:0x5021 ^ 0xA001 = 0xF020

CRC = 0xF020

字节 0x00:

crc ^= 0x00 = 0xF020

循环:

0xF020 & 1 = 0 → 0x7810

0x7810 & 1 = 0 → 0x3C08

0x3C08 & 1 = 0 → 0x1E04

0x1E04 & 1 = 0 → 0x0F02

0x0F02 & 1 = 0 → 0x0781

0x0781 & 1 = 1 → 右移:0x03C0 ^ 0xA001 = 0xA3C1

0xA3C1 & 1 = 1 → 右移:0x51E0 ^ 0xA001 = 0xF1E1

0xF1E1 & 1 = 1 → 右移:0x78F0 ^ 0xA001 = 0xD8F1

CRC = 0xD8F1

字节 0x00:

crc ^= 0x00 = 0xD8F1

循环:

0xD8F1 & 1 = 1 → 右移:0x6C78 ^ 0xA001 = 0xCC79

0xCC79 & 1 = 1 → 右移:0x663C ^ 0xA001 = 0xC63D

0xC63D & 1 = 1 → 右移:0x631E ^ 0xA001 = 0xC31F

0xC31F & 1 = 1 → 右移:0x618F ^ 0xA001 = 0xC18E

0xC18E & 1 = 0 → 0x60C7

0x60C7 & 1 = 1 → 右移:0x3063 ^ 0xA001 = 0x9062

0x9062 & 1 = 0 → 0x4831

0x4831 & 1 = 1 → 右移:0x2418 ^ 0xA001 = 0x8419

CRC = 0x8419

字节 0x01:

crc ^= 0x01 = 0x8418

循环:

0x8418 & 1 = 0 → 0x420C

0x420C & 1 = 0 → 0x2106

0x2106 & 1 = 0 → 0x1083

0x1083 & 1 = 1 → 右移:0x0841 ^ 0xA001 = 0xA840

0xA840 & 1 = 0 → 0x5420

0x5420 & 1 = 0 → 0x2A10

0x2A10 & 1 = 0 → 0x1508

0x1508 & 1 = 0 → 0x0A84

CRC = 0x0A84

最终 CRC = 0x0A84

3. 传输顺序

CRC 计算结果 0x0A84 在传输时,低字节在前,即先发 0x84,再发 0x0A。

所以整帧为:

yaml 复制代码
01 03 00 00 00 01 84 0A

4. CRC(循环冗余校验)在线计算

网址:CRC(循环冗余校验)在线计算

相关推荐
boss-dog1 天前
UR robot ROS2 Driver 快速入门使用
机械臂·ros2·urdf·moveit2·ur
boss-dog2 天前
Moveit2使用说明(C++)
c++·ros2·moveit2
小帽哥aicv2 天前
ubuntu22 安装ros2-humble, Navigation2, RTABMap
linux·ros2
一个平凡而乐于分享的小比特3 天前
I2C、SPI、CAN、串口通信详细对比
can·uart·spi·i2c
PegasusYu3 天前
Electron使用WebAssembly实现CRC-16 X25校验
electron·nodejs·wasm·webassembly·crc16·crc-16·x25
Lilixxs4 天前
三菱 FX3U Modbus CRC16 校验码生成程序(结构化工程,计算法)
plc·modbus·三菱·crc16·fx3u·plc 程序
叠叠乐4 天前
ubuntu ROS1 wifi开关 热点开关 链接指定wifi 扫描wifi节点
ubuntu·ros2
一个平凡而乐于分享的小比特4 天前
CAN通信协议详解:工业通信的“神经系统”
can·汽车电子·工业控制
敬往事一杯酒哈5 天前
1.4 ROS2 集成开发环境搭建
ros2