02-读与写功能码实战


3.2 读与写功能码实战

本节摘要:读功能码 01/02/03/04、写功能码 05/06/15/16,逐条给出手工组报文的完整过程与解读。本节用"读频率、写启动、批量下设定值"三个场景,把八条常用功能码全部过一遍。位置:3.1 拆了 PDU 骨架,本节让骨架长出肌肉。

场景一:读变频器输出频率(03 读保持寄存器)

设备点表:输出频率在保持寄存器偏移 0,float32,高字在前。

请求:01 03 00 00 00 02 C4 0B 应答:01 03 04 41 A0 00 00 5A 8B 字节: 41 A0 00 00 → IEEE754 浮点 20.0 → 输出频率 20.0Hz ​

读到 4 字节后按 IEEE754 解出 20.0Hz,与面板一致。注意浮点的判读要按点表缩放——本例无缩放,直接是 Hz。

场景二:启动一台从站设备(05 写单线圈)

控制命令字在 41001(偏移 1000),但"启动"在很多实现里是线圈 00001(偏移 0)——本例用线圈模型:

请求:01 05 00 00 FF 00 8C 3A 地址1 功能05 线圈偏移0 值FF00(通) CRC 应答:01 05 00 00 FF 00 8C 3A ← 原样回显 = 已执行 停止则写 0000:01 05 00 00 00 00 CD CA ​

写 0xFF00 是"置位"、0x0000 是"复位",这是 Modbus 的硬性规定,不是随便传 1/0。回显与请求逐字节一致才确认成功。

场景三:批量下发一组设定参数(16 写多寄存器)

要同时写 4 个寄存器(偏移 10-13:比例、积分、微分、输出上限):

请求:01 10 00 0A 00 04 08 00 64 00 32 00 0A 00 14 [CRC] 地址1 功能16 起始偏移10 数量4 字节数8 数据: 0064=100, 0032=50, 000A=10, 0014=20 应答:01 10 00 0A 00 04 [CRC] ← 只回地址与数量 ​

16 与 06 的取舍:写单点用 06(回显、简单);连续写多个用 16(一次事务、省轮询)。批量写的关键前提是"这批寄存器确实连续"——点表里不连续的地址段,宁可分两次写也别硬凑。

读多与读少的边界

03 一次最多读 125 个寄存器,01/02 最多 2000 个位,15/16 一次最多写 123 个寄存器/1968 位——这是规范上限,超限请求会得到异常码 03(非法数据值)。工程上建议单次读不超过 16-32 个寄存器:一次读太多,从站组包时间与错误概率都上升,且单寄存器偶发错误会拖累整包。

功能码选择矩阵

面对具体读写需求,功能码怎么选:

需求 选哪个 理由
读一个线圈 01 位读
读一批连续线圈 01(一次 ≤2000 位) 合并请求
读实时模拟量 04 输入寄存器 只读区,语义清晰
读可调参数 03 保持寄存器 读写区
置位一个输出 05 单点写,回显确认
批量写设定 16 一次事务,省轮询
设备标识 43/14(MEI) 标准设备信息

03 读与 04 读的实际差异

03(保持寄存器)与 04(输入寄存器)的报文结构完全一样,只是功能码不同——03 读的是可写区、04 读的是只读区。用 03 去读只有 04 语义的设备会得到异常码 02 或读到错误值;反之亦然。调试器里最常见的乌龙是"功能码选错":两个码的报文只差一个字节,数据却完全对不上。经验:先看点表标注的类别,再选功能码;不确定时两个码各试一次,看哪个返回合理值。

05 与 06 的确认语义

05 写线圈与 06 写寄存器的响应是请求原样回显。这个设计有深意:主站拿回显逐字节比对即可确认"从站确实收到并执行了这条请求"。若回显与请求不一致(极少见,通常是地址混淆),说明链路或从站实现有问题。注意回显只是"收到并执行",不代表"执行成功"——写线圈后如果设备因故无法执行(如处于急停),部分实现会回异常而非回显,所以关键写操作后建议读回验证。

易错点补充

  • 16 写多个寄存器时字节数错误:字节数必须等于数量×2,且后续数据长度要匹配,长度不匹配会被从站当帧错乱丢弃;
  • 一次写跨点表非连续段:点表连续段才适合 16 批量写,跨段数据用多次 06 更安全;
  • 读回验证缺失:写关键参数(频率、限值)后不读回,写失败(异常码 04/从站忙)时程序不知道,误以为成功——关键写必读回。

易错点清单

  • 05 写线圈把值传成 0x0001:规范只认 0xFF00/0x0000,其它值多数实现当非法数据值拒绝;
  • 16 的字节数算错:字节数 = 寄存器数量 × 2,多一字节或少一字节都会让从站解析错乱;
  • 批量写前不核对连续性:写进不连续地址中间夹着的"别的寄存器",轻则误改参数,重则触发设备保护。

要点回顾:八条功能码分读写两组;05/06 回显确认、15/16 回地址数量;批量写先核对连续性;单次读 16-32 个寄存器是工程甜点。报文会发了,下一节看答不上来的情况——异常响应排障。

实战复盘:批量下发参数时的"半套生效"

某注塑机项目要一次性写入 20 个工艺参数(温度、压力、时间),用 16 写多寄存器。第一次执行后设备表现异常:一半参数生效、一半没生效。排查发现两个问题:一是 20 个参数在点表里不连续(中间夹着只读的诊断寄存器),16 批量写把诊断寄存器也写了一遍;二是写完后没有读回验证,程序不知道哪些失败。

正确做法:按点表连续段分组写(连续段才用 16,跨段拆成多次 06),写完后整段读回比对,不一致的段单独重写并告警。复盘结论:16 写多寄存器的高效建立在"点表连续 + 可写"两个前提上,前提不满足时,一次 06 一个参数反而更安全。

小结:八条功能码按读写与点位/字位分组记忆;写单点回显、写多点回地址数量;关键写操作必读回验证;批量写前提是点表连续且可写。
延伸练习:用手工组帧的方式完成一次 16 写多寄存器并逐字节验证回显;再用 03 读回确认写入生效。手写三次这类报文后,功能码的字节结构会变成肌肉记忆,看抓包不再需要翻手册。完成练习后对照本节要点自查:能否不看示例写出 03 读与 16 写的完整报文(含字节数与数据段)?能,则进入下一节的异常排障。(本章节的报文示例均可直接用于 Modbus Poll 手工收发验证。)

作者与出处
原作者:灏天文库
来源:平台策划编纂
整理人: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U