首页 > 编程语言 >Java使用modbus4j通过串口modbus-rtu协议 连接设备 demo

Java使用modbus4j通过串口modbus-rtu协议 连接设备 demo

时间:2024-01-13 18:33:13浏览次数:34  
标签:modbus4j return int port rtu timeout 串口 buf public

前言

项目中需要使用串口来连接操控烟雾报警器

且只能使用modbus-rtu协议

在找了一堆资料后终于成功了在此呈上代码和资料链接

【ModBus】modbus之modbus4j的使用和流程原理解析(5)-CSDN博客

使用modbus4j通过串口解析modbus协议(java)_java modbus4j-CSDN博客

 串口通讯需要使用modbus4j包

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

maven拉取modbus4j包时拉取不下来

去官网下载jar引入本地maven仓库

执行下述命令

mvn install:install-file -Dfile=<path-to-file> -DgroupId=<group-id> -DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=<packaging>

<path-to-file>: 要安装的JAR的本地路径 ./libs/json-simple-1.1.1.jar
<group-id>:要安装的JAR的Group Id
<artifact-id>: 要安装的JAR的 Artificial Id
<version>: JAR 版本
<packaging>: 打包类型,例如JAR\

下面是本人使用的命令(不过是另一个第三方jar包)

mvn install:install-file   -Dfile=D:\Users\Administrator\IdeaProjects\campus-screen\ruoyi-admin\lib\examples.jar  -DgroupId=com.sun.jna  -DartifactId=examples -Dversion=1.0  -Dpackaging=jar

     上面的命令解释:
     -Dfile:指明你当前jar包的位置(就是第1步存放jar的路径+jar包名);
     -DgroupId, -DartifactId,  -Dversion:三个参数,就是指明了存放maven仓库中的位置;
     -Dpackaging :猜测就是指明文件类型;

Maven Repository: com.infiniteautomation » modbus4j » 3.0.5 (mvnrepository.com)

Java使用modbus4j通过串口modbus-rtu协议 连接设备 demo_iot

下述代码直接使用即可

package com.ruoyi.system.domain.iot.agreement.detector;
 
/**
 *
 * Copyright (c) 2009-2020 Freedomotic Team http://www.freedomotic-iot.com
 *
 * This file is part of Freedomotic
 *
 * This Program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2, or (at your option) any later version.
 *
 * This Program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * Freedomotic; see the file COPYING. If not, see
 * <http://www.gnu.org/licenses/>.
 */
 
import com.serotonin.modbus4j.serial.SerialPortWrapper;
import jssc.SerialPort;
import jssc.SerialPortException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import java.io.InputStream;
import java.io.OutputStream;
 
/**
 *
 */
public class SerialPortWrapperImpl implements SerialPortWrapper {
 
    private static final Logger LOG = LoggerFactory.getLogger(SerialPortWrapperImpl.class);
    private SerialPort port;
    private String commPortId;
    private int baudRate;
    private int dataBits;
    private int stopBits;
    private int parity;
    private int flowControlIn;
    private int flowControlOut;
 
    public SerialPortWrapperImpl(String commPortId, int baudRate, int dataBits, int stopBits, int parity, int flowControlIn,
                                 int flowControlOut) {
 
        this.commPortId = commPortId;
        this.baudRate = baudRate;
        this.dataBits = dataBits;
        this.stopBits = stopBits;
        this.parity = parity;
        this.flowControlIn = flowControlIn;
        this.flowControlOut = flowControlOut;
 
        port = new SerialPort(this.commPortId);
 
    }
 
    @Override
    public void close() throws Exception {
        port.closePort();
        //listeners.forEach(PortConnectionListener::closed);
        LOG.debug("Serial port {} closed", port.getPortName());
    }
 
