Modbus协议作为一种广泛应用于工业自动化领域的通信协议,其核心在于通过不同的命令码(Function Code)实现设备间的数据交互,Modbus命令码是Modbus报文中的关键字段,用于标识具体的操作功能,如读取 coils(线圈状态)、discrete inputs(离散输入)、holding registers(保持寄存器)和input registers(输入寄存器)等,Modbus协议支持多种通信串行链路(如RTU、ASCII)和以太网(如TCP/IP),但命令码的定义在所有传输方式中保持一致,确保了协议的通用性和兼容性。

Modbus命令码主要分为两大类:公共功能码(Public Function Codes)和用户自定义功能码(User-Defined Function Codes),公共功能码由Modbus组织官方定义和管理,具有标准化的行为和规范,而用户自定义功能码则由设备制造商根据特定需求自行定义,通常用于扩展协议功能或实现私有功能,以下将详细介绍常用的公共功能码及其应用场景,并通过表格形式归纳总结。
常用公共功能码详解
-
功能码01(读取线圈状态)
该命令用于读取一个或多个coils的状态(1位二进制值,0为OFF,1为ON),报文中的起始地址(address)和数量(quantity)参数决定了读取的范围,起始地址为0,数量为8,将读取前8个线圈的状态,响应报文包含一个字节数组,每个bit对应一个线圈的状态,该功能常用于读取开关量输出设备的状态,如继电器、接触器等。 -
功能码02(读取离散输入)
与功能码01类似,但功能码02用于读取离散输入的状态(1位二进制值),这些输入通常是外部物理信号(如传感器状态)的映射,由设备内部只读存储,其报文格式和响应结构与功能码01相同,但应用场景不同,常用于读取限位开关、光电传感器等输入信号的状态。
(图片来源网络,侵删) -
功能码03(读取保持寄存器)
保持寄存器是设备可读写的16位寄存器,用于存储配置参数、测量值等数据,功能码03允许读取一个或多个保持寄存器的值(每个寄存器16位),起始地址和数量参数指定了读取范围,响应报文以字节数组形式返回寄存器值(高位在前),该功能是Modbus中最常用的功能之一,例如读取变频器的频率设定值、温度传感器的当前温度等。 -
功能码04(读取输入寄存器)
输入寄存器是只读的16位寄存器,通常用于存储设备的测量数据(如电压、电流、功率等)或系统状态,功能码04的报文格式与功能码03相同,但数据来源不同,读取电能表的累计用电量或PLC的模拟量输入值。 -
功能码05(写入单个线圈)
该命令用于将一个线圈的状态设置为ON(0xFF00)或OFF(0x0000),报文包含目标线圈地址和状态值(0x0000或0xFF00),响应报文返回相同的地址和状态值以确认操作,常用于控制单个开关量输出设备,如启动/停止电机。 -
功能码06(写入单个保持寄存器)
与功能码05类似,但功能码06用于写入单个保持寄存器的16位值,报文包含目标寄存器地址和写入值,响应报文返回相同的地址和值,修改PID控制器的比例系数或设定设备的运行速度。
(图片来源网络,侵删) -
功能码15(写入多个线圈)
当需要同时控制多个线圈时,使用功能码15可提高通信效率,报文包含起始地址、线圈数量和字节数组(每个bit对应一个线圈状态),响应报文返回起始地址和数量以确认写入,一次性控制8个指示灯的开关状态。 -
功能码16(写入多个保持寄存器)
功能码16允许一次性写入多个保持寄存器的值,适用于批量更新设备参数,报文包含起始地址、寄存器数量、字节数组和寄存器值数组,响应报文返回起始地址和数量,同时配置多个PID参数或更新设备的工作模式。 -
功能码22(屏蔽写寄存器)
该命令用于对保持寄存器的特定位进行操作(置位、复位或保持不变),报文包含目标寄存器地址、与掩码(AND)和或掩码(OR),通过逻辑运算修改寄存器值,修改寄存器的某一位以启用/禁用特定功能。 -
功能码23(读写多个寄存器)
结合读取和写入操作,功能码23允许在一次通信中先读取一组寄存器的值,再写入另一组寄存器的值,报文包含读取和写入的起始地址、数量及数据,响应报文返回读取的数据,适用于需要数据交互的场景,如数据交换和同步。
Modbus命令码分类与功能总结表
| 功能码 | 名称 | 操作数据类型 | 是否支持读写 | 典型应用场景 |
|--------|--------------------|--------------------|--------------|----------------------------------|
| 01 | 读取线圈状态 | Coils(1位) | 读 | 读取开关量输出状态 |
| 02 | 读取离散输入 | Discrete Inputs(1位) | 读 | 读取传感器或开关输入状态 |
| 03 | 读取保持寄存器 | Holding Registers(16位) | 读 | 读取配置参数、测量值 |
| 04 | 读取输入寄存器 | Input Registers(16位) | 读 | 读取模拟量输入或系统状态 |
| 05 | 写入单个线圈 | Coils(1位) | 写 | 控制单个开关量输出 |
| 06 | 写入单个保持寄存器 | Holding Registers(16位) | 写 | 修改单个寄存器参数 |
| 15 | 写入多个线圈 | Coils(1位) | 写 | 批量控制开关量输出 |
| 16 | 写入多个保持寄存器 | Holding Registers(16位) | 写 | 批量更新设备参数 |
| 22 | 屏蔽写寄存器 | Holding Registers(16位) | 写 | 对寄存器特定位进行修改 |
| 23 | 读写多个寄存器 | Holding Registers(16位) | 读+写 | 数据交换和同步操作 |
注意事项
- 地址范围:Modbus协议中的地址定义存在差异,例如Modbus TCP/IP使用0-based地址(如400001对应寄存器0),而Modbus RTU/ASCII可能使用1-based地址,需根据设备规范确认。
- 异常响应:当命令执行失败时,设备返回异常码(Exception Code),如“非法功能码”(0x01)、“非法数据地址”(0x02)等,需通过异常码排查问题。
- 数据对齐:多字节数据(如寄存器值)需注意字节序(Big-Endian或Little-Endian),避免解析错误。
相关问答FAQs
Q1:Modbus功能码15和16的主要区别是什么?
A1:功能码15用于写入多个线圈(1位数据),适用于批量控制开关量输出(如同时控制多个指示灯);功能码16用于写入多个保持寄存器(16位数据),适用于批量更新数值型参数(如同时修改多个PID参数),两者的数据类型和操作对象不同,需根据具体需求选择。
Q2:如何处理Modbus通信中的异常响应?
A2:当设备返回异常响应时,首先检查异常码(Exception Code),异常码0x03表示“非法数据值”,需确认输入的数据范围是否符合设备要求;异常码0x04表示“从设备故障”,需检查设备电源或通信线路,还需核对报文格式(如地址、数量、校验和)是否正确,确保主站和从站的配置一致。
