Modbus协议总结

Modbus TCP 通信概述

Modbus TCP是一种基于TCP/IP协议的Modbus通信协议,用于在客户机和服务器之间进行数据通信。它常用于工业自动化控制、电力监控与管理、温湿度监测等领域。Modbus TCP协议使用标准的TCP/IP协议栈,通过以太网进行通信,并支持多个设备同时访问同一个Modbus TCP服务器。

Modbus TCP协议是在RTU协议前面添加MBAP报文头,由于TCP是基于可靠连接的服务,RTU协议中的CRC校验码就不再需要,所以在Modbus TCP协议中是没有CRC校验码。(使用上的主要区别)。

通信原理

  • TCP/IP协议:Modbus TCP使用TCP/IP协议作为底层通信协议。TCP(传输控制协议)提供了可靠的、面向连接的通信,确保数据的可靠传输;IP(互联网协议)提供了网络寻址和路由功能,使得不同设备能够相互通信。
  • 连接建立:客户机通过建立TCP连接与服务器进行通信。客户机通过指定服务器的IP地址和端口号(默认为502)来建立连接。
  • 帧结构:Modbus TCP使用了标准的Modbus帧结构,并在TCP报文中传输。帧结构包括事务标识符、协议标识符(固定为0x0000)、长度字段、单元标识符、功能码、数据字段和CRC校验(在Modbus TCP中不使用,由TCP/IP协议保证数据完整性)。

Modbus TCP 通信

通信过程

  1. 连接建立:客户机主动建立TCP连接,与服务器进行通信。
  2. 请求发送:客户机向服务器发送请求消息,请求读取或写入数据。请求消息中包含了事务标识符、协议标识符、长度字段、单元标识符、功能码以及相关的数据和操作参数。
  3. 响应接收:服务器接收到客户机的请求后,根据请求的功能码执行相应的操作,并生成响应消息。响应消息中包含了事务标识符、协议标识符、长度字段、单元标识符、功能码以及请求的结果数据。
  4. 异常处理:如果服务器无法满足客户机的请求,或者执行请求时发生错误,服务器将生成一个异常响应消息。异常响应消息包含了事务标识符、协议标识符、异常功能码和异常代码。
  5. 连接关闭:当通信完成后,客户机可以选择关闭TCP连接。

Modbus TCP 协议帧结构

Modbus TCP在Modbus串行通信的基础上,去除了校验(由于TCP本身就带有校验)和设备地址(Modbus TCP弱化了设备地址,用IP地址来取代)。

Modbus TCP协议帧由两部分组成:MBAP(Modbus Application Protocol)头部和PDU(Protocol Data Unit)数据单元

1)MBAP头部

MBAP报文头由事务元标识符、协议标识符、长度和单元标识符构成,总共为7个字节长度,其具体描述如下:

2)PDU数据单元

PDU数据单元由功能码(Function Code)数据字段组成。

  • 功能码(Function Code):用于指定请求的类型,长度为1字节,功能码主要有如下类型:

  • 数据字段:数据部分的长度和内容取决于功能码的类型和请求的具体要求。

3)PDU数据单元类型

在Modbus TCP中,PDU有三种类型:

A)请求型协议数据单元(Request PDU)

请求型协议数据单元(Request PDU)是由Modbus主站(客户端)发送给从站(服务器)的PDU,用于请求数据或服务。对于读取请求,数据部分可能包含要读取的寄存器地址和数量;对于写入请求,数据部分可能包含要写入的值和地址。

以读取保持寄存器为例(功能码03),Request PDU可能如下:

  • 单元标识符(1字节):0x01(假设为非广播地址)
  • 功能码(1字节):0x03(读取保持寄存器)
  • 起始地址(2字节):0x0000(要读取的寄存器的起始地址)
  • 寄存器数量(2字节):0x0002(要读取的寄存器数量)

B)应答型协议数据单元(Response PDU)

应答型协议数据单元(Response PDU)是由Modbus从站(服务器)发送给主站(客户端)的PDU,用于响应主站的请求。

以读取保持寄存器为例(功能码03),Response PDU可能如下:

  • 单元标识符(1字节):0x01
  • 功能码(1字节):0x03(与请求PDU中的功能码相同,表示读取保持寄存器)
  • 字节数(2字节):0x0008(表示接下来的数据字段有8个字节)
  • 数据(8字节):假设为读取到的保持寄存器的值

C)异常应答型协议数据单元(Exception Response PDU):当服务器无法处理客户端的请求时,会发送一个异常应答PDU,通知客户端发生了错误。

Modbus TCP使用的通讯资源端口号

在Modbus服务器中按缺省协议使用Port 502 通信端口,在Modbus客户器程序中设置任意通信端口,为避免与其他通讯协议的冲突一般建议2000开始可以使用。

