ModbusTCP 聚合端口 9502 说明

用途

9502 是新增的 ModbusTCP 聚合入口,用于第三方只建立一个 TCP 客户端就访问四个 485 通道下的从机设备。

现有端口保持不变:

  • 502:集中器宿主机参数,Unit ID=255
  • 5502COM1
  • 6502COM2
  • 7502COM3
  • 8502COM4

Unit ID 映射规则

  • 1~64 -> COM1 / ID 1~64
  • 65~128 -> COM2 / ID 1~64
  • 129~192 -> COM3 / ID 1~64
  • 193~254 -> COM4 / ID 1~62

示例:

  • Unit ID=1 -> COM1 / ID1
  • Unit ID=64 -> COM1 / ID64
  • Unit ID=65 -> COM2 / ID1
  • Unit ID=193 -> COM4 / ID1
  • Unit ID=254 -> COM4 / ID62

兼容性说明

  • 9502 只用于聚合访问从机设备,不承担集中器宿主机参数访问
  • 宿主机参数仍然通过 502 + Unit ID=255 访问
  • 原有 5502/6502/7502/8502 访问方式不受影响

当前边界

由于 ModbusTCP Unit ID 只有 1 字节,本方案在 9502 上最多只支持到 Unit ID=254,因此 COM4 当前最多映射到本地 ID=62

当前现场每路只使用到 32 台设备,9502 方案可以满足现有需求;如果后续 COM4 需要稳定支持 63/64 号设备,需要重新设计聚合协议。

第三方对接示例报文

第三方接入时,建议统一使用标准 Modbus TCP 帧格式:

  • Transaction ID:调用方自定义,响应原样带回
  • Protocol ID:固定 0x0000
  • Length:按标准 Modbus TCP PDU 长度填写
  • Unit ID:这里填写 9502 方案下的全局设备 ID

全局 ID 计算公式:

  • Global Unit ID = (COM - 1) * 64 + Local ID

例如:

  • COM1 ID1 -> 1
  • COM2 ID1 -> 65
  • COM2 ID5 -> 69
  • COM3 ID10 -> 138
  • COM4 ID1 -> 193
  • COM4 ID32 -> 224

示例1:读取 COM1 ID1

目标:

  • 实际设备:COM1 / ID1
  • 聚合 Unit ID:1
  • 功能码:03
  • 起始地址:0x0000
  • 读取数量:2 个寄存器

请求报文:

00 01 00 00 00 06 01 03 00 00 00 02

字段拆解:

  • 00 01:Transaction ID
  • 00 00:Protocol ID
  • 00 06:Length
  • 01:Unit ID,表示 COM1 ID1
  • 03:读保持寄存器
  • 00 00:起始地址
  • 00 02:读取 2 个寄存器

示例响应:

00 01 00 00 00 07 01 03 04 12 34 56 78

说明:

  • 响应里的 Unit ID 仍然是 01
  • 04 表示后面有 4 个数据字节,即 2 个寄存器
  • 12 3456 78 只是示例寄存器值

pymodbus 示例:

from pymodbus.client import ModbusTcpClient

client = ModbusTcpClient("192.168.1.100", port=9502)
client.connect()

result = client.read_holding_registers(address=0x0000, count=2, slave=1)
print(result.registers)

client.close()

示例2:读取 COM2 ID1

目标:

  • 实际设备:COM2 / ID1
  • 聚合 Unit ID:65
  • 功能码:03
  • 起始地址:0x0000
  • 读取数量:2 个寄存器

请求报文:

00 02 00 00 00 06 41 03 00 00 00 02

说明:

  • 41 十六进制即十进制 65
  • 9502 收到后会自动路由到 6502 对应的 COM2 ID1
  • 响应时仍然返回 41,不会改回本地 01

pymodbus 示例:

from pymodbus.client import ModbusTcpClient

client = ModbusTcpClient("192.168.1.100", port=9502)
client.connect()

result = client.read_holding_registers(address=0x0000, count=2, slave=65)
print(result.registers)

client.close()

示例3:写单个寄存器到 COM2 ID5

目标:

  • 实际设备:COM2 / ID5
  • 聚合 Unit ID:69
  • 功能码:06
  • 寄存器地址:0x0010
  • 写入值:0x1234

标准请求报文:

00 03 00 00 00 06 45 06 00 10 12 34

当前实现响应报文:

00 03 00 00 00 06 45 06 00 10 00 01

说明:

  • 45 十六进制即十进制 69
  • 当前实现支持标准 0x06 报文格式,第三方按标准格式发即可
  • 响应保持聚合 Unit ID 45
  • 当前代码对 0x06 的响应格式沿用现有实现,最后两个字节返回的是确认后的寄存器数量字段表现,不建议第三方依赖这两个字节承载“原值回显”的语义

pymodbus 示例:

from pymodbus.client import ModbusTcpClient

client = ModbusTcpClient("192.168.1.100", port=9502)
client.connect()

result = client.write_register(address=0x0010, value=0x1234, slave=69)
print(result)

client.close()

示例4:写多个寄存器到 COM4 ID1

目标:

  • 实际设备:COM4 / ID1
  • 聚合 Unit ID:193
  • 功能码:10
  • 起始地址:0x0064
  • 写入寄存器值:0x000A0x0014

请求报文:

00 04 00 00 00 0B C1 10 00 64 00 02 04 00 0A 00 14

响应报文:

00 04 00 00 00 06 C1 10 00 64 00 02

说明:

  • C1 十六进制即十进制 193
  • 00 0B 表示后续长度为 11 字节
  • 00 02 表示写入 2 个寄存器
  • 04 表示后面有 4 个数据字节

pymodbus 示例:

from pymodbus.client import ModbusTcpClient

client = ModbusTcpClient("192.168.1.100", port=9502)
client.connect()

result = client.write_registers(address=0x0064, values=[0x000A, 0x0014], slave=193)
print(result)

client.close()

示例5:读取 COM4 ID32

目标:

  • 实际设备:COM4 / ID32
  • 聚合 Unit ID:224
  • 功能码:03
  • 起始地址:0x0000
  • 读取数量:2

请求报文:

00 05 00 00 00 06 E0 03 00 00 00 02

说明:

  • E0 十六进制即十进制 224
  • 224 = 193 + 31,对应 COM4 ID32

示例6:目标从机无响应时的异常报文

如果 9502 路由到目标从机后等待超时,当前实现会返回标准 Modbus TCP 异常码 0x0B

例如请求 COM2 ID1

请求:

00 06 00 00 00 06 41 03 00 00 00 02

异常响应:

00 06 00 00 00 03 41 83 0B

说明:

  • 41 仍然是外部请求看到的聚合 Unit ID
  • 83 表示 03 功能码的异常响应
  • 0B 表示 Gateway Target Device Failed to Respond

第三方接入建议

  • 第三方如果已经支持标准 Modbus TCP,直接把端口改为 9502、把 Unit ID 改成全局 ID 即可
  • 建议优先使用标准 03/04/10/05/0F 报文;06 请求可正常下发,但当前响应沿用现有兼容实现,若第三方严格校验标准回显,建议优先改用 10
  • 宿主机参数访问不要走 9502,仍然走 502 + Unit ID=255
  • 若现场未来要扩展到 COM4 ID63/64,请提前确认协议升级方案,不能继续默认沿用 9502 当前映射