    @Override
    public void open() {
        try {
            port.openPort();
            port.setParams(this.getBaudRate(), this.getDataBits(), this.getStopBits(), this.getParity());
            port.setFlowControlMode(this.getFlowControlIn() | this.getFlowControlOut());
 
            //listeners.forEach(PortConnectionListener::opened);
            LOG.debug("Serial port {} opened", port.getPortName());
        } catch (SerialPortException ex) {
            LOG.error("Error opening port : {} for {} ", port.getPortName(), ex);
        }
    }
 
    @Override
    public InputStream getInputStream() {
        return new SerialInputStream(port);
    }
 
    @Override
    public OutputStream getOutputStream() {
        return new SerialOutputStream(port);
    }
 
    @Override
    public int getBaudRate() {
        return baudRate;
        //return SerialPort.BAUDRATE_9600;
    }
 
    @Override
    public int getFlowControlIn() {
        return flowControlIn;
        //return SerialPort.FLOWCONTROL_NONE;
    }
 
    @Override
    public int getFlowControlOut() {
        return flowControlOut;
        //return SerialPort.FLOWCONTROL_NONE;
    }
 
    @Override
    public int getDataBits() {
        return dataBits;
        //return SerialPort.DATABITS_8;
    }
 
    @Override
    public int getStopBits() {
        return stopBits;
        //return SerialPort.STOPBITS_1;
    }
 
    @Override
    public int getParity() {
        return parity;
        //return SerialPort.PARITY_NONE;
    }
}
package com.ruoyi.system.domain.iot.agreement.detector;
 
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
 
import jssc.SerialPort;
 
import java.io.IOException;
import java.io.InputStream;
 
/**
 * Class that wraps a {@link SerialPort} to provide {@link InputStream}
 * functionality. This stream also provides support for performing blocking
 * reads with timeouts.
 * <br>
 * It is instantiated by passing the constructor a {@link SerialPort} instance.
 * Do not create multiple streams for the same serial port unless you implement
 * your own synchronization.
 *
 * @author Charles Hache <[email protected]>
 *
 * Attribution: https://github.com/therealchalz/java-simple-serial-connector
 *
 */
public class SerialInputStream extends InputStream {
 
    private SerialPort serialPort;
    private int defaultTimeout = 0;
 
    /**
     * Instantiates a SerialInputStream for the given {@link SerialPort} Do not
     * create multiple streams for the same serial port unless you implement
     * your own synchronization.
     *
     * @param sp The serial port to stream.
     */
    public SerialInputStream(SerialPort sp) {
        serialPort = sp;
    }
 
    /**
     * Set the default timeout (ms) of this SerialInputStream. This affects
     * subsequent calls to {@link #read()}, {@link #(int[])}, and
     * {@link #(int[], int, int)} The default timeout can be 'unset'
     * by setting it to 0.
     *
     * @param time The timeout in milliseconds.
     */
    public void setTimeout(int time) {
        defaultTimeout = time;
    }
 
    /**
     * Reads the next byte from the port. If the timeout of this stream has been
     * set, then this method blocks until data is available or until the timeout
     * has been hit. If the timeout is not set or has been set to 0, then this
     * method blocks indefinitely.
     */
    @Override
    public int read() throws IOException {
        return read(defaultTimeout);
    }
 
    /**
     * The same contract as {@link #read()}, except overrides this stream's
     * default timeout with the given timeout in milliseconds.
     *
     * @param timeout The timeout in milliseconds.
     * @return The read byte.
     * @throws IOException On serial port error or timeout
     */
    public int read(int timeout) throws IOException {
        byte[] buf = new byte[1];
        try {
            if (timeout > 0) {
                buf = serialPort.readBytes(1, timeout);
            } else {
                buf = serialPort.readBytes(1);
            }
            return buf[0];
        } catch (Exception e) {
            throw new IOException(e);
        }
    }
 
