4、常用功能码详解:01/02/03/04/05/06/15/16

Modbus RTU 协议的核心在于功能码(Function Code),它决定了主站(Master)与从站(Slave)之间的交互类型。本章将详细解析工业现场最常用的 8 个功能码:位操作类的 01、02、05、15,以及字操作类的 03、04、06、16。理解这些功能码的报文结构是进行数据采集与边缘计算转发的基础。

4.1 功能码分类与概览

根据操作对象(线圈或寄存器)与操作类型(读或写),功能码可分为以下四类:

类别 功能码 名称 操作对象 操作类型
位读取 01 读线圈状态 线圈(DO) 读取
02 读离散输入状态 离散输入(DI) 读取
字读取 03 读保持寄存器 保持寄存器(AO) 读取
04 读输入寄存器 输入寄存器(AI) 读取
位写入 05 写单个线圈 线圈(DO) 写入
15 写多个线圈 线圈(DO) 写入
字写入 06 写单个寄存器 保持寄存器(AO) 写入
16 写多个寄存器 保持寄存器(AO) 写入
现场经验: 在边缘计算网关中,03 功能码用于采集传感器数值(如温度、压力),01 功能码用于采集设备启停状态,06 和 16 用于下发控制参数。

4.2 位操作功能码详解

4.2.1 功能码 01:读线圈状态

定义: 读取从站中离散输出线圈(0x 区)的 ON/OFF 状态。常用于读取继电器、接触器或指示灯状态。

请求报文格式:

从站地址 + 0x01 + 起始地址(Hi) + 起始地址(Lo) + 线圈数量(Hi) + 线圈数量(Lo) + CRC(Lo) + CRC(Hi)

响应报文格式:

从站地址 + 0x01 + 字节数 + 数据(Byte1) + ... + 数据(ByteN) + CRC(Lo) + CRC(Hi)

示例: 读取地址为 01 的从站,起始线圈地址 0x0000,连续读取 10 个线圈。

  • 请求: 01 01 00 00 00 0A BC 0D
  • 响应: 01 01 02 CD 00 3E 9B (表示前 8 个线圈状态为 0xCD,即 1100 1101)

4.2.2 功能码 02:读离散输入状态

定义: 读取从站中离散输入触点(1x 区)的 ON/OFF 状态。常用于读取按钮、限位开关或光电传感器信号。

请求与响应报文格式: 与功能码 01 完全一致,仅功能码字段不同。

  • 请求: 从站地址 + 0x02 + 起始地址 + 数量 + CRC
  • 响应: 从站地址 + 0x02 + 字节数 + 数据 + CRC

4.2.3 功能码 05:写单个线圈

定义: 强制将单个线圈(0x 区)设置为 ON 或 OFF。常用于远程启停单台设备。

请求报文格式:

从站地址 + 0x05 + 线圈地址(Hi) + 线圈地址(Lo) + 数据(Hi) + 数据(Lo) + CRC(Lo) + CRC(Hi)

数据规则: 0xFF00 表示 ON,0x0000 表示 OFF。其他值视为无效。

响应报文: 成功时,从站原样返回请求报文(回显)。

示例: 将从站 01 的线圈地址 0x000A 置为 ON。

  • 请求: 01 05 00 0A FF 00 6C 36
  • 响应: 01 05 00 0A FF 00 6C 36 (回显确认)

4.2.4 功能码 15:写多个线圈

定义: 连续写入多个线圈(0x 区)的状态。常用于批量设置输出或初始化设备状态。

请求报文格式:

从站地址 + 0x0F + 起始地址(Hi) + 起始地址(Lo) + 线圈数量(Hi) + 线圈数量(Lo) + 字节数 + 数据(Byte1) + ... + CRC

响应报文格式:

从站地址 + 0x0F + 起始地址(Hi) + 起始地址(Lo) + 线圈数量(Hi) + 线圈数量(Lo) + CRC
注意: 功能码 15 的请求中必须包含 字节数 字段,该字段表示后续数据占用的字节数。例如写入 10 个线圈,需要 2 个字节(10位数据)。

4.3 字操作功能码详解

4.3.1 功能码 03:读保持寄存器

定义: 读取从站中保持寄存器(4x 区)的当前值。保持寄存器支持读写,是采集模拟量输出、PID 参数、累计值等数据的主要方式。

请求报文格式:

从站地址 + 0x03 + 起始地址(Hi) + 起始地址(Lo) + 寄存器数量(Hi) + 寄存器数量(Lo) + CRC

响应报文格式:

从站地址 + 0x03 + 字节数 + 数据(Hi) + 数据(Lo) + ... + CRC

