ModbusRTU协议封装,控制RJ45报警器,复制一下就能用哦~

本文只对   写保持寄存器 HoldingRegister  做操作,其他类型的寄存器方法方法也在ModbusWriteOrRead类中,可自行测试。
报警器设备型号(USB版):JD01AX07 01

设备外观及亮灯:

文档说明-部分: 

注: 以下图第一个绿灯开启的二进制命令为例:

01 06:寄存器类型

00 00:寄存器地址

00 01:数据(打开)

48 0A:CRC校验码

 

 接下来上代码:没有yml配置,需要将配置写入静态代码,如果有可以在静态代码中读取配置信息的方法请@我修改,谢谢~

maven配置:因为引入了外部lib,所以一定要加jar包路径


<dependency>
            <groupId>jssc</groupId>
            <artifactId>jssc</artifactId>
            <version>2.8.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/libs/jssc.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.serotonin.modbus4j</groupId>
            <artifactId>modbus4j</artifactId>
            <version>3.0.3</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/libs/modbus4j-3.0.3.jar</systemPath>
        </dependency>

        
<plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
<!--                    <executable>true</executable>-->
<!--                    <fork>true</fork>-->
                    <!--值为true是指打包时包含scope为system的第三方Jar包-->
                    <includeSystemScope>true</includeSystemScope>

                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

文章后面有lib附件,直接引用

需要注意的地方:当设备插入时会使用某一个空闲串口,打开计算机管理,找到使用的串口,替换到工具类的串口参数。(虚拟机串口查询:ls /dev/tty*)

工具类封装:

