Java使用modbus4j實(shí)現(xiàn)modbus?tcp通訊
一、什么是modbus
Modbus是由Modicon(現(xiàn)為施耐德電氣公司的一個(gè)品牌)在1979年發(fā)明的,是全球第一個(gè)真正用于工業(yè)現(xiàn)場(chǎng)的總線協(xié)議。
ModBus網(wǎng)絡(luò)是一個(gè)工業(yè)通信系統(tǒng),由帶智能終端的可編程序控制器和計(jì)算機(jī)通過(guò)公用線路或局部專用線路連接而成。其系統(tǒng)結(jié)構(gòu)既包括硬件、亦包括軟件。它可應(yīng)用于各種數(shù)據(jù)采集和過(guò)程監(jiān)控。
ModBus網(wǎng)絡(luò)只有一個(gè)主機(jī),所有通信都由他發(fā)出。網(wǎng)絡(luò)可支持247個(gè)之多的遠(yuǎn)程從屬控制器,但實(shí)際所支持的從機(jī)數(shù)要由所用通信設(shè)備決定。采用這個(gè)系統(tǒng),各PC可以和中心主機(jī)交換信息而不影響各PC執(zhí)行本身的控制任務(wù)。
二、Java實(shí)現(xiàn)modbus協(xié)議通訊
Java編程中,使用modbus4j實(shí)現(xiàn)Java中的modbus協(xié)議通訊
modbus4j實(shí)現(xiàn)了Java與modbus協(xié)議的以下幾種通訊方式:
- modbus TCP/IP通訊
- modubs UDP/IP通訊
- modbus RTU/IP通訊
核心依賴:
modbus4j.jar
commons-lang3-3.0.jar
下載地址代碼里有
Java讀取工具類
package com.leftso.project.demo.modbus4j; 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; /** * modbus通訊工具類,采用modbus4j實(shí)現(xiàn) * * @author lxq * @dependencies modbus4j-3.0.3.jar * @website https://github.com/infiniteautomation/modbus4j */ public class Modbus4jUtils { /** * 工廠。 */ static ModbusFactory modbusFactory; static { if (modbusFactory == null) { modbusFactory = new ModbusFactory(); } } /** * 獲取master * * @return * @throws ModbusInitException */ public static ModbusMaster getMaster() throws ModbusInitException { IpParameters params = new IpParameters(); params.setHost("localhost"); params.setPort(502); // // modbusFactory.createRtuMaster(wapper); //RTU 協(xié)議 // modbusFactory.createUdpMaster(params);//UDP 協(xié)議 // modbusFactory.createAsciiMaster(wrapper);//ASCII 協(xié)議 ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 協(xié)議 master.init(); return master; } /** * 讀取[01 Coil Status 0x]類型 開(kāi)關(guān)數(shù)據(jù) * * @param slaveId * slaveId * @param offset * 位置 * @return 讀取值 * @throws ModbusTransportException * 異常 * @throws ErrorResponseException * 異常 * @throws ModbusInitException * 異常 */ public static Boolean readCoilStatus(int slaveId, int offset) throws ModbusTransportException, ErrorResponseException, ModbusInitException { // 01 Coil Status BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset); Boolean value = getMaster().getValue(loc); return value; } /** * 讀取[02 Input Status 1x]類型 開(kāi)關(guān)數(shù)據(jù) * * @param slaveId * @param offset * @return * @throws ModbusTransportException * @throws ErrorResponseException * @throws ModbusInitException */ public static Boolean readInputStatus(int slaveId, int offset) throws ModbusTransportException, ErrorResponseException, ModbusInitException { // 02 Input Status BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset); Boolean value = getMaster().getValue(loc); return value; } /** * 讀取[03 Holding Register類型 2x]模擬量數(shù)據(jù) * * @param slaveId * slave Id * @param offset * 位置 * @param dataType * 數(shù)據(jù)類型,來(lái)自com.serotonin.modbus4j.code.DataType * @return * @throws ModbusTransportException * 異常 * @throws ErrorResponseException * 異常 * @throws ModbusInitException * 異常 */ public static Number readHoldingRegister(int slaveId, int offset, int dataType) throws ModbusTransportException, ErrorResponseException, ModbusInitException { // 03 Holding Register類型數(shù)據(jù)讀取 BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType); Number value = getMaster().getValue(loc); return value; } /** * 讀取[04 Input Registers 3x]類型 模擬量數(shù)據(jù) * * @param slaveId * slaveId * @param offset * 位置 * @param dataType * 數(shù)據(jù)類型,來(lái)自com.serotonin.modbus4j.code.DataType * @return 返回結(jié)果 * @throws ModbusTransportException * 異常 * @throws ErrorResponseException * 異常 * @throws ModbusInitException * 異常 */ public static Number readInputRegisters(int slaveId, int offset, int dataType) throws ModbusTransportException, ErrorResponseException, ModbusInitException { // 04 Input Registers類型數(shù)據(jù)讀取 BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType); Number value = getMaster().getValue(loc); return value; } /** * 批量讀取使用方法 * * @throws ModbusTransportException * @throws ErrorResponseException * @throws ModbusInitException */ public static void batchRead() throws ModbusTransportException, ErrorResponseException, ModbusInitException { BatchRead<Integer> batch = new BatchRead<Integer>(); batch.addLocator(0, BaseLocator.holdingRegister(1, 1, DataType.FOUR_BYTE_FLOAT)); batch.addLocator(1, BaseLocator.inputStatus(1, 0)); ModbusMaster master = getMaster(); batch.setContiguousRequests(false); BatchResults<Integer> results = master.send(batch); System.out.println(results.getValue(0)); System.out.println(results.getValue(1)); } /** * 測(cè)試 * * @param args */ public static void main(String[] args) { try { // 01測(cè)試 Boolean v011 = readCoilStatus(1, 0); Boolean v012 = readCoilStatus(1, 1); Boolean v013 = readCoilStatus(1, 6); System.out.println("v011:" + v011); System.out.println("v012:" + v012); System.out.println("v013:" + v013); // 02測(cè)試 Boolean v021 = readInputStatus(1, 0); Boolean v022 = readInputStatus(1, 1); Boolean v023 = readInputStatus(1, 2); System.out.println("v021:" + v021); System.out.println("v022:" + v022); System.out.println("v023:" + v023); // 03測(cè)試 Number v031 = readHoldingRegister(1, 1, DataType.FOUR_BYTE_FLOAT);// 注意,float Number v032 = readHoldingRegister(1, 3, DataType.FOUR_BYTE_FLOAT);// 同上 System.out.println("v031:" + v031); System.out.println("v032:" + v032); // 04測(cè)試 Number v041 = readInputRegisters(1, 1, DataType.FOUR_BYTE_FLOAT);// Number v042 = readInputRegisters(1, 3, DataType.FOUR_BYTE_FLOAT);// System.out.println("v041:" + v041); System.out.println("v042:" + v042); // 批量讀取 batchRead(); } catch (Exception e) { e.printStackTrace(); } } }
三、測(cè)試
使用ModbusSlave模擬modbus協(xié)議
slave中模擬數(shù)據(jù)如下
運(yùn)行工具類的main方法:
11:14:54.547 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 00 00 00 00 06 01 01 00 00 00 01
11:14:54.550 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
11:14:54.598 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 00 00 00 00 04 01 01 01 01
11:14:54.600 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 00 00 00 00 06 01 01 00 01 00 01
11:14:54.600 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
11:14:54.650 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 00 00 00 00 04 01 01 01 00
11:14:54.652 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 00 00 00 00 06 01 01 00 06 00 01
11:14:54.652 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
11:14:54.703 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 00 00 00 00 04 01 01 01 01
v011:true
v012:false
v013:true
11:14:54.704 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 00 00 00 00 06 01 02 00 00 00 01
11:14:54.704 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
11:14:54.755 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 00 00 00 00 04 01 02 01 01
11:14:54.757 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 00 00 00 00 06 01 02 00 01 00 01
11:14:54.757 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
11:14:54.807 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 00 00 00 00 04 01 02 01 00
11:14:54.810 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 00 00 00 00 06 01 02 00 02 00 01
11:14:54.810 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
11:14:54.860 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 00 00 00 00 04 01 02 01 01
v021:true
v022:false
v023:true
11:14:54.866 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 00 00 00 00 06 01 03 00 01 00 02
11:14:54.866 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
11:14:54.915 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 00 00 00 00 07 01 03 04 40 20 00 00
11:14:54.917 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 00 00 00 00 06 01 03 00 03 00 02
11:14:54.917 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
11:14:54.967 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 00 00 00 00 07 01 03 04 41 28 00 00
v031:2.5
v032:10.5
11:14:54.971 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 00 00 00 00 06 01 04 00 01 00 02
11:14:54.971 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
11:14:55.020 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 00 00 00 00 07 01 04 04 3F C0 00 00
11:14:55.021 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 00 00 00 00 06 01 04 00 03 00 02
11:14:55.021 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
11:14:55.072 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 00 00 00 00 07 01 04 04 40 40 00 00
v041:1.5
v042:3.0
11:14:55.074 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 00 00 00 00 06 01 02 00 00 00 01
11:14:55.074 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
11:14:55.123 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 00 00 00 00 04 01 02 01 01
11:14:55.125 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 01 00 00 00 06 01 03 00 01 00 02
11:14:55.125 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
11:14:55.179 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 01 00 00 00 07 01 03 04 40 20 00 00
2.5
true
觀察輸出結(jié)果與 slave上的模擬數(shù)據(jù)一致
四、Java通過(guò)modbus4j對(duì)數(shù)據(jù)的寫入
Modbus4jWriteUtils.java
package com.leftso.project.demo.modbus4j; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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.msg.ModbusResponse; 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.msg.WriteRegisterRequest; import com.serotonin.modbus4j.msg.WriteRegisterResponse; import com.serotonin.modbus4j.msg.WriteRegistersRequest; /** * modbus4j寫入數(shù)據(jù) * * @author xq * */ public class Modbus4jWriteUtils { static Log log = LogFactory.getLog(Modbus4jWriteUtils.class); /** * 工廠。 */ static ModbusFactory modbusFactory; static { if (modbusFactory == null) { modbusFactory = new ModbusFactory(); } } /** * 獲取tcpMaster * * @return * @throws ModbusInitException */ public static ModbusMaster getMaster() throws ModbusInitException { IpParameters params = new IpParameters(); params.setHost("localhost"); params.setPort(502); ModbusMaster tcpMaster = modbusFactory.createTcpMaster(params, false); tcpMaster.init(); return tcpMaster; } /** * 寫 [01 Coil Status(0x)]寫一個(gè) function ID = 5 * * @param slaveId * slave的ID * @param writeOffset * 位置 * @param writeValue * 值 * @return 是否寫入成功 * @throws ModbusTransportException * @throws ModbusInitException */ public static boolean writeCoil(int slaveId, int writeOffset, boolean writeValue) throws ModbusTransportException, ModbusInitException { // 獲取master ModbusMaster tcpMaster = getMaster(); // 創(chuàng)建請(qǐng)求 WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue); // 發(fā)送請(qǐng)求并獲取響應(yīng)對(duì)象 WriteCoilResponse response = (WriteCoilResponse) tcpMaster.send(request); if (response.isException()) { return false; } else { return true; } } /** * 寫[01 Coil Status(0x)] 寫多個(gè) function ID = 15 * * @param slaveId * slaveId * @param startOffset * 開(kāi)始位置 * @param bdata * 寫入的數(shù)據(jù) * @return 是否寫入成功 * @throws ModbusTransportException * @throws ModbusInitException */ public static boolean writeCoils(int slaveId, int startOffset, boolean[] bdata) throws ModbusTransportException, ModbusInitException { // 獲取master ModbusMaster tcpMaster = getMaster(); // 創(chuàng)建請(qǐng)求 WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, bdata); // 發(fā)送請(qǐng)求并獲取響應(yīng)對(duì)象 WriteCoilsResponse response = (WriteCoilsResponse) tcpMaster.send(request); if (response.isException()) { return false; } else { return true; } } /*** * 寫[03 Holding Register(4x)] 寫一個(gè) function ID = 6 * * @param slaveId * @param writeOffset * @param writeValue * @return * @throws ModbusTransportException * @throws ModbusInitException */ public static boolean writeRegister(int slaveId, int writeOffset, short writeValue) throws ModbusTransportException, ModbusInitException { // 獲取master ModbusMaster tcpMaster = getMaster(); // 創(chuàng)建請(qǐng)求對(duì)象 WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue); WriteRegisterResponse response = (WriteRegisterResponse) tcpMaster.send(request); if (response.isException()) { log.error(response.getExceptionMessage()); return false; } else { return true; } } /** * * 寫入[03 Holding Register(4x)]寫多個(gè) function ID=16 * * @param slaveId * modbus的slaveID * @param startOffset * 起始位置偏移量值 * @param sdata * 寫入的數(shù)據(jù) * @return 返回是否寫入成功 * @throws ModbusTransportException * @throws ModbusInitException */ public static boolean writeRegisters(int slaveId, int startOffset, short[] sdata) throws ModbusTransportException, ModbusInitException { // 獲取master ModbusMaster tcpMaster = getMaster(); // 創(chuàng)建請(qǐng)求對(duì)象 WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, sdata); // 發(fā)送請(qǐng)求并獲取響應(yīng)對(duì)象 ModbusResponse response = tcpMaster.send(request); if (response.isException()) { log.error(response.getExceptionMessage()); return false; } else { return true; } } /** * 寫入數(shù)字類型的模擬量(如:寫入Float類型的模擬量、Double類型模擬量、整數(shù)類型Short、Integer、Long) * * @param slaveId * @param offset * @param value * 寫入值,Number的子類,例如寫入Float浮點(diǎn)類型,Double雙精度類型,以及整型short,int,long * @param registerCount * ,com.serotonin.modbus4j.code.DataType * @throws ModbusTransportException * @throws ErrorResponseException * @throws ModbusInitException */ public static void writeHoldingRegister(int slaveId, int offset, Number value, int dataType) throws ModbusTransportException, ErrorResponseException, ModbusInitException { // 獲取master ModbusMaster tcpMaster = getMaster(); // 類型 BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, dataType); tcpMaster.setValue(locator, value); } public static void main(String[] args) { try { //@formatter:off // 測(cè)試01 // boolean t01 = writeCoil(1, 0, true); // System.out.println("T01:" + t01); // 測(cè)試02 // boolean t02 = writeCoils(1, 0, new boolean[] { true, false, true }); // System.out.println("T02:" + t02); // 測(cè)試03 // short v = -3; // boolean t03 = writeRegister(1, 0, v); // System.out.println("T03:" + t03); // 測(cè)試04 // boolean t04 = writeRegisters(1, 0, new short[] { -3, 3, 9 }); // System.out.println("t04:" + t04); //寫模擬量 writeHoldingRegister(1,0, 10.1f, DataType.FOUR_BYTE_FLOAT); //@formatter:on } catch (Exception e) { e.printStackTrace(); } } }
以上就是Java使用modbus4j實(shí)現(xiàn)modbus tcp通訊的詳細(xì)內(nèi)容,更多關(guān)于Java modbus tcp通訊的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實(shí)現(xiàn)求子數(shù)組和的最大值算法示例
這篇文章主要介紹了Java實(shí)現(xiàn)求子數(shù)組和的最大值算法,涉及Java數(shù)組遍歷、判斷、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下2018-02-02java多線程編程之InheritableThreadLocal
這篇文章主要為大家詳細(xì)介紹了java多線程編程之InheritableThreadLocal,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Java inputstream和outputstream使用詳解
這篇文章主要介紹了Java inputstream和outputstream使用詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08Java Druid連接池與Apache的DBUtils使用教程
這篇文章主要介紹了Java Druid連接池與Apache的DBUtils使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-12-12SpringBoot實(shí)現(xiàn)接口等冪次校驗(yàn)的示例代碼
本文主要介紹了SpringBoot實(shí)現(xiàn)接口等冪次校驗(yàn)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01基于SpringBoot實(shí)現(xiàn)發(fā)送帶附件的郵件
這篇文章主要介紹了基于SpringBoot實(shí)現(xiàn)發(fā)送帶附件的郵件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11解讀Spring配置文件中的property標(biāo)簽中的屬性
這篇文章主要介紹了Spring配置文件中的property標(biāo)簽中的屬性,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01