ModbusTcp使用
Modbus TCP是Modbus协议在TCP/IP网络上的扩展,是工业自动化领域广泛应用的通信协议。
一、Modbus TCP核心概念
1、协议定位
Modbus TCP是基于TCP/IP的应用层协议,由施耐德公司于1996年推出,通过以太网实现设备间的高效通信。其本质是将传统Modbus RTU协议封装在TCP/IP协议栈中,支持客户端-服务器模型 。
2、主从架构
- 客户端(主站):主动发起请求,如工控机、PLC主控端。
- 服务器(从站):响应客户端请求,如传感器、执行器。通信必须由客户端发起,服务器无法主动发送数据 。
二、协议帧结构
Modbus TCP帧(ADU)由【MBAP头(7字节)】和【PDU(可变长度)】组成:
1.MBAP头(Modbus应用协议头)
-
- 事务标识符(2字节):用于匹配请求与响应,解决网络传输顺序问题。
- 协议标识符(2字节):固定为
0x0000
,标识Modbus协议。 - 长度(2字节):后续PDU及单元标识符的总字节数。
- 单元标识符(1字节):设备地址,TCP/IP网络中通常设为
0xFF
或设备实际地址 。
2.PDU(协议数据单元)
-
- 功能码(1字节):指示操作类型(如读/写寄存器)。
- 数据域(可变):具体操作参数,如寄存器地址、数量等 。
注:功能码(我们常用的是保持寄存器)
代码 | (PLC-)中文名称 | 寄存器PLC地址 | 位操作/字操作 | 操作数量 | |
01(0x01) | 读线圈状态 | 00001-09999 | 位 | 单个或多个 | |
02(0x02) | 读离散输入状态 | 10001-19999 | 位 | 单个或多个 | |
03(0x03) | 读保持寄存器 | 40001-49999 | 字 | 单个或多个 | 批量读 |
04(0x04) | 读输入寄存器 | 30001-39999 | 字 | 单个或多个 | |
05(0x05) | 写单个线圈 | 00001-09999 | 位 | 单个 | |
06(0x06) | 写单个保持寄存器 | 40001-49999 | 字 | 单个 | 单个写 |
15(0x0F) | 写多个线圈 | 00001-09999 | 位 | 多个 | |
16(0x10) | 写多个保持寄存器 | 40001-49999 | 字 | 多个 | 批量写 |
三、字节顺序(大小端)
- 大端(Big-Endian) vs 小端(Little-Endian)
-
- 大端:高位字节在前,低位字节在后(如 Modbus 协议默认使用大端 )。
- 小端:低位字节在前,高位字节在后(如 x86/x64 架构的 CPU 默认使用小端)。
如果大小端转换
例如:大端转为小端(modbus中字节数组转为C#的int类型)
方法一:
Num = BitConverter.ToInt16(num.Reverse().ToArray(), 0);
方法二:
Num = (short)((num[0] << 8) | num[1]);解析:
假设
num
是一个byte[]
数组,包含两个元素:num[0]
和num[1]
。
- 高位字节处理
num[0] << 8
:将第一个字节左移 8 位(即乘以 256),使其占据 16 位整数的高 8 位。- 例如,若
num[0] = 0x12
(二进制0001 0010
),左移后变为0x1200
(二进制0001 0010 0000 0000
)。
- 低位字节处理
num[1]
:直接取第二个字节,占据 16 位整数的低 8 位。- 例如,若
num[1] = 0x34
(二进制0011 0100
)。
- 按位或运算合并
(0x1200 | 0x34) = 0x1234
(十进制 4660)。- 若
num[0] = 0xFE
(-2 的补码),num[1] = 0xB6
(-74 的补码),合并后为0xFEB6
(十进制 -330)。
- 字节序的本质:字节序仅影响字节在内存中的存储顺序,不影响数值本身的逻辑定义。
- 大端(Big-Endian):高位在前(如
0x12 0x34
→0x1234
)。- 小端(Little-Endian):低位在前(如
0x34 0x12
→0x1234
)。
四、常见Modbus TCP报文实例及解析
1、功能码0x03:(单个/多个)读保持寄存器
请求报文
00 01 00 00 00 06 01 【03 00 0A 00 02】
- MBAP头:
-
- 事务标识符:
00 01
(用于匹配请求与响应) - 协议标识符:
00 00
(固定为Modbus TCP) - 长度:
00 06
(后续PDU+单元标识符共6字节) - 单元标识符:
01
(从站地址-站号)
- 事务标识符:
- PDU:
-
- 功能码:
03
(读保持寄存器) - 起始地址:
00 0A
(第10号寄存器) - 寄存器数量:
00 02
(读取2个寄存器)
- 功能码:
响应报文
00 01 00 00 00 07 01 【03 04 12 34 56 78】
- MBAP头:与请求一致(事务标识符匹配)
- PDU:
-
- 功能码:
03
- 数据长度:
04
(4字节,即2个寄存器的数据) - 数据:
12 34
(第10号寄存器值)、56 78
(第11号寄存器值) 解析:从站返回2个寄存器的值,每个寄存器占2字节,高位在前 。
- 功能码:
2、功能码0x10:写多个保持寄存器
请求报文
00 06 00 00 00 0B FF 【 10 00 02 00 02 04 00 21 00 2A】
- MBAP头:单元标识符
FF
(通用地址) - PDU:
-
- 功能码:
10
- 起始地址:
00 02
(第2号寄存器) - 寄存器数量:
00 02
(写入2个寄存器) - 数据长度:
04
(4字节数据) - 数据:
00 21
(第2号寄存器值)、00 2A
(第3号寄存器值)
- 功能码:
响应报文
00 06 00 00 00 06 FF【 10 00 02 00 02】
- PDU:返回写入的起始地址和数量,确认操作成功 。
3、功能码0x06:写单个保持寄存器
请求报文
00 01 00 00 00 06 01 【 06 00 02 00 A3】
- MBAP头(7字节):
-
- 事务标识符:
00 01
(用于匹配请求与响应) - 协议标识符:
00 00
(固定为Modbus TCP协议) - 长度:
00 06
(后续PDU+单元标识符共6字节) - 单元标识符:
01
(从站地址)
- 事务标识符:
- PDU(5字节):
-
- 功能码:
06
(写单个保持寄存器) - 寄存器地址:
00 02
(目标寄存器地址为2号寄存器) - 写入值:
00 A3
(寄存器写入值为0x00A3,即十进制163)
- 功能码:
响应报文
00 01 00 00 00 06 01【 06 00 02 00 A3】
- PMBAP头与请求一致(事务标识符
00 01
匹配) - PDU与请求完全一致,表示操作成功 。
小白需知:
报文是16进制
1个字节(byte)=8位(bit)
如00是1个字节(因为是16进制,2的4次方占4位,所以一个0是四位,00是八位=1个字节)
2个字节是一个地址
两个ASSIIC是一个地址,如“3A110011”占四个地址
如
00 06 00 00 00 0B FF 【 10 00 02 00 02 04 00 21 00 2A】
中00 21是一个寄存器地址,00 2A是一个寄存器地址【short ushort】 是16位 占两个字节如 00 21
【int uint】 是32位 占四个字节如00 21 00 2A
long 是64位 占八个字节