【物联网】Modbus 协议简介

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

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

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

相关文章

认清趋势的力量!北大请摆摊鹅姨做演讲!阿伟告白失败,AI有资格做僚机?——早读(逆天打工人爬取热门微信文章解读)

趋势的力量&#xff0c;AWSL 引言Python 代码第一篇 人民日报 【夜读】最好的伯乐&#xff0c;是努力的自己第二篇 来啦新闻早班车要闻社会政策 结尾 “识时务者为俊杰&#xff0c;通机变者为英豪” 生活中&#xff0c;我们如骑行者穿越车水马龙 察觉人潮车流的趋势 不论体能优…

DCAI:Data-Centric AI 以数据为中心的AI

1. 什么是DCAI&#xff1f; 1.1. 当下的研究背景 想象当中的数据集&#xff1a;通常是干净且精选的(例如猫或狗的图片)。 猫就是猫&#xff0c;狗就是狗 实际现实生活中的数据集&#xff1a;非常混乱~ https://labelerrors.com/ 比如这个网站里提供了一些人们常用的开源数据集…

产品推荐 - ALINX XILINX FPGA开发板 Artix-7 XC7A100T-2FGG484I

01开发板介绍 此款开发板采用核心板扩展板的模式&#xff0c;方便用户对核心板的二次开发利用。FPGA使用的是Xilinx公司的ARTIX-7系列的芯片&#xff0c;型号为XC7A100T-2FGG484I。在核心板使用了2片MICRON公司的MT41J256M16HA-125 DDR3芯片&#xff0c;组合成32bit的数据总线…

栈的应用——括号匹配

用栈实现 1、初始化一个栈&#xff0c;用来存左括号 2、遍历扫描括号字符串 如果遇到左括号&#xff0c;无脑入栈如果遇到右括号&#xff0c;此时栈空返回false&#xff0c;不空的话进行括号匹配。匹配不成功返回false&#xff0c;匹配成功将栈顶的那个左括号出栈。 遍历完之后…

MongoDB聚合运算符:$firstN

文章目录 语法使用空值或缺失值的处理 f i r s t N 与 firstN与 firstN与topN对比关于窗口功能和聚合表达式的支持内存限制 举例查找单场比赛的前三名运动员得分查找多场比赛中前三名运动员的得分 s o r t 与 sort与 sort与firstN一起使用根据group的键计算n在聚合表达式中使用…

Git中的换行符CRLF和LF问题

目录 第一章、问题分析1.1&#xff09;Git报错提示1.2&#xff09;报错分析 第二章、解决方式2.1&#xff09;在Windows上开发并需要与Unix或macOS上的开发人员协作2.1&#xff09;在Unix或macOS开发并需要与Windows上的开发人员协作2.3&#xff09;不需要与其他操作系统的开发…

【PyTorch】成功解决ModuleNotFoundError: No module named ‘torch’

【PyTorch】成功解决ModuleNotFoundError: No module named ‘torch’ &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希…

Java多线程实战-异步操作日志记录解决方案(AOP+注解+多线程)

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️本系列源码仓库&#xff1a;多线程并发编程学习的多个代码片段(github) &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正…

C++笔记:从零开始一步步手撕高阶数据结构AVL树

文章目录 高度平衡二叉搜索树实现一颗AVL树结点与树的描述——定义类AVL树的插入操作步骤1&#xff1a;按照二叉搜索树的方法插入结点步骤2&#xff1a;自底向上调整平衡因子步骤3&#xff1a;触发旋转操作&#xff08;AVL树平衡的精髓&#xff09;右单旋左单旋左右双旋右左双旋…

TSINGSEE青犀视频AI方案:数据+算力+算法,人工智能的三大基石

背景分析 随着信息技术的迅猛发展&#xff0c;人工智能&#xff08;AI&#xff09;已经逐渐渗透到我们生活的各个领域&#xff0c;从智能家居到自动驾驶&#xff0c;从医疗诊断到金融风控&#xff0c;AI的应用正在改变着我们的生活方式。而数据、算法和算力&#xff0c;正是构成…

【矩阵】48. 旋转图像【中等】

旋转图像 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,…

开源大数据集群部署(十六)Hadoop集群部署(一)

作者&#xff1a;櫰木 按照上文中hadoop集群规划进行安装。 1 HADOOP集群安装 在hd1.dtstack.com主机root权限下安装hadoop集群 解压 [roothd1.dtstack.com software]# tar -zvxf hadoop-3.2.4.tar.gz -C /opt/ [roothd1.dtstack.com software]# chown -R hdfs:hadoop /opt…

基于伪逆的三点法测距,MATLAB源代码(MATLAB函数)

程序介绍 这是一个函数&#xff0c;输入距离和已知点位置&#xff0c;输出未知点的位置。 已知点三个&#xff0c;未知点一个&#xff0c;已知点和未知点的距离也是有三个。 完整源代码 function [p_out] triposition(R_calcu,baseP) % p [5,5;10,9;15,12;20,22;25,3]; %r…

rust学习笔记(1-7)

原文 8万字带你入门Rust 1.包管理工具Cargo 新建项目 1&#xff09;打开 cmd 输入命令查看 cargo 版本 cargo --version2&#xff09; 使用 cargo new 项目名 在文件夹&#xff0c;按 shift 鼠标右键 &#xff0c;打开命令行&#xff0c;运行如下命令&#xff0c;即可创建…

python-1星-可变参数

可变参数是指在函数调用时&#xff0c;可以传入任意数量的参数。 在Python中&#xff0c;可用*args表示可变参数&#xff0c;args是一个元组类型&#xff0c;存储了传入的所有参数。 1、1个星&#xff08;*&#xff09;说明&#xff1a; 1&#xff09;单星号 2&#xff09;…

基于springboot的七彩云南文化旅游网站的设计与实现(论文+源码)_kaic

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装七彩云南文化旅游网站软件来发挥其高效地信息处理的作用&am…

5.82 BCC工具之tcpdrop.py解读

一,工具简介 tcpdrop工具打印被内核丢弃的 TCP 数据包或段的详细信息,包括导致丢弃的内核堆栈跟踪。 当网络出现拥堵、资源不足或其他原因导致数据包被内核丢弃时,tcpdrop可以帮助开发者和网络管理员识别并定位问题。 该工具通过钩住内核中处理TCP数据包的相关函数,捕获…

【使用postman测试python接口】

打开python服务 设置postman如下&#xff0c;并发送&#xff1a; postman新建请求设置请求方式为post设置地址、raw、json方式、内容如下 结果&#xff1a; python如下&#xff1a; from flask import Flask, request, jsonifyapp Flask(__name__) # 实例化对象app.route…

你为什么是你,而不是别人?认识人格的力量

你为什么是你&#xff0c;而不是别人&#xff1f;让你做自我介绍&#xff0c;你会怎么描述自己呢&#xff1f; 人格心理学是心理学的一门重要分支学科。探求、描述和揭示个体思想、情绪及行为的独特模式&#xff0c;综合个人与环境诸多影响因素&#xff0c;对现实社会中的个人作…

Vite为什么比Webpack快

一、引言 主流的前端构建工具包括以下几种&#xff1a; Webpack&#xff1a;当下最热门的前端资源模块化管理和打包工具。它能够将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。同时&#xff0c;Webpack还支持代码分割&#xff0c;可以按需加载模块&#…