0
点赞
收藏
分享

微信扫一扫

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

前言

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

且只能使用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_串口通信

下述代码直接使用即可

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 <chalz@member.fsf.org>
 *
 * 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 <chalz@member.fsf.org>
 *
 * 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_java_02

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

value就是传给寄存器的值


举报

相关推荐

0 条评论