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(循环冗余校验)在线计算

相关推荐
来可电子-CAN2 天前
告别“选择性采集”,精准定位新能源汽车售后故障——4路CANFD数据记录仪替代方案解析
汽车·can·汽车电子·工程机械·煤矿
-点灯-3 天前
【无标题】
ros2
General_G3 天前
irobot_benchmark的编译和使用
linux·中间件·机器人·ros2
阿豪只会阿巴4 天前
【多喝热水系列】从零开始的ROS2之旅——Day10 话题的订阅与发布1:Python
开发语言·c++·python·ubuntu·ros2
阿豪只会阿巴5 天前
【多喝热水系列】从零开始的ROS2之旅——Day9 初识话题通信:基本命令
c++·笔记·python·ubuntu·ros2
阿豪只会阿巴5 天前
项目心得——发布者和订阅者问题解决思路
linux·开发语言·笔记·python·ubuntu·ros2
仰科网关5 天前
工厂环境监控传感器Modbus数据上传数据到环保局HJ212平台的项目案例
网关·modbus·vfbox·协议转换·hj212
Tipriest_7 天前
ROS 2 rosbag2 播放出现 “Message queue starved. Messages will be delayed.” 的处理步骤
消息队列·ros2·缓存机制
不脱发的程序猿9 天前
CAN总线如何区分和识别帧类型
单片机·嵌入式硬件·嵌入式·can