举例5:浮点数参数读取(读取温度测量值)
查看参数列表,温度测量值地址为320,根据Modbus协议,读取参数地址转换为16进制为:00H A0H,读取长度为2个字:00H 02H。
16进制发送读取命令如下:00 00 00 00 00 06 01 03 00 A0 00 02(复制使用时去掉中间空格,以16进制发送)
00 00 00 00 00 06 01:Modbus命令头,用户直接复制,不能更改
03:读取寄存器功能代码
00 A0:读取参数寄存器地址16进制代码
00 02:读取寄存器地址长度
接收到数据格式如下:00 00 00 00 00 07 01 03 04 42 48 02 C8
00 00 00 00 00 07 01:Modbus返回命令头
03:读取寄存器功能代码
04:返回数据长度,四个字节
42 48 02 C8:寄存器数据值,我们将此16进制数转换为浮点数值为:50.002716。
注:具体转换方法可以常见附件转换程序算法。
通过Java与Modbus-TCP/IP网络通讯实现举例5中的功能
package com.nwpusct.csal.controller.tcpconnect;
import java.io.*;
import java.math.BigInteger;
import java.net.Socket;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.DatatypeConverter;
import static org.apache.poi.util.HexDump.toHex;
/**
* 类描述:TODO
*
* @author HBO
* @date 2023-08-22 09:21
**/
public class SocketUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(SocketUtils.class);
private static Socket socket = null;
private static String archivesCenterAPIIP = "127.0.0.1";
private static String archivesCenterAPIPort ="502";
public static boolean connection() {
if (socket != null) {
return true;
}
try {
socket = new Socket(archivesCenterAPIIP, NumberUtils.toInt(archivesCenterAPIPort));
return true;
} catch (Exception e) {
LOGGER.error("connection error", e);
return false;
}
}
public static void stop() {
try {
if (socket != null) {
socket.close();
socket = null;
}
} catch (Exception e) {
LOGGER.error("connection error", e);
}
}
/**
* 发送数据
*
* @param cmd
* 需要发送的数据(十六进制的字符串形式)
* @return 接受到的数据(十六进制的字符串形式)
*/
public static String sendCmd(String cmd) {
if (!connection() || socket == null) {
return "error";
}
try {
OutputStream out = socket.getOutputStream();
byte[] hexStrToByteArrs = hexStrToByteArrs(cmd);
if (hexStrToByteArrs == null) {
return "error";
}
out.write(hexStrToByteArrs);
InputStream in = socket.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
stop();
return bytesToHexString(buf) ;
} catch (IOException e) {
LOGGER.error("sendCmd error", e);
return "error";
}
}
/**
* 将十六进制的字符串转换成字节数组
*
* @param hexString
* @return
*/
public static byte[] hexStrToByteArrs(String hexString) {
if (StringUtils.isEmpty(hexString)) {
return null;
}
hexString = hexString.replaceAll(" ", "");
int len = hexString.length();
int index = 0;
byte[] bytes = new byte[len / 2];
while (index < len) {
String sub = hexString.substring(index, index + 2);
bytes[index / 2] = (byte) Integer.parseInt(sub, 16);
index += 2;
}
return bytes;
}
/**
* 数组转换成十六进制字符串
*
* @param
* @return HexString
*/
public static final String bytesToHexString(byte[] bArray) {
StringBuffer sb = new StringBuffer(bArray.length);
String sTemp;
for (int i = 0; i < bArray.length; i++) {
sTemp = Integer.toHexString(0xFF & bArray[i]);
if (sTemp.length() < 2)
sb.append(0);
sb.append(sTemp.toUpperCase());
// 在这里故意追加一个逗号便于最后的区分
sb.append(" ");
}
return sb.toString();
}
/*
* 将16进制数字解码成字符串,适用于所有字符(包括中文)
*/
public static String decode(String bytes) {
String hexString = "0123456789ABCDEF";
ByteArrayOutputStream baos = new ByteArrayOutputStream(bytes.length() / 2);
// 将每2位16进制整数组装成一个字节
for (int i = 0; i < bytes.length(); i += 2)
baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString
.indexOf(bytes.charAt(i + 1))));
return new String(baos.toByteArray());
}
/**
* 16进制数转换为浮点数值
*
* @param str 16进制数据 424802C8= 50.002716
* @throws IOException
* @throws ModbusInitException
* @throws ModbusTransportException
* @throws ErrorResponseException
*/
public static Float intBitsToFloat(String str) {
BigInteger b = new BigInteger(str, 16);
float value = Float.intBitsToFloat(b.intValue());
return value;
}
public static void main(String[] args) throws UnsupportedEncodingException {
//34.6°
String str = sendCmd("00 00 00 00 00 06 01 03 00 04 00 02");
// String str="00 00 00 00 00 06 01 03 00 02 00 02";
String x = str.replaceAll("\\s*", "");
String s = str.split(" ")[8];
String substring = x.substring(18, Integer.parseInt(s) * 2 + 18);
System.out.println(substring);
System.out.println(intBitsToFloat(substring));
}
}
package com.nwpusct.csal.controller.tcpconnect;
import com.nwpusct.csal.common.util.RestResult;
import com.nwpusct.csal.common.util.RestResultUtil;
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 io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
/**
* 类描述:TODO
* 监测高低温箱温度
*
* @author HBO
* @date 2023-08-21 09:34
**/
@CrossOrigin
@RestController
@Api(tags = {"监测高低温箱温度"})
@RequestMapping(value = "/modbus")
public class ModbusController {
@Value(value = "${high.ip}")
public String ip;//从站IP
@Value(value = "${high.port}")
public int port;//modbus端口
@Value(value = "${low.ip}")
public String lowIp;
@Value(value = "${low.port}")
public int lowPort;
/**
* 工厂。
*/
static ModbusFactory modbusFactory;
static {
if (modbusFactory == null) {
modbusFactory = new ModbusFactory();
}
}
@GetMapping(value = "/readModbusHigh")
@ApiOperation(value = "高温箱")
public RestResult<Object> readModbusHigh() {
//第二中方式
try {
Number number = readHoldingRegisterH(1, 320, DataType.FOUR_BYTE_FLOAT);
return RestResultUtil.genSuccessResult(number);
} catch (Exception e) {
return RestResultUtil.genSuccessResult(null);
}
}
/**
* 获取master 高温箱
*
* @return
* @throws ModbusInitException
*/
public ModbusMaster getMasterH() throws ModbusInitException {
IpParameters params = new IpParameters();
params.setHost(ip);
params.setPort(port);
//
// modbusFactory.createRtuMaster(wapper); //RTU 协议
// modbusFactory.createUdpMaster(params);//UDP 协议
// modbusFactory.createAsciiMaster(wrapper);//ASCII 协议
ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
master.init();
return master;
}
/**
* 读取[03 Holding Register类型 2x]模拟量数据 高温箱
*
* @param slaveId slave Id
* @param offset 位置 序列号
* @param dataType 数据类型,来自com.serotonin.modbus4j.code.DataType
* @return
* @throws ModbusTransportException 异常
* @throws ErrorResponseException 异常
* @throws ModbusInitException 异常
*/
public Number readHoldingRegisterH(int slaveId, int offset, int dataType)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 03 Holding Register类型数据读取
BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
Number value = getMasterH().getValue(loc);
return value;
}
@GetMapping(value = "/readModbusLow")
@ApiOperation(value = "高低温箱")
public RestResult<Object> readModbusLow() {
try {
Number number = readHoldingRegisterL(1, 320, DataType.FOUR_BYTE_FLOAT);
return RestResultUtil.genSuccessResult(number);
} catch (Exception e) {
return RestResultUtil.genSuccessResult(null);
}
}
/**
* 获取master 高低温箱
*
* @return
* @throws ModbusInitException
*/
public ModbusMaster getMasterL() throws ModbusInitException {
IpParameters params = new IpParameters();
params.setHost(lowIp);
params.setPort(lowPort);
ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
master.init();
return master;
}
/**
* 读取[03 Holding Register类型 2x]模拟量数据 高低温箱
*
* @param slaveId slave Id
* @param offset 位置 序列号
* @param dataType 数据类型,来自com.serotonin.modbus4j.code.DataType
* @return
* @throws ModbusTransportException 异常
* @throws ErrorResponseException 异常
* @throws ModbusInitException 异常
*/
public Number readHoldingRegisterL(int slaveId, int offset, int dataType)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 03 Holding Register类型数据读取
BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
Number value = getMasterL().getValue(loc);
return value;
}
}
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
</dependencies>
<!-- 若想引用modbus4j需要引入下列repository id:ias-snapshots id:ias-releases 两个 ,使用默认仓库下载,不要使用阿里云仓库-->
<repositories>
<repository>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
<id>ias-snapshots</id>
<name>Infinite Automation Snapshot Repository</name>
<url>https://maven.mangoautomation.net/repository/ias-snapshot/</url>
</repository>
<repository>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>ias-releases</id>
<name>Infinite Automation Release Repository</name>
<url>https://maven.mangoautomation.net/repository/ias-release/</url>
</repository>
</repositories>