Java使用modbus4j實現(xiàn)modbus?tcp通訊
一、什么是modbus
Modbus是由Modicon(現(xiàn)為施耐德電氣公司的一個品牌)在1979年發(fā)明的,是全球第一個真正用于工業(yè)現(xiàn)場的總線協(xié)議。
ModBus網(wǎng)絡是一個工業(yè)通信系統(tǒng),由帶智能終端的可編程序控制器和計算機通過公用線路或局部專用線路連接而成。其系統(tǒng)結構既包括硬件、亦包括軟件。它可應用于各種數(shù)據(jù)采集和過程監(jiān)控。
ModBus網(wǎng)絡只有一個主機,所有通信都由他發(fā)出。網(wǎng)絡可支持247個之多的遠程從屬控制器,但實際所支持的從機數(shù)要由所用通信設備決定。采用這個系統(tǒng),各PC可以和中心主機交換信息而不影響各PC執(zhí)行本身的控制任務。
二、Java實現(xiàn)modbus協(xié)議通訊
Java編程中,使用modbus4j實現(xiàn)Java中的modbus協(xié)議通訊
modbus4j實現(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實現(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]類型 開關數(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]類型 開關數(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ù)類型,來自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ù)類型,來自com.serotonin.modbus4j.code.DataType
* @return 返回結果
* @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));
}
/**
* 測試
*
* @param args
*/
public static void main(String[] args) {
try {
// 01測試
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測試
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測試
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測試
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();
}
}
}三、測試
使用ModbusSlave模擬modbus協(xié)議
slave中模擬數(shù)據(jù)如下
運行工具類的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
觀察輸出結果與 slave上的模擬數(shù)據(jù)一致
四、Java通過modbus4j對數(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)]寫一個 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)建請求
WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);
// 發(fā)送請求并獲取響應對象
WriteCoilResponse response = (WriteCoilResponse) tcpMaster.send(request);
if (response.isException()) {
return false;
} else {
return true;
}
}
/**
* 寫[01 Coil Status(0x)] 寫多個 function ID = 15
*
* @param slaveId
* slaveId
* @param startOffset
* 開始位置
* @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)建請求
WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, bdata);
// 發(fā)送請求并獲取響應對象
WriteCoilsResponse response = (WriteCoilsResponse) tcpMaster.send(request);
if (response.isException()) {
return false;
} else {
return true;
}
}
/***
* 寫[03 Holding Register(4x)] 寫一個 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)建請求對象
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)]寫多個 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)建請求對象
WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, sdata);
// 發(fā)送請求并獲取響應對象
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浮點類型,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
// 測試01
// boolean t01 = writeCoil(1, 0, true);
// System.out.println("T01:" + t01);
// 測試02
// boolean t02 = writeCoils(1, 0, new boolean[] { true, false, true });
// System.out.println("T02:" + t02);
// 測試03
// short v = -3;
// boolean t03 = writeRegister(1, 0, v);
// System.out.println("T03:" + t03);
// 測試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實現(xiàn)modbus tcp通訊的詳細內容,更多關于Java modbus tcp通訊的資料請關注腳本之家其它相關文章!
相關文章
Java實現(xiàn)求子數(shù)組和的最大值算法示例
這篇文章主要介紹了Java實現(xiàn)求子數(shù)組和的最大值算法,涉及Java數(shù)組遍歷、判斷、運算等相關操作技巧,需要的朋友可以參考下2018-02-02
java多線程編程之InheritableThreadLocal
這篇文章主要為大家詳細介紹了java多線程編程之InheritableThreadLocal,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10
Java inputstream和outputstream使用詳解
這篇文章主要介紹了Java inputstream和outputstream使用詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下2021-08-08
Java Druid連接池與Apache的DBUtils使用教程
這篇文章主要介紹了Java Druid連接池與Apache的DBUtils使用方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-12-12
SpringBoot實現(xiàn)接口等冪次校驗的示例代碼
本文主要介紹了SpringBoot實現(xiàn)接口等冪次校驗的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01
基于SpringBoot實現(xiàn)發(fā)送帶附件的郵件
這篇文章主要介紹了基于SpringBoot實現(xiàn)發(fā)送帶附件的郵件,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-11-11

