当前位置: 首页 > news >正文

modbus-TCP协议详解

modbus-TCP协议详解

1996年施耐德公司推出基于以太网TCP/IP的modbus协议:modbus-TCP。

MODBUS-TCP使MODBUS-RTU协议运行于以太网,MODBUS-TCP使用TCP/IP以太网在站点间传送MODBUS报文,MODBUS-TCP结合了以太网物理网络和网络标准TCP/IP以及以MODBUS作为应用协议标准的数据表示方法。MODBUS-TCP通信报文包在以太网TCP/IP数据包中。与传统的串口方式,MODBUS-TCP插入一个标准的MODBUS报文到TCP报文中,不再带有数据校验和地址。

MODBUS报文解析

| MBAP Header | Function code | Data |
| Header | PDU |

MBAP header包含下面几个部分:

  • Transaction ID
  • Protocol ID
  • Length
  • UnitID
id名称长度说明
1Transaction ID 事务处理标识2字节报文的序列号,一般每次通讯加1,用于区别不同的报文
2Protocol ID 协议标识2字节00 00 代表modbus-Tcp
3Length2字节Unit长度 + PDU的长度
4UnitID单元标识符1

下面的这一串MBAP header|00 01| 00 00|00 06| 01 |, 其含义如下:

事务标识为1,协议是modbus-tcp协议,数据长度是:6,从站号是1。

需要注意的是MODBUS协议是一个大端的协议,前两个byte 00 01代表0x1 , 因此Transaction ID=1。而长度字段00 06代表0x6, 即UnitID和PDU的长度总和为6。

PDU部分相对复杂一些,主要是对一些寄存器进行读写操作。

modbus的操作对象有四种:线圈寄存器离散输入寄存器输入寄存器保持寄存器

寄存器种类数据类型访问类型功能码
线圈寄存器bit读写01H 05H 0FH
离散输入寄存器bit只读02H
输入寄存器2 bytes(word)只读04H
保持寄存器2 bytes(word)读写03H 06H 10H

线圈寄存器和离散输入寄存器是以bit为单位的寄存器,只能存储开关量,线圈寄存器可读可写,而离散输入寄存器只可读。

输入寄存器和保持寄存器以为2个byte为单位的寄存器,可以存储离散的变量, 保持寄存器可读可写, 输入寄存器只读。

常用的功能码作用如下:

功能码功能
0x01读单个或者多个线圈寄存器
0x02读离散量输入寄存器
0x03读保持寄存器
0x04读输入寄存器
0x05写单个线圈寄存器
0x06写单个保持寄存器
0x10写多个保持寄存器
0x0F写多个线圈寄存器

常用功能码详解

功能码0x1:读线圈寄存器

每个线圈寄存器可以存储一个bit的信息, 功能码0x01就是用于读取slave中线圈寄存器的状态,可以是单个线圈寄存器,也可以是多个连续的线圈寄存器

发送报文

发送报文由下面几个部分组成,总共12字节:

MBAP header(7字节) + 功能码(1字节) + 线圈寄存器起始地址的高位(1字节) + 线圈寄存器起始地址的低位(1字节) + 线圈寄存器数量的高位(1字节) + 线圈寄存器数量的低位(1字节)

下面是一个用Modbus-Poll和Modbus-Slave测试的实际的例子,其含义是读取线圈寄存器的起始地址是0x0, 读取数量为 0x0a(十进制10)个。

0x1-request

MBAP header功能码起始地址高字节起始地址低字节寄存器数量的高位寄存器数量的低位
01 66 00 00 00 06 01010000000a

其中:

TransanctionID = 358, Length = 6。

功能码为0x1,代表读取线圈寄存器。

读取的线圈寄存器的起始地址为0。

读取的线圈寄存器的数量为0xa(十进制10)个。

响应报文

响应报文的长度不是固定的,长度和用户请求的数据长度有关,由下面几个部分组成:

MBAP header(7字节) + 功能码(1字节) + 线圈寄存器的值

下面是一个实际的响应报文的内容:

0x1-request

MBAP header功能码字节数请求的数据1请求的数据2
01 66 00 00 00 05 0101022102

