首页 > 其他分享 >SpringBoot+modbus4j实现ModebusTCP通讯读取数据

SpringBoot+modbus4j实现ModebusTCP通讯读取数据

时间:2023-12-29 15:44:28浏览次数:44  
标签:modbus4j 读取数据 serotonin master import com throws SpringBoot

场景

Windows上ModbusTCP模拟Master与Slave工具的使用:

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/135290463

Modebus TCP

Modbus由MODICON公司于1979年开发,是一种工业现场总线协议标准。

1996年施耐德公司推出基于以太网TCP/IP的Modbus协议:ModbusTCP。

Modbus协议是一项应用层报文传输协议,包括ASCII、RTU、TCP三种报文类型。

标准的Modbus协议物理层接口有RS232、RS422、RS485和以太网接口,采用master/slave方式通信。

Modbus的操作对象有四种:

线圈、离散输入、保持寄存器、输入寄存器。

Modbus功能码:

 

关于Java的开源库:

Jamod:

Java Modbus实现:Java Modbus库。该库由Dieter Wimberger实施。

ModbusPal:

ModbusPal是一个正在进行的Java项目,用于创建逼真的Modbus从站模拟器。

下面介绍基于Modebus4j实现读线圈状态数据。

由于预定义的数学函数和/或Python脚本,寄存器值是动态生成的。

ModbusPal依赖于RxTx进行串行通信,而Jython则依赖于脚本支持。

Modbus4J:

Serotonin Software用Java编写的Modbus协议的高性能且易于使用的实现。

支持ASCII,RTU,TCP和UDP传输作为从站或主站,自动请求分区,响应数据类型解析和节点扫描。

JLibModbus:

JLibModbus是java语言中Modbus协议的一种实现。jSSC和RXTX用于通过串行端口进行通信。

该库是一个经过积极测试和改进的项目。

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi

实现

1、基于modbus4j实现线圈状态数据的读取。

modbus4j

https://github.com/MangoAutomation/modbus4j

按照官网介绍,需要在pom文件中添加repository的配置

    <repositories>
        <repository>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
            <id>ias-snapshots</id>
            <name>Infinite Automation Snapshot Repository</name>
            <url>https://maven.mangoautomation.net/repository/ias-snapshot/</url>
        </repository>
        <repository>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <id>ias-releases</id>
            <name>Infinite Automation Release Repository</name>
            <url>https://maven.mangoautomation.net/repository/ias-release/</url>
        </repository>
    </repositories>

添加位置

 

然后添加依赖

        <dependency>
            <groupId>com.infiniteautomation</groupId>
            <artifactId>modbus4j</artifactId>
            <version>3.0.3</version>
        </dependency>

2、新建modbus4j工具类

package com.badao.demo.utils;

import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
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;

public class Modbus4jUtils {

    /**
     * 工厂。
     */
    static ModbusFactory modbusFactory;

    static {
        if (modbusFactory == null) {
            modbusFactory = new ModbusFactory();
        }
    }

    /**
     * 获取master
     *
     * @return
     * @throws ModbusInitException
     */
    public static ModbusMaster getMaster(String ip,int port) throws ModbusInitException {
        IpParameters params = new IpParameters();
        params.setHost(ip);
        params.setPort(port);
        // modbusFactory.createRtuMaster(wapper); //RTU 协议
        // modbusFactory.createUdpMaster(params);//UDP 协议
        // modbusFactory.createAsciiMaster(wrapper);//ASCII 协议
        ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
        master.init();
        return master;
    }

    /**
     * 读取[01 Coil Status 0x]类型 开关数据
     *
     * @param slaveId
     *            slaveId
     * @param offset
     *            位置
     * @return 读取值
     * @throws ModbusTransportException
     *             异常
     * @throws ErrorResponseException
     *             异常
     */
    public static Boolean readCoilStatus(ModbusMaster master,int slaveId, int offset)
            throws ModbusTransportException, ErrorResponseException {
        // 01 Coil Status
        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
        Boolean value = master.getValue(loc);
        return value;
    }

    /**
     * 读取[02 Input Status 1x]类型 开关数据
     *
     * @param slaveId
     * @param offset
     * @return
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     */
    public static Boolean readInputStatus(ModbusMaster master,int slaveId, int offset)
            throws ModbusTransportException, ErrorResponseException {
        // 02 Input Status
        BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
        Boolean value = master.getValue(loc);
        return value;
    }

