本文将从网络定位、报文结构、寄存器模型、地址转换到实际调试,为你提供一个完整的Modbus TCP/IP地址知识框架。
一、核心思想:分层寻址
Modbus TCP/IP的寻址是分层的,可以理解为:
-
网络层 :通过 IP地址 找到网络上的设备(如PLC)。
-
传输层 :通过 端口号(默认502)找到设备上的Modbus服务。
-
应用层 :通过 单元标识符 找到设备后的具体子设备。
-
数据层 :通过 功能码 + 寄存器地址 找到该子设备内的具体数据。
二、网络与传输层:连接的基础
-
IP地址:在TCP/IP网络中唯一标识一个设备。通信双方需确保IP在同一网段且不冲突。
-
端口号 :默认使用 502 端口。这是IANA官方分配给Modbus协议的端口,几乎所有设备都监听此端口。
安全提示:将Modbus设备直接暴露在公网上极其危险,攻击者会扫描公网的502端口。
三、应用层核心:MBAP报文头与单元标识符
Modbus TCP报文在TCP数据部分封装了一个7字节的 MBAP (Modbus Application Protocol) 头。
| 字段 | 长度 | 描述 | 作用 |
|---|---|---|---|
| 事务元标识符 | 2字节 | 递增的ID | 匹配请求和响应 |
| 协议标识符 | 2字节 | 固定为 0x0000 |
区分Modbus协议 |
| 长度 | 2字节 | 后续字节总数 | 告诉接收方数据长度 |
| 单元标识符 | 1字节 | 0-255 | 核心:设备内部的"子地址" |
单元标识符 (Unit ID) 的两种场景:
-
场景一:访问原生TCP/IP设备(如现代PLC)
- Unit ID通常被忽略,可设为
0x00或 0xFF。
- Unit ID通常被忽略,可设为
-
场景二:通过网关访问串行设备(如老旧仪表)
-
Unit ID告诉网关,请求要转发给下面哪个串口设备。
-
例子 :网关IP 192.168.1.100,想访问地址为
5的串行仪表。则请求中IP地址为 192.168.1.100,Unit ID为5。
-
四、数据层:寄存器模型与功能码
1. 四种寄存器类型
| 访问类型 | 数据宽度 | 名称 (PLC地址范围) | 协议地址范围 | 功能码示例 |
|---|---|---|---|---|
| 读-写 | 1 Bit | 线圈 00001-09999 |
0x0000 - 0x270F | 读: 0x01, 写: 0x05/0x0F |
| 只读 | 1 Bit | 离散输入 10001-19999 |
0x0000 - 0x270F | 读: 0x02 |
| 读-写 | 16 Bits | 保持寄存器 40001-49999 |
0x0000 - 0x270F | 读: 0x03, 写: 0x06/0x10 |
| 只读 | 16 Bits | 输入寄存器 30001-39999 |
0x0000 - 0x270F | 读: 0x04 |
2. PLC地址 vs. 协议地址(关键区别)
| PLC地址 | 协议地址 | |
|---|---|---|
| 作用 | 给人看,直观表示类型和位置 | 给机器用,计算偏移量 |
| 示例 | 40001(4表示保持寄存器,0001表示第1个) | 0x0000 |
| 转换 | 起始地址固定 | 协议地址 = PLC地址 - 该类型起始地址 |
转换示例:
-
40001 → 40001
-40001=0 → 0x0000 -
40010 → 40010
-40001=9 → 0x0009 -
30001 → 30001
-30001=0 → 0x0000
绝大多数编程错误都源于混淆了这两种地址。
五、常用功能码速查
| 功能码 (十进制/十六进制) | 描述 |
|---|---|
| 1 (0x01) | 读取线圈 |
| 2 (0x02) | 读取离散输入 |
| 3 (0x03) | 读取保持寄存器 |
| 4 (0x04) | 读取输入寄存器 |
| 5 (0x05) | 写单个线圈 |
| 6 (0x06) | 写单个保持寄存器 |
| 15 (0x0F) | 写多个线圈 |
| 16 (0x10) | 写多个保持寄存器 |
六、实战组合示例
目标 :读取电机驱动器的转速,手册写明转速存放在保持寄存器地址40010。
步骤:
-
连接 :客户端与驱动器(IP 192.168.1.10,端口502)建立TCP连接。
-
构建MBAP头部:
-
事务元标识:0x0001
-
协议标识:0x0000
-
长度:0x0006(后续6字节)
-
单元标识:0xFF(原生设备)
-
-
构建PDU:
-
功能码:
0x03(读保持寄存器) -
起始地址:40010 → 协议地址0x0009
-
寄存器数量:0x0001
-
-
发送报文 (十六进制):
00 01 00 00 00 06 FF 03 00 09 00 01 -
接收响应 (假设转速1500 RPM):
00 01 00 00 00 05 FF 03 02 05 DC -
解析 :
0x05DC(十六进制)= 1500(十进制)
七、常见陷阱与调试技巧
| 陷阱 | 现象 | 解决方案 |
|---|---|---|
| 地址偏移错误 | 读40001得到40002的值 | 确认软件要求输入的是PLC地址还是协议地址 |
| 字节/字顺序错误 | 读32位浮点数得到奇怪值(如65535) | 在软件中尝试不同交换选项(ABCD/CDAB/BADC/DCBA) |
| 单元标识符被忽略 | 设了Unit ID=5但设备不认 | 查阅文档,不确定时先试0x00或0xFF |
| 连接超时 | 始终连不上 | 1. Ping测试 2. telnet <IP> 502测试端口 3. 检查防火墙 |