3. Modbus协议在电力仪表中的应用

在SCADA系统中,Modbus是电力仪表接入最普遍的现场总线协议之一。它本身并不规定“电压”“电流”这些物理量如何表达,而是定义了一套“主站提问、从站应答”的报文规则,以及一组按地址编号访问的寄存器空间。理解Modbus的关键,不是背功能码,而是把帧结构、功能码、寄存器映射三者串起来:帧决定报文怎么发,功能码决定访问哪类数据,寄存器映射决定数据代表什么物理量、用什么数据类型、如何换算。

一、RTU与TCP:同一种应用层,两种承载方式

Modbus RTU运行在串行链路上(RS-485/RS-232),以二进制紧凑编码,靠3.5个字符时间的静默间隔划分帧边界;Modbus TCP运行在以太网上,用TCP承载,去掉了CRC校验,改用MBAP报文头来标识事务与长度。两者应用层PDU(功能码+数据)完全一致,因此同一台仪表既可有RTU口,也可有TCP口,寄存器地址含义通常不变。

RTU帧结构为:从站地址(1B) + 功能码(1B) + 数据(N B) + CRC16(2B)。例如读取1号从站保持寄存器40001起2个寄存器,请求帧为 01 03 00 00 00 02 C4 0B。TCP帧则在PDU前加7字节MBAP头:事务标识(2B) + 协议标识(2B,固定0) + 长度(2B) + 单元标识(1B),随后是功能码与数据。单元标识在网关场景中常用来指向背后的RTU从站。

Modbus RTU 与 TCP 帧结构对照 Modbus RTU 帧(串行链路) 从站地址 1 Byte 功能码 1 Byte 数据域(起始地址/数量/字节数…) N Byte CRC16 2 Byte 帧边界:≥3.5 字符静默间隔;示例请求 01 03 00 00 00 02 C4 0B Modbus TCP 帧(以太网承载) 事务标识 2 Byte 协议标识 2 Byte=0 长度 2 Byte 单元标识 1 Byte 功能码 1 Byte 数据域 N Byte MBAP 头共 7 字节;无 CRC,由 TCP 保证完整性 常用功能码 0x03 读保持寄存器 电压/电流/功率 0x04 读输入寄存器 实时测量值 0x06 写单个寄存器 参数/变比设置 0x10 写多个寄存器 批量配置

二、功能码:访问哪一类寄存器

功能码决定“读还是写、读哪类寄存器”。电力仪表采集最常用的是0x03(读保持寄存器)和0x04(读输入寄存器)。两者在报文格式上完全一样,区别在于访问的地址空间不同:0x03访问可读可写的保持寄存器,0x04访问只读的输入寄存器。很多仪表把实时测量值放在输入寄存器,把配置参数放在保持寄存器,因此读电压用0x04、改变比用0x06是常见组合。

写操作中,0x06写单个寄存器,0x10写多个连续寄存器。异常时从站返回“功能码+0x80”,并在数据域给出异常码,例如0x02表示非法数据地址、0x03表示非法数据值。SCADA调试时看到 01 83 02 …,就应优先检查寄存器地址是否超出仪表支持范围,而不是怀疑通信链路。

三、寄存器映射:地址编号与数据类型的约定

Modbus协议本身只认0~65535的寄存器偏移,而工程中常见的“40001”“30001”是数据模型编号,需要转换后才能填入报文。转换规则是:

  • 0xxxx 线圈:偏移 = 编号 − 1,功能码0x01/0x05/0x0F;
  • 1xxxx 离散输入:偏移 = 编号 − 10001,功能码0x02;
  • 3xxxx 输入寄存器:偏移 = 编号 − 30001,功能码0x04;
  • 4xxxx 保持寄存器:偏移 = 编号 − 40001,功能码0x03/0x06/0x10。

因此“读40001”在报文中起始地址写0x0000,“读40009”写0x0008。这一步是SCADA点表配置最容易出错的地方:点表里写40001,报文里却填了40001,从站会直接返回非法地址。

数据类型同样关键。电力仪表一个寄存器只有16位,而电压、功率等量常用32位表示,于是出现32位整数/浮点跨两个寄存器的排列问题。主流仪表多采用“高字在前”(Big-Endian word order),即第一个寄存器是高16位;也有仪表采用“低字在前”。同一台仪表内部,字序通常一致,但不同厂家可能不同。解析时若发现数值明显异常(如功率为负、数值跳变巨大),应优先怀疑字序或字节序设置错误。

四、典型寄存器地址解析示例

下面以一台常见三相多功能电力仪表的示例点表为例(参数为教学示例,实际以仪表说明书为准)。假设采用0x04读输入寄存器,32位数据高字在前,电压变比1、电流变比1。

数据模型编号报文偏移物理量数据类型单位/换算
300010x0000A相电压UINT160.1 V
300070x0006A相电流UINT160.001 A
300130x000C总有功功率INT32(高字在前)0.001 kW
300250x0018总有功电能UINT320.01 kWh
400010x0000电压变比UINT161

以读取A相电压为例,请求帧为 01 04 00 00 00 01 31 CA。若从站返回 01 04 02 08 9A …,则数据为0x089A=2202,乘以0.1 V得220.2 V,与现场220 V相符,说明地址、功能码、换算均正确。

再以总有功功率为例,读取30013起2个寄存器,请求 01 04 00 0C 00 02 B1 C9。若返回数据为 00 05 1E 3C,按高字在前组合为0x00051E3C=335420,乘以0.001 kW得335.42 kW。若把字序误设为低字在前,组合成0x1E3C0005,数值会大得离谱,这就是字序错误的典型表现。

调试建议:先用单点读(数量=1)验证地址与功能码,再读32位量验证字序;确认无误后再批量读取连续寄存器,减少报文数量、提高采集效率。
注意:不同厂家对同一物理量的寄存器地址、数据类型、字序、换算系数可能完全不同,切勿跨型号直接套用点表。应以对应型号的通信协议手册为准,并在投运前用实际读数与现场表计或标准源比对。

把以上四件事连起来看:RTU/TCP决定报文怎么封装和传输,功能码决定访问哪类寄存器,寄存器映射决定地址如何从数据模型编号转换为报文偏移,数据类型与换算决定原始码值如何还原为工程值。SCADA侧的点表配置,本质上就是把“数据模型编号 + 功能码 + 数据类型 + 字序 + 换算系数”这五项写清楚,并保证与仪表手册一致。做到这一点,Modbus电力仪表采集的绝大部分问题都能在配置阶段被消除。