news 2026/5/11 19:12:17

Modbus 协议分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Modbus 协议分析

目录

  • 一、前言
  • 二、Modbus RTU 帧格式
  • 三、四种寄存器模型
  • 四、常用功能码报文拆解
  • 五、IDLE 中断与 Modbus 帧边界的天然契合
  • 六、从 OOP 视角看 Modbus 后端
  • 七、ModbusPoll 工具验证
  • 八、常见坑
  • 九、结尾

一、前言

大家好,这里是Hello_Embed

上一篇我们把 UART 封装成了统一的UART_Device接口——InitSendRecvByte三个方法,底层换串口上层。

本篇进入项目核心协议:Modbus RTU。它是整个"工业互联设备管理系统"中,PC 上位机和 STM32H5 中控之间、中控和各路传感器之间的通用通信语言


二、Modbus RTU 帧格式

| 地址(1B) | 功能码(1B) | 数据(NB) | CRC16(2B) | |----------|-----------|---------|-----------|

帧与帧之间用3.5 字符时间的静默(IDLE)分隔。在 115200 波特率下,1 字符 ≈ 87μs,3.5 字符 ≈ 305μs。


三、四种寄存器模型

Modbus 从站内部维护四张"表",每种表对应不同的功能码:

类型前缀功能码(读/写)大小用途举例
线圈 Coil0x01 / 05,151 bit继电器输出、LED 开关
离散输入 DI1x02 / 无写1 bit按键、限位开关
保持寄存器 HR4x03 / 06,1616 bit参数配置、设定值
输入寄存器 IR3x04 / 无写16 bit温度、湿度、光照读数

编号从 1 开始,但协议地址从 0 开始。例如"保持寄存器 1"→ 协议地址0x0000


四、常用功能码报文拆解

4.1 读保持寄存器 (03)

请求:从站 1,读寄存器地址 0,读 1 个

01 03 00 00 00 01 84 0A │ │ └───┘ └───┘ └───┘ │ │ │ │ │ │ │ │ │ CRC16 │ │ │ 读取数量 = 1 个寄存器 │ │ 起始地址 = 0x0000 │ 功能码 03 = 读保持寄存器 从站地址 1

响应

01 03 02 00 05 38 47 │ │ │ └───┘ └───┘ │ │ │ │ │ │ │ │ │ CRC16 │ │ │ 寄存器值 = 0x0005 │ │ 数据字节数 = 2 │ 功能码 从站地址

4.2 写单个保持寄存器 (06)

请求:写地址 1 的寄存器,值为 10

01 06 00 01 00 0A 19 CD │ │ └───┘ └───┘ └───┘ │ │ │ │ │ │ │ │ │ CRC16 │ │ │ 写入值 = 0x000A (10) │ │ 寄存器地址 = 0x0001 │ 功能码 06 = 写单个寄存器 从站地址 1

响应:原样回传(确认写入成功)。

4.3 读离散输入 (02)

请求:读从站 1 的离散输入,起始地址 0,读 3 个

01 02 00 00 00 03 38 0B

响应:返回 1 字节,低 3 位对应 3 个离散输入的状态。


五、IDLE 中断与 Modbus 帧边界的天然契合

DMA+IDLE 接收模式是专门为 Modbus RTU "量身定制"的:

Modbus 帧 1 (N1字节) → 静默 305μs → Modbus 帧 2 (N2字节) → 静默 305μs → ... HAL_UARTEx_ReceiveToIdle_DMA 的行为: 收到帧 1 最后一个字节 → 1字符时间无数据 → IDLE 中断 → RxEventCallback(Size=N1) ← 完美!Size 就是帧长度 → 入队 → 重启 DMA 收到帧 2 ...

不需要自己拼帧——IDLE 中断天然告诉你了每帧的边界。上层只需从 Queue 取出 Size 个字节就是一帧完整报文。


六、从 OOP 视角看 Modbus 后端

libmodbus 通过modbus_new_rtu()接收设备名:

modbus_t*ctx=modbus_new_rtu("uart4",115200,'N',8,1);

内部流程:

modbus_new_rtu("uart4") → GetUARTDevice("uart4") // 拿到 OOP 设备指针 → ctx->backend.send = pDev->send // 绑定 Send → ctx->backend.recv = pDev->RecvByte // 绑定 RecvByte → ctx->backend.connect = ... // 调用 pDev->Init

这就是 OOP 封装的终极意义——libmodbus 完全不关心底层是 UART2、UART4 还是 USB CDC。协议栈只管send()RecvByte(),物理层由设备表管理。

// 用板载 UART4(接到 RS-485)modbus_t*ch2=modbus_new_rtu("uart4",115200,'N',8,1);// 用 USB CDC(虚拟串口,接到 PC 上位机)modbus_t*usb=modbus_new_rtu("usb",115200,'N',8,1);// 上层 modbus_reply / modbus_receive 代码完全一样!

七、ModbusPoll 工具验证

PC 端工具路径:Tools/Modbus/(ModbusPoll 主站 + ModbusSlave 从站模拟器)

调试流程:

  1. 用 ModbusSlave 模拟从站:设置地址、寄存器初始值
  2. 用 ModbusPoll 发命令:观察请求帧和响应帧的原始报文
  3. STM32 上先用 ModbusSlave 软件验证 PC 端主站逻辑正确
  4. 再替换为 STM32 从站(代码写好后)

验证链路:

PC ModbusPoll ←─USB CDC──→ STM32H5 ←─UART4(RS-485)──→ STM32F030传感器 主站 中控 从站

八、常见坑

8.1 CRC 计算

CRC 是整帧计算(地址+功能码+数据),不包含 CRC 字段本身。

8.2 寄存器地址偏移

"保持寄存器 1"在协议里地址是0x0000,不是0x0001。Modbus 编号从 1 开始,协议地址从 0 开始。

8.3 帧间间隔不够

如果连续发两帧 Modbus 报文,间隔小于 3.5 字符(< 305μs @115200),从机会把两帧当成一帧,CRC 校验失败。发送时必须保证至少 305μs 的静默。

8.4 broadcast 无响应

地址 0 是广播地址,所有从站执行命令但不回应。不要等广播的响应。


九、结尾

本篇把 Modbus RTU 的核心概念全串起来了:

学习路径回顾:

Note 7-8: UART 三种方式(查询/中断/DMA) Note 9: SPI DMA Note 10: DMA+IDLE Note 11: RTOS 信号量 Note 12: UART_Device OOP 封装 Note 13: Modbus 协议分析 ← 本篇

下一篇预告:libmodbus 源码走读——核心数据结构、发送/接收/回复的全景分析,以及移植到 STM32H5 的关键步骤。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/11 19:06:31

BetterNCM安装器终极指南:3分钟为网易云音乐注入新活力

BetterNCM安装器终极指南&#xff1a;3分钟为网易云音乐注入新活力 【免费下载链接】BetterNCM-Installer 一键安装 Better 系软件 项目地址: https://gitcode.com/gh_mirrors/be/BetterNCM-Installer 你是否厌倦了网易云音乐PC版功能单一、界面单调的现状&#xff1f;想…

作者头像 李华
网站建设 2026/5/11 19:05:31

WaveSwipeRefreshLayout常见问题解决:10个开发者必知陷阱

WaveSwipeRefreshLayout常见问题解决&#xff1a;10个开发者必知陷阱 【免费下载链接】WaveSwipeRefreshLayout 项目地址: https://gitcode.com/gh_mirrors/wa/WaveSwipeRefreshLayout WaveSwipeRefreshLayout是一款为Android应用提供流畅波浪动画效果的下拉刷新控件&a…

作者头像 李华
网站建设 2026/5/11 19:03:34

实战演练:使用SharpShooter生成无阶段Payload攻击链

实战演练&#xff1a;使用SharpShooter生成无阶段Payload攻击链 【免费下载链接】SharpShooter Payload Generation Framework 项目地址: https://gitcode.com/gh_mirrors/sh/SharpShooter SharpShooter是一款功能强大的Payload生成框架&#xff0c;能够创建多种格式的无…

作者头像 李华