    /**
     * Non-blocking read of up to buf.length bytes from the stream. This call
     * behaves as read(buf, 0, buf.length) would.
     *
     * @param buf The buffer to fill.
     * @return The number of bytes read, which can be 0.
     * @throws IOException on error.
     */
    @Override
    public int read(byte[] buf) throws IOException {
        return read(buf, 0, buf.length);
    }
 
    /**
     * Non-blocking read of up to length bytes from the stream. This method
     * returns what is immediately available in the input buffer.
     *
     * @param buf The buffer to fill.
     * @param offset The offset into the buffer to start copying data.
     * @param length The maximum number of bytes to read.
     * @return The actual number of bytes read, which can be 0.
     * @throws IOException on error.
     */
    @Override
    public int read(byte[] buf, int offset, int length) throws IOException {
 
        if (buf.length < offset + length) {
            length = buf.length - offset;
        }
 
        int available = this.available();
 
        if (available > length) {
            available = length;
        }
 
        try {
            byte[] readBuf = serialPort.readBytes(available);
//            System.arraycopy(readBuf, 0, buf, offset, length);
            System.arraycopy(readBuf, 0, buf, offset, readBuf.length);
            return readBuf.length;
        } catch (Exception e) {
            throw new IOException(e);
        }
    }
 
    /**
     * Blocks until buf.length bytes are read, an error occurs, or the default
     * timeout is hit (if specified). This behaves as blockingRead(buf, 0,
     * buf.length) would.
     *
     * @param buf The buffer to fill with data.
     * @return The number of bytes read.
     * @throws IOException On error or timeout.
     */
    public int blockingRead(byte[] buf) throws IOException {
        return blockingRead(buf, 0, buf.length, defaultTimeout);
    }
 
    /**
     * The same contract as {@link #blockingRead(byte[])} except overrides this
     * stream's default timeout with the given one.
     *
     * @param buf The buffer to fill.
     * @param timeout The timeout in milliseconds.
     * @return The number of bytes read.
     * @throws IOException On error or timeout.
     */
    public int blockingRead(byte[] buf, int timeout) throws IOException {
        return blockingRead(buf, 0, buf.length, timeout);
    }
 
    /**
     * Blocks until length bytes are read, an error occurs, or the default
     * timeout is hit (if specified). Saves the data into the given buffer at
     * the specified offset. If the stream's timeout is not set, behaves as
     * {@link #read(byte[], int, int)} would.
     *
     * @param buf The buffer to fill.
     * @param offset The offset in buffer to save the data.
     * @param length The number of bytes to read.
     * @return the number of bytes read.
     * @throws IOException on error or timeout.
     */
    public int blockingRead(byte[] buf, int offset, int length) throws IOException {
        return blockingRead(buf, offset, length, defaultTimeout);
    }
 
    /**
     * The same contract as {@link #blockingRead(byte[], int, int)} except
     * overrides this stream's default timeout with the given one.
     *
     * @param buf The buffer to fill.
     * @param offset Offset in the buffer to start saving data.
     * @param length The number of bytes to read.
     * @param timeout The timeout in milliseconds.
     * @return The number of bytes read.
     * @throws IOException On error or timeout.
     */
    public int blockingRead(byte[] buf, int offset, int length, int timeout) throws IOException {
        if (buf.length < offset + length) {
            throw new IOException("Not enough buffer space for serial data");
        }
 
        if (timeout < 1) {
            return read(buf, offset, length);
        }
 
        try {
            byte[] readBuf = serialPort.readBytes(length, timeout);
            System.arraycopy(readBuf, 0, buf, offset, length);
            return readBuf.length;
        } catch (Exception e) {
            throw new IOException(e);
        }
    }
 
    @Override
    public int available() throws IOException {
        int ret;
        try {
            ret = serialPort.getInputBufferBytesCount();
            if (ret >= 0) {
                return ret;
            }
            throw new IOException("Error checking available bytes from the serial port.");
        } catch (Exception e) {
            throw new IOException("Error checking available bytes from the serial port.");
        }
    }
 
}
 
