Java与Modbus-TCP/IP网络通讯

1.需求样例

举例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。注:具体转换方法可以常见附件转换程序算法。

2.实现功能

通过Java与Modbus-TCP/IP网络通讯实现举例5中的功能

3.功能代码

1)

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));}}

2)

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;}
}

4.maven引入依赖包

 <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>

5.测试模拟工具(私信关注博主)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/52202.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

腾讯云服务器价格表大全_轻量服务器_CVM云服务器报价明细

腾讯云服务器租用费用表&#xff1a;轻量应用服务器2核2G4M带宽112元一年&#xff0c;540元三年、2核4G5M带宽218元一年&#xff0c;2核4G5M带宽756元三年、云服务器CVM S5实例2核2G配置280.8元一年、GPU服务器GN10Xp实例145元7天&#xff0c;腾讯云服务器网长期更新腾讯云轻量…

在Ubuntu上启动一个简单的用户登录接口服务

一个简单的用户登录接口 我使用 Python 和 Flask 框架来创建这个接口 首先&#xff0c;确保你已经安装了 Python 和 Flask。如果没有安装&#xff0c;可以通过以下命令在 Ubuntu 上安装&#xff1a; sudo apt update sudo apt install python3 python3-pip pip3 install Fla…

KASLR 内核随机地址配置开启

CONFIG_RANDOMIZE_BASE kernel features ---> Randomize of module region independently from the core kernel 参考链接&#xff1a;KASLR 内核动态地址 - kk Blog —— 通用基础 (abcdxyzk.github.io)

5G网关如何提升智慧乡村农业生产效率

得益于我国持续推进5G建设&#xff0c;截至今年5月&#xff0c;我国5G基站总数已达284.4万个&#xff0c;覆盖全国所有地级市、县城城区和9成以上的乡镇镇区&#xff0c;实现“镇镇通5G”&#xff0c;全面覆盖了从城市到农村的延伸。 依托5G网络的技术优势&#xff0c;智慧乡村…

5.6.webrtc三大线程

那今天呢&#xff1f;我们来介绍一下web rtc的三大线程&#xff0c;那为什么要介绍这三大线程呢&#xff1f;最关键的原因在于web rtc的所有其他线程都是由这三大线程所创建的。那当我们将这三个线程理解清楚之后呢&#xff1f;我们就知道其他线程与它们之间是怎样关系&#xf…

机器学习之Adam(Adaptive Moment Estimation)自适应学习率

Adam&#xff08;Adaptive Moment Estimation&#xff09;是一种常用的优化算法&#xff0c;特别适用于训练神经网络和深度学习模型。它是一种自适应学习率的优化算法&#xff0c;可以根据不同参数的梯度信息来动态调整学习率&#xff0c;以提高训练的效率和稳定性。 Adam算法…

如何提取视频的音频到手机?这个音频提取方法很简单

提取视频中的音频可以帮助您获得视频的声音部分&#xff0c;而无需观看整个视频。这对于那些只想听视频的声音或想将视频的声音与其他音频内容混合使用的人来说非常方便。此外&#xff0c;提取音频也可以为需要创建音频剪辑或混音的音频制作者提供帮助。那么怎么提取呢&#xf…

Java接入支付宝支付

本文只接入了支付宝中的APP支付&#xff0c;如果要拓展更多支付方式的的话&#xff0c;请看文末补充 项目支付流程 前端发起创建订单请求后端接受请求创建订单&#xff0c;并将订单参数进行支付宝对应签名并返回前端拿到签名后调起支付宝支付 本文主要写的就是2的过程 前期准…

报名倒计时!| 基于RflySim平台飞控底层算法开发专题培训(第二期)

RflySim 暑期学校 飞思实验室“基于RflySim平台飞控底层算法开发”系列专题培训第二期开启报名了&#xff01;专题培训由戴训华副教授以及飞思实验室学生&工程师团队主讲&#xff0c;采用“线上线下”集中授课形式&#xff0c;培训时间为8月28日-9月3日&#xff1b;课程内…

基于XL32F003单片机的可控硅调光方案

