【物联网】Modbus 协议及Qinghub物联网平台应用

2024-03-16 06:52

本文主要是介绍【物联网】Modbus 协议及Qinghub物联网平台应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Modbus 协议简介

QingHub设计器在设计物联网数据采集时不可避免的需要针对Modbus协议的设备做相关数据采集,这里就我们的实际项目经验分享Modbus协议

你可以通过QingHub作业直接体验试用,也可以根据手册开发相应的代码块。 qinghub项目已经全面开源。

源码文件地址: https://gitee.com/qingplus/qingcloud-platform

QingHub设计器体验

简介

Modbus由MODICON公司于1979年开发,是一种工业现场总线协议标准。1996年施耐德公司推出基于以太网TCP/IP的Modbus协议:ModbusTCP。Modbus协议是一项应用层报文传输协议,包括ASCII、RTU、TCP三种报文类型。 标准的Modbus协议物理层接口有RS232、RS422、RS485和以太网接口,采用master/slave方式通信。

功能码

重点介绍常用如下几个功能码:
1: 读线圈寄存器
2: 读离散输入寄存器
3: 读保持寄存器
4: 读输入寄存器
5: 写单个线圈寄存器
6: 写单个保持寄存器
15: 写多个线圈寄存器
16: 写多个保持寄存器

几种继承器介绍

线圈寄存器

实际上就可以类比为开关量,每个bit都对应一个信号的开关状态。所以一个byte就可以同时控制8路的信号。

离散输入寄存器

如果线圈寄存器理解了这个自然也明白了。离散输入寄存器就相当于线圈寄存器的只读模式,他也是每个bit表示一个开关量,而他的开关量只能读取输入的开关信号,是不能够写的。

保持寄存器

这个寄存器的单位不再是bit而是两个byte,也就是可以存放具体的数据量的,并且是可读写的。比如设置时间年月日,不但可以写也可以读出来现在的时间。写分为单个写和多个写。

输入寄存器

只剩下这最后一个了,这个和保持寄存器类似,但是也是只支持读而不能写。一个寄存器也是占据两个byte的空间。

通信协议 (重点看这里就可以了)

Modbus设备可分为主站(poll)和从站(slave)。主站只有一个,从站有多个,主站向各从站发送请求帧,从站给予响应。在使用TCP通信时,主站为client端,主动建立连接;从站为server端,等待连接(当然只要你愿意并足够熟悉,也可以反向操作)。

Mobus 的报文大致分为两类: MBAP+PDU。
MBAP= Modbus Application Protocol Header(Modbus应用协议) 头部
PDU = Protocol Data Unit (数据单元)

MBAP报文

  • MBAP为报文头,长度为7字节,组成如下:
事务处理标识协议标识长度单元标识符
2字节2字节2字节1字节

含义:
事务处理标识:可以理解为报文的序列号,一般每次通信之后就要加1以区别不同的通信数据报文。
协议标识符:00 00表示ModbusTCP协议。
长度:表示接下来的数据长度,单位为字节。
单元标识符:可以理解为设备地址。

PDU报文结构

PDU结构
PDU由功能码+数据组成。功能码为1字节,数据长度不定,由具体功能决定。
主站请求:功能码+数据
从站正常响应:请求功能码+响应数据
从站异常响应:异常功能码+异常码,其中异常功能码即将请求功能码的最高有效位置1,异常码指示差错类型

指令实例

查询(功能码0x03)

基本流程就是:
发送:地址 + 我要查 +(寄存器起始地址+个数)+校验
回复:地址 +(回)我要查 +(数据的字节数+数据) +校验

主机发送: 01 03 00 00 00 01 84 0A
含义:
01-地址
03-功能码,代表查询功能,其他功能后面再说
00 00-代表查询的起始寄存器地址.说明从0x0000开始查询.
00 01-代表查询了一个寄存器.结合前面的00 00,意思就是查询从0开始的1个寄存器值;
84 0A-CRC

