2、Modbus协议详解:Modbus RTU帧结构、Modbus TCP帧结构、功能码详解(01/02/03/04/05/06/15/16)

Modbus协议是工业自动化领域应用最广泛的通信协议之一,它简单、开放且易于实现。在将其转换为OPC UA之前,深入理解Modbus协议的底层细节至关重要。本节将重点剖析两种最常用的传输模式:Modbus RTU和Modbus TCP,并详细解释核心功能码的用法。

2.1 Modbus RTU帧结构

Modbus RTU(Remote Terminal Unit)采用二进制编码,数据以字节流形式传输,通常通过RS-232或RS-485串行接口进行通信。其帧结构紧凑,效率高,是现场总线中最常见的模式。

RTU帧结构(无校验时):

字段 长度(字节) 描述
地址码 1 从站设备地址(1-247),0为广播地址
功能码 1 指示操作类型(如读线圈、读寄存器)
数据区 N 包含起始地址、数据数量或具体数据值
CRC校验 2 循环冗余校验(低字节在前,高字节在后)

关键特性:

  • 帧间隔:RTU要求帧与帧之间至少有3.5个字符时间的静默间隔,用于帧同步。
  • 字节格式:每个字节包含1个起始位、8个数据位、1个停止位(通常无校验位或偶校验)。
  • CRC计算:CRC-16(Modbus多项式:0x8005)覆盖地址码、功能码和数据区。

示例:读取从站地址为1的保持寄存器,起始地址0,读取2个寄存器。

请求帧(主站 -> 从站):
地址码: 0x01
功能码: 0x03
起始地址高字节: 0x00
起始地址低字节: 0x00
寄存器数量高字节: 0x00
寄存器数量低字节: 0x02
CRC低字节: 0xC4
CRC高字节: 0x0B

响应帧(从站 -> 主站):
地址码: 0x01
功能码: 0x03
字节数: 0x04
数据1高字节: 0x00
数据1低字节: 0x0A
数据2高字节: 0x01
数据2低字节: 0x2C
CRC低字节: 0x?? (根据实际数据计算)
CRC高字节: 0x??

2.2 Modbus TCP帧结构

Modbus TCP基于以太网,使用TCP/IP协议栈(默认端口502)。它在RTU的基础上移除了地址码和CRC校验,增加了MBAP报文头,以适应网络传输。

TCP帧结构:

字段 长度(字节) 描述
事务处理标识符 2 用于请求/响应配对,通常由客户端递增
协议标识符 2 固定为0x0000(表示Modbus协议)
长度 2 后续字节数(从单元标识符开始到数据结束)
单元标识符 1 相当于RTU的地址码,用于网关路由
功能码 1 同RTU
数据区 N 同RTU

关键特性:

  • 无CRC:TCP/IP协议本身提供可靠传输和校验,因此不再需要CRC。
  • 单元标识符:在直接以太网连接时通常设为0xFF或0x00;当通过网关连接多个串行设备时,用于区分不同从站。
  • 事务处理标识符:客户端必须为每个请求生成唯一ID,服务器在响应中复制该ID,用于处理并发请求。

示例:与RTU示例相同的请求(读取保持寄存器)。

请求帧(客户端 -> 服务器):
事务处理标识符: 0x0001
协议标识符: 0x0000
长度: 0x0006 (后续6个字节)
单元标识符: 0xFF
功能码: 0x03
起始地址: 0x0000
寄存器数量: 0x0002

响应帧(服务器 -> 客户端):
事务处理标识符: 0x0001
协议标识符: 0x0000
长度: 0x0007 (后续7个字节)
单元标识符: 0xFF
功能码: 0x03
字节数: 0x04
数据: 0x000A 0x012C

2.3 核心功能码详解

功能码定义了主站(或客户端)要对从站(或服务器)执行的操作。以下是在协议转换中最常用的8个功能码。

2.3.1 位操作功能码