Modbus TCP 通信示例

以通过Modbus TCP的03功能码读取起始地址为0000中的温度数据(以float数据类型表示)为例:

  • Modbus TCP 请求帧

请求帧包括以下字段:

Transaction Identifier: 
0x1234  (随意选择的标识符,用于匹配响应)  
Protocol Identifier:     0x0000 (Modbus协议标识符)  
Length:                  0x0006 (后续字节的长度,包括单元标识符、功能码、起始地址和寄存器数量长度)  
Unit Identifier:         0x01   (设备或从站标识符)  
Function Code:           0x03   (读取多个保持寄存器的功能码)  
Starting Address:        0x0000 (起始地址,温度数据存储的地址)  
Quantity of Registers:   0x0002 (要读取的寄存器数量,因为float是32位,所以需要2个寄存器)

将上述信息转换成十六进制表示的请求报文如下:

12 34 00 00 00 06 01 03 00 00 00 02
  • Modbus TCP 响应帧

假设服务器正确响应,响应帧包括以下字段:

Transaction Identifier: 
0x1234 (与请求中的事务标识符相匹配)  
Protocol Identifier:    0x0000 (Modbus协议标识符)  
Length:                 0x0007 (后续字节的长度)  
Unit Identifier:        0x01   (设备或从站标识符)  
Function Code:          0x03   (读取多个保持寄存器的功能码)  
Byte Count:             0x04   (后续数据字节的数量,因为读取了2个寄存器,所以总共4个字节)  
Register Data:          xx xx xx xx (实际的寄存器数据,表示float类型的温度值)

将上述响应报文转换成十六进制可能如下:

12 34 00 00 00 07 01 03 04 xx xx xx xx

这里的 xx xx xx xx 代表从寄存器中读取的4个字节的数据,这些字节需要按照Modbus规范(通常是两个字节颠倒顺序,即大端模式或小端模式,具体取决于设备的实现)来解析成一个float类型的温度值。

Modbus TCP 异常应答

当发生通讯异常时,响应前7位仍然为modbus正常协议格式,第八位响应功能码(请求功能码+0x80),第九位异常码。

异常数据即包含异常码的数据:

目前使用的异常码:01,02,03和04。

  • 响应功能码 = 请求功能码 + 0x80

  • 响应报文提供异常码显示出错原因

常见异常码含义:

功能码详解

声明:协议中的起始地址指的是索引,后面的地址指的是具体地址,对于任意一个存储区,索引都是从0开始的,但是对应的具体地址,与存储区是相关的,比如输出线圈,0对应00001;输入线圈,0对应10001;输入寄存器,0对应30001;保持寄存器,0对应40001。即起始地址转为十进制后+1等于对应plc的实际地址
————————————————

1.读取输出线圈
发送报文格式如下:

事务处理/协议标识符 报文长度 单元标识符 功能码 起始高 起始低 数量高 数量低
00 00 00 00 00 06 01 01 00 13 00 1B

发送报文含义:读取服务器1号从站输出线圈,起始地址为0x13=19,对应地址为00020,线圈数量为0x1B=27,即读取1号从站输出线圈,地址从00020-00046,共27个线圈的状态值。

返回报文格式如下:

事务处理/协议标识符 报文长度 单元标识码 功能码 字节计数 线圈字节
00 00 00 00 00 07 01 01 04 CD 6B B2 02

返回报文含义:返回服务器1号从站输出线圈00020-00046,共27个线圈的状态值,返回字节数为4个,分别为CD 6B B2 05。

CD=1100 1101 对应 00020-00027

6B=0110 1011 对应 00028-00035

B2=1011 0010 对应 00036-00043

05=0000 0101 对应 00044-00046

2.读取输入线圈
发送报文格式如下:

事务处理/协议标识符 报文长度 单元标识符 功能码 起始高 起始低 数量高 数量低
00 00 00 00 00 06 01 02 00 C4 00 1D

发送报文含义:读取服务器1号从站输入线圈,起始地址为0xC4=196,对应地址为10197,线圈数量为0x1D=29,即读取1号从站输入线圈,地址从10197-10225,共29个线圈的状态值。

返回报文格式

事务处理/协议标识符 报文长度 单元标识码 功能码 字节计数 线圈字节
00 00 00 00 00 07 01 02 04 CD 6B B2 05

返回报文含义:返回服务器1号从站输入线圈10197-10225,共29个线圈的状态值,返回字节数为4个,分别为CD 6B B2 05。

CD=1100 1101 对应 10197-10204

6B=0110 1011 对应 10205-10212

B2=1011 0010 对应 10213-10220