从机回复: 01 03 02 12 34 B5 33
含义:
01-地址
03-功能码
02-代表后面数据的字节数,因为上面说到,一个寄存器有2个字节,所以后面的字节数肯定是2*查询的寄存器个数;
12 34-寄存器的值是12 34,结合发送的数据看出,01这个寄存器的值为12 34
B5 33-CRC校验码

修改单个寄存器(功能码0x06)

主机送: 01 06 00 00 00 01 48 0A
01-从机地址
06-功能码:修改单个寄存器功能,修改有些不同,有修改一个寄存器和修改多个寄存器;
00 00-修改的起始寄存器地址.说明从0x0000开始.
00 01-修改的值为00 01.结合前面的00 00,意思就是修改0号寄存器值为00 01;
48 0A-CRC

从机回复: 01 06 00 00 00 01 48 0A
01-从机地址
06-功能码:修改单个寄存器功能;
00 00-修改的起始寄存器地址.说明是0x0000.
00 01-修改的值为00 01.结合前面的00 00,意思就是修改0号寄存器值为00 01;
48 0A-CRC

修改多个寄存器(功能码0x10)

主机发送: 01 10 00 00 00 02 04 11 22 33 44 42 5A
01-从机地址
10-功能码,代表修改多个寄存器功能;
00 00-代表修改的起始寄存器地址.说明从0x0000开始.
00 02代表修改的寄存器数量
04 -表示修改的总字节数,由于只修改了1个寄存器,所以数据要有两个字节;
11 22 33 44-表示修改的值,结合上面,就是从第0000寄存器开始修改2寄存器值为11 22 33 44,就是把0000寄存器改为11 22,0001为33 44,
42 5A -循环冗余校验,是modbus的校验公式,从首个字节开始到22前面为止;

从机回复: 01 10 00 00 00 02 41 C8
01-从机地址
10-功能码
00 00-代表修改的起始寄存器地址.说明是0x0000.
00 02-代表修改的寄存器数量,只需要回复这么多久足够了,从机告诉主机修改了哪几个寄存器就足够了;
41 C8-循环冗余校验;

java 开发

maven 依赖
<!-- Modbus -->
<dependency><groupId>com.infiniteautomation</groupId><artifactId>modbus4j</artifactId><version>3.1.0</version>
</dependency>
<dependency><groupId>com.digitalpetri.modbus</groupId><artifactId>modbus-master-tcp</artifactId><version>1.2.0</version>
</dependency>
API 实例

第一:建立连接

/*** 获取 Modbus Master* @return ModbusMaster* @throws ModbusInitException ModbusInitException*/
public ModbusMaster getMaster(ModbusConfig modbusConfig) throws ModbusInitException {log.debug("Modbus Tcp Connection Info {},{}", modbusConfig.getHostName(),modbusConfig.getPort());ModbusMaster modbusMaster = masterMap.get(modbusConfig.getEquipmentId());if (null == modbusMaster) {IpParameters params = new IpParameters();params.setHost(modbusConfig.getHostName());params.setPort(modbusConfig.getPort());**params.setEncapsulated(true);**modbusMaster = modbusFactory.createTcpMaster(params, true);modbusMaster.init();masterMap.put(modbusConfig.getEquipmentId(), modbusMaster);}return modbusMaster;
}

注意
这里有一个需要特别关注的地方,params.setEncapsulated(true)

如果encapsulated=true时:API 在构建消息是会自动加上CRC 校验码。

public byte[] getMessageData() {ByteQueue msgQueue = new ByteQueue();modbusMessage.write(msgQueue);ModbusUtils.pushShort(msgQueue, ModbusUtils.calculateCRC(modbusMessage));return msgQueue.popAll();
}

如果encapsulated=false时:消息会加上事务处理标识,协议标识6个字节:

public byte[] getMessageData() {ByteQueue msgQueue = new ByteQueue();modbusMessage.write(msgQueue);ByteQueue xaQueue = new ByteQueue();ModbusUtils.pushShort(xaQueue, transactionId);ModbusUtils.pushShort(xaQueue, ModbusUtils.IP_PROTOCOL_ID);ModbusUtils.pushShort(xaQueue, msgQueue.size());xaQueue.push(msgQueue);return xaQueue.popAll();
}

第二: API实例