import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
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 com.serotonin.modbus4j.msg.WriteCoilRequest;
import com.serotonin.modbus4j.msg.WriteCoilResponse;
import com.serotonin.modbus4j.msg.WriteCoilsRequest;
import com.serotonin.modbus4j.msg.WriteCoilsResponse;
import com.serotonin.modbus4j.serial.SerialPortWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class ModbusWriteOrRead {

    //设备id
    private static final Integer SLAVE_ID = 1;
    // master 工厂
    static ModbusFactory modbusFactory;

    // master 对象
    static ModbusMaster master;

    // 静态方法初始化 master
    static {
        modbusFactory = new ModbusFactory();
        // 使用 Modbus-TCP 进行通信
//        IpParameters param = new IpParameters();
//        param.setHost("localhost");
//        param.setPort(502);
//        master = modbusFactory.createTcpMaster(param, false);
        // 使用 Modbus-RTU 进行通信 // 设置串口参数,串口是COM12,波特率是9600,数据长8字节
        SerialPortWrapper serialParameters = new SerialPortWrapperImpl("COM5", 9600,
                8, 1, 0, 0, 0);
        master = modbusFactory.createRtuMaster(serialParameters);
        try {
            //设置超时时间
            master.setTimeout(3000);
            //设置重连次数
            master.setRetries(3);
            master.init();
        } catch (ModbusInitException e) {
            log.error("master 初始化失败~");
            throw new RuntimeException("master 初始化失败~");
        }
    }

    /**
     * 主方法测试
     * 绿灯黄灯亮度红灯默认亮度8080, 第一个80指的是红灯亮度,16进制80对应十进制128,为亮度最大值的一半,第二个80是绿灯亮度,含义同红灯,当设置十进制65535时对应16进制的FFFF,FF对应255,此时为最亮
     * 注:已调最大亮度,红绿黄亮度值最大
     */
    public static void maain(String[] args) throws ModbusTransportException, ErrorResponseException {

//        writeRegister(SLAVE_ID, SlaveOffsetEnum.OFFSET_CONTROL_RED_OFF.getOffset(), SlaveOffsetEnum.OFFSET_CONTROL_RED_OFF.getValue(), DataType.TWO_BYTE_INT_UNSIGNED);
//        writeRegister(SLAVE_ID, 3, 255, DataType.TWO_BYTE_INT_UNSIGNED);
//        writeRegister(SLAVE_ID, 1, 0, DataType.TWO_BYTE_INT_UNSIGNED);
//        writeRegister(SLAVE_ID, 2, 0, DataType.TWO_BYTE_INT_UNSIGNED);
//        writeRegister(SLAVE_ID, 5, 0, DataType.TWO_BYTE_INT_UNSIGNED);
        batchRead();
//        writeRegister(SLAVE_ID, SlaveOffsetEnum.OFFSET_CONTROL_RED_ON.getOffset(), SlaveOffsetEnum.OFFSET_CONTROL_RED_ON.getValue(), DataType.TWO_BYTE_INT_UNSIGNED);
//        System.out.println("=====读线圈 CoilStatus=====");
//        System.out.println("0>>>" + readCoilStatus(1, 0));
//        System.out.println("5>>>" + readCoilStatus(1, 5));
//        System.out.println("=====读离散量输入 InputStatus=====");
//        System.out.println("7>>>" + readInputStatus(1, 7));
//        System.out.println("8>>>" + readInputStatus(1, 8));
//        System.out.println("=====读保持寄存器 HoldingRegister=====");
//        System.out.println("0>>>" + readHoldingRegister(1, 0, DataType.FOUR_BYTE_INT_SIGNED));
//        System.out.println("2>>>" + readHoldingRegister(1, 2, DataType.FOUR_BYTE_INT_SIGNED));
//        System.out.println("=====读输入寄存器 InputRegisters=====");
//        System.out.println("6>>>" + readInputRegisters(2, 1, DataType.FOUR_BYTE_INT_SIGNED));
//        System.out.println("8>>>" + readInputRegisters(2, 2, DataType.FOUR_BYTE_INT_SIGNED));
//        System.out.println("=====测试批量读取=====");
//        batchRead();
    }

    /**
     * 读线圈 CoilStatus
     *
     * @param slaveId 从机id
     * @param offset  偏移量
     * @return 读取数据值
     */
    public static Boolean readCoilStatus(int slaveId, int offset)
            throws ModbusTransportException, ErrorResponseException {
        BaseLocator<Boolean> locator = BaseLocator.coilStatus(slaveId, offset);
        return master.getValue(locator);
    }


    /**
     * 读离散量输入 InputStatus
     *
     * @param slaveId 从机id
     * @param offset  偏移量
     * @return 读取数据值
     */
    public static Boolean readInputStatus(int slaveId, int offset)
            throws ModbusTransportException, ErrorResponseException {
        BaseLocator<Boolean> locator = BaseLocator.inputStatus(slaveId, offset);
        return master.getValue(locator);
    }

    /**
     * 读保持寄存器 HoldingRegister
     *
     * @param slaveId  从机id
     * @param offset   偏移量
     * @param dataType 数据类型
     * @return 读取数据值
     */
    public static Number readHoldingRegister(int slaveId, int offset, int dataType)
            throws ModbusTransportException, ErrorResponseException {
        BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, dataType);
        return master.getValue(locator);
    }


    /**
     * 读输入寄存器 InputRegisters
     *
     * @param slaveId  从机id
     * @param offset   偏移量
     * @param dataType 数据类型
     * @return 读取数据值
     */
    public static Number readInputRegisters(int slaveId, int offset, int dataType)
            throws ModbusTransportException, ErrorResponseException {
        BaseLocator<Number> locator = BaseLocator.inputRegister(slaveId, offset, dataType);
        return master.getValue(locator);
    }

    /**
     * 写线圈 CoilStatus
     *
     * @param slaveId     从机id
     * @param writeOffset 偏移量
     * @param writeValue  写入值
     * @return 写入结果
     */
    public static boolean writeCoil(int slaveId, int writeOffset, boolean writeValue)
            throws ModbusTransportException {
        // 创建请求
        WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);
        // 发送请求并获取响应对象
        WriteCoilResponse response = (WriteCoilResponse) master.send(request);
        return !response.isException();
    }

    /**
     * 批量写线圈 CoilStatus
     *
     * @param slaveId     从机id
     * @param startOffset 写入起始偏移量
     * @param bdata       写入数据集
     * @return 写入结果
     */
    public static boolean writeCoils(int slaveId, int startOffset, boolean[] bdata)
            throws ModbusTransportException {
        // 创建请求
        WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, bdata);
        // 发送请求并获取响应对象
        WriteCoilsResponse response = (WriteCoilsResponse) master.send(request);
        return !response.isException();
    }

    /**
     * 写保持寄存器 HoldingRegister
     *
     * @param slaveId     从机id
     * @param writeOffset 偏移量
     * @param writeValue  写入值
     * @param dataType    写入值数据类型
     */
    public static void writeRegister(int slaveId, int writeOffset, Number writeValue, int dataType)
            throws ModbusTransportException, ErrorResponseException {
        // 创建寻址对象
        BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, writeOffset, dataType);
        // 执行写入操作
        master.setValue(locator, writeValue);
    }

    /**
     * @param
     * @Description: 批量读取使用方法
     * @return:
     * @Author: hyh
     * @Date: 2023/6/12 15:56
     */
    public static void batchRead() throws ModbusTransportException, ErrorResponseException {
        log.info("绿灯 寄存器地址:0值= " + readHoldingRegister(SLAVE_ID, 0, DataType.TWO_BYTE_INT_UNSIGNED).toString());
        log.info("黄灯 寄存器地址:1值= " + readHoldingRegister(SLAVE_ID, 1, DataType.TWO_BYTE_INT_UNSIGNED).toString());
        log.info("红灯 寄存器地址:2值= " + readHoldingRegister(SLAVE_ID, 2, DataType.TWO_BYTE_INT_UNSIGNED).toString());
        log.info("亮度 寄存器地址:3值= " + readHoldingRegister(SLAVE_ID, 3, DataType.TWO_BYTE_INT_UNSIGNED).toString());
        log.info("寄存器地址:4值= " + readHoldingRegister(SLAVE_ID, 4, DataType.TWO_BYTE_INT_UNSIGNED).toString());
        log.info("蜂鸣器 寄存器地址:5值= " + readHoldingRegister(SLAVE_ID, 5, DataType.TWO_BYTE_INT_UNSIGNED).toString());
        log.info("寄存器地址:6值= " + readHoldingRegister(SLAVE_ID, 6, DataType.TWO_BYTE_INT_UNSIGNED).toString());
        log.info("寄存器地址:7值= " + readHoldingRegister(SLAVE_ID, 7, DataType.TWO_BYTE_INT_UNSIGNED).toString());
        log.info("寄存器地址:8值= " + readHoldingRegister(SLAVE_ID, 8, DataType.TWO_BYTE_INT_UNSIGNED).toString());

    }