05=0000 0101 对应 10221-10225

3.读取保持寄存器
发送报文格式如下:

事务处理/协议标识符 报文长度 单元标识符 功能码 起始高 起始低 数量高 数量低
00 00 00 00 00 06 01 03 00 6B 00 02

发送报文含义:读取服务器1号从站保持寄存器,起始地址为0x6B=107,对应地址为40108,寄存器数量为0x02=2,即读取1号从站保持寄存器,地址从40108-40109,共2个寄存器的数值。

返回报文格式如下:

事务处理/协议标识符 报文长度 单元标识符 功能码 字节计数 1高 1低 2高 2低
00 00 00 00 00 07 01 03 04 02 2B 01 06

返回报文含义:返回服务器1号从站保持寄存器40108-40109,共2个寄存器的数值,返回字节数为4个,分别为02 2B 01 06,40108对应数值为0x022B,40109对应数值为0x0106。

4.读取输入寄存器
发送报文格式如下:

事务处理/协议标识符 报文长度 单元标识符 功能码 起始高 起始低 数量高 数量低
00 00 00 00 00 06 01 04 00 6B 00 02

发送报文含义:读取服务器1号从站输入寄存器,起始地址为0x6B=107,对应地址为30108,寄存器数量为0x02=2,即读取1号从站保持寄存器,地址从30108-30109,共2个寄存器的数值。

返回报文格式如下:

事务处理/协议标识符 报文长度 单元标识符 功能码 字节计数 1高 1低 2高 2低
00 00 00 00 00 07 01 04 04 02 2B 01 06

返回报文含义:返回服务器1号从站输入寄存器30108-30109,共2个寄存器的数值,返回字节数为4个,分别为02 2B 01 06,30108对应数值为0x022B,30109对应数值为0x0106。

5.预置单线圈
发送报文格式如下:

事务处理/协议标识符 报文长度 单元标识符 功能码 线圈高 线圈低 断通标志 断通标志
00 00 00 00 00 06 01 05 00 AC FF 00

发送报文含义:预置服务器1号从站单个线圈的值,线圈地址为0x00AC=172,对应地址为00173,断通标志0xFF00表示置位,0x000表示复位,即置位1号从站输出线圈00173。

返回报文格式如下:

事务处理/协议标识符 报文长度 单元标识符 功能码 线圈高 线圈低 断通标志 断通标志
00 00 00 00 00 06 01 05 00 AC FF 00

返回报文含义:预置单输出线圈原报文返回。

6.预置单寄存器
发送报文格式如下:

事务处理/协议标识符 报文长度 单元标识符 功能码 寄存器高 寄存器低 写入值 写入值
00 00 00 00 00 06 01 06 00 87 03 9E

发送报文含义:预置服务器1号从站单个保持寄存器的值,寄存器地址为0x0087=135,对应地址为40136,写入值为0x039E,即预置1号从站保持寄存器40136值为0x039E。

返回报文格式如下:

事务处理/协议标识符 报文长度 单元标识符 功能码 线圈高 线圈低 断通标志 断通标志
00 00 00 00 00 06 01 06 00 87 03 9E

返回报文含义:预置单保持寄存器原报文返回。

7.预置多线圈
发送报文格式如下:

事务处理/协议标识符 报文长度 单元标识符 功能码 起始 数量 字节数 字节
00 00 00 00 00 09 01 0F 00 13 00 0A 02 CD 00

发送报文含义:预置服务器1号从站多个线圈的值,线圈地址为0x0013=19,对应地址为00020,线圈数为0x0A=10,写入值为0xCD00,即预置1号从站线圈00020-00027=0xCD=1100 1101,00028-00029=0x00=0000 0000。

返回报文格式如下:

事务处理/协议标识符 报文长度 单元标识码 功能码 起始 数量
00 00 00 00 00 06 01 0F 00 13 00 0A

返回报文含义:预置多输出线圈返回报文是在原报文基础上除去字节数及具体字节后返回。

8.预置多寄存器
发送报文格式如下:

事务处理/协议标识符 报文长度 单元标识符 功能码 起始 数量 字节数 字节
00 00 00 00 00 0B 01 10 00 87 00 02 04 01 05 0A 10

发送报文含义:预置服务器1号从站多个寄存器的值,寄存器地址为0x0087=135,起始地址为40136,寄存器数量为0x02=2,结束地址为40137,写入值为0xCD00和0x0A10,即预置1号从站寄存器40136=0x0105,40137=0x0A10。

返回报文格式如下:

事务处理/协议标识符 报文长度 单元标识码 功能码 起始 数量
00 00 00 00 00 07 01 10 00 87 00 02

————————————————

posted @   ·面具·  阅读(84)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示