文章目录 |
---|
《Modbus软件开发实战指南》 - 杨更更 |
Modbus是OSI模型第7层之上的应用层报文传输协议
,它在不同类型总线或网络设备之间提供主站设备/从站设备(或客户机/服务器)通信,国际互联网组织规定并保留了TCP/IP协议栈上的系统502
端口,专门用于访问Modbus设备。
在通常情况下,Modbus协议它是一个 服务器 / 客户端 形式的通讯,它也叫主站与从站之间的通讯。
例如Modbus RTU协议中
37 03 10 3F 80 00 00 00 00 00 00 3F 80 00 00 40 40 00 00 24 dd(十六进制)
37:从站地址;
03:功能码;
10:读取的字节数;
24 dd:crc校验码;
其它就是传送的数据,而对于Modbus TCP协议来说,TCP协议是在RTU协议前面添加MBAP报文头,由于TCP是基于可靠连接的服务,RTU协议中的CRC校验码就不再需要,所以在Modbus TCP协议中是没有CRC校验码。
链接地址 |
---|
MThings-首页 (gulink.cn) |
Download (modbustools.com) |
学习开发Modbus协议软件之前,可以先使用网上的一些调试工具,先学会用,先学懂里面的一些专业的术语。
主站设备仿真工具
使用说明会在后面模拟实战时进行贴图。
从站设备仿真工具,用于接收主设备的命令包,并回送数据包;可用于测试和调试Modbus主站设备,便于观察Modbus通信过程中的各种报文数据。该软件支持Modbus RTU、ASCII、TCP/IP等协议。
使用说明会在后面模拟实战时进行贴图。
首先安装完成上面这个链接的调试软件,安装完成后是这个样子的
它相当于可以模拟服务端及客户端,启动以后,检查自己的端口,你会发现已经启动
然后看一下模拟软件上的配置信息
同时打开数据面板,我们可以看到数据的发送和接收,我们现在学习这个工具的目的是为了后面将它作为模拟设备工具进行调试连接。
暂时先这样。
Modbus的前置知识,重要
在Modbus协议中,所有的数据都存放在寄存器
中,寄存器根据存放的数据类型以及各自读写特性,将寄存器分为4个部分:
寄存器种类 | 举例说明 | 作用 |
---|---|---|
线圈状态 - Coil Status | LED显示、电磁阀输出等 | 输出,可读写 |
离散输入 - Input Status | 开关 | 输入,只读 |
保持寄存器 - Holding Register | 模拟量输出设定值,变量阀输出大小、传感器报警上下限 | 输出,可读写 |
输入寄存器 - InputRegister | 模拟量输入 | 输入,只读 |
如果通过寄存器的地址分配来看:
寄存器种类 | Modbus协议地址 |
---|---|
线圈状态 | 0000H~FFFFH |
离散输入 | 0000H~FFFFH |
保持寄存器 | 0000H~FFFFH |
输入寄存器 | 0000H~FFFFH |
Modbus RTU协议中
37 03 10 3F 80 00 00 00 00 00 00 3F 80 00 00 40 40 00 00 24 dd(十六进制)
37:从站地址;
03:功能码;
10:读取的字节数;
24 dd:CRC-16标准校验码;
其余的就是数据的传送,这个前面也有进行说明。
从理论上,在RTU模式中,消息的发送和接收以至少3.5个字符时间的停顿间隔为标志,而这个间隔时间,第一,只对RTU模式有效
,第二,目的是作为区别前后两帧数据的分隔符
。
从设备地址,Modbus消息帧的地址域包含2个字符(ASCII模式)或者1个字节(RTU模式)
。
寻址范围 | 说明 |
---|---|
0 | 广播地址 |
1-247 | 从站地址 |
248-255 | 保留区域 |
循环冗余校验,待定。
不太好理解,网上有句话是这么说的
大端模式(Big-Endian)是指数据的低位保存在内存的高位地址中,数据的高位保存在内存的低位地址中。
小端模式(Little-Endian)是指数据的低位保存在内存的低位地址中,数据的高位保存在内存的高位地址中。
其实就相当于反过来了,例如在小端模式中
1 | 2 | 3 |
---|---|---|
数据内容 | 0x34 | 0x12 |
内存地址 | 0x4000 | 0x40001 |
而在大端模式上
1 | 2 | 3 |
---|---|---|
数据内容 | 0x12 | 0x34 |
内存地址 | 0x4000 | 0x40001 |
功能码占用一个字节,取值范围是1-27,其它值代表异常码。
功能码可分为位操作和字操作两类。位操作的最小单位为一个字节,字操作的最小单位为两个字节。
代码 | 中文名称 | 英文名 | 位操作/字操作 | 操作数量 |
---|---|---|---|---|
01 | 读线圈状态 | READ COIL STATUS | 位操作 | 单个或多个 |
02 | 读离散输入状态 | READ INPUT STATUS | 位操作 | 单个或多个 |
03 | 读保持寄存器 | READ HOLDING REGISTER | 字操作 | 单个或多个 |
04 | 读输入寄存器 | READ INPUT REGISTER | 字操作 | 单个或多个 |
05 | 写线圈状态 | WRITE SINGLE COIL | 位操作 | 单个 |
06 | 写单个保持寄存器 | WRITE SINGLE REGISTER | 字操作 | 单个 |
15 | 写多个线圈 | WRITE MULTIPLE COIL | 位操作 | 多个 |
16 | 写多个保持寄存器 | WRITE MULTIPLE REGISTER | 字操作 | 多个 |
线圈与寄存器
假设没有Modbus协议,我们想要制定一个协议,我们首先要明确,协议的目的是为了数据传输,因此,为了更好地存储不同的数据类型,我们会将布尔和非布尔的数据分开存储,因此,就有了线圈和寄存器的概念。
线圈和寄存器,这个经常被很多人诟病,认为不应该这么翻译,感觉不容易理解。从电气角度来看,在电气控制回路中,一般都是靠接触器或中间继电器来实现控制,接触器或中继最终靠的是线圈的得电和失电来控制触点闭合和断开,因此用线圈表示布尔量;而寄存器在计算机中,就是用来存储数据的,因此非布尔的数据放在寄存器里。
待定
待定
待定
待定
待定
待定
待定
待定
待定
待定
待定
待定
待定
该篇章主要作为Java开发去读取Modbus协议设备的数据,例如电表
是Serotonin Software用Java编写的Modbus协议的高性能且易于使用的实现。支持ASCII,RTU,TCP和UDP传输作为从站或主站,自动请求分区,响应数据类型解析和节点扫描。
首先是将POM依赖进入,这里对于包下载不做说明
<dependency>
<groupId>com.serotonin.modbus4jgroupId>
<artifactId>modbus4jartifactId>
<version>3.0.3version>
<scope>systemscope>
<systemPath>${project.basedir}/lib/modbus4j-3.0.3.jarsystemPath>
然后来看看其它大神写的工具类,最后我们会根据实际的情况做一些改动
import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.locator.BaseLocator;
/**
* modbus通讯工具类,采用modbus4j实现
* @author lxq
* @dependencies modbus4j-3.0.3.jar
* @website https://github.com/infiniteautomation/modbus4j
*/
public class Modbus4jUtils {
/**
* 工厂。
*/
static ModbusFactory modbusFactory;
static {
if (modbusFactory == null)