2. Modbus协议核心机制

Modbus 是工业现场最常用的串行/以太网应用层协议之一。它本身不定义物理层,而是把“主站问、从站答”的交互规则、数据模型和错误处理方式固定下来。理解 Modbus 的关键,不是背功能码表,而是先分清三种传输方式如何把同一套协议数据单元(PDU)封装成不同的帧,再理解功能码如何映射到四类数据区,最后掌握异常响应的判断方法。

一、三种传输方式:同一 PDU,不同封装

Modbus 的核心是 PDU:功能码 + 数据。例如读保持寄存器请求的 PDU 是 03 00 00 00 02,其中 03 是功能码,后面是起始地址和数量。三种传输方式在 PDU 前后加上不同字段,形成 ADU(应用数据单元)。

Modbus RTU 使用二进制编码,帧与帧之间靠至少 3.5 个字符时间的静默间隔分隔。典型帧结构为:从站地址(1 字节)+ PDU + CRC16 校验(2 字节,低字节在前)。例如从站 1 读 40001 开始的 2 个保持寄存器,请求帧为 01 03 00 00 00 02 C4 0B。RTU 效率高,是串行现场最常用的方式。

Modbus ASCII 把每个字节用两个 ASCII 字符表示,帧以冒号 : 开始,以 CRLF 结束,并带 LRC 校验。例如同样的请求会变成 :010300000002FA\r\n。ASCII 可读性好、字符间隔容忍度高,但传输效率约为 RTU 的一半,现代工程中较少使用。

Modbus TCP 在 PDU 前加 7 字节 MBAP 报文头:事务标识(2 字节)、协议标识(2 字节,固定 0)、长度(2 字节)、单元标识(1 字节)。它没有 CRC,因为 TCP/IP 已提供校验和可靠传输。MBAP 中的事务标识用于把请求和响应配对,单元标识在网关场景中常用来标识后端串行从站。

Modbus 三种传输方式的帧封装对比 Modbus RTU 从站地址 PDU(功能码 + 数据) CRC16 二进制编码,3.5 字符静默分隔 Modbus ASCII : 从站地址 PDU(ASCII 字符) LRC CRLF 可读性好,效率低 Modbus TCP 事务标识 2 字节 协议标识 固定 0 长度 2 字节 单元标识 1 字节 PDU(功能码 + 数据) 无 CRC,MBAP 头 7 字节 共同点:三种方式承载同一 PDU;差异只在地址/校验/分隔字段。网关转换时,PDU 保持不变,仅重新封装。

二、功能码与四类数据区

Modbus 把从站数据抽象为四类数据区,用“区号 + 地址”定位。功能码决定操作哪类区、是读还是写。工程中最常用的功能码如下:

功能码名称数据区地址范围(协议地址)常用 PLC 地址
01读线圈线圈(可读写位)0x0000–0xFFFF00001–09999
02读离散输入离散输入(只读位)0x0000–0xFFFF10001–19999
03读保持寄存器保持寄存器(可读写字)0x0000–0xFFFF40001–49999
04读输入寄存器输入寄存器(只读字)0x0000–0xFFFF30001–39999
05写单个线圈线圈0x0000–0xFFFF00001–09999
06写单个寄存器保持寄存器0x0000–0xFFFF40001–49999
15写多个线圈线圈0x0000–0xFFFF00001–09999
16写多个寄存器保持寄存器0x0000–0xFFFF40001–49999

这里最容易出错的是“协议地址”和“PLC 地址”的偏移。协议帧里出现的地址从 0 开始,而工程习惯用 1 起始的 40001 表示第一个保持寄存器。因此 40001 对应协议地址 0x0000,40002 对应 0x0001。写代码或配置网关时,必须确认工具要求填哪一种,否则会出现整体偏移一位的典型故障。

三、寄存器映射:把设备数据翻译成 Modbus 地址

寄存器映射的本质是“设备内部变量 ↔ Modbus 地址”的对照表。以一台支持 Modbus RTU 的温控器为例,假设其说明书给出如下映射(示例参数,仅用于说明方法):

设备变量          类型      协议地址    功能码   说明
当前温度          输入寄存器  0x0000     04      单位 0.1℃,只读
设定温度          保持寄存器  0x0000     03/06   单位 0.1℃,可读写
运行状态          离散输入    0x0000     02      0=停止,1=运行
启停命令          线圈        0x0000     01/05   写 1 启动,写 0 停止
报警代码          输入寄存器  0x0001     04      0=无报警

若主站要读取当前温度,请求 PDU 为 04 00 00 00 01;从站返回 04 02 01 2C,其中 01 2C 是十六进制 300,按 0.1℃ 换算即 30.0℃。若要把设定温度改为 25.0℃,则用功能码 06 写 06 00 00 00 FA,其中 00 FA 是 250,即 25.0℃。可以看到,映射表决定了“地址 + 功能码 + 数据格式”三要素,缺一不可。

四、异常响应:从站如何告诉主站“我做不到”

当从站无法正常执行请求时,它不会沉默,而是返回异常响应。异常响应的 PDU 结构为:功能码最高位置 1 + 异常码。例如功能码 03 的异常响应功能码是 0x83(03 | 0x80)。常见异常码包括:

  • 01 非法功能:从站不支持该功能码,例如只支持 03/06 却收到 16。
  • 02 非法数据地址:请求的地址超出从站映射范围,例如访问 0x0100 但设备只有 0x0000–0x000F。
  • 03 非法数据值:写入的值不合法,例如设定温度超出允许范围。
  • 04 从站设备故障:从站执行时发生内部错误。
  • 05 确认:从站已接受请求但需要较长时间处理,主站应稍后重试。
  • 06 从站忙:从站正在处理长任务,暂时无法响应。
  • 0B 网关目标设备无响应:网关后面的串行从站没有应答,常见于接线、波特率或站号错误。

排查时,先看异常码,再回到请求帧核对功能码、地址、数量和值。例如收到 83 02,说明功能码 03 被识别,但地址越界,应检查映射表地址范围;收到 83 0B,则问题多半在网关后端链路,而不是 Modbus TCP 本身。

工程建议:在网关配置阶段,先建立一张“设备变量—功能码—协议地址—数据格式—读写属性”的映射表,再用 Modbus Poll 或类似工具逐条验证。验证顺序建议从只读输入寄存器开始,再验证保持寄存器读写,最后验证线圈和离散输入,这样能快速定位是映射错误、字节序问题还是链路问题。