3. 数据模型与寄存器映射:线圈、离散输入、保持寄存器、输入寄存器

好,咱们今天聊点实在的。Modbus 协议里最核心、也最容易让人迷糊的,就是这四种数据模型。说白了,它们就是 PLC 或者从站设备里,给外部世界看的那几个“抽屉”。你想想看,一个设备里那么多数据,总得有个规矩,告诉别人哪个抽屉放开关量,哪个抽屉放模拟量,对吧?

我个人习惯,把这四种模型分成两组来记:一组是“只读”的,一组是“可读可写”的。这样逻辑上就清晰多了。

3.1 四种数据模型概览

先看一张图,把整个知识体系串起来。这张图我当年带徒弟的时候,每次都要画一遍。

Modbus 四种数据模型结构图 线圈 (Coil) 功能码: 01, 05, 15 位操作 (0/1) 可读可写 离散输入 (Discrete Input) 功能码: 02 位操作 (0/1) 只读 保持寄存器 (Holding Register) 功能码: 03, 06, 16 16位字操作 可读可写 输入寄存器 (Input Register) 功能码: 04 16位字操作 只读 注:线圈和保持寄存器支持读写操作,离散输入和输入寄存器仅支持读取

嗯,这张图你看完,心里大概就有个谱了。接下来咱们一个一个拆开讲。

3.2 线圈 (Coil) —— 开关量的“小开关”

线圈,其实就是个位变量。要么是 0,要么是 1。在风电设备里,最常见的用途就是控制继电器的通断、指示灯的亮灭。

功能码对应关系:

  • 01 (读线圈):读取一组线圈的当前状态
  • 05 (写单个线圈):强制一个线圈为 ON 或 OFF
  • 15 (写多个线圈):一次性写入多个线圈的状态

重要提醒:线圈的地址编号通常从 0 开始。比如 00001 对应地址 0,00002 对应地址 1。但有些设备厂商会从 1 开始编号,这个坑我踩过好几次。

我记得有一次调试风机偏航系统,主控发 05 功能码写线圈,从站就是不响应。查了半天,发现是地址偏移搞错了。主控以为线圈地址是 1,但从站固件里写的是地址 0。嗯,这种问题,协议分析仪一抓一个准。

3.3 离散输入 (Discrete Input) —— 只读的“状态指示灯”

离散输入和线圈很像,也是位变量。但区别在于——它只能读,不能写。说白了,它就是设备用来告诉外界“我现在是什么状态”的只读信号。

功能码对应关系:

  • 02 (读离散输入):读取一组离散输入的状态

在风电场景里,离散输入常用来读取限位开关的状态、急停按钮的状态、或者某个故障报警的触发信号。你想想看,这些信号都是设备自己产生的,外部不应该去修改它,所以设计成只读是合理的。

我的小技巧:调试的时候,如果发现离散输入读回来的值一直不对,先别急着怀疑协议。拿万用表量一下输入端的电平,很多时候是硬件接线松了。

3.4 保持寄存器 (Holding Register) —— 最常用的“数据仓库”

保持寄存器是 16 位(2 字节)的数据单元。它支持读写,所以用途最广。风电设备里的设定值、运行参数、控制指令,大部分都放在这里。

功能码对应关系:

  • 03 (读保持寄存器):读取一个或多个寄存器的值
  • 06 (写单个寄存器):写入一个寄存器的值
  • 16 (写多个寄存器):一次性写入多个寄存器的值

我个人习惯,把保持寄存器分成三类来管理:

  1. 配置类:比如风机的额定功率、切入风速、切出风速。这些值一般写一次就不动了。
  2. 控制类:比如启动/停止命令、偏航角度设定。这些值会频繁变化。
  3. 状态类:比如当前发电功率、累计发电量。虽然是只读的,但为了方便,也放在保持寄存器里。

曾经踩过的坑:有一次做变桨系统对接,对方把 32 位浮点数拆成两个 16 位寄存器存放。但字节顺序搞反了。我读回来的数据全是乱码。后来约定好采用大端模式(高字节在前),问题才解决。所以,寄存器映射表里一定要注明数据类型和字节顺序。

3.5 输入寄存器 (Input Register) —— 只读的“传感器数据”

输入寄存器和保持寄存器一样,也是 16 位数据单元。但它是只读的。通常用来存放传感器采集的实时数据,比如风速、温度、振动值。

功能码对应关系:

  • 04 (读输入寄存器):读取一个或多个输入寄存器的值

你可能会问:既然保持寄存器也能存只读数据,为什么还要搞个输入寄存器?

嗯,这个问题我当年也困惑过。后来想明白了——这是为了安全。把传感器数据放在输入寄存器里,外部程序只能读,不能写。万一主站程序有 bug,也不会误修改传感器的原始数据。这在风电这种对安全性要求高的行业里,很重要。

3.6 寄存器映射表 —— 调试的“地图”

搞清楚了四种数据模型,下一步就是做寄存器映射表。这张表就是你和设备沟通的“地图”。没有它,你连从站里有什么数据都不知道。

一个标准的寄存器映射表,至少包含以下信息:

地址 类型 名称 数据类型 读写属性 单位 备注
00001 线圈 风机启动 Bit 读写 - 1=启动, 0=停止
10001 离散输入 急停状态 Bit 只读 - 1=急停按下
40001 保持寄存器 当前功率 Uint16 只读 kW 实际值×10
40002 保持寄存器 风速 Float32 只读 m/s 占用40002-40003
30001 输入寄存器 齿轮箱温度 Int16 只读 实际值×10

核心要点:调试前,一定要拿到这份映射表。如果厂商给的表不完整,我建议你直接用 Modbus 扫描工具把所有地址扫一遍。虽然费时间,但比盲调靠谱得多。

3.7 实战中的避坑指南

最后,分享几个我这些年积累的经验:

  • 地址偏移问题:有些设备地址从 0 开始,有些从 1 开始。调试前先确认清楚。
  • 字节顺序:32 位数据(浮点数、长整型)跨两个寄存器时,一定要确认是大端还是小端。我建议统一用大端。
  • 数据类型对齐:比如一个 32 位浮点数,必须从偶数地址开始存放。否则有些从站会报错。
  • 写操作后的延时:写完保持寄存器后,不要立刻去读。给从站一点处理时间,一般 10-50ms 就够了。

我曾经在海上风电场调试时,遇到一个从站,写保持寄存器后必须等 100ms 才能读到正确值。一开始没注意,导致主站逻辑一直报错。后来加了延时,问题就解决了。

好了,这四种数据模型,说白了就是 Modbus 世界的“四大家族”。搞清楚了它们,你就掌握了和任何 Modbus 从站对话的基础。下一节,咱们聊聊报文格式,看看这些数据到底是怎么在线上跑的。


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