基于JAVA实现modbus rtu通信(一)

前言

本次实现modbus rtu数据读写,在做java的modbus rtu通信时查了好多资料,大多数都是用modbus4j+rxtx实现,不过这种实现方式有一个弊端,就是需要调用dll,而且跨平台不兼容,这对于一个强迫症来说是致命的,本次记录另一种跨平台实现方案。

实现方式

        使用modbus4j实现modbus通信,同时使用jssc来实现串口数据读写。

Maven依赖

    <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>
    <dependencies>
        <dependency>
            <groupId>io.github.java-native</groupId>
            <artifactId>jssc</artifactId>
            <version>2.9.4</version>
        </dependency>
        <dependency>
            <groupId>com.infiniteautomation</groupId>
            <artifactId>modbus4j</artifactId>
            <version>3.0.4</version>
        </dependency>
     </dependencies>

其中jssc是用来实现串口通信的库,可以根据操作系统自动识别。

代码实现

串口的输入流实现类 SerialInputStream.java

import jssc.SerialPort;

import java.io.IOException;
import java.io.InputStream;

public class SerialInputStream extends InputStream {

    private SerialPort serialPort;
    private int defaultTimeout = 50;

    public SerialInputStream(SerialPort sp) {
        serialPort = sp;
    }

    public void setTimeout(int time) {
        defaultTimeout = time;
    }

    @Override
    public int read() throws IOException {
        return read(defaultTimeout);
    }

    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);
        }
    }

    @Override
    public int read(byte[] buf) throws IOException {
        return read(buf, 0, buf.length);
    }

    @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, readBuf.length);
            return readBuf.length;
        } catch (Exception e) {
            throw new IOException(e);
        }
    }

    public int blockingRead(byte[] buf) throws IOException {
        return blockingRead(buf, 0, buf.length, defaultTimeout);
    }

    public int blockingRead(byte[] buf, int timeout) throws IOException {
        return blockingRead(buf, 0, buf.length, timeout);
    }

    public int blockingRead(byte[] buf, int offset, int length) throws IOException {
        return blockingRead(buf, offset, length, defaultTimeout);
    }

    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;
            }
        } catch (Exception e) {
            //TODO 异常处理
        }
        return 0;
    }
}

串口输出流实现类 SerialOutputStream.java

import jssc.SerialPort;
import jssc.SerialPortException;

import java.io.IOException;
import java.io.OutputStream;

public class SerialOutputStream extends OutputStream {
    SerialPort serialPort;

    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);
        }
    }

}

modbus4j的串口实现类


import com.serotonin.modbus4j.serial.SerialPortWrapper;
import jssc.SerialPort;
import jssc.SerialPortException;
import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;
import java.io.OutputStream;

@Slf4j
public class SerialPortWrapperImpl implements SerialPortWrapper {
    private final SerialPort port;
    private final int baudRate;
    private final int dataBits;
    private final int stopBits;
    private final int parity;
    private final int flowControlIn;
    private final int flowControlOut;

    public SerialPortWrapperImpl(String commPortId, int baudRate, int dataBits, int stopBits, int parity, int flowControlIn,
                                 int flowControlOut) {

        this.baudRate = baudRate;
        this.dataBits = dataBits;
        this.stopBits = stopBits;
        this.parity = parity;
        this.flowControlIn = flowControlIn;
        this.flowControlOut = flowControlOut;

        port = new SerialPort(commPortId);

    }

    @Override
    public void close() throws Exception {
        port.closePort();
        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());
            log.debug("Serial port {} opened", port.getPortName());
        } catch (SerialPortException e) {
            log.error("Error opening port : {} for {} ", port.getPortName(), e.getMessage());
        }
    }

    @Override
    public InputStream getInputStream() {
        return new SerialInputStream(port);
    }

    @Override
    public OutputStream getOutputStream() {
        return new SerialOutputStream(port);
    }


    @Override
    public int getBaudRate() {
        return baudRate;
    }

    @Override
    public int getFlowControlIn() {
        return flowControlIn;
    }

    @Override
    public int getFlowControlOut() {
        return flowControlOut;
    }

    @Override
    public int getDataBits() {
        return dataBits;
    }

    @Override
    public int getStopBits() {
        return stopBits;
    }

    @Override
    public int getParity() {
        return parity;
    }
}

上面这个是比较关键的串口实现,到这里已经可以和网上的modbus4j资料完成采集,具体实现下节实现

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
Java实现Modbus RTU通信可以使用modbus4j库。首先,需要准备好串口环境,可以使用虚拟串口驱动来模拟串口。然后,可以通过以下代码来实现批量写入数据到寄存器的功能: ```java import com.serotonin.modbus4j.ModbusMaster; import com.serotonin.modbus4j.ModbusFactory; import com.serotonin.modbus4j.ModbusTransportException; import com.serotonin.modbus4j.exception.ModbusInitException; import com.serotonin.modbus4j.exception.ModbusSlaveException; import com.serotonin.modbus4j.msg.WriteRegistersRequest; import com.serotonin.modbus4j.msg.WriteRegistersResponse; public class ModbusRTUExample { public static void main(String[] args) { // 创建ModbusMaster实例 ModbusFactory modbusFactory = new ModbusFactory(); ModbusMaster master = modbusFactory.createRtuMaster("/dev/ttyUSB0"); // 替换为实际的串口名称 try { // 初始化ModbusMaster master.init(); // 设置从站地址 int slaveId = 1; // 替换为实际的从站地址 // 设置起始地址的偏移量 int start = 0; // 替换为实际的起始地址的偏移量 // 设置待写入的数据 short[] values = {1, 2, 3}; // 替换为实际的待写入数据 // 执行写入操作 writeRegisters(master, slaveId, start, values); } catch (ModbusInitException e) { e.printStackTrace(); } finally { // 断开与Modbus设备的连 master.destroy(); } } public static void writeRegisters(ModbusMaster master, int slaveId, int start, short[] values) { try { // 创建写入请求 WriteRegistersRequest request = new WriteRegistersRequest(slaveId, start, values); // 发送请求并获取响应 WriteRegistersResponse response = (WriteRegistersResponse) master.send(request); // 判断是否出现异常 if (response.isException()) { System.out.println("Exception response: message=" + response.getExceptionMessage()); } else { System.out.println("Success"); } } catch (ModbusTransportException | ModbusSlaveException e) { e.printStackTrace(); } } } ``` 上述代码示例中,我们使用了modbus4j库来实现Modbus RTU通信。首先,需要创建ModbusMaster实例,并通过`init()`方法进行初始化。然后,设置从站地址、起始地址偏移量和待写入的数据。最后,通过`writeRegisters()`方法执行写入操作,并判断是否出现异常。请注意,需要将`/dev/ttyUSB0`替换为实际的串口名称,`slaveId`、`start`和`values`也需要替换为实际的值。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Java串口通讯Modbus Rtu](https://blog.csdn.net/james112496/article/details/125462694)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值