Modbus 协议核心知识学习笔记

一、Modbus 事务处理

Modbus 是一个请求与应答的通信协议。它像一次对话,主设备(客户端)发起请求,从设备(服务器端)进行处理并回复响应。

1. 协议分层:PDU 与 ADU

为了适应不同的网络(如串口RS485、以太网TCP/IP),Modbus 协议分为两层:

  • PDU(协议数据单元) :这是协议的核心,与具体网络无关。格式固定为:功能码 + 数据。功能码告诉从设备要做什么(如读或写),数据区提供具体信息(如寄存器地址、数量)。

  • ADU(应用数据单元) :这是在 PDU 基础上,为适应具体传输网络而增加的完整数据包。在串行网络中,它会在 PDU 前加上从设备地址 ,在后面加上差错校验码(如CRC)。

通用 Modbus 帧(ADU)结构如下:

地址域 功能域 (PDU) 差错校验
1字节 功能码 (1字节) + 数据 (N字节) 2字节 (如CRC)

2. 事务处理过程

  1. 正常处理:主设备发送查询ADU。从设备收到后,执行功能码指定的操作,然后返回一个正常的响应ADU。响应中通常包含原功能码和请求的数据或操作确认。

  2. 异常处理 :如果从设备接收到的请求有错误(如功能码不支持、寄存器地址不存在),它会返回一个异常响应。异常响应的功能码是在原功能码的最高位加上1(即原功能码值 + 0x80),并附带一个异常码来说明错误原因。

二、Modbus 功能码详解

功能码是 Modbus 协议的灵魂,它定义了操作的类型。功能码主要分为三类:公共功能码(已明确定义)、用户自定义功能码(65-72, 100-110)和保留功能码。

以下是常用的公共功能码详解:

01 (0x01) -- 读取线圈

  • 功能 :读取从设备线圈(即可读可写的数字量输出DO)的ON/OFF状态。

  • 查询报文:需指定起始线圈地址(2字节,从0开始)和要读取的线圈数量(2字节,1-2000)。

  • 响应报文 :返回一个字节计数,后面跟着状态数据。每个线圈的状态用1个比特(bit)表示(1=ON, 0=OFF),8个线圈的状态 packed 成1个字节。字节内的顺序是:第一个字节的最低位(LSB)对应起始地址线圈的状态。

  • 举例:读线圈地址19开始的37个状态。响应需要5个字节来存放37个比特的状态信息。

02 (0x02) -- 读取离散量输入

  • 功能 :读取从设备离散输入(即只读的数字量输入DI)的ON/OFF状态。

  • 报文格式 :与功能码01完全相同,只是功能码不同。同样指定起始地址和数量(1-2000),返回按比特打包的状态字节。

03 (0x03) -- 读取保持寄存器

  • 功能 :读取从设备保持寄存器(即可读可写的模拟量或参数,16位)的值。

  • 查询报文:需指定起始寄存器地址(2字节)和要读取的寄存器数量(2字节,1-125)。

  • 响应报文:返回一个字节计数(=寄存器数量 × 2),后面跟着每个寄存器的数据(每个寄存器2字节,高字节在前)。

  • 重要提示 :保持寄存器以字(Word,2字节) 为单位。若要读取32位浮点数,需要连续读取2个寄存器(4字节),并注意主从设备之间字节序(大小端)必须一致

04 (0x04) -- 读取输入寄存器

  • 功能 :读取从设备输入寄存器(即只读的模拟量输入AI,16位)的值。

  • 报文格式 :与功能码03完全相同,只是功能码不同。同样需要注意多字节数据的字节序问题。

05 (0x05) -- 写单个线圈

  • 功能 :将单个线圈设为ON或OFF。支持广播模式(地址0)。

  • 查询报文 :指定线圈地址(2字节)和设定值(2字节,只能为0xFF00(ON)或0x0000(OFF))。

  • 响应报文:成功时,原样返回查询报文作为确认。

06 (0x06) -- 写单个保持寄存器

  • 功能 :写入单个保持寄存器的值。支持广播模式

  • 查询报文:指定寄存器地址(2字节)和要写入的16位数据(2字节)。

  • 响应报文:成功时,原样返回查询报文作为确认。

08 (0x08) -- 诊断功能(仅用于串行链路)

  • 功能 :用于通信链路诊断和内部故障检测。通过2字节的子功能码区分具体诊断类型。

  • 常见子功能码

    • 0x0000:原样返回查询数据(用于回环测试)。

    • 0x0001:重启通信选项。

    • 0x000A:清除计数器和诊断寄存器。

    • 0x000B-0x0012:返回各种通信错误计数(如CRC错误、异常响应、设备忙等计数)。

  • 响应报文:通常根据子功能码返回相应的诊断数据。

