3、通信协议基础:Modbus RTU/TCP协议详解、数据帧结构、寄存器地址映射

各位工程师朋友,咱们今天聊聊Modbus。说实话,在光储一体机这个行当里,Modbus就是最通用的“普通话”。不管你是做逆变器的、做BMS的,还是做EMS的,最后都得靠它来对话。

我个人习惯把Modbus比作“快递系统”。你要寄东西(数据),得先写好地址(寄存器地址),选好快递方式(RTU还是TCP),然后打包(组帧),最后发出去。对方收到后拆包、验货、回复。就这么简单。

3.1 Modbus的两种“快递方式”

Modbus主要有两种变体:RTU和TCP。我刚开始接触时也搞混过,后来踩了坑才明白——选错协议,设备根本不理你。

特性 Modbus RTU Modbus TCP
物理层 RS-485/RS-232 以太网(RJ45)
传输方式 串行,半双工 网络,全双工
最大节点数 32(RS-485) 理论上无限制
典型距离 1200米(加中继可更远) 100米(交换机级联可更远)
校验方式 CRC16 TCP/IP协议栈自带
应用场景 现场总线、老旧设备 远程监控、高速通信

核心区别一句话:RTU靠硬件连线,TCP靠网络IP。RTU适合短距离、低成本、抗干扰强的现场环境;TCP适合长距离、大数据量、需要远程访问的场景。

我记得有一次在西北某光伏电站,现场用的全是RS-485走Modbus RTU。结果因为接地没做好,通信老是丢包。后来我建议换成TCP走光纤环网,问题立马解决。嗯,选对协议真的很重要。

3.2 数据帧结构——拆开包裹看看

不管是RTU还是TCP,Modbus的数据帧结构都遵循一个基本框架。咱们先看RTU的帧结构,因为它更“原始”一些。

3.2.1 Modbus RTU 帧结构

| 地址码 (1字节) | 功能码 (1字节) | 数据区 (N字节) | CRC校验 (2字节) |
  • 地址码:设备ID,范围1-247。0是广播地址,所有设备都会收,但不回复。
  • 功能码:告诉设备你要干啥。比如03是读保持寄存器,06是写单个寄存器。
  • 数据区:具体要读写的寄存器地址、数据内容等。
  • CRC校验:16位循环冗余校验,确保数据没被干扰。

我的小技巧:调试RTU通信时,先用串口助手抓一下原始报文。看到CRC校验不对,十有八九是波特率或校验位设置错了。我曾经被这个坑过整整一个下午。

3.2.2 Modbus TCP 帧结构

TCP的帧结构比RTU多了一个MBAP头(Modbus Application Protocol Header)。说白了,就是把地址码和CRC校验替换成了网络传输需要的头部信息。

| MBAP头 (7字节) | 功能码 (1字节) | 数据区 (N字节) |

MBAP头包含:

  • 事务处理标识(2字节):用于匹配请求和响应
  • 协议标识(2字节):固定为0x0000
  • 长度(2字节):后续字节数
  • 单元标识(1字节):相当于RTU的地址码

你想想看,TCP的帧结构其实更简洁。因为底层的TCP/IP协议已经帮你做好了差错控制和重传,所以Modbus TCP不需要再自己搞CRC校验了。

3.3 寄存器地址映射——光储系统的“内存地图”

这部分是实战中最容易出错的。寄存器地址映射,说白了就是一张“内存地图”,告诉你哪个地址存了什么数据。

Modbus定义了四种寄存器类型:

类型 功能码 读写属性 数据宽度 典型用途
线圈(Coil) 01/05/15 可读可写 1位 开关状态、继电器控制
离散输入(Discrete Input) 02 只读 1位 按钮、限位开关
输入寄存器(Input Register) 04 只读 16位 模拟量输入、传感器数据
保持寄存器(Holding Register) 03/06/16 可读可写 16位 参数设置、运行数据

光储一体机中常用的寄存器映射示例:

// 保持寄存器地址映射(以某品牌光储一体机为例)
地址 0x0000: 设备型号(只读,16位)
地址 0x0001: 设备状态(只读,0=待机,1=运行,2=故障)
地址 0x0002: 直流母线电压(只读,单位0.1V)
地址 0x0003: 交流输出电压(只读,单位0.1V)
地址 0x0004: 输出功率(只读,单位W)
地址 0x0010: 工作模式设置(读写,0=并网,1=离网,2=混合)
地址 0x0011: 功率设定值(读写,单位W)
地址 0x0012: 电池充放电电流限制(读写,单位0.1A)

这里有个坑,我必须要提醒你。很多设备厂商的寄存器地址是从0开始的,但有些上位机软件显示的是从1开始的。比如设备手册说“地址0x0000是设备型号”,你用软件读的时候可能得填“40001”(保持寄存器的起始地址是40001)。

避坑指南:我曾经在调试一台储能变流器时,按照手册写的地址0x0100去读数据,结果死活读不到。后来发现手册用的是“协议地址”,而我的上位机用的是“PLC地址”。两者差了1!所以,拿到设备手册后,先确认地址的基准是0还是1。

3.4 实战:用Modbus读取光储一体机的运行数据

咱们来一个完整的例子。假设你要读取光储一体机的直流母线电压(地址0x0002)和输出功率(地址0x0004)。

Modbus RTU请求报文:

发送:01 03 00 02 00 02 65 CB
解释:
01  - 设备地址(1号设备)
03  - 功能码(读保持寄存器)
00 02 - 起始地址(0x0002)
00 02 - 读取数量(2个寄存器)
65 CB - CRC16校验

设备响应报文:

接收:01 03 04 0B B8 00 3C 7A 9E
解释:
01  - 设备地址
03  - 功能码
04  - 数据字节数(4字节)
0B B8 - 第一个寄存器数据(0x0BB8 = 3000,即300.0V)
00 3C - 第二个寄存器数据(0x003C = 60,即60W)
7A 9E - CRC16校验

你看,直流母线电压300.0V,输出功率60W。就这么简单。

我的调试习惯:先用Modbus Poll这类工具手动读一下,确认通信正常、地址正确、数据解析无误。然后再写代码。这样能省去很多调试时间。

3.5 知识体系总览

下面这张图是我自己整理的Modbus知识体系,你可以把它当作学习路线图。

Modbus通信协议知识体系 Modbus RTU Modbus TCP RTU帧结构 地址码 | 功能码 | 数据区 | CRC校验 物理层:RS-485/RS-232 TCP帧结构 MBAP头 | 功能码 | 数据区 物理层:以太网(RJ45) 寄存器地址映射(4种类型) 线圈 (Coil) 功能码01/05/15 离散输入 功能码02 输入寄存器 功能码04 保持寄存器 功能码03/06/16 实战:光储一体机远程监控 读取直流母线电压、输出功率、电池状态等

这张图把Modbus的知识体系分成了四层:协议类型、帧结构、寄存器映射、实战应用。你从最底层开始学,一层层往上走,最后就能搞定光储一体机的远程监控了。

好了,关于Modbus的基础知识就讲到这里。记住,理论是死的,设备是活的。多动手、多抓包、多分析,你很快就能成为Modbus高手。

本章要点回顾:

  • Modbus RTU适合现场总线,Modbus TCP适合远程监控
  • RTU帧结构包含CRC校验,TCP帧结构依赖网络协议栈
  • 四种寄存器类型各有用途,保持寄存器最常用
  • 地址映射注意0基准和1基准的区别
  • 调试时先用工具手动验证,再写代码

公众号:蓝海资料掘金营,微信deep3321