    /**
     * 读取[03 Holding Register类型 2x]模拟量数据
     *
     * @param slaveId
     *            slave Id
     * @param offset
     *            位置
     * @param dataType
     *            数据类型,来自com.serotonin.modbus4j.code.DataType
     * @return
     * @throws ModbusTransportException
     *             异常
     * @throws ErrorResponseException
     *             异常
     */
    public static Number readHoldingRegister(ModbusMaster master,int slaveId, int offset, int dataType)
            throws ModbusTransportException, ErrorResponseException {
        // 03 Holding Register类型数据读取
        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
        Number value = master.getValue(loc);
        return value;
    }

    /**
     * 读取[04 Input Registers 3x]类型 模拟量数据
     *
     * @param slaveId
     *            slaveId
     * @param offset
     *            位置
     * @param dataType
     *            数据类型,来自com.serotonin.modbus4j.code.DataType
     * @return 返回结果
     * @throws ModbusTransportException
     *             异常
     * @throws ErrorResponseException
     *             异常
     */
    public static Number readInputRegisters(ModbusMaster master,int slaveId, int offset, int dataType)
            throws ModbusTransportException, ErrorResponseException {
        // 04 Input Registers类型数据读取
        BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
        Number value = master.getValue(loc);
        return value;
    }

    /**
     * 批量读取使用方法
     *
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     * @throws ModbusInitException
     * @return
     */
    public static BatchResults<Integer> batchRead(ModbusMaster master,BatchRead<Integer> batchRead) throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 是否连续请求
        batchRead.setContiguousRequests(false);
        BatchResults<Integer> results = master.send(batchRead);
        return results;
    }
}

3、使用方式

新建master

ModbusMaster master = Modbus4jUtils.getMaster(modebustcpIp, port);

这里的ip和端口来自配置文件

单个读取数据

Boolean aBoolean = Modbus4jUtils.readCoilStatus(master, 1, 0);

这里1代表slaveId,0代表offset

批量读取数据

        BatchRead<Integer> batch = new BatchRead<>();
        List<Locator> locatorList = locatorConfig.getLocatorList();
        locatorList.forEach(locator -> batch.addLocator(locator.getId(), BaseLocator.coilStatus(locator.getSlaveId(),locator.getOffset())));

        BatchResults<Integer> batchResults = Modbus4jUtils.batchRead(master, batch);
        Boolean valueOne = (Boolean) batchResults.getValue(0);
        Boolean valueTwo = (Boolean) batchResults.getValue(1);
        Boolean valueThree = (Boolean) batchResults.getValue(2);

这里批量读取的配置来自配置文件

4、业务示例

在定时任务中批量读取指定slaveId和offset的线圈状态数据

import com.badao.demo.config.LocatorConfig;
import com.badao.demo.entity.Locator;
import com.badao.demo.utils.Modbus4jUtils;
import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.locator.BaseLocator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import java.time.LocalDateTime;
import java.util.List;

@Configuration
@EnableScheduling
public class GetModbusTCPDataTask {

    @Value("${modebustcp.ip}")
    private String modebustcpIp;

    @Value("${modebustcp.port}")
    private Integer port;

    @Autowired
    private LocatorConfig locatorConfig;

    @Scheduled(fixedRateString = "2000")
    public void  getData() throws ModbusInitException {
        ModbusMaster master = Modbus4jUtils.getMaster(modebustcpIp, port);
        BatchRead<Integer> batch = new BatchRead<>();
        List<Locator> locatorList = locatorConfig.getLocatorList();
        locatorList.forEach(locator -> batch.addLocator(locator.getId(), BaseLocator.coilStatus(locator.getSlaveId(),locator.getOffset())));
        try {
            //单个读取
            //Boolean aBoolean = Modbus4jUtils.readCoilStatus(master, 1, 0);
            //批量读取
            BatchResults<Integer> batchResults = Modbus4jUtils.batchRead(master, batch);
            Boolean valueOne = (Boolean) batchResults.getValue(0);
            Boolean valueTwo = (Boolean) batchResults.getValue(1);
            Boolean valueThree = (Boolean) batchResults.getValue(2);
            System.out.println(LocalDateTime.now());
            System.out.println("valueOne:"+valueOne);
            System.out.println("valueTwo:"+valueTwo);
            System.out.println("valueThree:"+valueThree);
        } catch (ModbusTransportException e) {
            e.printStackTrace();
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (ModbusInitException e) {
            e.printStackTrace();
        }
    }
}

5、本地测试效果

 

6、线上测试效果

线上使用RS485转以太网模块,会将其转换成MODBUS TCP服务端,端口为默认502,slaveid为2

 

通讯测试效果

 

7、SpringBoot中进行ModbusTCP通讯时提示:

com.serotonin.modbus4j.exception.ErrorResponseException:Illegal function

这是因为功能码不对应,使用Modbus Slave Definition定义的功能码为03 Holding Register(4x),而在代码中连接后执行

的是读取线圈状态的功能码

 

所以将功能码修改对应即可

 

标签:modbus4j,读取数据,serotonin,master,import,com,throws,SpringBoot
From: https://www.cnblogs.com/badaoliumangqizhi/p/17935025.html

相关文章