返回的第一个字节21,转化为二进制为00100001, 其中bit0代表00寄存器,bit7代表07寄存器。

0x70x60x50x40x30x20x10x0
00100001

返回的第二个字节02,转化为二进制为00000010, 其中bit0代表08寄存器,bit1代表09寄存器。

0x90x8
10

功能码0x5: 写单个线圈寄存器0x05:

功能码0x5的作用是对单个线圈寄存器写值ON/OFF。

发送报文

发送报文由下面几个部分组成,总共12字节:

MBAP header(7字节) + 功能码(1字节) + 线圈寄存器起始地址的高位(1字节) + 线圈寄存器起始地址的低位(1字节) + 要写的值的高位(1字节) + 要写的值的低位(1字节)

将从站中的一个输出写成ON或OFF,0xFF00代表为ON,0x0000代表为OFF。

下面是一个实际的例子:

0x5-request

MBAP header功能码起始地址高字节起始地址低字节写的值的高位写的值的低位
00 6f 00 00 00 06 01050004ff00

在这个例子中,对从站01的0x4号线圈执行ON操作。

响应报文

可以看到,如果写单个线圈成功,返回报文的值和发送报文的值相同:

0x5-request

功能码0x0F:写多个线圈寄存器

将一个从站中的多个线圈寄存器的写为ON或OFF,数据域中置1的位请求相应输出位ON,置0的位请求响应输出为OFF。

发送报文

发送报文由下面几部分组成:

MBAP 功能码 + 起始地址H 起始地址L + 输出数量H 输出数量L + 字节长度 + 输出值H 输出值L

其总长度为 13 + (修改的线圈寄存器数量/8 + 1)。

下面是一个实际的例子

0xF-request

按照协议进行对应的结果如下:

MBAP header功能码线圈寄存器起始位置线圈寄存器的数量字节数第一个byte的值第二个byte的值
01 71 00 00 00 09 010f00 0000 0a027000

其中第一个byte的值是0x70, 转换为二进制是01110000,其中低位bit0代表00寄存器,bit7代表07寄存器。

0x70x60x50x40x30x20x10x0
01110000

第二个byte的值是0x0, 转换为二进制是00000000,其中低位bit0代表08寄存器,bit1代表09寄存器。

0x90x8
00

该请求的作用起始就是将04 05 06寄存器的状态改为ON。

返回报文

返回的报文相对比较简单,由下面几个部分组成:

MBAP header + 功能码 + 起始地址H 起始地址L + 输出数量H 输出数量L

下面是一个实际的例子:

0xF-response

按照协议对应各部分的内容如下:

MBAP header功能码线圈寄存器起始位置线圈寄存器的数量
01 71 00 00 00 06 010f00 0000 0a

功能码0x02:读离散量输入寄存器

功能码0x2和0x1是比较类似的。只是操作的离散量输入寄存器是只读的,没有写操作的接口。

每个离散量输入寄存器可以存储一个bit的信息, 功能码0x02就是用于读取slave中离散量输入寄存器的状态,可以是单个线圈寄存器,也可以是多个连续的线圈寄存器

发送报文

发送报文由下面几个部分组成,总共12字节:

MBAP header(7字节) + 功能码(1字节) + 离散量输入寄存器起始地址的高位(1字节) + 离散量输入寄存器起始地址的低位(1字节) + 离散量输入寄存器数量的高位(1字节) + 离散量输入寄存器数量的低位(1字节)

下面是一个用Modbus-Poll和Modbus-Slave测试的实际的例子,其含义是读取线圈寄存器的起始地址是0x0, 读取数量为 0x0a(十进制10)个。

0x2-request

MBAP header功能码起始地址高字节起始地址低字节寄存器数量的高位寄存器数量的低位
01 b9 00 00 00 06 01010000000a

其中:

TransanctionID = 441, Length = 6。

功能码为0x1,代表读取线圈寄存器。

读取的线圈寄存器的起始地址为0。

读取的线圈寄存器的数量为0xa(十进制10)个。

响应报文

响应报文的长度不是固定的,长度和用户请求的数据长度有关,由下面几个部分组成:

MBAP header(7字节) + 功能码(1字节) + 离散量输入寄存器的值

下面是一个实际的响应报文的内容:

0x2-request

MBAP header功能码字节数请求的数据1请求的数据2
01 b9 00 00 00 05 0101021202

返回的第一个字节12,转化为二进制为00010010, 其中bit0代表00寄存器,bit7代表07寄存器。

0x70x60x50x40x30x20x10x0
00010010

返回的第二个字节02,转化为二进制为00000010, 其中bit0代表08寄存器,bit1代表09寄存器。

0x90x8
10

功能码0x03:读保持寄存器

功能码0x03用于读取保持寄存器的值,从远程设备中读保持寄存器连续块的内容。

发送报文

请求报文的结构如下:

MBAP header + 功能码 + 起始地址H 起始地址L + 寄存器数量H 寄存器数量L(共12字节)

下面是一个实际的例子:

0x3-request

按照协议对照如下:

MBAP header功能码起始地址寄存器数量
05 f1 00 00 00 06 010300 0000 0a

响应报文

响应报文的结构由下面几个部分组成:

MBAP header + 功能码 + 数据长度 + 寄存器数据

数据总长度 = 9 + 寄存器数量 × 2

下面是一个response的结构:

0x3-response

从中我们可以提取出下面的对应关系:

MBAP header功能码字节数第0byte值第1byte值第2byte值第3byte值第4byte值第5byte值第6byte值第7byte值第8byte值第9byte值
05 f1 00 00 00 17 01031401 2c00 0000 0000 3700 0000 0000 6400 0000 3c00 00

由上面的对应关系,我们可以提取出我们想要读取的保持寄存器的值:

第0个寄存器第1个寄存器第2个寄存器第3个寄存器第4个寄存器第5个寄存器第6个寄存器第7个寄存器第8个寄存器第9个寄存器
3000055001000600

功能码0x04:读输入寄存器

功能码0x4用于读取输入寄存器的值,输入寄存器是只读的,因此没有功能码可以写输入寄存器。

发送报文

请求报文格式如下:

MBAP header + 功能码 + 起始地址H 起始地址L + 寄存器数量H 寄存器数量L(共12字节)

下面是一个实际的例子:

0x4-request

MBAP header功能码起始地址寄存器数量
0b f8 00 00 00 06 010400 0000 0a

该请求的含义是读取0-9号寄存器的值。

响应报文

响应报文的结构由下面几个部分组成:

MBAP header + 功能码 + 数据长度 + 寄存器数据

数据总长度 = 9 + 寄存器数量 × 2

下面是一个response的结构:

0x4-response

从中我们可以提取出下面的对应关系:

MBAP header功能码字节数第0byte值第1byte值第2byte值第3byte值第4byte值第5byte值第6byte值第7byte值第8byte值第9byte值
0b f8 00 00 00 17 01041400 0000 0000 c800 0001 2c00 0000 0000 0000 4200 00

由上面的对应关系,我们可以提取出我们想要读取的保持寄存器的值:

第0个寄存器第1个寄存器第2个寄存器第3个寄存器第4个寄存器第5个寄存器第6个寄存器第7个寄存器第8个寄存器第9个寄存器
002000300000660

功能码0x06:写单个保持寄存器

在一个远程设备中写一个保持寄存器。

发送报文

请求报文格式如下:

MBAP header + 功能码 + 寄存器地址H 寄存器地址L + 寄存器值H 寄存器值L(共12字节)

下面是一个实际的例子:

0x6-request

MBAP header功能码保持寄存器地址保持寄存器的值
1F 97 00 00 00 06 010600 0400 64

该请求的含义是向地址为0x4的寄存器写入100。

响应报文

响应报文如下:

MBAP header + 功能码 + 寄存器地址H 寄存器地址L + 寄存器值H 寄存器值L(共12字节)

成功响应的报文与发送报文格式相同。

0x6-response

功能码0x10:写多个保持寄存器

在一个远程设备中写连续寄存器块(1~123个寄存器)

发送报文

请求报文格式如下:

MBAP header + 功能码 + 起始地址H 起始地址L + 寄存器数量H 寄存器数量L + 字节长度 + 寄存器值(13+寄存器数量×2)