//    public static void batchRead() throws ModbusTransportException, ErrorResponseException {
//
//        BatchRead<Integer> batch = new BatchRead<Integer>();
//
        batch.addLocator(0, BaseLocator.coilStatus(1, 0));
        batch.addLocator(1, BaseLocator.inputStatus(1, 7));
        batch.addLocator(2, BaseLocator.holdingRegister(1, 0, DataType.FOUR_BYTE_FLOAT));
        batch.addLocator(3, BaseLocator.inputRegister(1, 6, DataType.FOUR_BYTE_FLOAT));
//
//        batch.addLocator(0, BaseLocator.holdingRegister(1, 0, DataType.FOUR_BYTE_FLOAT));
//        batch.addLocator(1, BaseLocator.holdingRegister(1, 1, DataType.FOUR_BYTE_FLOAT));
//        batch.addLocator(2, BaseLocator.holdingRegister(1, 2, DataType.FOUR_BYTE_FLOAT));
//        batch.addLocator(3, BaseLocator.holdingRegister(1, 3, DataType.FOUR_BYTE_FLOAT));
//        batch.addLocator(4, BaseLocator.holdingRegister(1, 4, DataType.FOUR_BYTE_FLOAT));
//        batch.addLocator(5, BaseLocator.holdingRegister(1, 5, DataType.FOUR_BYTE_FLOAT));
//        batch.addLocator(6, BaseLocator.holdingRegister(1, 6, DataType.FOUR_BYTE_FLOAT));
//        batch.addLocator(7, BaseLocator.holdingRegister(1, 7, DataType.FOUR_BYTE_FLOAT));
//        batch.addLocator(8, BaseLocator.holdingRegister(1, 8, DataType.FOUR_BYTE_FLOAT));
//        batch.setContiguousRequests(false);
//        BatchResults<Integer> results = master.send(batch);
//    }

}

连接及发送方法重写:

package com.vcom.acoustooptic.utils;

import com.serotonin.modbus4j.serial.SerialPortWrapper;
import jssc.SerialPort;
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 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;
        //设定数据位的位数  RTU:8位    ASCII:7位
        this.dataBits = dataBits;
        //停止位的位数,如果无奇偶校验为2,有奇偶校验为1
        this.stopBits = stopBits;
        //奇偶校验位  无校验:0 奇校验:1 偶校验:2
        this.parity = parity;
        //硬件之间输入流应答控制
        this.flowControlIn = flowControlIn;
        //硬件之间输出流应答控制
        this.flowControlOut = flowControlOut;
        // 设定MODBUS通讯的串行口
        port = new SerialPort(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 (Exception 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;
    }
}

注意:DataType-写入读取类型要一致

TWO_BYTE_INT_UNSIGNED 这个是写入到一个寄存器里面

FOUR_BYTE_INT_UNSIGNED 这个是写入到多个寄存器

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值