■ 1. ModBus-TCP/IP学习链接

Modbus TCP通信笔记

■ 2. ModBus-TCP/IP简介

RS-485常与MODBUS协议结合使用,MODBUS协议定义了数据帧的结构和通信规则。
ModBus 网络只有一个主机,所有通信都由他发出
网络可支持 247 个之多的远程从属控制器

Modbus协议包括ASCII、RTU、TCP等,并没有规定物理层。此协议定义了控制器能够认识和使用的消息结构
Modbus的ASCII、RTU协议规定了消息、数据的结构、命令和就答的方式。

数据通讯采用 Maser/Slave方式,
Master端发出数据请求消息,
Slave端 接收到正确消息后就可以发送数据到Master端以响应请求;
Master端 也可以直接发消息修改Slave端的数据,实现双向读写。
Modbus协议需要对数据进行校验,串行协议中除有奇偶校验外,ASCII模式采用LRC校验,RTU模式采用16位CRC校验。

一种基于以太网TCP/IP的应用层协议——Modbus TCP/IP协议。
Modbus TCP是Modbus协议在以太网上的一种实现,它保留了Modbus协议的核心功能和数据模型,但对消息封装进行了调整,使其符合TCP/IP的要求。
在进行下一步之前我们首先对Modbus中的一些概念做一个了解。
在这里插入图片描述

■ 2.1 Modbus 存储区

存储的数据类型分为布尔量和寄存器
==Modbus规定了4个存储区,分别是0、1、3、4 ==

所属区名称地址范围(5位)数据类型存储类型通讯类型S7-200 SMART 数据区
0区输出线圈(D0 )00001-09999布尔量(0-1)读/写Q0.0-Q31.7
1区输入线圈(DI)10001-19999布尔量(0-1)I0.0-I31.7
2区输出寄存器(A0)20001-29999寄存器(16位)读/写AIW0-AIW110
3区输入寄存器(AI)30001-39999寄存器 16位)T-T+2*(xxxx-1)

■ 2.2 Modbus 地址映射到 CPU 地址

Modbus 地址CPU 地址
00001Q0.0
00002Q0.1
…………
10001I0.0
10002I0.1
…………
30001AIW0
30002AIW2
…………
40001Vx(保持寄存器起始地址) 例:VW0
40002Vx+2 =(保持寄存器起始地址+2)例:VW2
…… ……

■ 2.3 操作对象

对象含义
线圈PLC的输出位,开关量,在Modbus中可读可写
离散量PLC的输入位,开关量,在Modbus中只读
输入寄存器PLC中只能从模拟量输入端改变的寄存器,在Modbus中只读
保持寄存器PLC中用于输出模拟量信号的寄存器,在Modbus中可读可写

■ 2.4 功能码

项目功能码说明
读操作
0x01:读输出线圈状态。
0x02:读输入线圈状态。
0x03:读输出寄存器的值。
0x04:读输入寄存器的值
写操作
0x05:写单个线圈状态。
0x06:写单个寄存器的值。
0x0F:写多个线圈状态。
0x10:写多个寄存器的值。

在这里插入图片描述

■ 2.5 角色

主站(Master)角色:客户端(Client),主动发起通信请求。
从站(Slave)角色:服务器(Server)被动响应请求。

■ 2.6 字节序: Modbus使用大端序(Big-Endian)

Modbus使用大端序(Big-Endian)

■ 2.7 错误码

在这里插入图片描述

■ 3. Modbus TCP/IP的报文帧

ModbusTCP的数据帧可分为两部分:MBAP+PDU
MBAP:包含事务标识符、协议标识符、消息长度、设备地址
Modbus PDU:原始Modbus协议的数据部分,包括功能码、数据地址和数据值。
在这里插入图片描述

■ MBAP报文头

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

■ 帧结构PDU

PDU由功能码+数据组成。功能码为1字节,数据长度不定,由具体功能决定。

■ ADU详细结构

■ 0x01:读线圈

在从站中读连续线圈状态,ON=1,OFF=0。

请求:

MBAP功能码起始地址H
起始地址L
线圈数量H
线圈数量L
7字节1字节2字节2字节

响应:

MBAP功能码线圈数据长度数据
7字节1字节1字节线圈数据

这是一个请求读线圈输出20-38的实例:
在这里插入图片描述