/*** 读线圈寄存器* @param modbusMaster* @param slaveId* @param initOffset* @param count* @return* @throws ModbusTransportException*/
private static String batchCoilStatus01(ModbusMaster modbusMaster,Integer slaveId,Integer initOffset,Integer count) throws ModbusTransportException {ReadCoilsRequest request= new ReadCoilsRequest(slaveId,initOffset,count);ReadCoilsResponse response = (ReadCoilsResponse) modbusMaster.send(request);byte[] data  = response.getData();String bytes = ByteUtils.toHexAscii(data);return bytes;
}/*** 读离散输入寄存器* @param modbusMaster* @param slaveId* @param initOffset* @param count* @return* @throws ModbusTransportException*/
private static String batchInputStatus02(ModbusMaster modbusMaster,Integer slaveId,Integer initOffset,Integer count) throws ModbusTransportException {ReadDiscreteInputsRequest request= new ReadDiscreteInputsRequest(slaveId,initOffset,count);ReadDiscreteInputsResponse response = (ReadDiscreteInputsResponse) modbusMaster.send(request);byte[] data  = response.getData();String bytes = ByteUtils.toHexAscii(data);return bytes;
}
/***批量读取保持继承器* @param modbusMaster* @param slaveId* @param initOffset* @param count* @return* @throws ModbusTransportException*/
private static String batchRead03(ModbusMaster modbusMaster,Integer slaveId,Integer initOffset,Integer count) throws  ModbusTransportException {ReadHoldingRegistersRequest request= new ReadHoldingRegistersRequest(slaveId,initOffset,count);ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) modbusMaster.send(request);byte[] data  = response.getData();String bytes = ByteUtils.toHexAscii(data);return bytes;
}/*** 批量读取输入继承器* @param modbusMaster* @param slaveId* @param initOffset* @param count* @return* @throws ModbusTransportException*/
private static String batchRead04(ModbusMaster modbusMaster ,Integer slaveId,Integer initOffset, Integer count) throws  ModbusTransportException {ReadInputRegistersRequest request= new ReadInputRegistersRequest(slaveId,initOffset,count);ReadInputRegistersResponse response = (ReadInputRegistersResponse) modbusMaster.send(request);byte[] data  = response.getData();String bytes = ByteUtils.toHexAscii(data);return bytes;
}

轻云UC设计器实例

基础信息

组件名称 : modbus-connector
组件版本: 1.0.0
组件类型: 系统默认
状 态: 正式发布
组件描述:通过MODBUS 连接网关,采集或下发相关指令到设备端。

配置文件:

配置文件作为MODBUS配置界面元素的基础,MODBUS所有高级配置均可以通过重构该配置文件体现在前端界面上。配置参数分为三组: 基础配置,连接配置,高级配置,一般情况可以随意扩展高级配置。

注: 配置文件仅供修改升级组件式利用,一般情况下对用户透明。无需做任何更改,除非用户需要手动维护组件心跳或通信端口时,一般情况下禁止修改。