  • springboot(功能权限分配和脚本实现功能分配)
    一、功能权限分配添加菜单按钮:这时的按钮菜单是手动添加,后面可以自动生成 进入到角色管理,修改普通角色,添加权限之后,登录普通角色,在这之前需要先重置一下普通角色的密码 登录普通角色,普通角色就可以拥有权限,进行一系列操作: 二、脚本功能权限分配运行代码生成器的facor......
  • 基于SpringBoot的宠物管理系统的设计与实现(可做毕业设计参考)
    关键词:SpringBoot;宠物管理;宠物医院;宠物店管理;毕业;我们专注于软件开发工程领域,熟练掌握多种开发技术,包括基于SpringBoot、Vue.js、SSM框架的应用开发,以及针对AndroidAPP和微信小程序的开发。需要程序可以ADDME添+my企鹅numberisonezerothreetwothreesevenonetwoone回头......
  • SpringBoot中读取yml中配置的list对象的配置项
    场景SpringBoot中通过ConfigurationProperties注解的方式读取application.yml中配置的属性值:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108385148参考上面获取yml配置文件中简单的配置项的方式。如果需要获取application.yml中配置的list数据,且每个list有多......
  • 【SpringBoot零基础入门到项目实战②】安装Java和Maven,创建你的第一个项目
    文章目录导言安装JavaWindows系统macOS系统Linux系统安装和配置MavenWindows系统macOS系统Linux系统配置Maven本地仓库使用阿里镜像加速创建第一个SpringBoot项目拓展学习(提前了解后面会讲到)1.深入理解SpringBoot的项目结构2.学习SpringBoot的自动配置3.掌握SpringBoot......
  • Java 系统学习 | Springboot 写 hello world
    经过一段时间基础学习,现在开始使用Springboot框架完成项目,特地记录一下,方便后续查漏补缺。本篇使用Springboot3框架,IDEA2022编辑器,java17版本。新建项目file->new->project弹框中填入自己的信息Name项目名称Location项目存放路径LanguageJavaB......
  • 如何使用 Prometheus 监控SpringBoot系统
    公众号「架构成长指南」,专注于生产实践、云原生、分布式系统、大数据技术分享在从零开始:使用Prometheus与Grafana搭建监控系统中,主要讲解了如何使用监控系统资源并进行告警,这节主要分享下,如何在业务系统中使用Prometheus来监控业务系统指标,业务系统使用SpringBoot构建。我们要......
  • 手把手从安装本地虚拟机,基于docker,部署springboot+vue项目(若依框架前后端分离版本演示
    目录1.安装本地虚拟机centos2.安装docker,拉取镜像,创建容器3.打包部署后端4.配置nginx5.打包部署前端6.常见问题汇总1.安装本地虚拟机centos部署环境提供vm16,和centos7,其中把镜像改成.iso文件就可以了阿里云链接:https://www.alipan.com/s/BTnpjuHWtEp为什么用阿里云,不限速啊,秉......
  • SpringBoot+JaywayJsonPath实现Json数据的DSL(按照指定节点表达式解析json获取指定数
    场景若依前后端分离版手把手教你本地搭建环境并运行项目:若依前后端分离版手把手教你本地搭建环境并运行项目_前后端分离项目本地运行在上面搭建SpringBoot项目的基础上,并且在项目中引入fastjson、hutool等所需依赖后。JaywayJsonPath:GitHub-json-path/JsonPath:JavaJsonPathi......
  • 【SpringBoot快速入门】(4)SpringBoot项目案例代码示例
    目录1创建工程3配置文件4静态资源之前我们已经学习的Spring、SpringMVC、Mabatis、Maven,详细讲解了Spring、SpringMVC、Mabatis整合SSM的方案和案例,上一节我们学习了SpringBoot的开发步骤、工程构建方法以及工程的快速启动,从这一节开始,我们开始学习SpringBoot配置文件。接下来......
  • 【SpringBoot快速入门】(3)SpringBoot整合junit和MyBatis 详细代码示例与讲解
    目录1.SpringBoot整合junit1.1环境准备1.2编写测试类2.SpringBoot整合mybatis2.1回顾Spring整合Mybatis2.2SpringBoot整合mybatis2.2.1创建模块2.2.2定义实体类2.2.3定义dao接口2.2.4定义测试类2.2.5编写配置2.2.6测试2.2.7使用Druid数据源之前我们已经学习的Spring、......