实验一:如:数据长度为0x01个字节,数据为0x01,第一个线圈为ON,其余为OFF。

主站(客户端):发送 00 01 00 00 00 06 01	01	00	00	00	08
00 01 	事务标识符
00 00 	协议标识符
00 06 	后面报文长度
01	  	地址
01	  	功能码   0x01:读线圈
00	00	起始地址
00	08  线圈数量 (位) 


主站(客户端):接收 00 01 00 00 00 04 01	01	01	01
00 01   事务标识符
00 00   协议标识符
00 04   后面报文长度
01	    地址
01	    功能码   0x01:读线圈
01		线圈数据长度  线圈数据长度=1+(线圈数量-1)/8
01      数据

实验二:自己验证OK

■ 0x02:读离散量输入

在从站中读连续离散量输入状态,ON=1,OFF=0。

请求:

MBAP功能码起始地址H
起始地址L
离散量输入数量H
离散量输入数量L
7字节1字节2字节2字节

响应:

MBAP功能码离散量输入数据长度数据
7字节1字节1字节
长度=1+(离散量输入数量-1)/8
离散量输入数据

这是一个请求读取离散量输入197-218的实例:
在这里插入图片描述

实验一:如:在从站(服务器)0x01中,读取开始地址为0x0000的线圈数据,读0x0008位。

主站(客户端):发送 00 01 00 00 00 06 01	02	00	00	00	08
00 01  事务标识符
00 00  协议标识符
00 06  后面报文长度
01	   地址 
02	   功能码   0x02:读离散量输入 
00 00  起始地址
00 08  离散量输入数量   多少位


主站(客户端):接收 00 01 00 00 00 04 01	02	01	01
00 01  事务标识符
00 00  协议标识符
00 04  后面报文长度
01	   地址
02	   功能码  0x02:读离散量输入 
01     数据长度   数据长度=1+(离散量输入-1)/8
01     数据

实验二:自己验证OK

在这里插入代码片

实验一:
如:在从站(服务器)0x01中,读取开始地址为0x0000的线圈数据,读0x0008位。

主站(客户端):发送 00 01 00 00 00 06 01	02	00	00	00	08
00 01  事务标识符
00 00  协议标识符
00 06  后面报文长度
01	   地址 
02	   功能码   0x02:读离散量输入 
00 00  起始地址
00 08  离散量输入数量


主站(客户端):接收 00 01 00 00 00 04 01	02	01	01
00 01  事务标识符
00 00  协议标识符
00 04  后面报文长度
01	   地址
02	   功能码  0x02:读离散量输入 
01     数据长度     长度=1+(离散量输入数量-1)/8 
01     数据

实验二:自己验证OK

在这里插入代码片

■ 0x03:读保持寄存器

请求

MBAP功能码起始地址H
起始地址L
寄存器数量H
寄存器数量L
7字节1字节2字节2字节

响应:

MBAP功能码数据长度数据
7字节1字节1字节
数据长度=寄存器数量*2
数据

==这是一个请求读寄存器108-110的实例: ==
在这里插入图片描述

实验一:如:在从站0x01中,读取开始地址为0x0000的保持寄存器数据,读0x003个

主站(客户端):发送 00 01 00 00 00 06 01	03	00	00	00	03
00 01 	事务标识符
00 00 	协议标识符
00 06 	后面报文长度
01	  	地址
03	  	功能码   0x03:读保持寄存器
00 00 	起始地址	
00 03 	寄存器数量


主站(客户端):接收 00 01 00 00 00 09 01	03	06	00 21 00 00 00 00
00 01 	事务标识符
00 00 	协议标识符
00 09   后面报文长度
01	    地址
03		功能码   0x03:读保持寄存器
06	    数据长度    数据长度=寄存器数量*2
00 21 00 00 00 00  数据

实验二:自己验证OK

在这里插入代码片

■ 0x04:读输入寄存器

请求

MBAP功能码起始地址H
起始地址L
寄存器数量H
寄存器数量L
7字节1字节2字节2字节

响应:

MBAP功能码数据长度数据
7字节1字节1字节数据

==这是一个请求读输入寄存器9的实例: ==
在这里插入图片描述

实验一:如:在从站0x01中,读取开始地址为0x0000的输入寄存器数据,读0x003个

