GKMLT通讯工具箱(WPF MVVM) - 02-Modbus RTU 与 TCP 报文格式、原理与CRC校验

目录

  1. 通讯方式对比
  2. Modbus协议概述
  3. [Modbus RTU详解](#Modbus RTU详解)
  4. [Modbus TCP详解](#Modbus TCP详解)
  5. [RTU vs TCP对比](#RTU vs TCP对比)
  6. CRC16校验原理
  7. 实战示例

串口通讯 vs 网口通讯

物理层对比

复制代码
┌─────────────────────┐  ┌─────────────────────┐
│   串口通讯 (RTU)    │  │   网口通讯 (TCP)    │
├─────────────────────┤  ├─────────────────────┤
│ • RS-232 / RS-485   │  │ • 以太网 / 光纤      │
│ • 点对点 / 总线型   │  │ • 交换机 / 路由器    │
│ • 传输距离: 短      │  │ • 传输距离: 长       │
│ • 速率: 低          │  │ • 速率: 高          │
│ • 抗干扰: 强        │  │ • 抗干扰: 需屏蔽    │
└─────────────────────┘  └─────────────────────┘

应用场景对比

  • 串口: 工业现场设备 → 短距离、实时控制
  • 网口: 远程监控 → 跨网络、数据采集

Modbus 协议基础

主从架构

复制代码
Master (主站)              Slave (从站)
      ↓ 发送请求
      ↓ ↕ 返回响应
      
┌─────────────┐         ┌─────────────┐
│ PLC/上位机  │────────→│  传感器     │
│             │         │  执行器     │
│             │←────────│  变频器     │
└─────────────┘         └─────────────┘

核心特点

  • 单向通讯:只能由主站发起
  • 事务模型:一次一个事务
  • 地址空间:线圈、离散输入、寄存器

Modbus 功能码

8种标准功能码

功能码 名称 数据类型 方向
0x01 读取线圈 Bool[]
0x02 读取离散输入 Bool[]
0x03 读取保持寄存器 Byte[]
0x04 读取输入寄存器 Byte[]
0x05 写入单个线圈 -
0x06 写入单个寄存器 -
0x0F 写入多个线圈 -
0x10 写入多个寄存器 -

Modbus RTU 报文结构

完整帧结构

复制代码
┌─────────────────────────────────────────────────┐
│            Modbus RTU 数据帧                      │
├─────────────────────────────────────────────────┤
│ [从站地址][功能码][数据区][CRC16低][CRC16高]     │
│   1字节   1字节   N字节    1字节    1字节           │
└─────────────────────────────────────────────────┘

关键特性

  • ✅ 串行传输(RS-232/485)
  • ✅ 二进制编码
  • ✅ CRC16循环冗余校验
  • ✅ 紧凑的帧结构

Modbus RTU 读取报文示例

读取保持寄存器 (功能码 0x03)

请求报文 (读取10个寄存器)

复制代码
HEX: 01 03 00 00 00 0A [CRC_L] [CRC_H]
     ┌─┬─┬────┬────┬───────┐
     │ │ │    │    │       │
     ↓ ↓ ↓    ↓    ↓       ↓
    [01][03][00][00][00][0A][xx][xx]
     │  │  │   │    │      │
     │  │  │   │    │      └─ CRC16校验
     │  │  │   │    └──── 数量(10)
     │  │  └───┴─────── 起始地址(0)
     │  └─────── 功能码(读保持寄存器)
     └────────── 从站地址(1)

响应报文 (返回20字节数据)

复制代码
HEX: 01 03 14 [20字节寄存器数据] [CRC_L] [CRC_H]
     ┌─┬─┬──┬───────────────────┬───────┐
     │ │ │  │                   │       │
     ↓ ↓ ↓  ↓                   ↓       ↓
    [01][03][14][D0 D1 D2 D3 ... 0F][xx][xx]
     │  │  │      └── 实际数据 ──┘       │
     │  │  └─── 字节数(20)              │
     │  └───── 功能码                    │
     └──────── 从站地址                   └─ CRC16校验

Modbus TCP 报文结构

MBAP + Modbus PDU

复制代码
┌────────────────────────────────────────────────────────────┐
│              Modbus TCP 数据帧                              │
├────────────────────────────────────────────────────────────┤
│ MBAP Header (7字节)         │ Modbus PDU (N+1字节)         │
├──────────────┬───────────┼──────────────────────────────┤
│ 事务ID      │ 协议ID    │[单元ID][功能码][数据区]      │
│  2字节      │  2字节    │  1字节  1字节   N字节        │
├──────────────┴───────────┴──────────────────────────────┤
│ Transaction │ Protocol  │ Unit   │Function│   Data       │
│    ID       │   ID      │   ID   │   Code  │              │
└──────────────┴───────────┴────────┴────────┴──────────────┘

MBAP头结构

  • Transaction ID (2字节): 事务标识符,匹配请求/响应
  • Protocol ID (2字节): 协议标识符,Modbus TCP = 0x0000
  • Length (2字节): 后续字节数
  • Unit ID (1字节): 从站地址

Modbus TCP 读取报文示例

读取保持寄存器 (功能码 0x03)

请求报文

复制代码
HEX: 00 01 00 00 00 06 01 03 00 00 00 0A
     ┌───┬───┬───────┬───┬───┬────┬───┬────┬────┬────┐
     │   │   │       │   │   │    │   │    │    │    │
     ↓   ↓   ↓       ↓   ↓   ↓    ↓   ↓    ↓    ↓    ↓
    [00][01][00][00][00][06][01][03][00][00][00][0A]
     │   │   │       │   │   │    │   │    │    └── 数量(10)
     │   │   │       │   │   │    │   │    └─────── 起始地址(0)
     │   │   │       │   │   │    │   └────────── 功能码(0x03)
     │   │   │       │   │   │    └─────────────── 单元ID(从站1)
     │   │   │       │   │   └──────────────────── 长度(6字节)
     │   │   │       │   └────────────────────────── 协议ID(0)
     │   │   │       └─────────────────────────────── 事务ID(1)
     │   │   └──────────────────────────────────────────── 帧头(7字节)
     │   └────────────────────────────────────────────────── MBAP头
     └───┴──────────────────────────────────────────────────── 完整TCP报文

响应报文

复制代码
HEX: 00 01 00 00 00 15 01 03 14 [20字节寄存器数据]
     ┌───┬───┬───────┬───┬────┬───┬──┬──────────────┐
     │   │   │       │   │     │   │  │              │
     ↓   ↓   ↓       ↓   ↓     ↓   ↓  ↓              ↓
    [00][01][00][00][00][15][01][03][14][D0 D1 ... 0F]
     │   │   │       │   │     │   │  └── 字节计数     │
     │   │   │       │   │     │   │  └── 实际数据(20字节) │
     │   │   │       │   │     │   └──────────────────── 功能码
     │   │   │       │   │     └─────────────────────── 单元ID
     │   │   │       │   └────────────────────────────── 长度(21字节)
     │   │   │       └─────────────────────────────────── 协议ID
     │   │   └──────────────────────────────────────────── 事务ID
     │   └───────────────────────────────────────────────── MBAP头
     └───┴────────────────────────────────────────────────── 完整报文

RTU vs TCP 核心区别

报文结构对比图

复制代码
┌─────────────────────────────────────────────────────────────┐
│                  Modbus RTU 报文结构                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────┬────┬─────────────┬────────┐                    │
│  │从站地址│功能│   数据区     │CRC16   │                    │
│  │ (1B)   │码  │   (N Bytes)   │(2B)    │                    │
│  └─────────┴────┴─────────────┴────────┘                    │
│  简单紧凑                                                    │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                  Modbus TCP 报文结构                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────── MBAP Header ─────────────┬─────────┐    │
│  │TransID│ProtID│Length│UnitID│ 功能码│ 数据区   │    │
│  │ (2B)  │(2B) │ (2B) │ (1B) │ (1B)  │(N Bytes) │    │
│  ├───────┼──────┼──────┼──────┼──────┼──────────┤    │
│  │事务ID │ 协议 │ 长度 │ 单元 │ 功能 │   数据   │    │
│  │       │ 标识 │       │ 标识 │  码  │          │    │
│  └───────┴──────┴──────┴──────┴──────┴──────────┘    │
│  复杂但标准化                                                │
└─────────────────────────────────────────────────────────────┘

RTU vs TCP 详细对比

特性 Modbus RTU Modbus TCP
传输层 串口(RS-232/485) TCP/IP
最大长度 256字节 260字节
地址标识 从站地址(1字节) 单元标识符(1字节)
寻址范围 1-247 1-247
校验方式 CRC16 TCP校验和
帧头开销 2字节(从站+功能) 7字节(MBAP)
默认端口 串口参数 502
速度 较慢 较快
传输距离 <1200米 无限制(网络)

CRC16 校验原理 (1/4)

什么是CRC?

CRC (Cyclic Redundancy Check) - 循环冗余校验

复制代码
定义: 根据数据块产生简短固定位数校验码的散列函数
      主要用于检测或验证数据传输/存储后可能出现的错误

┌─────────────────────────────────────────────────┐
│  原始数据                                        │
│  ↓                                              │
│  生成CRC校验码                                   │
│  ↓                                              │
│  数据 + CRC ──→ 传输/存储 ──→ 接收端验证                │
└─────────────────────────────────────────────────┘

CRC16 特点

  • 校验码: 2字节 (16位)
  • 多项式: x¹⁶ + x¹⁵ + 1 (Modbus)
  • 初始值: 0xFFFF
  • 反转输入/输出: 是

CRC16 校验原理 (2/4)

计算流程图

复制代码
┌─────────────────────────────────────────────────────┐
│              CRC16 计算流程                           │
└─────────────────────────────────────────────────────┘

初始化:
  CRC高字节 = 0xFF
  CRC低字节 = 0xFF
  索引指针 = 0

┌──────────────────────────────────────────┐
│  开始处理每个字节                      │
└──────────────────────────────────────────┘
          ↓
┌──────────────────────────────────────────┐
│  取下一个字节                        │
│  dataByte = buffer[index++]           │
└──────────────────────────────────────────┘
          ↓
┌──────────────────────────────────────────┐
│  计算索引                            │
│  index = CRC_H ⊕ dataByte            │
│  └── CRC_H = 高字节                    │
└──────────────────────────────────────────┘
          ↓
┌──────────────────────────────────────────┐
│  查表更新CRC                         │
│  CRC_H = CRC_L ⊕ TABLE[index]         │
│  CRC_L = TABLE_H[index]                │
└──────────────────────────────────────────�
          ↓
    还有数据? ──→ 否 ──→ 返回CRC
          ↓ 是

CRC16 校验原理 (3/4)

查表法计算

查表原理

复制代码
预计算的查找表 (256字节)

┌─────────────────────────────────────────┐
│  索引 0x00: CRC_H = 0x00, CRC_L = 0x00    │
│  索引 0x01: CRC_H = 0xC1, CRC_L = 0xC0    │
│  索引 0x02: CRC_H = 0x81, CRC_L = 0xC1    │
│  ...                                   │
│  索引 0xFF: CRC_H = 0x40, CRC_L = 0x81    │
└─────────────────────────────────────────┘

计算步骤:
1. 取当前CRC高字节与数据字节异或
2. 异或结果作为索引
3. 从查找表取出新的CRC高低字节
4. 重复直到所有数据处理完

示例计算

复制代码
数据: 0x01, 0x03, 0x00, 0x00, 0x0A

初始: CRC = 0xFFFF

第1字节(0x01):
  index = 0xFF ⊕ 0x01 = 0xFE
  CRC_H = 0x40 ⊕ aucCRCLo[0xFE] = ...
  CRC_L = aucCRCHi[0xFE] = ...

... (重复5次)

最终: CRC = [CRC_L] [CRC_H]

CRC16 校验原理 (4/4)

在Modbus RTU中的应用

报文验证流程

复制代码
发送端:
┌──────────────┐
│  数据        │
│  01 03 00 00 │
│  00 0A       │
└──────┬───────┘
       ↓
┌──────────────┐
│  计算CRC16   │
│  CRC = ...    │
└──────┬───────┘
       ↓
┌──────────────┐
│  附加CRC     │
│ 01 03 00 00 │
│  00 0A CRC_L │
│  CRC_H       │
└──────────────┘

接收端:
┌──────────────┐
│  接收数据    │
│  含CRC       │
└──────┬───────┘
       ↓
┌──────────────┐
│  计算CRC16   │
│  CRC_calc    │
└──────┬───────┘
       ↓
┌──────────────┐
│  比较CRC     │
│  CRC_recv == │
│  CRC_calc ?   │
└──────┬───────┘
       ↓
    ✓ 校验通过  ✗ 数据错误

Modbus RTU 写入报文

写入单个寄存器 (0x06)

请求报文

复制代码
HEX: 01 06 00 00 00 01 [CRC_L] [CRC_H]
     ┌─┬─┬────┬────┬────┬──────┐
     │ │ │    │    │    │       │
     ↓ ↓ ↓    ↓    ↓    ↓       ↓
    [01][06][00][00][00][01][xx][xx]
     │  │  │   │    │    └─ CRC16
     │  │  │   │    └───── 写入值 (0x0001)
     │  │  │   └───────── 寄存器地址 (0)
     │  │  └───────────── 功能码 (写单个寄存器)
     │  └────────────────── 从站地址 (1)

响应报文 (Echo - 回显)

复制代码
HEX: 01 06 00 00 00 01 [CRC_L] [CRC_H]
     └─────────────── 完全相同 ───────┘

特点: 响应报文与请求报文完全相同(回显机制)


Modbus TCP 写入报文

写入多个寄存器 (0x10)

请求报文

复制代码
HEX: 00 05 00 00 00 0F 01 10 00 00 00 02 04 00 10 20 30
     ┌───┬───┬───────┬───┬────┬───┬────┬────┬────┬────┬────┬────
     │   │   │       │   │    │   │    │    │    │    │    │    │
     ↓   ↓   ↓       ↓   ↓    ↓   ↓    ↓    ↓    ↓    ↓    ↓    ↓
    [00][05][00][00][00][0F][01][10][00][00][00][02][04][00][10][20][30]
     │   │   │       │   │    │   │    │    │    │    │    │    └─ 数据
     │   │   │       │   │    │   │    │    │    │    │    └───── 字节计数(4)
     │   │   │       │   │    │   │    │    │    │    └─────────── 数量(2)
     │   │   │       │   │    │   │    │    │    └─────────────── 起始地址(0)
     │   │   │       │   │    │   │    │    └────────────────────── 功能码(0x10)
     │   │   │       │   │    │   │    └───────────────────────────── 单元ID(1)
     │   │   │       │   │    │   └─────────────────────────────────── 长度(15)
     │   │   │       │   │    └──────────────────────────────────────── 协议ID(0)
     │   │   │       │   └───────────────────────────────────────────── 事务ID(5)
     │   │   │       └────────────────────────────────────────────────── MBAP头
     │   │   └─────────────────────────────────────────────────────── 数据PDU
     │   └─────────────────────────────────────────────────────────────── Modbus TCP帧

Modbus TCP 响应报文

写入多个寄存器响应

响应报文

复制代码
HEX: 00 05 00 00 00 06 01 10 00 00 00 02
     ┌───┬───┬───────┬───┬────┬───┬────┬────┬────┐
     │   │   │       │   │    │   │    │    │    │
     ↓   ↓   ↓       ↓   ↓    ↓   ↓    ↓    ↓    ↓
    [00][05][00][00][00][06][01][10][00][00][00][02]
     │   │   │       │   │    │   │    │    └───── 数量(2)
     │   │   │       │   │    │   │    └─────────── 起始地址(0)
     │   │   │       │   │    │   └─────────────── 功能码
     │   │   │       │   │    └─────────────────────── 单元ID
     │   │   │       │   └────────────────────────────── 长度(6)
     │   │   │       └─────────────────────────────────── 协议ID
     │   │   └──────────────────────────────────────────── 事务ID
     │   └───────────────────────────────────────────────── MBAP头

注意: 响应只包含MBAP头 + 功能码 + 地址 + 数量,不包含写入的数据


Modbus 完整通讯流程

RTU 通讯流程

复制代码
主站 (Master)              从站 (Slave)
     │                         │
     │ ①发送请求报文            │
     ├─────────────────────→│
     │  [Slave][FC][Data][CRC] │
     │                         │
     │ ②接收响应报文            │
     │←─────────────────────┤
     │  [Slave][FC][Data][CRC] │
     │                         │
     │ ③CRC验证                 │
     │  ✓ 通过 → 处理数据       │
     │  ✗ 失败 → 重传/报错      │

TCP 通讯流程

复制代码
客户端 (Client)             服务器 (Server)
     │                         │
     │ ①建立TCP连接            │
     ├─────────────────────→│
     │  Socket(Connect)        │
     │                         │
     │ ②发送Modbus请求         │
     │  ├─────────────────────→│
     │  [MBAP][PDU]             │
     │                         │
     │ ③接收Modbus响应         │
     │  ←─────────────────────┤
     │  [MBAP][PDU]             │
     │                         │
     │ ④TCP校验和               │
     │  ✓ 通过 → 处理数据       │
     │  ✗ 失败 → 重传/报错      │

实际应用场景对比

工业现场设备

复制代码
┌─────────────────────────────────────────────────────────────┐
│                   工业自动化系统                         │
└─────────────────────────────────────────────────────────────┘

  ┌──────┐  RS-485总线  ┌──────┐  ┌──────┐  ┌──────┐
  │  PLC │◄──────►│ 传感器│◄────►│  执行器│◄──►│  HMI │
  └──────┘          └──────┘  └──────┘  └──────┘
      │               ▲       │           ▲
      │               │       │           │
  Modbus RTU       Modbus RTU  Modbus RTU   Modbus RTU


  ┌──────┐  以太网交换机  ┌──────┐  ┌──────────┐
  │ 上位机│◄───────────►│  PLC │◄─►│  远程I/O   │
  └──────┘              └──────┘  └──────────┘
      │                  ▲         ▲
      │             Modbus TCP  Modbus TCP


  跨地域监控

性能与可靠性对比

传输性能

指标 Modbus RTU Modbus TCP
帧开销 2字节 7字节
吞吐量 中等
延迟 低(<10ms) 中(10-50ms)
并发性 单路 多路

可靠性

特性 Modbus RTU Modbus TCP
纠错 CRC16 TCP校验和+重传
干扰抑制 强(RS-485) 中(需屏蔽)
距离限制 <1200m 无限制
故障隔离 总线故障影响全部 网络节点隔离

如何选择 Modbus RTU 或 TCP?

选择流程图

复制代码
开始
  │
  ├─ 设备有串口?
  │   │
  │   ├─ 是 ──→ 距离 < 100米?
  │   │          │
  │   │          ├─ 是 ─→ ✅ Modbus RTU
  │   │          │
  │   │          └─ 否 ─→ ❌ 考虑其他方案
  │   │
  │   └─ 否 ──→ 设备有网口?
  │              │
  │              ├─ 是 ──→ ✅ Modbus TCP
  │              │
  │              └─ 否 ─→ ❌ 需要转换器
  │
  └─ 环境要求高可靠性?
      │
      ├─ 是 ──→ 有RS-485? ─→ ✅ Modbus RTU
      │
      └─ 否 ──→ 需远程访问? ─→ ✅ Modbus TCP

常见问题与解决

Q1: CRC校验失败

问题: 返回报文错误

复制代码
原因: 
  • 波特率/数据位/校验位/停止位配置不匹配
  • 从站地址错误
  • 通讯线路干扰

解决:

复制代码
1. 检查串口参数配置
2. 验证从站地址是否正确
3. 检查线路连接和屏蔽
4. 增加超时时间

Q2: TCP连接超时

问题: 无法连接到设备

复制代码
原因:
  • IP地址或端口号错误
  • 网络不通
  • 防火墙阻止

解决:

复制代码
1. ping设备IP地址
2. 检查端口号(默认502)
3. 关闭防火墙或添加白名单
4. 确认设备支持Modbus TCP

总结

核心要点回顾

Modbus RTU

  • ✅ 串口通讯,紧凑高效
  • ✅ CRC16校验,可靠性强
  • ✅ 适合工业现场短距离
  • ✅ RS-485总线支持多设备

Modbus TCP

  • ✅ 网络通讯,跨地域
  • ✅ MBAP头标准化
  • ✅ 支持并发通讯
  • ✅ 适合远程监控集成

CRC16校验

  • ✅ 16位校验码
  • ✅ 查表法快速计算
  • ✅ 检测数据完整性
  • ✅ 工业标准算法

END

相关推荐
雨浓YN1 小时前
GKMLT通讯工具箱(WPF MVVM) - 01-网口/串口通讯与 ModBus RTU/TCP
网络·网络协议·tcp/ip
志栋智能3 小时前
运维超自动化:构建弹性IT架构的关键支撑
运维·服务器·网络·人工智能·架构·自动化
网安情报局10 小时前
除了 CDN,DDoS 攻击还有哪些更有效的防护方式?
网络
Promise微笑10 小时前
2026年国产替代油介损测试仪:油介损全场景解决方案与技术演进
大数据·网络·人工智能
AnalogElectronic13 小时前
linux 测试网络和端口是否连通的命令详解
linux·网络·php
Rust研习社14 小时前
使用 Axum 构建高性能异步 Web 服务
开发语言·前端·网络·后端·http·rust
灰子学技术14 小时前
Envoy HTTP 流量层面的 Metric 指标分析
网络·网络协议·http
上海云盾-小余14 小时前
海外恶意 UDP 攻击溯源:分层封禁策略与业务兼容平衡方案
网络·网络协议·udp
智慧光迅AINOPOL14 小时前
校园全光网建设指南:从架构到调优,打造稳定高体验校园网络
网络·全光网解决方案·全光网·酒店全光解决方案·泛住宿全光网解决方案