Modbus对接 - Java

文章目录

  • 一、如何真正理解Modbus
    • 1.1 数据格式
    • 1.2 数据交互过程
  • 二、调试环境部署
    • 2.1 Modbus Poll
    • 2.2 Modbus Slave
    • 2.3 MThings
  • 三、协议相关知识
    • 3.1 寄存器
    • 3.2 RTU的消息帧
      • 格式举例
      • 停顿间隔
      • 地址域
      • CRC-16(待定)
    • 3.3 大端与小端
    • 3.4 功能码
      • (0x01)读取线圈/离散量输出状态
      • (0x02)读取离散量输入值
      • (0x03)读取保持寄存器值
      • (0x04)读取输入寄存器值
      • (0x05)写单个线圈或单个离散输出
      • (0x06)写单个保持寄存器
      • (0x08)诊断功能
      • (0x0B)获取通信事件计数器
      • (0x0C)获取通信事件记录
      • (0x0F)写多个线圈
      • (0x10)写多个保持寄存器
      • (0x11)报告从站ID
    • 3.5 异常响应
  • 四、开发实战
    • 4.1 Modbus4J入门-TCP
    • 4.2 Modbus4J入门-RTU
    • 4.3 场景之电水表读取
    • 4.4 关于超时
    • 4.5 控制Modbus设备的场景
  • 五、推荐学习链接

一、如何真正理解Modbus

文章目录
《Modbus软件开发实战指南》 - 杨更更

Modbus是OSI模型第7层之上的应用层报文传输协议,它在不同类型总线或网络设备之间提供主站设备/从站设备(或客户机/服务器)通信,国际互联网组织规定并保留了TCP/IP协议栈上的系统502端口,专门用于访问Modbus设备。

在通常情况下,Modbus协议它是一个 服务器 / 客户端 形式的通讯,它也叫主站与从站之间的通讯。

1.1 数据格式

Modbus对接 - Java_第1张图片

例如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校验码。

1.2 数据交互过程

Modbus对接 - Java_第2张图片

二、调试环境部署

链接地址
MThings-首页 (gulink.cn)
Download (modbustools.com)

学习开发Modbus协议软件之前,可以先使用网上的一些调试工具,先学会用,先学懂里面的一些专业的术语。

2.1 Modbus Poll

主站设备仿真工具

Modbus对接 - Java_第3张图片

使用说明会在后面模拟实战时进行贴图。

2.2 Modbus Slave

从站设备仿真工具,用于接收主设备的命令包,并回送数据包;可用于测试和调试Modbus主站设备,便于观察Modbus通信过程中的各种报文数据。该软件支持Modbus RTU、ASCII、TCP/IP等协议。

Modbus对接 - Java_第4张图片

使用说明会在后面模拟实战时进行贴图。

2.3 MThings

首先安装完成上面这个链接的调试软件,安装完成后是这个样子的

Modbus对接 - Java_第5张图片

它相当于可以模拟服务端及客户端,启动以后,检查自己的端口,你会发现已经启动

Modbus对接 - Java_第6张图片

然后看一下模拟软件上的配置信息

Modbus对接 - Java_第7张图片

同时打开数据面板,我们可以看到数据的发送和接收,我们现在学习这个工具的目的是为了后面将它作为模拟设备工具进行调试连接。

Modbus对接 - Java_第8张图片

暂时先这样。

三、协议相关知识

Modbus的前置知识,重要

3.1 寄存器

在Modbus协议中,所有的数据都存放在寄存器中,寄存器根据存放的数据类型以及各自读写特性,将寄存器分为4个部分:

寄存器种类 举例说明 作用
线圈状态 - Coil Status LED显示、电磁阀输出等 输出,可读写
离散输入 - Input Status 开关 输入,只读
保持寄存器 - Holding Register 模拟量输出设定值,变量阀输出大小、传感器报警上下限 输出,可读写
输入寄存器 - InputRegister 模拟量输入 输入,只读

如果通过寄存器的地址分配来看:

寄存器种类 Modbus协议地址
线圈状态 0000H~FFFFH
离散输入 0000H~FFFFH
保持寄存器 0000H~FFFFH
输入寄存器 0000H~FFFFH

3.2 RTU的消息帧

Modbus对接 - Java_第9张图片

格式举例

Modbus对接 - Java_第10张图片

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 保留区域

CRC-16(待定)

循环冗余校验,待定。

3.3 大端与小端

不太好理解,网上有句话是这么说的

大端模式(Big-Endian)是指数据的低位保存在内存的高位地址中,数据的高位保存在内存的低位地址中。

小端模式(Little-Endian)是指数据的低位保存在内存的低位地址中,数据的高位保存在内存的高位地址中。

其实就相当于反过来了,例如在小端模式中

1 2 3
数据内容 0x34 0x12
内存地址 0x4000 0x40001

而在大端模式上

1 2 3
数据内容 0x12 0x34
内存地址 0x4000 0x40001

3.4 功能码

功能码占用一个字节,取值范围是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协议,我们想要制定一个协议,我们首先要明确,协议的目的是为了数据传输,因此,为了更好地存储不同的数据类型,我们会将布尔和非布尔的数据分开存储,因此,就有了线圈和寄存器的概念。

线圈和寄存器,这个经常被很多人诟病,认为不应该这么翻译,感觉不容易理解。从电气角度来看,在电气控制回路中,一般都是靠接触器或中间继电器来实现控制,接触器或中继最终靠的是线圈的得电和失电来控制触点闭合和断开,因此用线圈表示布尔量;而寄存器在计算机中,就是用来存储数据的,因此非布尔的数据放在寄存器里。

(0x01)读取线圈/离散量输出状态

待定

(0x02)读取离散量输入值

待定

(0x03)读取保持寄存器值

待定

(0x04)读取输入寄存器值

待定

(0x05)写单个线圈或单个离散输出

待定

(0x06)写单个保持寄存器

待定

(0x08)诊断功能

待定

(0x0B)获取通信事件计数器

待定

(0x0C)获取通信事件记录

待定

(0x0F)写多个线圈

待定

(0x10)写多个保持寄存器

待定

(0x11)报告从站ID

待定

3.5 异常响应

待定

四、开发实战

该篇章主要作为Java开发去读取Modbus协议设备的数据,例如电表

4.1 Modbus4J入门-TCP

是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) 

你可能感兴趣的:(物联网,java,modbus)