主站(客户端):发送 00 01 00 00 00 06 01	04	00	00	00	03
00 01 	事务标识符
00 00 	协议标识符
00 06 	后面报文长度
01		地址
04		功能码   0x04:读输入寄存器
00	00	起始地址
00	03	寄存器数量

主站(客户端):接收 00 01 00 00 00 09 01	04	06	00 21 00 00 00 00
00 01 	事务标识符
00 00 	协议标识符
00 09  	后面报文长度
01		地址
04		功能码  0x04:读输入寄存器
06	    数据长度   数据长度=寄存器数量*2
00 21 00 00 00 00  数据

实验二:自己验证OK

在这里插入代码片

■ 0x05:写单个线圈

请求

MBAP功能码线圈地址H
线圈地址L
输出值H
输出值L
7字节1字节2字节2字节
0xFF00 请求输出为ON,
0x0000 请求输出为OFF

响应:

MBAP功能码线圈地址H
线圈地址L
输出值H
输出值L
7字节1字节2字节2字节

==这是一个请求写线圈173为ON的实例: ==
在这里插入图片描述

实验一:如:在从站(服务器)0x01中,将地址为0x0000 的线圈设置为ON

主站(客户端):发送 00 01 00 00 00 06 01	05	00	00	FF	00
00 01 	事务标识符
00 00 	协议标识符
00 06 	后面报文长度
01		地址
05		功能码   0x05:写单个线圈
00	00	起始地址  
FF	00	输出值   0xFF00请求输出为ON, 0x000请求输出为OFF


主站(客户端):接收 00 01 00 00 00 06 01	05	00	00	FF	00
00 01 	事务标识符
00 00 	协议标识符
00 06 	后面报文长度
01		地址
05		功能码   0x05:写单个线圈
00	00	起始地址 
FF	00  输出值    0xFF00请求输出为ON, 0x000请求输出为OFF

实验二:自己验证OK

在这里插入代码片

■ 0x06:写单个寄存器

在主站(客户端)将从站(服务器)中的一个保持寄存器设置

请求:

MBAP功能码保持寄存器地址H
保持寄存器地址L
设置值H
设置值L
7字节1字节2字节2字节

响应:

MBAP功能码保持寄存器地址H
保持寄存器地址L
设置值H
设置值L
7字节1字节2字节2字节

这是一个请求将十六进制00 03写入寄存器2的实例:
在这里插入图片描述

实验一:如:在从站(服务器)0x01中,将地址为0x0000的保持寄存器设置为0x000A。

主站(客户端):发送 00 01 00 00 00 06 01	06	00	00	00	0A
00 01 	事务标识符
00 00 	协议标识符
00 06 	后面报文长度
01		地址
06		功能码  0x06:写单个保持寄存器
00 00	保持寄存器地址
00 0A	设置值


主站(客户端):接收 00 01 00 00 00 06 01	06	00	00	00	0A
00 01 	事务标识符
00 00 	协议标识符
00 06 	后面报文长度
01		地址
06		功能码  0x06:写单个保持寄存器
00 00	保持寄存器地址
00 0A	设置值

实验二:自己验证OK
主站:修改 42008地址 word 修改为88
只能主站(客户端)修改值后同步到从站(服务器),从站(服务器)修改后没有同步到主站

主站(客户端):发送 00 00 00 00 00 06 01 06 07 D7 00 58

//42008 WORD 修改为88
00 00  事务标识符
00 00  协议标识符
00 06  后面报文长度
01     地址
06     功能码  0x06:写单个保持寄存器
07 D7  寄存器地址          0x07D7 = 2007     
00 58  设置值              0x0058 = 88

主站(客户端):接收 00 00 00 00 00 06 01 06 07 D7 00 58
00 00  事务标识符
00 00  协议标识符
00 06  后面报文长度
01     地址
06     功能码  0x06:写单个保持寄存器
07 D7  寄存器地址          0x07D7 = 2007     
00 58  设置值              0x0058 = 88

■ 0x0F:写多个线圈

请求

MBAP功能码线圈起始地址H
线圈起始地址L
线圈数H
线圈数L
线圈输出字节长度线圈输出值
7字节1字节2字节2字节1字节
线圈输出字节长度=1+(线圈数-1)/8
(线圈输出字节长度)个字节

注意:线圈输出字节长度=1+(线圈数-1)/8

