Java语言实现Modbus协议通过用串口读取数据(以RTU为例)

Java语言实现Modbus协议通过用串口读取数据(以RTU为例)
和豆包deepSeek友好的聊了一天也是终于实现了这一个功能。。。首先下载依赖dependency groupIdcom.infiniteautomation/groupId artifactIdmodbus4j/artifactId version3.0.3/version /dependency dependency groupIdcom.fazecast/groupId artifactIdjserialcomm/artifactId version2.10.4/version /dependency完整的POM.xml文件如下?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion groupIdorg.example/groupId artifactIdprojectDemo/artifactId version1.0-SNAPSHOT/version repositories repository releases enabledfalse/enabled /releases snapshots enabledtrue/enabled /snapshots idias-snapshots/id nameInfinite Automation Snapshot Repository/name urlhttps://maven.mangoautomation.net/repository/ias-snapshot//url /repository repository releases enabledtrue/enabled /releases snapshots enabledfalse/enabled /snapshots idias-releases/id nameInfinite Automation Release Repository/name urlhttps://maven.mangoautomation.net/repository/ias-release//url /repository /repositories dependencies !--串口 jSerialComm 正常可用-- dependency groupIdcom.fazecast/groupId artifactIdjSerialComm/artifactId version2.10.4/version /dependency !-- 稳定版modbus4j -- dependency groupIdcom.infiniteautomation/groupId artifactIdmodbus4j/artifactId version3.0.3/version /dependency dependency groupIdcom.fazecast/groupId artifactIdjserialcomm/artifactId version2.10.4/version /dependency /dependencies properties maven.compiler.source21/maven.compiler.source maven.compiler.target21/maven.compiler.target project.build.sourceEncodingUTF-8/project.build.sourceEncoding /properties /project然后创建两个工具类package org.modbus.util; import com.serotonin.modbus4j.BatchRead; import com.serotonin.modbus4j.BatchResults; 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.ip.IpParameters; import com.serotonin.modbus4j.locator.BaseLocator; import com.serotonin.modbus4j.serial.SerialPortWrapper; import java.util.ArrayList; import java.util.List; public class Modbus4jUtils { /** * 工厂。 */ static ModbusFactory modbusFactory; static { if (modbusFactory null) { modbusFactory new ModbusFactory(); } } /** * 获取master * * return * throws ModbusInitException */ public static ModbusMaster getMaster(SerialPortWrapper wrapper, int type) { if (type 1) { //RTU return modbusFactory.createRtuMaster(wrapper); } else if (type 2) { //ASC return modbusFactory.createAsciiMaster(wrapper); } else { throw new RuntimeException(参数有误); } } /** * 获取master * * return * throws ModbusInitException */ public static ModbusMaster getMaster(IpParameters params, Boolean keepAlive) { if (keepAlive ! null) { //TCP return modbusFactory.createTcpMaster(params, keepAlive); } else return modbusFactory.createUdpMaster(params); //UDP } /** * 读取[01 Coil Status 0x]类型 开关数据 * * param slaveId slaveId * param startAddress 起始寄存器位置 * param numberOfPoints 读取寄存器数量 * throws ModbusTransportException 异常 * throws ErrorResponseException 异常 * throws ModbusInitException 异常 */ public static BatchResultsInteger readCoilStatus(ModbusMaster master, int slaveId, int startAddress, int numberOfPoints) throws ModbusTransportException, ErrorResponseException { BatchReadInteger batch new BatchReadInteger(); for (int istartAddress,j0;inumberOfPoints;i,j){ batch.addLocator(j, BaseLocator.coilStatus(slaveId, i)); } batch.setContiguousRequests(false); BatchResultsInteger results master.send(batch); return results; } /** * 读取[02 Input Status 1x]类型 开关数据 * * param slaveId * param startAddress 起始寄存器位置 * param numberOfPoints 读取寄存器数量 * return * throws ModbusTransportException * throws ErrorResponseException * throws ModbusInitException */ public static BatchResultsInteger readInputStatus(ModbusMaster master, int slaveId, int startAddress, int numberOfPoints) throws ModbusTransportException, ErrorResponseException{ BatchReadInteger batch new BatchReadInteger(); for (int istartAddress,j0;inumberOfPoints;i,j){ batch.addLocator(j, BaseLocator.inputStatus(slaveId, i)); } batch.setContiguousRequests(false); BatchResultsInteger results master.send(batch); return results; } /** * 读取[03 Holding Register类型 2x]模拟量数据 * * param slaveId slave Id * param startAddress 起始寄存器位置 * param numberOfPoints 读取寄存器数量 * param dataType 数据类型,来自com.serotonin.modbus4j.code.DataType * return * throws ModbusTransportException 异常 * throws ErrorResponseException 异常 */ public static BatchResultsInteger readHoldingRegister(ModbusMaster master, int slaveId, int startAddress, int numberOfPoints, int dataType) throws ModbusTransportException, ErrorResponseException { BatchReadInteger batch new BatchReadInteger(); for (int istartAddress,j0;inumberOfPoints;i,j){ batch.addLocator(j, BaseLocator.holdingRegister(slaveId, i, dataType)); } batch.setContiguousRequests(false); BatchResultsInteger results master.send(batch); return results; } /** * 读取[04 Input Registers 3x]类型 模拟量数据 * * param slaveId slaveId * param startAddress 起始寄存器位置 * param numberOfPoints 读取寄存器数量 * param dataType 数据类型,来自com.serotonin.modbus4j.code.DataType * return 返回结果 * throws ModbusTransportException 异常 * throws ErrorResponseException 异常 */ public static BatchResultsInteger readInputRegisters(ModbusMaster master, int slaveId, int startAddress, int numberOfPoints, int dataType) throws ModbusTransportException, ErrorResponseException { BatchReadInteger batch new BatchReadInteger(); for (int istartAddress,j0;inumberOfPoints;i,j){ batch.addLocator(j, BaseLocator.inputRegister(slaveId, i, dataType)); } batch.setContiguousRequests(false); BatchResultsInteger results master.send(batch); return results; } /** * 批量读取使用方法 * * throws ModbusTransportException * throws ErrorResponseException * throws ModbusInitException */ public static void batchRead(ModbusMaster master) throws ModbusTransportException, ErrorResponseException, ModbusInitException { BatchReadInteger batch new BatchReadInteger(); batch.addLocator(0, BaseLocator.holdingRegister(1, 1, DataType.FOUR_BYTE_FLOAT)); batch.addLocator(1, BaseLocator.inputStatus(1, 0)); batch.setContiguousRequests(false); BatchResultsInteger results master.send(batch); System.out.println(results.getValue(0)); System.out.println(results.getValue(1)); } }这个工具类封装了创建工厂读取数据的所有方法package org.modbus.util; import com.serotonin.modbus4j.serial.SerialPortWrapper; import com.fazecast.jSerialComm.SerialPort; import java.io.InputStream; import java.io.OutputStream; public class SerialPortWrapperJSerialImpl implements SerialPortWrapper { private SerialPort serialPort; private final String portName; private final int baudRate; private final int dataBits; private final int stopBits; private final int parity; public SerialPortWrapperJSerialImpl(String portName, int baudRate, int dataBits, int stopBits, int parity) { this.portName portName; this.baudRate baudRate; this.dataBits dataBits; this.stopBits stopBits; this.parity parity; } Override public int getBaudRate() { return baudRate; } Override public int getDataBits() { return dataBits; } Override public int getStopBits() { return stopBits; } Override public int getParity() { return parity; } Override public int getFlowControlIn() { return 0; } Override public int getFlowControlOut() { return 0; } Override public void open() throws Exception { if (serialPort ! null serialPort.isOpen()) { return; } serialPort SerialPort.getCommPort(portName); serialPort.setBaudRate(baudRate); serialPort.setNumDataBits(dataBits); serialPort.setNumStopBits(stopBits); // 转换modbus4j parity常量到jSerialComm switch (parity) { case 0: serialPort.setParity(SerialPort.NO_PARITY); break; case 1: serialPort.setParity(SerialPort.ODD_PARITY); break; case 2: serialPort.setParity(SerialPort.EVEN_PARITY); break; default: serialPort.setParity(SerialPort.NO_PARITY); } // 关闭硬件流控485不需要 serialPort.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED); // 超时防止阻塞 serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 1000, 0); serialPort.openPort(); } Override public void close() throws Exception { if (serialPort ! null serialPort.isOpen()) { serialPort.closePort(); } serialPort null; } Override public InputStream getInputStream() { return serialPort.getInputStream(); } Override public OutputStream getOutputStream() { return serialPort.getOutputStream(); } }这个工具用来初始化串口好了一切准备就绪开始测试package org.modbus; import com.fazecast.jSerialComm.SerialPort; import com.serotonin.modbus4j.BatchResults; 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.serial.SerialPortWrapper; import org.modbus.util.Modbus4jUtils; import org.modbus.util.SerialPortWrapperJSerialImpl; public class Demo02 { public static void main(String[] args) throws ModbusTransportException, ErrorResponseException, ModbusInitException { redTest(); } private static void redTest() throws ModbusTransportException, ErrorResponseException, ModbusInitException { // 1. 实例化JSSC串口包装类8N1无校验 SerialPortWrapper wrapper new SerialPortWrapperJSerialImpl(COM1,9600,8,1,0); ModbusMaster master Modbus4jUtils.getMaster(wrapper, 1); master.init(); //读取从站1的保持型寄存器0~9 BatchResultsInteger res Modbus4jUtils.readHoldingRegister(master, 1, 0, 9, DataType.TWO_BYTE_INT_UNSIGNED); System.out.println(res); //读取从站1的线圈状态0~7 BatchResultsInteger coils Modbus4jUtils.readCoilStatus(master,1,0,8); System.out.println(coils); //读取从站1的输入线圈0~7 BatchResultsInteger inputs Modbus4jUtils.readInputStatus(master,1,0,8); System.out.println(inputs); //读取从站5的输入寄存器0~4 BatchResultsInteger inputRegisters Modbus4jUtils.readInputRegisters(master,5,0,5,DataType.TWO_BYTE_INT_UNSIGNED); System.out.println(inputRegisters); } }配置主站我这里使用的是虚拟的然后我们run一下看一下效果家人们牛逼坏了我搞了一天啊