示例: 读取从站 01,起始寄存器 0x0064,连续读取 2 个寄存器。

  • 请求: 01 03 00 64 00 02 84 0A
  • 响应: 01 03 04 00 0A 01 2C 7A 43 (寄存器1=10,寄存器2=300)

4.3.2 功能码 04:读输入寄存器

定义: 读取从站中输入寄存器(3x 区)的当前值。输入寄存器为只读,通常用于读取传感器原始值(如 AD 采样值)。

请求与响应报文格式: 与功能码 03 完全一致,仅功能码字段不同。

  • 请求: 从站地址 + 0x04 + 起始地址 + 数量 + CRC
  • 响应: 从站地址 + 0x04 + 字节数 + 数据 + CRC

4.3.3 功能码 06:写单个寄存器

定义: 将单个保持寄存器(4x 区)写入指定值。常用于设定单点参数,如设定温度目标值。

请求报文格式:

从站地址 + 0x06 + 寄存器地址(Hi) + 寄存器地址(Lo) + 数据(Hi) + 数据(Lo) + CRC

响应报文: 成功时,从站原样返回请求报文(回显)。

示例: 将从站 01 的寄存器 0x0001 写入值 0x03E8(1000)。

  • 请求: 01 06 00 01 03 E8 18 0A
  • 响应: 01 06 00 01 03 E8 18 0A

4.3.4 功能码 16:写多个寄存器

定义: 连续写入多个保持寄存器(4x 区)。常用于批量下发配方参数或更新固件。

请求报文格式:

从站地址 + 0x10 + 起始地址(Hi) + 起始地址(Lo) + 寄存器数量(Hi) + 寄存器数量(Lo) + 字节数 + 数据(Hi) + 数据(Lo) + ... + CRC

响应报文格式:

从站地址 + 0x10 + 起始地址(Hi) + 起始地址(Lo) + 寄存器数量(Hi) + 寄存器数量(Lo) + CRC
关键对比: 功能码 06 与 16 的区别在于操作数量。06 用于单点微调,16 用于批量设置。在边缘计算转发场景中,若需同时更新多个参数(如 PID 的 P、I、D 值),应优先使用 16 功能码以减少总线通信次数。

4.4 功能码应用场景与报文结构对比

下图展示了主站通过不同功能码与从站进行数据交互的典型流程,涵盖了位操作与字操作的核心路径。

Modbus 主站与从站功能码交互流程 Modbus 主站 Modbus 从站 功能码 01/02:读位 功能码 03/04:读字 功能码 05/15:写位 功能码 06/16:写字 从站响应报文(回显/数据) 通用报文结构(RTU 模式) 请求帧:从站地址 (1B) + 功能码 (1B) + 数据域 (N B) + CRC (2B) 响应帧:从站地址 (1B) + 功能码 (1B) + 数据域 (N B) + CRC (2B) 异常响应:从站地址 (1B) + 功能码+0x80 (1B) + 异常码 (1B) + CRC (2B) 注:数据域内容因功能码而异,详见各功能码定义。

4.5 功能码选择决策表

在实际项目中,根据数据类型与操作需求选择正确的功能码至关重要。下表总结了各功能码的适用场景:

需求描述 推荐功能码 操作对象 典型应用
读取设备启停状态 01 线圈 电机运行/停止状态
读取传感器开关信号 02 离散输入 限位开关、急停按钮
读取模拟量输出值 03 保持寄存器 变频器频率、阀门开度
读取模拟量输入值 04 输入寄存器 温度、压力传感器原始值
远程启停单台设备 05 单个线圈 启动/停止一台水泵
批量设置输出状态 15 多个线圈 初始化一组指示灯
修改单个参数 06 单个寄存器 设定温度目标值
批量下发配方参数 16 多个寄存器 更新 PID 参数组

4.6 异常响应与错误处理

当从站无法执行请求时,会返回异常响应帧。异常响应帧的功能码为 请求功能码 + 0x80,并附带一个异常码。

常见异常码:

  • 01 (ILLEGAL FUNCTION): 从站不支持该功能码。
  • 02 (ILLEGAL DATA ADDRESS): 请求的地址超出从站有效范围。
  • 03 (ILLEGAL DATA VALUE): 请求的数据值无效(如写入 0x0001 到线圈)。
  • 04 (SLAVE DEVICE FAILURE): 从站内部故障,无法执行操作。
调试技巧: 在边缘计算网关中,建议对每个 Modbus 请求设置超时(通常 500ms~1000ms),并解析异常响应码。若连续收到异常码 02,应检查从站地址映射表;若收到异常码 03,应检查数据格式(如字节序、数值范围)。

4.7 本章小结