package com.ruoyi.system.domain.iot.agreement.detector;
 
/**
 *
 * Copyright (c) 2009-2020 Freedomotic Team http://www.freedomotic-iot.com
 *
 * This file is part of Freedomotic
 *
 * This Program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2, or (at your option) any later version.
 *
 * This Program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * Freedomotic; see the file COPYING. If not, see
 * <http://www.gnu.org/licenses/>.
 */
 
import jssc.SerialPort;
import jssc.SerialPortException;
 
import java.io.IOException;
import java.io.OutputStream;
 
/**
 * Class that wraps a {@link SerialPort} to provide {@link OutputStream}
 * functionality.
 * <br>
 * It is instantiated by passing the constructor a {@link SerialPort} instance.
 * Do not create multiple streams for the same serial port unless you implement
 * your own synchronization.
 *
 * @author Charles Hache <[email protected]>
 *
 * Attribution: https://github.com/therealchalz/java-simple-serial-connector
 *
 */
public class SerialOutputStream extends OutputStream {
 
    SerialPort serialPort;
 
    /**
     * Instantiates a SerialOutputStream for the given {@link SerialPort} Do not
     * create multiple streams for the same serial port unless you implement
     * your own synchronization.
     *
     * @param sp The serial port to stream.
     */
    public SerialOutputStream(SerialPort sp) {
        serialPort = sp;
    }
 
    @Override
    public void write(int b) throws IOException {
        try {
            serialPort.writeInt(b);
        } catch (SerialPortException e) {
            throw new IOException(e);
        }
    }
 
    @Override
    public void write(byte[] b) throws IOException {
        write(b, 0, b.length);
 
    }
 
    @Override
    public void write(byte[] b, int off, int len) throws IOException {
        byte[] buffer = new byte[len];
        System.arraycopy(b, off, buffer, 0, len);
        try {
            serialPort.writeBytes(buffer);
        } catch (SerialPortException e) {
            throw new IOException(e);
        }
    }
}
 
 
package com.ruoyi.system.domain.iot.agreement.detector;
 
/**
 *
 * Copyright (c) 2009-2020 Freedomotic Team http://www.freedomotic-iot.com
 *
 * This file is part of Freedomotic
 *
 * This Program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2, or (at your option) any later version.
 *
 * This Program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * Freedomotic; see the file COPYING. If not, see
 * <http://www.gnu.org/licenses/>.
 */
 
import com.serotonin.modbus4j.serial.SerialPortWrapper;
import jssc.SerialPort;
import jssc.SerialPortException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import java.io.InputStream;
import java.io.OutputStream;
 
/**
 *
 */
public class SerialPortWrapperImpl implements SerialPortWrapper {
 
    private static final Logger LOG = LoggerFactory.getLogger(SerialPortWrapperImpl.class);
    private SerialPort port;
    private String commPortId;
    private int baudRate;
    private int dataBits;
    private int stopBits;
    private int parity;
    private int flowControlIn;
    private int flowControlOut;
 
    public SerialPortWrapperImpl(String commPortId, int baudRate, int dataBits, int stopBits, int parity, int flowControlIn,
                                 int flowControlOut) {
 
        this.commPortId = commPortId;
        this.baudRate = baudRate;
        this.dataBits = dataBits;
        this.stopBits = stopBits;
        this.parity = parity;
        this.flowControlIn = flowControlIn;
        this.flowControlOut = flowControlOut;
 
        port = new SerialPort(this.commPortId);
 
    }
 
    @Override
    public void close() throws Exception {
        port.closePort();
        //listeners.forEach(PortConnectionListener::closed);
        LOG.debug("Serial port {} closed", port.getPortName());
    }
 