df:component:name: modbus-connectortype: 2   #1:采集器;2:接收器;3:转换器;4:存储器;5:解析器;6:状态解析器:7:同步器;8:消息通知transportPort: 49096    #内部akka通信端口heartbeatCron: 0/30 * * ? * * *       #网关心跳数据上报时间#########本地环境用##########instance-id: 998topic: DEMO-TOPIC-998response-topic: DEMO-TOPIC-RESPONSE-198executor:akka-address: 192.168.3.195:49095rest-address: 192.168.3.195:49090#############结束##############parameter:connection[0]:                      #组件连接参数数组name: Host                        #参数名称,自定义key: hostName                     #参数key,自定义required: true                    #是否必传 true或falsevalue-type: string                #参数值类型,支持 string, int, floatdefault-value: 127.0.0.1          #参数默认值,自定义input-type: input                 #参数输入类型,支持 input-输入框,select-下拉框description: 数据采集端TCP 连接地址                 #参数值描述,自定义connection[1]:name: Portkey: portrequired: truevalue-type: intinput-type: inputdefault-value: 502description: Modbus数据采集端TCP连接端口号connection[2]:name: 设备编号key: equipmentIdrequired: truevalue-type: stringinput-type: inputdefault-value: 80100012description: 设备编号(平台分配得设备编号)base[0]:name: 从站编号key: slaveIdrequired: truevalue-type: intinput-type: inputdescription: 采集设备序号(slaveId即设备地址)base[1]:name: 功能码key: functionCoderequired: falsevalue-type: intinput-type: selectselect-option: 01|1,02|2,03|3,04|4,05|5,15|15,6|6,16|16description: 命名空间功能码 [1:读线圈状态、2:读离散输入状态、3:读保持寄存器、4:读输入寄存器,5:写单个线圈,15:写多个线圈,6:写单个保持寄存器,16:写多个保持寄存器]base[2]:name: 偏移量key: offsetrequired: falsevalue-type: intinput-type: inputdescription: 偏移量base[3]:name: 数量key: numberOfRegistersrequired: truevalue-type: intinput-type: inputdefault-value: 1description: 继承器数量(从偏移量开始读取多少个继承器)base[4]:name: Encapsulatedkey: encapsulatedrequired: falsevalue-type: intinput-type: selectselect-option: true|1,false|2default-value: 1description: Master发送指令到slave时得消息格式为EncapMessage或者XaMessageadvance[0]:name: CRONkey: cronrequired: truevalue-type: stringinput-type: inputdefault-value: 1/10 * * ? * * *description: 网关采集器定时任务

组件测试

  1. 配置网关

从组件列表中选择modbus-connector并拖动到作业设计器。
image.png

  1. 参数说明

修改右侧配置参数并保存,参数使用说明可以通过每个参数旁边的?查看。
image.png
参数含义可以对照Modbus Slave 软件中的相关信息。 Modbus Slave 下载
image.png

  1. 启动网关

注意观察执行日志,确保网关正常运行,状态status 字段为1时表示正常运行中
image.png

  1. 测试验证

1)前提准备:
下载并启动 Modbus Slave 调试工具
image.png

连接成功后记录相关信息:
IP: 192.168.3.45
Port : 502
Slave ID: 1
function code : 3
偏移量: 0 (我们以0位作为测试数据)

2)进入到轻云UC通用设计中心,进入到设计器,并拖动modbus-connector组件到画板。
按规上面modbus slave 中的配置信息,设定好modbus-connector配置信息:
image.png
image.png
注意配置中的功能码,偏移量,从站编号,IP ,端口,需要与测试工具中的配置信息一致。
3)切换到UC设计器,重启modbus-connector网关,可以从执行日志板块看到数据。
这里的数据时定时获取的,通过配置参照中的表达式。如: 1/10 * * ? * * * 每10秒获取一次数据。
image.png

你可以通过Qinghub作业直接体验试用,也可以根据手册开发相应的代码块。 qinghub项目已经全面开源。
源码文件地址: https://gitee.com/qingplus/qingcloud-platform
qinghub作业配置

这篇关于【物联网】Modbus 协议及Qinghub物联网平台应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/814657

相关文章

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

zoj3820(树的直径的应用)

题意:在一颗树上找两个点,使得所有点到选择与其更近的一个点的距离的最大值最小。 思路:如果是选择一个点的话,那么点就是直径的中点。现在考虑两个点的情况,先求树的直径,再把直径最中间的边去掉,再求剩下的两个子树中直径的中点。 代码如下: #include <stdio.h>#include <string.h>#include <algorithm>#include <map>#

如何解决线上平台抽佣高 线下门店客流少的痛点!

目前,许多传统零售店铺正遭遇客源下降的难题。尽管广告推广能带来一定的客流,但其费用昂贵。鉴于此,众多零售商纷纷选择加入像美团、饿了么和抖音这样的大型在线平台,但这些平台的高佣金率导致了利润的大幅缩水。在这样的市场环境下,商家之间的合作网络逐渐成为一种有效的解决方案,通过资源和客户基础的共享,实现共同的利益增长。 以最近在上海兴起的一个跨行业合作平台为例,该平台融合了环保消费积分系统,在短

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影