提示:可以使用Modbus slave工具模擬Modbus數(shù)據(jù)站并添加一些數(shù)據(jù)。
1、pom引入依賴(lài)
<dependency>
<groupId>com.intelligt.modbus</groupId>
<artifactId>jlibmodbus</artifactId>
<version>1.2.9.7</version>
</dependency>
2、創(chuàng)建modbus主機(jī)連接
public class JlibModbusBase {
static ModbusMaster modbusMaster;
public static void initJlibModbusMaster(String ip) {
// 如果連接不存在,創(chuàng)建一個(gè)主機(jī)連接
if (ObjectUtils.isEmpty(modbusMaster)) {
// 設(shè)置主機(jī)TCP參數(shù)
TcpParameters tcpParameters = new TcpParameters();
// 設(shè)置TCP的ip地址-本地地址
InetAddress address = null;
try {
address = InetAddress.getByName(ip);
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
tcpParameters.setHost(address);
// TCP設(shè)置長(zhǎng)連接
tcpParameters.setKeepAlive(true);
// TCP設(shè)置端口,這里設(shè)置是默認(rèn)端口502
tcpParameters.setPort(502);
modbusMaster = ModbusMasterFactory.createModbusMasterTCP(tcpParameters);
Modbus.setAutoIncrementTransactionId(true);
}
}
public static void release() {
if (modbusMaster != null) {
try {
modbusMaster.disconnect();
} catch (ModbusIOException e) {
throw new RuntimeException(e);
}
}
}
}
3、通過(guò)連接獲取功能碼0x04與0x03的數(shù)據(jù)
public class JlibModbusBaseTool {
/**
* "功能碼0x04"
* 讀取HoldingRegister數(shù)據(jù)
*
* @param slaveId 寄存器地址ID
* @param offset 寄存器讀取開(kāi)始地址
* @param quantity 讀取寄存器數(shù)量
* @return int數(shù)組
*/
public static int[] readInputRegisters(int slaveId, int offset, int quantity) {
try {
return modbusMaster.readInputRegisters(slaveId, offset, quantity);
} catch (ModbusProtocolException | ModbusNumberException | ModbusIOException e) {
throw new RuntimeException(e);
} finally {
release();
}
}
/**
* "功能碼0x03"
* 讀取HoldingRegister數(shù)據(jù)
*
* @param slaveId 寄存器地址ID
* @param offset 寄存器讀取開(kāi)始地址
* @param quantity 讀取寄存器數(shù)量
* @return int數(shù)組
*/
public static int[] readHoldingRegisters(int slaveId, int offset, int quantity) {
try {
return modbusMaster.readHoldingRegisters(slaveId, offset, quantity);
} catch (ModbusProtocolException | ModbusNumberException | ModbusIOException e) {
throw new RuntimeException(e);
} finally {
release();
}
}
4、根據(jù)具體業(yè)務(wù)情況,進(jìn)行方法的調(diào)用與數(shù)據(jù)解析。在本人實(shí)際業(yè)務(wù)中,存在兩個(gè)IP地址(實(shí)際中上文的主機(jī)連接,可以根據(jù)IP的不同,實(shí)時(shí)創(chuàng)建不同的連接)。因?yàn)樽x取寄存器數(shù)量時(shí),最多可以讀取124個(gè)寄存器。所以根據(jù)業(yè)務(wù)實(shí)際情況,進(jìn)行多次的循環(huán)取數(shù)。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-508200.html
//讀取的寄存器數(shù)量,一次讀取兩臺(tái)設(shè)備寄存器數(shù)據(jù)
//因?yàn)閷?shí)際使用中數(shù)據(jù)為float數(shù)據(jù),下文還會(huì)進(jìn)行數(shù)據(jù)的轉(zhuǎn)換
int quantity = 96;
int[] result = null;
int salveId = 0;
//獲取數(shù)據(jù)
result = JlibModbusBaseTool.readInputRegisters(salveId,offset,quantity);
//首先將int[]轉(zhuǎn)化為集合,然后將讀取到的數(shù)據(jù)集合,分成兩個(gè)集合
List<Integer> intList = Arrays.stream(result).boxed().toList();
int LIMIT_TOW = 48;
ArrayList<List<Integer>> dataList = new ArrayList<>();
Stream.iterate(0, n -> n + 1).limit(countStep(intList.size(), LIMIT_TOW)).forEach(i -> {
dataList.add(intList.stream().skip(i * LIMIT_TOW).limit(LIMIT_TOW).collect(Collectors.toList()));
});
//計(jì)算分組數(shù)量
public static Integer countStep(Integer size,int limt) {
return (size + limt - 1) / limt;
}
//然后讀取int[]數(shù)據(jù),轉(zhuǎn)化為浮點(diǎn)類(lèi)型
// 兩個(gè)數(shù)據(jù)一組,組成16進(jìn)制字符轉(zhuǎn),轉(zhuǎn)化為float數(shù)據(jù)類(lèi)型
public static CcElectricityMeterNew convertFloat(int[] array, CcElectricityMeterNew meterNew){
for (int i = 0; i < array.length; i++) {
if ((i+1)%2==0) {
int first = array[i-1];
int second = array[i];
//在進(jìn)行字符串轉(zhuǎn)化時(shí),轉(zhuǎn)化的16進(jìn)制會(huì)存在缺少一位的情況,進(jìn)行左側(cè)補(bǔ)零操作
String hexStr = addZeroForStr(Integer.toHexString(first),4,1)+""+addZeroForStr(Integer.toHexString(second),4,1);
System.out.println(new BigDecimal(sfloat(hexStr)));
}
}
return meterNew;
}
//將字符串類(lèi)型的16進(jìn)制數(shù)據(jù),轉(zhuǎn)化為float字符串
private static String sfloat(String str){
Float value = Float.intBitsToFloat(new BigInteger(str, 16).intValue());
return String.valueOf(value);
}
/**
* 給字符串的左補(bǔ)0或右補(bǔ)0
* @param str 要處理的字符串
* @param length 補(bǔ)0后字符串總長(zhǎng)度
* @return 返回補(bǔ)零字符串
*/
public static String addZeroForStr(String str, int length,int type) {
int strLen = str.length();
if (strLen < length) {
while (strLen < length) {
StringBuffer sb = new StringBuffer();
if(type==1){
// 左補(bǔ)0
sb.append("0").append(str);
}else if(type==2){
//右補(bǔ)0
sb.append(str).append("0");
}
str = sb.toString();
strLen = str.length();
}
}
return str;
}
備注:使用jlibmodbus讀取Modbus TCP數(shù)據(jù)是非常簡(jiǎn)單的,在使用中需要根據(jù)自己需要的數(shù)據(jù)類(lèi)型進(jìn)行轉(zhuǎn)化;同時(shí)一次獲取寄存器的數(shù)量需要注意,合理進(jìn)行循環(huán)的數(shù)據(jù)獲取。在進(jìn)行modbus數(shù)據(jù)獲取時(shí),碰到一個(gè)問(wèn)題,在大量進(jìn)行重復(fù)連接數(shù)據(jù)獲取時(shí),modbus存在Connection reset 的問(wèn)題,導(dǎo)致數(shù)據(jù)獲取無(wú)法進(jìn)行后續(xù)數(shù)據(jù)獲取中斷,暫時(shí)沒(méi)有找到問(wèn)題的原因,如果有知道原理的大神,希望給與解答?。?!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-508200.html
到了這里,關(guān)于Java實(shí)現(xiàn)使用jlibmodbus讀取Modbus TCP數(shù)據(jù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!