    @Override
    public void open() {
        try {
            port.openPort();
            port.setParams(this.getBaudRate(), this.getDataBits(), this.getStopBits(), this.getParity());
            port.setFlowControlMode(this.getFlowControlIn() | this.getFlowControlOut());
 
            //listeners.forEach(PortConnectionListener::opened);
            LOG.debug("Serial port {} opened", port.getPortName());
        } catch (SerialPortException ex) {
            LOG.error("Error opening port : {} for {} ", port.getPortName(), ex);
        }
    }
 
    @Override
    public InputStream getInputStream() {
        return new SerialInputStream(port);
    }
 
    @Override
    public OutputStream getOutputStream() {
        return new SerialOutputStream(port);
    }
 
    @Override
    public int getBaudRate() {
        return baudRate;
        //return SerialPort.BAUDRATE_9600;
    }
 
    @Override
    public int getFlowControlIn() {
        return flowControlIn;
        //return SerialPort.FLOWCONTROL_NONE;
    }
 
    @Override
    public int getFlowControlOut() {
        return flowControlOut;
        //return SerialPort.FLOWCONTROL_NONE;
    }
 
    @Override
    public int getDataBits() {
        return dataBits;
        //return SerialPort.DATABITS_8;
    }
 
    @Override
    public int getStopBits() {
        return stopBits;
        //return SerialPort.STOPBITS_1;
    }
 
    @Override
    public int getParity() {
        return parity;
        //return SerialPort.PARITY_NONE;
    }
}
 

连接设备 COM3换成你自己的串口号,9600换成你的波特率

ModbusUtils.getSerialPortRtuMaster("COM3", 9600, 8, 2, 0);

读寄存器

    /**
     * 读寄存器
     * @param slaveId 设备地址
     * @param startOffset 寄存器地址
     * @param numberOfRegisters 查询寄存器的数量吧 (我也不太懂)
     * @throws ModbusTransportException
     */
    @Anonymous
    @PostMapping("read")
    public void read(int slaveId,int startOffset, int numberOfRegisters) throws ModbusTransportException {
        ReadInputRegistersRequest readRequest = new ReadInputRegistersRequest(slaveId, startOffset, numberOfRegisters);
        // 发送请求并接收响应
        ReadInputRegistersResponse response = (ReadInputRegistersResponse) master.send(readRequest);
        if (response.isException())
            System.out.println("Exception response: message=" + response.getExceptionMessage());
        else
            System.out.println(Arrays.toString(response.getShortData()));
    }

写寄存器

    /**
     * 写寄存器
     * @param slaveId 设备地址
     * @param writeOffset 寄存器地址
     * @param writeValue value值
     * @throws ModbusTransportException
     */
    @Anonymous
    @PostMapping("write")
    public void write(int slaveId,int writeOffset,int writeValue) throws ModbusTransportException {
        WriteRegisterRequest writeRequest = new WriteRegisterRequest(slaveId, writeOffset, writeValue);
        // 发送请求并接收响应
        WriteRegisterResponse response = (WriteRegisterResponse) master.send(writeRequest);
        if (response.isException())
            System.out.println("Exception response: message=" + response.getExceptionMessage());
        else
            System.out.println("写入寄存器成功");
    }

只连了一个设备的话设备地址(slaveId)应该都是1默认的

寄存器地址去看设备说明书

Java使用modbus4j通过串口modbus-rtu协议 连接设备 demo_ide_02

 第二个寄存器地址(writeOffset)是0033H转成10进制时51 

value就是传给寄存器的值


标签:modbus4j,return,int,port,rtu,timeout,串口,buf,public
From: https://blog.51cto.com/u_16497353/9232875

