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) | 写入 |
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
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
4.4 功能码应用场景与报文结构对比
下图展示了主站通过不同功能码与从站进行数据交互的典型流程,涵盖了位操作与字操作的核心路径。
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): 从站内部故障,无法执行操作。