可控硅调光是一种用于调节电源输出电压的技术&#xff0c;被广泛应用于各种场景。它主要通过改变波形的导通角度来调节输出电压的大小&#xff0c;从而实现对照明设备亮度的控制。在照明市场占据了很大的调光市场。 可控硅调光的兼容性强&#xff0c;应用范围广。例如&#xff…

2023科隆游戏展:虚幻5游戏百花齐放,云渲染助力虚幻5高速渲染

8月23日&#xff0c;欧洲权威级游戏展示会——科隆游戏展拉开帷幕。今年的参展游戏也相当给力&#xff0c;数十款游戏新预告片在展会上公布&#xff0c;其中有不少游戏使用虚幻5引擎制作&#xff0c;开创了游戏开发新纪元。 虚幻5游戏百花齐放&#xff0c;渲染堪比电影级效果 …

数学软件和编程环境Mathematica 13 「mac」

Mathematica 13是一种强大的计算机代数系统和编程环境&#xff0c;它提供了广泛的数学功能和符号计算能力&#xff0c;可以进行高级数值计算、数据分析、可视化和模拟等任务。 Mathematica使用自己的独特的程序语言&#xff0c;称为Wolfram语言&#xff0c;它结合了函数式编程、…

Kotlin 中的 设计模式

单例模式 饿汉模式 饿汉模式在类初始化的时候就创建了对象&#xff0c;所以不存在线程安全问题。 局限性&#xff1a; 1、如果构造方法中有耗时操作的话&#xff0c;会导致这个类的加载比较慢&#xff1b; 2、饿汉模式一开始就创建实例&#xff0c;但是并没有调用&#xf…

软考A计划-系统集成项目管理工程师-知识产权管理

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

【腾讯云Cloud Studio实战训练营】React 快速构建点餐页面+Python 拼图小游戏

文章目录 一、腾讯云 Cloud Studio 概述1.1 腾讯云 Cloud Studio 简介1.2 腾讯云 Cloud Studio 功能特点1.3 腾讯云 Cloud Studio 产品优势 二、Cloud Studio界面功能介绍2.1 注册登录2.1.1 新注册用户有免费的3000分钟体验 2.2 界面功能介绍2.2.1 空间模板2.2.2 开发空间关闭空…

js 实现一个数组对应位置插入另一个数组

js 实现一个数组对应位置插入另一个数组 文章目录 js 实现一个数组对应位置插入另一个数组前言一、网上的教程二、实现思路1.将两个数组分成三个数组2.将需要再指定位置插入另一个数组的数据进行拆分2-1.拆解的另一份数组数据2-2.拼接数组 - concat 前言 网上看了很多改写spli…

FPGA解析串口指令控制spi flash完成连续写、读、擦除数据

前言 最近在收拾抽屉时找到一个某宝的spi flash模块&#xff0c;如下图所示&#xff0c;我就想用能不能串口来读写flash&#xff0c;大致过程就是&#xff0c;串口向fpga发送一条指令&#xff0c;fpga解析出指令控制flah&#xff0c;这个指令协议目前就是&#xff1a; 55 AA …

剑指offer(C++)-JZ64:求1+2+3+...+n(算法-位运算)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 求123...n&#xff0c;要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句&…

QT使用QXlsx实现对Excel的创建与文字的存取 QT基础入门【Excel的操作】

准备:搭建环境引用头文件QT中使用QtXlsx库的三种方法 QT基础入门【Excel的操作】_吻等离子的博客-CSDN博客 #include "xlsxdocument.h"const QString ExcelName="./test.xlsx"; QTXLSX_USE_NAMESPACE // 添加Xlsx命名空间 1、初始化excel表格 注意!两…

行业首家·合规典范|昂首资本携手菲律宾警察局,树立经纪商合规经营典范

Anzo Capital 昂首资本携手菲律宾达沃市警察局长阿尔贝托P卢帕兹受邀参加由 AFP-PNP Southern Mindanao Press Corps( 菲律宾武装部队(AFP)和菲律宾国家警察(PNP)南部棉兰老岛记者团)举办的新闻发布会。 本次新闻发布会在菲律宾达沃市皇家曼达亚酒店举行&#xff0c;Anzo Cap…