相关文章

  • RK3568 学习笔记 : 开机上电与串口波特率
    前言开发板:【正点原子】ATK-DLRK3568开发板,包装什么的看上去有点高大上,也有点贵。。开发板资料的Linux-SDK编译通过了,想尝试第一次上电开机,不过,开始出了一点状况,串口信息是乱码,难道【调试串口】数据线有问题?波特率115200bps不正确?调试串口波特率开发板默认有镜像,因此先上电研......
  • VirtualBox运行虚拟Win7显示异常故障一例
    VirtualBox里一直在用的一个32位Win7虚拟环境,昨天突然在系统主机升级之后出现故障。主机是Ubuntu22.04,昨天只是一次例行升级。从症状看应该是显卡驱动不大利索,首先是主机和虚拟无法实现鼠标集成,鼠标被虚拟机捕获后只能手工脱离,再就是分辨率不正常,无法实现自动调整显示尺寸,分辨率......
  • 串口服务器在网络通信中的作用与应用场景
    在当今的网络通信技术中,串口服务器扮演了一个至关重要的角色。它是一个实现串口到网络功能转换的设备,通常用于设备的远程管理和控制。本文将探讨串口服务器在网络通信中的作用及其应用场景。串口服务器的基本原理串口通信是一种基本的计算机通信方式。它通过数据信号线和地线等按位......
  • 串口服务器技术概述与实际应用案例
    在当代信息化时代,串口服务器技术因其独特的通信转换功能,在众多领域发挥着不可替代的作用。本文将对串口服务器的技术原理进行概述,并结合实际应用案例,深入探讨其在现代通信中的应用。串口服务器技术原理串口服务器,主要是将传统的RS-232、RS-485、RS-422串口转换成TCP/IP网络接口。这......
  • 串口服务器485至以太网转换技术指南
    在现代工业和网络通信领域,串口服务器485至以太网转换技术扮演着至关重要的角色。本文旨在介绍这一技术的关键点和实际应用.串口服务器与RS-485接口串口服务器是一种网络设备,用于将串行通信(如RS-485)转换为以太网通信。RS-485接口是一种广泛应用的串行通信标准,它支持高速、远距离的多......
  • Virtualbox - VM can't start after OS update
      Executing'modprobevboxdrv'didn'twork:zzh@ZZHPC:~$sudomodprobevboxdrvmodprobe:FATAL:Modulevboxdrvnotfoundindirectory/lib/modules/6.5.0-14-generic HadtoremoveVirtualbox6.1andinstallVirtualbox7.0:zzh@ZZHPC:~......
  • stm32学习总结:5、Proteus8+STM32CubeMX+MDK仿真串口并使用串口打印日志(注意重定向prin
    stm32学习总结:5、Proteus8+STM32CubeMX+MDK仿真串口并使用串口打印日志(注意重定向printf到串口打印的问题)文章目录stm32学习总结:5、Proteus8+STM32CubeMX+MDK仿真串口并使用串口打印日志(注意重定向printf到串口打印的问题)一、前言二、资料收集三、注意事项四、STM32CubeMX配置五、......
  • Python创建virtualenv(虚拟环境)方法
    一前言   需求:      --公司之有一台服务器      -目前运行这一个5年前开发的Django项目,基于1.5      -现在要基于Django2.0开发一套程序      -无法卸载原来的版本,必须还要安装新版本二通过virtualenv软件创建安装:      ......
  • PyCharm新建解释器(Virtualenv环境)
    问题在研究新的库时,需要下载一些列的依赖库,一旦出现像版本硬件不匹配的问题,就要重新下载新版本的库,但又会影响其他程序的运行,这时就需要新建解释器前提至少安装一个版本的Python已安装PyCharm操作系统解释器基础库升级新建解释器,可以继承系统解释器所有库,所以对于像PIP这种公用的......
  • SpringBoot+modbus4j实现ModebusTCP通讯读取数据
    场景Windows上ModbusTCP模拟Master与Slave工具的使用:Windows上ModbusTCP模拟Master与Slave工具的使用ModebusTCPModbus由MODICON公司于1979年开发,是一种工业现场总线协议标准。1996年施耐德公司推出基于以太网TCP/IP的Modbus协议:ModbusTCP。Modbus协议是一项应用层报文传输协议,包......