Modbus tcp 协议详解
Modbus tcp 协议详解
Modbus TCP是一种基于以太网TCP/IP的应用层协议,它保留了Modbus协议的核心功能和数据模型,但对消息封装进行了调整,使其符合TCP/IP的要求。本文将详细介绍Modbus TCP协议的基本概念、存储区、功能码、协议报文结构,并通过工具使用和Java代码示例展示如何模拟主站与从站之间的通信。
1. 相关概念
1.1 Modbus
Modbus是一种广泛应用于工业自动化领域的通信协议。它提供了通用的语言在设备之间建立主从式的通信。Modbus协议简单、开放、易于实现,且支持多种物理层通信介质(RS232、RS485、TCP/IP网络等),因此成为了工业领域通信协议的业界标准之一。我们今天要介绍的是一种基于以太网TCP/IP的应用层协议——Modbus TCP/IP协议。
1.2 Modbus TCP
Modbus TCP是Modbus协议在以太网上的一种实现,它保留了Modbus协议的核心功能和数据模型,但对消息封装进行了调整,使其符合TCP/IP的要求。在进行下一步之前我们首先对Modbus中的一些概念做一个了解。
1.3 存储区
存储的数据类型分为布尔量和寄存器
- 布尔量:如水阀的开关、灯的开关等数据。
- 寄存器:如流速、导电率、温湿度、空气浓度等数据。
Modbus规定了4个存储区,分别是0、1、3、4,对应下面表格内容,具体为:
- 0区:可读可写的布尔量
- 1区:只读布尔量
- 3区:只读寄存器
- 4区:可读可写的寄存器
1.4 功能码
Modbus定义了一系列的功能码,这些功能码表示了主站请求从站执行的具体操作,下面表格是一些常见的功能码,具体为:
读操作
0x01:读输出线圈状态。
0x02:读输入线圈状态。
0x03:读输出寄存器的值。
0x04:读输入寄存器的值。
写操作
0x05:写单个线圈状态。
0x06:写单个寄存器的值。
0x0F:写多个线圈状态。
0x10:写多个寄存器的值。
1.5 协议报文
Modbus TCP/IP的报文被封装在一个标准的TCP数据段内,而不是像串行通信那样直接在物理层上发送。TCP报文提供了端到端的可靠传输,包括数据分段、重传、流量控制和拥塞控制等机制。
Modbus TCP/IP的报文帧主要包括:
- MBAP头:包含事务标识符、协议标识符、消息长度、设备地址
- Modbus PDU:原始Modbus协议的数据部分,包括功能码、数据地址和数据值。
下面我们用一个表格来根据一段报文解释这两部分的具体内容:
从上面的报文中我们可以知道:
- 事务标识符:占2个字节,一次通信的过程中主站和从站的报文帧的事务标识符是一致的。
- 协议标识符:占2个字节,00 00表示Modbus TCP协议。
- 后面报文的长度:占2个字节,表示后面报文的长度。
- 从站地址:占1个字节,表示设备的地址,也就是Salve ID的值。
- 功能码:占1个字节,例子中的03表示的是读输出寄存器的值。
- 起始地址:占2个字节,表示从该设备的哪个位置开始读。
- 读取数量:占2个字节,表示从起始位置往后读的数量。
- 长度:占2个字节,表示后面还报文的长度。
- 对应的值:根据不同的存储类型所占的字节不同。
接下来我们通过工具来模拟Modbus TCP通讯。
2. 工具使用
2.1 Modbus Slave
打开软件之后点击菜单栏的Connection→Connect,如图所示:
在弹出的界面选择协议类型为Modbus TCP/IP,输入IP,端口号点击OK
随后点击Setup→Slave Definition...进入从站设置界面
下面我们新建四个不同存储区的窗口来为后面模拟通讯做准备
根据图中任意方式都可以新建窗口。
可以看到四个窗口在从站地址为2,功能码分别为01、02、03、04。
需要注意的是01、02表示的是读输出线圈和输入线圈,只有开关量,对应的数值为1=On,0=Off。
03、04表示的是读输出寄存器和输入寄存器。
好了,接下来我们去使用工具模拟主站来读取从站的数据。在此之前我们可以勾选Auto increment模拟数据处于变化状态。
2.2 Modbus Poll
使用和从站相同的方法连接之后新建四个窗口分别读取,可以看到读取实时数据成功。
也可以通过查看日志确保主机处于正常读取状态。
下面我们通过使用modbus-master-tcp模拟一个主站去和从站之间进行通信。
3. Java模拟主站
3.1 使用modbus-master-tcp库
modbus-master-tcp是基于Netty编写,支持异步与并发。
下面通过Java模拟主站读取从站线圈状态:
Modbus由MODICON公司于1979年开发,是一种工业现场总线协议标准。1996年施耐德公司推出基于以太网TCP/IP的Modbus协议,ModbusTCP。
Modbus通信的设备分为主站(mater)和从站(slave),主站为主动方,从站为被动方。
通信过程
通信的过程为:
- 主站设备主动向从站设备发送请求
- 从站设备处理主站的请求后,向主站返回结果。
- 如果从站设备处理请求出现异常,则向主站设备返回异常功能码。
数据传输方式
modbus的数据传输被定义为对以下4个存储块的读写:
- 线圈(coils) 操作单位为1位字的开关量,PLC的输出位,在Modbus中可读可写
- 离散量(discreteinputs) 操作单位为1位字的开关量,PLC的输入位,在Modbus中只读
- 输入寄存器(inputregisters) 操作单位为16位字(两个字节)数据,PLC中只能从模拟量输入端改变的寄存器,在Modbus中只读
- 保持寄存器(holdingregisters) 操作单位为16位字(两个字节)数据,PLC中用于输出模拟量信号的寄存器,在Modbus中可读可写
MODBUS-TCP报文结构
modbus-tcp报文结构:
如上图所示:modbus-tcp的报文由MBAP+PDU组成。
MBAP报文头
其中MBAP报文头的组成为:
域 长度 描述
事务元标识符 2 个字节 MODBUS 请求/响应事务处理的识别码,主要用于在主站设备在接收到响应时能知道是哪个请求的响应
协议标识符 2 个字节 对于MODBUS 协议来说,这里恒为0
长度 2 个字节 以下字节的数量,也就是完整报文的字节数减去6
单元标识符 1 个字节 串行链路或其它总线上连接的远程从站的识别码,也就是要访问的从站的标识号,因为只有一个字节,所以一个主站最多只能访问256个从站设备
由上表可知,报文头为 7 个字节长。
PDU报文体
PDU的组成为功能码(一个字节)和数据(n个字节)
其中功能码为一个字节,modbus定义的功能码有:
- 01 读线圈(coils)状态,读取单个或多个
- 02 读离散输入(discreteinputs)状态,读取单个或多个
- 03 读保持寄存器(holdingregisters),读取单个或多个
- 04 读输入寄存器(inputregisters),读取单个或多个
- 05 写单个线圈(coils)状态,单个写入
- 06 写单个保持寄存器(holdingregisters),单个写入
- 15 写多个线圈(coils),多个写入
- 16 写多个保持寄存器(holdingregisters),多个写入
另外,当响应报文的功能码最高位为1时(即:(function & 0x80) != 0),表示为异常响应,这时数据为一个字节的异常码,具体的异常码定义有:
- 01 功能码不能被从机识别
- 02 从机的单元标识符不正确
- 03 值不被从机接受
- 04 当从机试图执行请求的操作时,发生了不可恢复的错误。
- 05 从机已接受请求并正在处理,但需要很长时间。返回此响应是为了防止在主机中发生超时错误。主站可以在下一个轮询程序中发出一个完整的消息,以确定处理是否完成。
- 06 从站正在处理长时间命令。Master应该稍后重试。
- 07 从站不能执行程序功能。主站应该向从站请求诊断或错误信息。
- 08 从站在内存中检测到奇偶校验错误。主设备可以重试请求,但从设备上可能需要服务。
- 10 专门用于Modbus网关。表示配置错误的网关。
- 11 专用于Modbus网关的响应。当从站无法响应时发送。
PDU报文详情
1、读线圈
请求报文:
正常响应报文:
异常响应报文:
2、读离散输入
请求报文:
正常响应报文:
异常响应报文:
3、读保持寄存器
请求报文:
正常响应报文:
异常响应报文:
4、读输入寄存器
请求报文:
正常响应报文:
异常响应报文:
5、写单个线圈
请求报文:
正常响应报文:
异常响应报文:
6、写单个保持寄存器
请求报文:
正常响应报文:
异常响应报文:
7、写多个线圈
请求报文:
正常响应报文:
异常响应报文:
8、写多个保持寄存器
请求报文:
正常响应报文:
异常响应报文: