Modbus TCP报文协议(ModbusTCP)(单元标识符、分站id、单元id、unitId、从站id)
Modbus TCP报文协议详解
概述
Modbus TCP是一种基于TCP/IP协议的工业通信协议,广泛应用于PLC、DCS和SCADA系统中。它继承了Modbus协议简单、可靠的特点,同时利用了以太网的高速和灵活性。
Modbus TCP报文结构
MBAP报头
Modbus TCP报文由MBAP(Modbus Application Protocol)报头和PDU(Protocol Data Unit,协议数据单元)组成。MBAP报头长度为7个字节,包含以下字段:
- 事务标识符(Transaction Identifier,2字节):用于请求和响应的配对。
- 协议标识符(Protocol Identifier,2字节):固定为0,表示Modbus协议。
- 长度(Length,2字节):后续数据的长度,包括单元标识符和PDU。
- 单元标识符(Unit Identifier,1字节):用于多从站的标识,在TCP/IP中通常为0。(注意,如果有多个从站,这个值必须为各个从站指定的地址)
协议数据单元(PDU)
PDU由功能码和数据字段组成:
- 功能码(Function Code,1字节):指定要执行的操作,例如读写寄存器。
- 数据字段(Data,N字节):包含与功能码相关的参数或数据。
常用功能码
- 0x01:读线圈状态
- 0x02:读离散输入状态
- 0x03:读保持寄存器
- 0x04:读输入寄存器
- 0x05:写单个线圈
- 0x06:写单个保持寄存器
- 0x0F:写多个线圈
- 0x10:写多个保持寄存器
报文示例
读保持寄存器请求报文
假设需要从地址为0x0000的寄存器开始读取10个保持寄存器,构建的请求报文如下:
-
MBAP报头
- 事务标识符:0x0001
- 协议标识符:0x0000
- 长度:0x0006(后续6个字节)
- 单元标识符:0x01
-
PDU
- 功能码:0x03
- 起始地址:0x0000
- 数量:0x000A
完整报文(16进制表示):
00 01 00 00 00 06 01 03 00 00 00 0A
00 0100 0000 06010300 0000 0A事务标识符协议标识符长度单元标识符功能码起始地址寄存器数量
响应报文
假设从站返回的数据为20个字节,对应10个保持寄存器的值:
-
MBAP报头
- 事务标识符:0x0001
- 协议标识符:0x0000
- 长度:0x0015(后续21个字节)
- 单元标识符:0x01
-
PDU
- 功能码:0x03
- 字节数:0x14(20个字节)
- 数据:20个字节的寄存器值
完整报文(16进制表示):
00 01 00 00 00 15 01 03 14 [20字节数据]
00 0100 0000 15010314[20字节数据]事务标识符协议标识符长度单元标识符功能码字节计数数据
Python示例代码
使用pymodbus
库实现Modbus TCP通信的示例代码:
from pymodbus.client.sync import ModbusTcpClient# 创建Modbus TCP客户端client = ModbusTcpClient(\'192.168.1.100\', port=502)# 连接到服务器client.connect()# 读取保持寄存器,地址从0开始,读取10个寄存器result = client.read_holding_registers(address=0, count=10, unit=1)# 检查是否成功读取if not result.isError(): # 输出读取的寄存器值 print(result.registers)else: print(\"读取失败\")# 写单个保持寄存器,地址为0,值为123client.write_register(address=0, value=123, unit=1)# 关闭连接client.close()
注意事项
- 端口号:Modbus TCP默认使用502端口,需要确保防火墙或路由器未阻挡此端口。
- 单元标识符:在TCP/IP网络中,单元标识符通常设置为0或1,但在一些网关或路由器中可能有特殊含义。
- 异常码处理:从站可能返回异常码,需要在程序中进行处理,确保通信的可靠性。
- 线程安全:在多线程环境中使用Modbus客户端时,需要注意线程安全,可能需要加锁或使用线程安全的客户端实例。
应用场景
- 工业自动化:用于PLC和上位机之间的数据交换。
- 能源管理:在电力、石油等行业,实现对设备的远程监控和控制。
- 楼宇自动化:对暖通空调、照明等系统进行集中控制。
结论
深入理解Modbus TCP报文协议,有助于在工业应用中实现高效可靠的通信。通过掌握报文结构、功能码和异常处理,可以开发出稳定的通信程序,满足各种工业现场的需求。
关于从站单元标识符(unitId)
Modbus TCP协议中的“单元标识符”(Unit Identifier,1字节)允许在一个IP地址下配置多个从站设备,但这并不是Modbus TCP的常规用法,而是协议设计中保留的一个特性。以下是详细解释:
1. 单元标识符的作用
- 协议设计背景:
Modbus TCP最初是为以太网通信设计的,继承了Modbus RTU/ASCII的主从架构。在串行通信(如RS485)中,每个从站通过唯一的从站地址(0-255)被标识。而在以太网中,设备通过IP地址唯一标识,因此理论上不需要额外的地址字段。
但为了兼容性和灵活性,Modbus TCP保留了“单元标识符”(即从站地址的替代),作为MBAP报文头的一部分(见知识库[2]、[7]、[12])。
- 实际用途:
- 虚拟从站:如果多个从站逻辑上共享一个IP地址(例如通过网关或虚拟化设备),可以通过不同的单元标识符区分它们。
- 多协议支持:某些设备可能同时支持Modbus TCP和其他协议(如Profinet),单元标识符可用于路由到不同的协议处理模块。
- 历史兼容:在混合网络(如以太网+串口桥接)中,单元标识符可能对应串口从站地址。
2. 为什么“一个IP下多个从站”不常见?
尽管协议支持,但实际应用中很少使用单元标识符来区分同一IP下的多个从站,原因如下:
1. IP地址的唯一性:
在以太网中,每个设备通常分配一个唯一的IP地址,这已经足够标识通信目标。使用单元标识符会增加复杂性,且容易引发配置错误(例如主站发送的单元标识符与从站配置不匹配)。
2. 设备实现限制:
大多数Modbus TCP从站设备(如PLC、传感器)仅支持通过IP地址进行通信,不支持通过单元标识符区分多个从站。因此,即使协议允许,硬件或软件可能不支持该功能。
3. 网络管理复杂性:
在大型工业网络中,为每个从站分配独立IP地址更易于管理和故障排查。而通过单元标识符管理同一IP下的多个从站,会增加网络配置和调试的难度。
3. 实际场景中的替代方案
如果需要实现“一个IP下多个从站”的功能,通常采用以下方法:
1. 网关/桥接设备:
使用支持Modbus TCP的网关(如知识库[5]、[8]提到的网关设备),将多个从站(如Modbus RTU设备)连接到同一个IP地址下,并通过网关的配置分配不同的单元标识符。
- 例如:网关作为Modbus TCP从站(IP地址为192.168.1.100),内部连接两个Modbus RTU设备,分别配置单元标识符为1和2。主站通过访问192.168.1.100:502,并指定单元标识符1或2来区分设备。
2. 虚拟化技术:
在软件层面(如虚拟机或容器)中运行多个Modbus TCP从站服务,共享同一个IP地址,但通过不同的端口或单元标识符隔离逻辑从站。
3. 分布式控制系统:
如知识库[6]所述,通过多路复用技术(如贝加莱控制器)在同一个以太网接口上同时与多个从站通信,但每个从站仍需独立的IP地址或通过其他机制区分。
4. 如何验证是否支持“单元标识符”功能?
- 检查设备文档:
确认从站设备是否支持通过单元标识符区分多个逻辑从站。例如,某些网关或工业计算机可能提供此功能。
- 抓包分析:
使用Wireshark等工具捕获Modbus TCP通信数据包,观察MBAP报文头中的“单元标识符”字段是否被设置为非零值(通常默认为0)。
- 配置测试:
如果设备支持该功能,尝试在主站请求中修改单元标识符(例如从0改为1),观察从站是否响应。