功能码01:读线圈(Read Coils)

  • 作用:读取从站的离散输出(线圈)状态,0或1。
  • 请求数据:起始地址(2字节)+ 线圈数量(2字节,1-2000)。
  • 响应数据:字节数(1字节)+ 线圈状态(每个线圈占1位,不足补0)。
  • 应用场景:读取继电器、指示灯等开关量输出。

功能码02:读离散输入(Read Discrete Inputs)

  • 作用:读取从站的离散输入状态,只读。
  • 请求数据:起始地址(2字节)+ 输入数量(2字节,1-2000)。
  • 响应数据:字节数(1字节)+ 输入状态(位映射)。
  • 应用场景:读取按钮、限位开关等传感器信号。

功能码05:写单个线圈(Write Single Coil)

  • 作用:强制一个线圈输出为ON或OFF。
  • 请求数据:输出地址(2字节)+ 输出值(2字节:0xFF00表示ON,0x0000表示OFF)。
  • 响应数据:与请求完全相同(回显)。
  • 应用场景:控制单个继电器或阀门。

功能码15:写多个线圈(Write Multiple Coils)

  • 作用:连续写入多个线圈状态。
  • 请求数据:起始地址(2字节)+ 线圈数量(2字节)+ 字节数(1字节)+ 输出值(位映射)。
  • 响应数据:起始地址(2字节)+ 线圈数量(2字节)。
  • 应用场景:批量设置一组输出设备的状态。

2.3.2 寄存器操作功能码

功能码03:读保持寄存器(Read Holding Registers)

  • 作用:读取从站的保持寄存器(16位,可读写)。
  • 请求数据:起始地址(2字节)+ 寄存器数量(2字节,1-125)。
  • 响应数据:字节数(1字节)+ 寄存器值(每个寄存器2字节,高字节在前)。
  • 应用场景:读取模拟量输出值、PID参数、设备配置等。

功能码04:读输入寄存器(Read Input Registers)

  • 作用:读取从站的输入寄存器(16位,只读)。
  • 请求数据:起始地址(2字节)+ 寄存器数量(2字节,1-125)。
  • 响应数据:字节数(1字节)+ 寄存器值。
  • 应用场景:读取模拟量输入(如温度、压力传感器值)。

功能码06:写单个寄存器(Write Single Register)

  • 作用:写入一个保持寄存器的值。
  • 请求数据:寄存器地址(2字节)+ 寄存器值(2字节)。
  • 响应数据:与请求完全相同(回显)。
  • 应用场景:设定单个模拟量输出或修改单个参数。

功能码16:写多个寄存器(Write Multiple Registers)

  • 作用:连续写入多个保持寄存器。
  • 请求数据:起始地址(2字节)+ 寄存器数量(2字节)+ 字节数(1字节)+ 寄存器值(N*2字节)。
  • 响应数据:起始地址(2字节)+ 寄存器数量(2字节)。
  • 应用场景:批量更新设备参数表或下载配置数据。

2.4 协议转换中的关键注意事项

在将Modbus数据映射到OPC UA时,需要特别注意以下几点:

  • 地址偏移:Modbus协议中地址通常从0开始(如保持寄存器40001对应地址0x0000),而OPC UA节点ID通常从1开始或自定义。转换时需处理地址偏移。
  • 数据类型映射:Modbus寄存器是16位无符号整数。32位浮点数、32位整数或字符串需要跨寄存器组合。例如,一个32位浮点数占用两个连续的保持寄存器(如地址0和1),转换时需按IEEE 754标准解析。
  • 字节序:Modbus默认大端序(高字节在前)。但某些设备可能使用小端序。在转换引擎中必须支持字节序配置。
  • 错误处理:Modbus异常响应(功能码+0x80)需映射为OPC UA的BadStatus或异常状态码。
  • 性能优化:对于大量连续地址的读取,优先使用功能码03/04的批量读取,而非逐个读取,以减少网络开销。