响应:

MBAP功能码线圈起始地址H
线圈起始地址L
线圈数H
线圈数L
7字节1字节2字节2字节

这是一个请求从线圈20开始写入10个线圈的实例:
在这里插入图片描述

实验一:如:在从站(服务器)0x01中,将以地址0x0000开始连续的4个线圈设置为ON

主站(客户端):发送 00 01 00 00 00 08 01	0F	00	00	00	04	01	0F
00 01 	事务标识符
00 00 	协议标识符
00 08 	后面报文长度
01		地址
0F		功能码   
00	00	线圈起始地址
00	04	线圈数 (位)
01		线圈输出字节长度  线圈输出字节长度=1+(线圈数-1)/8
0F		线圈输出值

主站(客户端):接收 00 01 00 00 00 06 01	0F	00	00	00	04
00 01 	事务标识符
00 00 	协议标识符
00 06 	后面报文长度
01		地址
0F		功能码
00	00	线圈起始地址
00	04	线圈数(位)

实验二:自己验证OK

在这里插入代码片

■ 0x10:写多个保持寄存器

请求

MBAP功能码寄存器起始地址H
寄存器起始地址L
寄存器数量H
寄存器数量L
数据字节长度寄存器数据
7字节1字节2字节2字节1字节
数据字节长度=寄存器数量×2
(数据字节长度)个字节

响应:

MBAP功能码寄存器起始地址H
寄存器起始地址L
寄存器数量H
寄存器数量L
7字节1字节2字节1字节

==这是一个请求将十六进制00 0A和01 02写入以2开始的两个寄存器的实例: ==
在这里插入图片描述

实验一:如:在从站(服务器)0x01中,向起始地址为0x0000,数量为0x0001的寄存器写入数据,数据长度为0x02,数据为0x000F

主站(客户端):发送 00 01 00 00 00 09 01	10	00	00	00	01	02	00 0F
00 01 	事务标识符
00 00 	协议标识符
00 09 	后面报文长度
01		地址
10		功能码
00	00	寄存器起始地址
00	01	寄存器数量
02		寄存器数据字节长度  寄存器数据字节长度=寄存器数量×2
00 0F	寄存器数据


主站(客户端):接收 00 01 00 00 00 06 01	10	00	00	00	01
00 01 	事务标识符
00 00 	协议标识符
00 06 	后面报文长度
01		地址
10		功能码
00	00	寄存器起始地址
00	01  寄存器数量

实验二:自己验证OK

在这里插入代码片

■ 4. Modbus TCP/IP 数据分析

在这里插入图片描述

主站(客户端):发送数据去读取从站数据 读取长度10个寄存器)并接收

Tx: --------------
00000000000601030000000A
Rx: --------------
(29)0000000000170103140001000A0014001E00280032003C00460050005A

Tx: --------------
00 00 
00 00 
00 06 后面报文长度
01    地址
03    功能码
00 00 起始地址
00 0A 读取长度   0xA=10个寄存器

Rx: --------------
00 00 事务标识符
00 00 协议标识符
00 17 后面报文长度 0x17 = 23个字节
01    地址
03    功能码
14    长度   数据的长度 0x14 = 20字节  和上面读取长度10对应上
00 01 00 0A 00 14 00 1E 00 28 00 32 00 3C 00 46 00 50 00 5A  寄存器的的值

从站(服务器):接收数据分析 并回复

Rx:00 00 00 00 00 06 01 03 00 00 00 0A 
Tx:00 00 00 00 00 17 01 03 14 00 01 00 0A 00 14 00 1E 00 28 00 32 00 3C 00 46 00 50 00 5A 

Rx:--------------
00 00 	事务标识符
00 00 	协议标识符
00 06	 后面报文长度
01    	地址
03    	功能码
00 00	 起始地址
00 0A	 读取长度10个寄存器  一个寄存器2个字节 所以接收回来是10*2字节

Tx:--------------
00 00 	事务标识符
00 00 	协议标识符
00 17 	后面报文长度 0x17 = 23个字节
01    	地址
03    	功能码
14    	长度   数据的长度 0x14 = 20字节  和上面读取长度10对应上
00 01 00 0A 00 14 00 1E 00 28 00 32 00 3C 00 46 00 50 00 5A  	寄存器的的值
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