本项目是在云逸的博客文章(https://www.cnblogs.com/ioufev/p/10831289.html)为基础,在其给出的demo的基础上做学习和修改。
本项目中介绍了JLibModbus、Modbus4J、ModbusMasterTcp三种框架的用法,即对应项目中的三个包,值得注意的是,本项目将尝试使用java socket
直接对接modbus,以求加深对modbus的理解。
Modbus是一种串行通信协议。Modbus 一个工业上常用的通讯协议、一种通讯约定。
Modbus协议包括RTU、ASCII、TCP。其中MODBUS-RTU最常用,比较简单,在单片机上很容易实现。
这些Modbus的框架似乎并不支持修改Discrete(0x03)状态数据和InputRegister(0x04)寄存器数据。
master
主要是三种框架(jLibModbus、modbus4J、modbusMasterTCP)的读写示例,socket读写示例,IEEE745标准等。
spring
SpringBoot整合modbusMasterTCP框架协议。
这里的自动连接是指,是否在软件启动后自动创建Slave链接。
勾上这个选项,那么当主机(master)连接从机(slave)时,将会忽略slaveId。即只区分功能代码,不区分从机ID。
即使主机待连接的从机ID不存在,也不会报错,只会返回相同功能代码的第一个从机数据。即使后面该ID的从机上线也无效。
如果不勾选,则会对功能代码和从机ID都进行匹配。
较为复杂,扩展性强,(异步)底层使用了Netty框架,需要有一定的Java NIO知识。
API文档:https://libmodbus.org/docs/v3.0.6/ 简单易用,扩展性差,性能一般。读取的数据类型只能为整数,需要自己转换。
无法直接通过maven官方仓库下载,需要先下载至本地。
示例:new byte[]{a, b, c, d, e, f, g, h, i, j, k, l} 共12个byte
MBAP报文头一般为7个字节(a, b, c, d, e, f, g),其中:
ab为传输标识符,可以设置为0,也可以设置为每次传输只增1。
cd为协议标识符,其中0000代表ModbusTCP协议,0001代表UNI-TE协议。
ef为后续报文长度,为报文剩下的所有字节数。
g为单元标识符,即设备ID,在MODBUS或MODBUS+串行链路子网中对设备进行寻址时,这个域是用于路由的目的地址。
h为功能码,常见的功能码有:
01:读取线圈状态(单个或多个)
02:读取离散输入状态(单个或多个)
03:读取保持寄存器数据(单个或多个)
04:读取输入寄存器数据(单个或多个)
05:写入单个线圈状态
06:写入单个保持寄存器数据
15:写入多个线圈状态
16:写入多个保持寄存器数据
ij为起始地址,kl为读取数量
示例:new byte[]{a, b, c, d, e, f, g, h, i, j1, j2, j3 ...} byte 数量不固定
其中,前7个字节(a, b, c, d, e, f, g)为MBAP报文头,h为功能码,i为数据报文长度,j1、j2、j3 ... 为返回数据内容。
根据IEEE754的标准,浮点数的存储至少需要32为bit,而一个地址只有16个bit,因此则要进行拆分,就涉及到存储顺序的问题,可以分为大端模式或小端模式。
小端:将低序字节存储在起始地址。大端:将高序字节存储在起始地址。
在本项目中,并没有考虑到大端和小端的问题,统一采用小端标准,因为小端标准更为复杂,改成大端标准也更为容易。
Modbus Slave软件中的修改步骤如下:
Format --> 32 Bit Float / 64 Bit Double --> Big-endian / Little-endian
例如,从机数据为:
index | value |
---|---|
0 | 1 |
1 | 1 |
2 | 1 |
3 | 0 |
4 | 0 |
5 | 0 |
6 | 0 |
7 | 0 |
8 | 1 |
9 | 1 |
则在响应报文数组中,数值数组第一个值为7(00000111),第二个值为3(11)
这些方法的参数quantity(需要读取的数量),这里的数量指的是地址数量,而不是数据的数量。因为不同类型的寄存器和不同的数据类型,在数据存储上均有差别,无法一概而论。
线圈(0x01)和离散输入(0x02)只能存储状态布尔值,其一个地址就只有一个binary位,就存储一个数据量。
保持寄存器(0x03)和输入寄存器(0x04)一个地址有16个bit位,前8位和后8位组成两个byte数据。
二进制数、有/无符号十进制数、十六进制数一个数据量,即对应一个地址数量;
按照IEEE754标准,一个单精度浮点数需要32位bit,即对应两个地址数量,最多能精确7位有效数字;
按照IEEE754标准,一个双精度浮点数需要64位bit,即对应四个地址数量,最多能精确15位有效数字;
同时也需要注意,这些bit并非按顺序存储,而是按以下步骤:
1、判断长度是否是8的倍数,不足则高位补0,补成0的倍数
2、8位一组分组
3、按小端模式,高位存储在高地址
例如:浮点数123.4556,对应的二进制为:01000010 11110110 11101001 01111001 (本来就是32位)
地址 | 数值 |
---|---|
0 | 0100 0010 1111 0110 |
1 | 1110 1001 0111 1001 |
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。