15 (0x0F) -- 写多个线圈

  • 功能 :连续写入多个线圈的状态。支持广播模式

  • 查询报文 :指定起始地址、线圈数量(1-2000),以及一个字节数字段,后面跟着状态数据。状态数据中,每个线圈占1比特,打包成字节。

  • 响应报文:返回起始地址和成功写入的线圈数量作为确认。

16 (0x10) -- 写多个保持寄存器

  • 功能 :连续写入多个保持寄存器的值。支持广播模式

  • 查询报文 :指定起始地址、寄存器数量(1-123),以及一个字节数字段(=数量 × 2),后面跟着要写入的每个寄存器的数据(每个2字节)。

  • 响应报文:返回起始地址和成功写入的寄存器数量作为确认。

  • 重要应用 :此功能码常用于写入32位浮点数(需占2个寄存器)或64位双精度浮点数(需占4个寄存器),必须严格约定字节序

其他功能码摘要

  • 11 (0x0B):获取通信事件计数器。返回状态字和事件计数值。

  • 12 (0x0C):获取通信事件记录。返回更详细的事件日志,包括状态字、事件计数、消息计数和事件字节。

  • 17 (0x11):报告从站ID(仅用于串行链路)。读取从设备的标识信息、运行状态等。

三、Modbus 异常响应

当从设备无法正常处理请求时,会返回异常响应。

  1. 异常响应格式

    • 功能码 = 原始请求功能码 + 0x80(即将最高位置1)。

    • 数据区 = 1字节的异常码

  2. 常见异常码

    • 01:非法功能码(不支持该功能)。

    • 02:非法数据地址(请求的寄存器地址不存在)。

    • 03:非法数据值(发送的数据超出有效范围或格式错误)。

    • 04:从站设备故障(从设备内部执行错误)。

举例 :主设备发送功能码04请求读取不存在的输入寄存器。从设备返回功能码 0x84 (04+0x80) 和异常码 0x02

四、核心要点与复习提示

  1. 牢记四种寄存器:结合硬件理解线圈(DO)、离散输入(DI)、保持寄存器(AO/参数)、输入寄存器(AI)。

  2. 理解通信模型:掌握"地址+功能码+数据+校验"的ADU结构,以及"请求-响应"的事务流程。

  3. 区分位与字操作

    • 功能码 01, 02, 05, 15 操作位(比特),状态打包在字节里。

    • 功能码 03, 04, 06, 16 操作字(2字节),数据以16位为单位传输。

  4. 注意地址起始 :在协议PDU中,所有线圈和寄存器地址都从0开始计数

  5. 关注广播模式:功能码05、06、15、16支持广播(地址0),用于同时控制所有从设备。

  6. 警惕字节序问题 :处理32/64位数据(浮点数)时,必须在主从设备间约定好字节顺序(大端或小端)。

  7. 看懂异常响应:功能码值大于0x80表示异常,需根据异常码排查问题。

通过分析具体功能码的报文示例,并理解正常与异常的处理路径,可以深入掌握 Modbus 协议的工作机制,为实际开发和调试打下坚实基础。

相关推荐
red_redemption44 分钟前
自由学习记录(214)
学习
疯狂打码的少年1 小时前
【数据结构】树的基本概念与二叉树定义
java·数据结构·笔记·算法
马上去吃汉堡王1 小时前
Windows11安装Geant4
笔记
气泡水。1 小时前
RHCSA笔记实记
linux·笔记
祈禾2 小时前
Redis三大特殊数据类型
运维·服务器·数据库·redis·笔记·缓存
祈禾2 小时前
计算机组成原理之编译、汇编、链接、解释
开发语言·汇编·笔记·学习
知识分享小能手3 小时前
线性代数学习教程,从入门到精通,矩阵的初等变换与线性方程组(6)
学习·线性代数·矩阵
我命由我123454 小时前
四流一致(合同流、业务流、资金流、发票流)
经验分享·学习·职场和发展·求职招聘·职场发展·产品经理·学习方法
知识分享小能手4 小时前
线性代数学习教程,从入门到精通,矩阵的初等变换与线性方程组(5)
学习·线性代数·矩阵
s1ckrain4 小时前
XR笔记-Extended Reality核心概念总结
笔记·xr·具身智能