Java Modbus RTU整合与虚拟串口测试:一站式指南

目的

在无设备的情况下,电脑搭建虚拟环境,进行代码编写以及测试

准备工作

一.测试工具

1.模拟虚拟串口工具,模式数据发送(主站),模拟数据接收(从站)
modbus RTU使用一问一答模式进行数据交互。
本文内容:主站发送读取数据请求,从站应答并返回数据
2.个人设置:COM2为主站,COM3为从站。所以测试类的串口,使用的COM2

工具下载链接: 下载地址

工具使用方式:参考链接

二.java读取寄存器数据

2.1 依赖包`java
       <dependency>
            <groupId>com.fazecast</groupId>
            <artifactId>jSerialComm</artifactId>
            <version>2.9.2</version>
        </dependency>
2.2 工具类

说明:发起读取数据请求时,将十进制数据转换为协议所使用的格式

package org.dromara.modbusTest;

public class ModbusRTURequestBuilder {

    /**
     * @param slaveAddress 从站地址
     * @param functionCode 功能码
     * @param startAddress 起始寄存器地址
     * @param registerCount 寄存器数量
     * @return Modbus-RTU 协议请求报文
     */
    public static byte[] buildModbusRTURequest(int slaveAddress, int functionCode, int startAddress, int registerCount) {
        // 创建一个字节数组用于存储报文
        byte[] request = new byte[8];

        // 设置从机地址
        request[0] = (byte) slaveAddress;

        // 设置功能码
        request[1] = (byte) functionCode;

        // 设置起始寄存器地址(高位和低位)
        request[2] = (byte) (startAddress >> 8);
        request[3] = (byte) (startAddress & 0xFF);

        // 设置寄存器数量(高位和低位)
        request[4] = (byte) (registerCount >> 8);
        request[5] = (byte) (registerCount & 0xFF);

        // 计算CRC校验并设置到报文中
        int crc = calculateCRC(request, 6);
        request[6] = (byte) (crc & 0xFF); // 低位
        request[7] = (byte) (crc >> 8); // 高位

        return request;
    }

    private static int calculateCRC(byte[] message, int length) {
        int crc = 0xFFFF;
        for (int i = 0; i < length; i++) {
            crc ^= (message[i] & 0xFF);
            for (int j = 0; j < 8; j++) {
                if ((crc & 1) == 1) {
                    crc = (crc >> 1) ^ 0xA001;
                } else {
                    crc = crc >> 1;
                }
            }
        }
        return crc;
    }
}

2.3 测试类

说明:主站(COM2)发起读取数据请求,对应的COM3接收到请求后,返回对应的数据。

package org.dromara.modbusTest;

import com.fazecast.jSerialComm.SerialPort;

import java.util.Arrays;

public class SerialSensorReader {
    public static void main(String[] args) {
        // 设置串口一些参数,除了串口号其他基本固定 COM2就是文章前配置的
        SerialPort serialPort = SerialPort.getCommPort("COM2"); // 串口设备名称
        serialPort.setBaudRate(9600); // 波特率
        serialPort.setNumDataBits(8); // 数据位
        serialPort.setParity(SerialPort.NO_PARITY); // 校验位
        serialPort.setNumStopBits(1); // 停止位

        if (serialPort.openPort()) {
            // 借助工具类,构建请求报文。表示:向从站地址1,发送功能3,寄存器起始地址0,读取寄存器数量10的请求(从起始地址开始,向后读取10个数据)
            byte[] requestMessage = ModbusRTURequestBuilder.buildModbusRTURequest(1, 3, 0, 10);
            // 读取数据
            serialPort.writeBytes(requestMessage, requestMessage.length);

            try {
                Thread.sleep(100); // 等待足够的时间以确保传感器响应
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 响应数据的长度根据以下公式自行调整
            // 报文长度组成:从站地址 + 功能码 + 数据总长度 + 数据个数 + CRC校验(2个)
            // 返回报文示例 [1, 3, 20, 0, 0, 0, 0, 0, 2, 39, 15, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 45, 30]
            //             从站地址(1) + 功能码(1) + 数据总长度(1) + 数据个数(20) + CRC校验(2)
            // 数据总长度20的原因:读取10个寄存器的数据,会返回*2的字节数
            byte[] responseData = new byte[25];

            // 获取响应
            int bytesRead = serialPort.readBytes(responseData, responseData.length);
            // 通过打印可以看到,获取的数据为十进制
            System.out.println(Arrays.toString(responseData));
            if (bytesRead == responseData.length) {
                // 解析数据,返回的数据为字节码两两一组,表示第7和第8(即数据区的第3个数据)进行换算
                int temperature = ((responseData[7] << 8) | (responseData[8] & 0xFF));
                int humidity = ((responseData[9] << 8) | (responseData[10] & 0xFF));

                System.out.println("温度: " + temperature);
                System.out.println("湿度: " + humidity);
            } else {
                System.out.println("未收到完整的响应数据");
            }

            serialPort.closePort();
        } else {
            System.out.println("无法打开串口");
        }
    }
}

请求报文解析

返回报文解析,及测试结果

有帮助的同学,能不能给个留个赞?

作者:java丶小萌新

物联沃分享整理
物联沃-IOTWORD物联网 » Java Modbus RTU整合与虚拟串口测试:一站式指南

发表回复