0x10-request

MBAP header功能码起始地址长度字节数字节0数据字节1数据字节2数据字节3数据字节4数据字节5数据字节6数据字节7数据字节8数据字节9数据
00 26 00 00 00 1b 011000 0000 0a14 0000 0000 0000 0000 0000 c800 0000 0000 6400 0000 64

响应报文

响应报文如下:

MBAP header + 功能码 + 起始地址H 起始地址L + 寄存器数量H 寄存器数量L(共12字节)

0x10-response

MBAP header功能码起始地址长度
00 26 00 00 00 1b 011000 0000 0a

实用调试工具

在研究modbus的过程中, 大量的使用了modbus poll和 modbus slave软件,这个软件可以很好的帮助理解modbus-tcp协议。

modbus poll: modbus客户端工具(主站)

modbus slave: modbus服务端工具(从站)

相关文章:

modbus-TCP协议详解

modbus-TCP协议详解 1996年施耐德公司推出基于以太网TCP/IP的modbus协议:modbus-TCP。 MODBUS-TCP使MODBUS-RTU协议运行于以太网,MODBUS-TCP使用TCP/IP以太网在站点间传送MODBUS报文,MODBUS-TCP结合了以太网物理网络和网络标准TCP/IP以及以…...

爬虫项目(12):正则、多线程抓取腾讯动漫,Flask展示数据

文章目录 书籍推荐正则抓取腾讯动漫数据Flask展示数据 书籍推荐 如果你对Python网络爬虫感兴趣,强烈推荐你阅读《Python网络爬虫入门到实战》。这本书详细介绍了Python网络爬虫的基础知识和高级技巧,是每位爬虫开发者的必读之作。详细介绍见&#x1f44…...

gedit编辑文件时常用快捷键

问题: 最近在修改文件时提到了gedit这个工具,与vi一样也是一个文件编辑器。但是在命令方面又有不同,在快捷键方面和Windows的使用习惯非常相似。 gedit举例: CTRL-Z:撤销CTRL-C:复制CTRL-V:粘贴CTRL-T:缩进CTRL-Q:退出CTRL-S:保…...

【C++干货铺】剖析string | 底层实现

个人主页点击直达:小白不是程序媛 C专栏:C干货铺 代码仓库:Gitee 目录 成员变量 成员函数 构造和拷贝构造 赋值重载 析构函数 operator[ ] size 迭代器 reserve(扩容函数) push_back(尾插函数&#xff09…...

nmap原理与使用

kali的命令行中可以直接使用 nmap 命令,打开一个「终端」,输入 nmap 后回车,可以看到 nmap 的版本,证明 nmap 可用。 一、端口扫描 扫描主机的「开放端口」,在nmap后面直接跟主机IP(默认扫描1000个端口&am…...

AI批量剪辑矩阵托管系统----源码技术开发

AI批量剪辑矩阵托管系统----源码技术开发 抖音账号矩阵系统是基于抖音开放平台研发的用于管理和运营多个抖音账号的平台。它可以帮助用户管理账号、发布内容、营销推广、分析数据等多项任务,从而提高账号的曝光度和影响力。 具体来说,抖音账号矩阵系统可…...

Pandas数据预处理python 数据分析之4——pandas 预处理在线闯关_头歌实践教学平台

Pandas数据预处理python 数据分析之4——pandas 预处理 第1关 数据读取与合并第2关 数据清洗第3关 数据转换 第1关 数据读取与合并 任务描述 本关任务:加载 csv 数据集,实现 DataFrame 合并。 编程要求 根据提示,在右侧编辑器补充代码&#…...

[html] 动态炫彩渐变背景

废话不多说&#xff0c;直接上源码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>ZXW-NUDT: 动态炫…...

AI 绘画 | Stable Diffusion 高清修复、细节优化

前言 在 Stable Diffusion 想要生成高清分辨率的图片。在文生图的功能里&#xff0c;需要设置更大的宽度和高度。在图生图的功能里&#xff0c;需要设置更大的重绘尺寸或者重绘尺寸。但是设置完更大的图像分辨率&#xff0c;需要更大显存&#xff0c;1024*1024的至少要电脑的空…...

想要检测TikTok网络是否安全?这五个网站请收好

Tiktok目前在海外大火&#xff0c;越来越多的人想要进入TikTok的海外市场并捞一桶金。然而&#xff0c;成功并非易事。想要在TikTok中立足&#xff0c;我们必须保证我们的设备、网络环境和网络节点完全符合官方的要求&#xff0c;并且没有任何异常或风险。那么我们该如何设置、…...

【docker:容器提交成镜像】

容器创建部分请看&#xff1a;点击此处查看我的另一篇文章 容器提交为镜像 docker commit -a "sinwa lee" -m "首页变化" mynginx lxhnginx:1.0docker run -d -p 88:80 --name lxhnginx lxhnginx:1.0为啥没有变啊&#xff0c;首页&#xff1f; 镜像打包 …...

UE5中一机一码功能

创建蓝图函数库 1、获取第一个有效的硬盘ID // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "GetDiskIDClass.gen…...

gpt支持json格式的数据返回(response_format: ‘json_object‘)

Api.h5.chatCreateChatCompletion({model: gpt-3.5-turbo-1106,token: sk-f4fe8b67-fcbe-46fd-8cc9-fd1dac5d6d59,messages: [{role: user,content:使用json格式返回十二生肖&#xff0c;包含中文名和英文名&#xff0c;[{id:"1", enName:"", cnName: &quo…...

MySQL(13):约束

约束(constraint)概述 数据完整性&#xff08;Data Integrity&#xff09;是指数据的精确性&#xff08;Accuracy&#xff09;和可靠性&#xff08;Reliability&#xff09;。 它是防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成无效操作或错误信息 而提…...

可以为一个servlet定义多个servlet-mapping、或url-pattern

在web描述符文件web.xml文件中&#xff0c;可以为同一个servlet定义多个servlet-mapping&#xff1b;也可以在同一个servlet-mapping中&#xff0c;定义多个url-pattern。也就是说&#xff0c;可以把多个地址&#xff08;相对于上下文路径&#xff09;映射到同一个servlet处理。…...

.net在使用存储过程中IN参数的拼接方案,使用Join()方法

有时候拼接SQL语句时&#xff0c;可能会需要将list中的元素都加上单引号&#xff0c;并以逗号分开&#xff0c;但是Join只能简单的分开&#xff0c;没有有单引号&#xff01; 1.第一种拼接方案 List<string> arrIds new List<string>(); arrIds.Add("aa&qu…...

基于RK3399的室内健身魔镜方案

I 方案背景 一、健身魔镜的兴起 2020年疫情席卷全球&#xff0c;宅家是防疫的措施之一&#xff0c;因而宅家运动火爆&#xff0c;随之而来的宅家运动器材也风靡起来&#xff0c;其中包含既有颜值又具有多种功能的健身魔镜。 Ⅱ 方案介绍 一、健身魔镜的方案介绍 …...

leetCode 25.K 个一组翻转链表

给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。k 是一个正整数&#xff0c;它的值小于 或 等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。你不能只是单纯的改变节点内部的值&a…...

ElasticSearch中常见的分词器介绍

文章目录 ElasticSearch中常见的分词器介绍前言分词器的作用如何指定分词器分词器的组成分词器的类型标准分词器空格分词器简单分词器关键词分词器停用词分词器IK分词器NGram分词器正则匹配分词器语言分词器自定义分词器 ElasticSearch中常见的分词器介绍 前言 ElasticSearch是…...

前端案例-css实现ul中对li进行换行

场景描述&#xff1a; 我想要实现&#xff0c;在展示的item个数少于4个的时候&#xff0c;则排成一行&#xff0c;并且均分&#xff08;比如说有3个&#xff0c;则每个的宽度为33.3%&#xff09;&#xff0c;如果item 个数大于4&#xff0c;则进行换行。 效果如下&#xff1a…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

Go 并发编程基础:通道(Channel)的使用

在 Go 中&#xff0c;Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式&#xff0c;用于在多个 Goroutine 之间传递数据&#xff0c;从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...