Modbus function code完全Parse:从基础到进阶的 21 个标准function code实战指南

freefree技术Resources

这篇内容可直接阅读,适合用于基础学习和Search引流。

🌐 This page is not yet available in English. Showing the Chinese version. Back to Chinese page.
本文目录
  1. 1. 一、Modbus data模型与function code的关系
  2. 2. 二、function codeCategory体系
  3. 3. 三、位Operationfunction code(Bit Access)深度Parse
  4. 4. 3.1 function code 0x01 — 读线圈(Read Coils)
  5. 5. 3.2 function code 0x02 — 读离散输入(Read Discrete Inputs)
  6. 6. 3.3 function code 0x05 — 写单个线圈(Write Single Coil)
  7. 7. 3.4 function code 0x0F — 写多个线圈(Write Multiple Coils)
  8. 8. 四、registerOperationfunction code(16-bit Access)深度Parse
  9. 9. 4.1 function code 0x03 — 读保持register(Read Holding Registers)
  10. 10. 4.2 function code 0x04 — 读输入register(Read Input Registers)
  11. 11. 4.3 function code 0x06 — 写单个register(Write Single Register)
  12. 12. 4.4 function code 0x10 — 写多个register(Write Multiple Registers)
  13. 13. 五、高级function code详解
  14. 14. 5.1 function code 0x07 — 读异常状态(Read Exception Status)
  15. 15. 5.2 function code 0x08 — 诊断(Diagnostics)
  16. 16. 5.3 function code 0x0B — 读通信事件计数器
  17. 17. 5.4 function code 0x16 — 掩码写register(Mask Write Register)
  18. 18. 六、function code对比速查表
  19. 19. 七、function code选择决策树
  20. 20. 八、常见陷阱与最佳实践
  21. 21. 8.1 byte序陷阱
  22. 22. 8.2 广播address(address 0)
  23. 23. 8.3 一次Request勿贪多
  24. 24. 九、实际案例:构建 Modbus Data Acquisitionsystem
  25. 25. 十、总结

Modbus function code完全Parse:从基础到进阶的 21 个标准function code实战指南

关键词:Modbus function code、Modbus Function Code、Modbus 01 02 03 04 05 06 15 16、Modbus 读register、Modbus 写线圈

function code(Function Code)是 Modbus protocol的灵魂。它定义了主站要对从站执行的Operation——是读取data还是写入data,Operation的对象是线圈、离散输入、保持register还是输入register。理解每一个function code的用途、messageformat和适用Scene,是精通 Modbus 通信的基石。

本文以 Modbus protocol specification V1.1b3 为蓝本,system化地ParseAll 21 个标准function code(包括公共function code、用户定义function code和保留function code),并配以完整的message示例和编程实现,帮助您从「会用的工程师」进阶为「真正理解的专家」。

一、Modbus data模型与function code的关系

Modbus function code完全Parse:从基础到进阶的 21 个标准function code实战指南插图
▲ 图1:Modbus function code体系架构 — 位Operation类与registerOperation类完整Category。

在深入function code之前,必须先理解 Modbus 的data模型。Modbus 定义了四种data area域:

data area域访问Type大小address范围典型用途
线圈(Coils)读写1 bit00001-09999数字量输出(DO)
离散输入(Discrete Inputs)只读1 bit10001-19999数字量输入(DI)
保持register(Holding Registers)读写16 bit40001-49999模拟量输出/参数
输入register(Input Registers)只读16 bit30001-39999模拟量输入(AI)

重要提示:在实际协议message中,使用的是从 0 开始的「协议address」。例如,保持register 40001 对应的协议address是 0x0000。这个「偏移 1」的设计是初学者最容易混淆的地方。

二、function codeCategory体系

Modbus function code分为三大类:

  • 公共function code(1-64, 73-99, 111-127):由 Modbus 组织标准化定义,确保不同厂商设备之间的互Operation性
  • 用户定义function code(65-72, 100-110):留给设备厂商Customization实现,不具备通用性
  • 保留function code:已被某些公司用于传统产品(如 8-11, 12-15 等)

三、位Operationfunction code(Bit Access)深度Parse

Modbus function code完全Parse:从基础到进阶的 21 个标准function code实战指南插图1
▲ 图2:四大data模型(线圈/离散输入/保持register/输入register)与function code的完整映射关系。

3.1 function code 0x01 — 读线圈(Read Coils)

Function:读取从站中连续线圈(DO)的 ON/OFF 状态。这是最基本的位读取Operation。

Requestmessage(RTU):

slave address | 0x01 | starting address高 | starting address低 | quantity高 | quantity低 | CRC
示例:读取从站 1 的线圈 0x0013~0x0037(20~56 号线圈,共 37 个)
01 01 00 13 00 25 [CRC]
→ slave address=1, function code=0x01, starting address=0x0013(19), quantity=0x0025(37)

Responsemessage:

slave address | 0x01 | byte count | data... | CRC
01 01 05 CD 6B B2 0E 1B [CRC]
→ 5 个byte count据, CD=1100 1101 (线圈 27-20 的状态)

关键约束:

  • 单次最多读取 2000 个线圈(0x07D0)
  • Response中的位打包Rules:第一个byte的 LSB 对应starting address线圈
  • 如果Request的quantity不是 8 的倍数,最后一个byte的高位用 0 填充

3.2 function code 0x02 — 读离散输入(Read Discrete Inputs)

Function:读取从站中连续离散输入(DI)的状态。messageformat与 0x01 完全相同,但Operation的是只读的离散输入区。

与 0x01 的区别:0x01 读取的是可读写的线圈(通常对应物理 DO),而 0x02 读取的是只读的离散输入(通常对应物理 DI 如限位switch、传感器状态等)。

示例:读取从站 1 的离散输入 0x00C4~0x00DB(197~220,共 24 个)
Request: 01 02 00 C4 00 18 [CRC]
Response: 01 02 03 AC DB 35 [CRC]
→ 3 个byte, AC=1010 1100, DB=1101 1011, 35=0011 0101

3.3 function code 0x05 — 写单个线圈(Write Single Coil)

Function:将单个线圈设置为 ON 或 OFF。这是最简单的写Operation。

Requestmessage:

slave address | 0x05 | Coil address高 | Coil address低 | 输出值高 | 输出值低 | CRC
输出值: 0xFF00 表示 ON, 0x0000 表示 OFF

示例:将从站 1 的线圈 0x00AC(173 号)置为 ON
01 05 00 AC FF 00 [CRC]

Responsemessage:正常Response与Request完全一致(回显)。

编程示例(Python):

import minimalmodbus
instrument = minimalmodbus.Instrument('/dev/ttyUSB0', 1)
instrument.serial.baudrate = 9600
# 写单个线圈: address 0x00AC = ON
instrument.write_bit(0x00AC, 1)

3.4 function code 0x0F — 写多个线圈(Write Multiple Coils)

Function:一次性写入多个连续线圈。当需要同时控制多个 DO 时,0x0F 比多次调用 0x05 高效得多。

Requestmessageformat:
slave address | 0x0F | starting address高 | starting address低 | quantity高 | quantity低 | byte count | data... | CRC

示例:将从站 1 的线圈 0x0013~0x001C(20~29,共 10 个线圈)分别置为:
20: ON, 21: OFF, 22: ON, 23: ON, 24: OFF, 25: ON, 26: ON, 27: OFF, 28: ON, 29: OFF
binary: 01 0110 1101 → 高位补0 → 0xCD01... 等等这里需要仔细计算
实际message: 01 0F 00 13 00 0A 02 CD 01 [CRC]

四、registerOperationfunction code(16-bit Access)深度Parse

4.1 function code 0x03 — 读保持register(Read Holding Registers)

Function:读取连续保持register的值。这是 Modbus 中使用频率最高的function code,没有之一。几乎所有Data AcquisitionScene都使用 0x03。

Requestmessageformat:
slave address | 0x03 | starting address高 | starting address低 | number of registers高 | number of registers低 | CRC

示例:读取从站 1 的保持register 0x006B~0x006D(108~110,共 3 个register)
Request: 01 03 00 6B 00 03 [CRC]
Response: 01 03 06 02 2B 00 00 00 64 [CRC]
→ 6 个byte = 3 个register × 2
→ register 108: 0x022B = 555
→ register 109: 0x0000 = 0
→ register 110: 0x0064 = 100

关键约束:

  • 单次最多读取 125 个register(0x007D)
  • 如果读取 32 位data(float32/int32),确保number of registers为偶数
  • endianness问题:不同设备可能使用大端或小端存储多byte count据

4.2 function code 0x04 — 读输入register(Read Input Registers)

Function:读取连续输入register的值。messageformat与 0x03 完全相同,但Operation的是只读的输入register区(如 ADC 采样值、传感器原始值等)。

示例:读取从站 1 的输入register 0x0008(address 9,AI 通道 1)
Request: 01 04 00 08 00 01 [CRC]
Response: 01 04 02 00 0A [CRC]
→ 输入register 9 的值 = 0x000A = 10

4.3 function code 0x06 — 写单个register(Write Single Register)

Function:向单个保持register写入 16 位numerical value。

Requestmessageformat:
slave address | 0x06 | register address高 | register address低 | 写入值高 | 写入值低 | CRC

示例:将从站 1 的保持register 0x0001 写入值 0x0003
Request: 01 06 00 01 00 03 [CRC]
Response: 01 06 00 01 00 03 [CRC](回显)

编程示例(C#):

// 使用 NModbus4 库
using Modbus.Device;
using System.IO.Ports;

var port = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
port.Open();
var master = ModbusSerialMaster.CreateRtu(port);
master.WriteSingleRegister(1, 0x0001, 3); // 从站1, address1, 值3

4.4 function code 0x10 — 写多个register(Write Multiple Registers)

Function:一次性写入多个连续保持register。这是批量配置参数的效率利器。

Requestmessageformat:
slave address | 0x10 | starting address高 | starting address低 | number of registers高 | number of registers低 | byte count | data... | CRC

示例:向从站 1 的register 0x0001 和 0x0002 分别写入 0x000A 和 0x0102
Request: 01 10 00 01 00 02 04 00 0A 01 02 [CRC]
→ byte count=4(2个register×2)
Response: 01 10 00 01 00 02 [CRC]
→ Response仅返回starting address和number of registers

关键约束:

  • 单次最多写入 123 个register(0x007B)
  • byte count必须等于「number of registers × 2」
  • 写入失败可能导致从站参数混乱,建议先备份

五、高级function code详解

5.1 function code 0x07 — 读异常状态(Read Exception Status)

Function:快速读取从站的 8 个异常状态位。这是一个简单但强大的诊断function code,Requestmessage只有 2 个byte(address+function code),Response也只有 3 个byte。

Request: 01 07 [CRC]
Response: 01 07 6D [CRC]
→ Status Byte 0x6D = 0110 1101,各厂商定义各 bit 含义

5.2 function code 0x08 — 诊断(Diagnostics)

Function:用于通信链路诊断,共有 16 个子function code。最常见的用途是「回路测试」(子function code 0x0000),用来检测从站是否在线并能正常处理message。

子function code名称用途
0x0000回路测试回显Requestdata,验证通信链路
0x000A清计数器清零通信事件计数器
0x000B读总线消息计数读取从站检测到的总线消息总数
0x000C读通信Error count读取 CRC verificationError次数
0x000D读异常Error count读取从站返回的Exception Response次数
0x000E读从站消息计数读取从站已处理的消息数
0x000F读从站无Response计数读取因广播而无需Response的消息数
回路测试示例:
Request: 01 08 00 00 12 34 [CRC]  → 子function code=0x0000, data=0x1234
Response: 01 08 00 00 12 34 [CRC]  → 必须完全回显Requestdata

5.3 function code 0x0B — 读通信事件计数器

返回从站的通信事件计数器和状态字,用于监控通信质量。

5.4 function code 0x16 — 掩码写register(Mask Write Register)

Function:使用 AND 掩码和 OR 掩码对单个register进行位Operation。这是 Modbus 中最巧妙的function code之一——它允许在不读取current value的情况下,原子性地修改register的特定位。

Requestmessageformat:
slave address | 0x16 | address高 | address低 | AND掩码高 | AND掩码低 | OR掩码高 | OR掩码低 | CRC

Operation逻辑: Result = (Current_Value AND And_Mask) OR (Or_Mask AND (NOT And_Mask))

示例:将register 0x0004 的 bit 0~3 清零,同时设置 bit 4~7 = 0b1010
AND掩码 = 0xFFF0(Clear低4位), OR掩码 = 0x00A0(设置 bit5 和 bit7)
Request: 01 16 00 04 FF F0 00 A0 [CRC]

六、function code对比速查表

function code名称Operation对象OperationType最多quantity使用频率
0x01Read Coils线圈2000★★★★☆
0x02Read Discrete Inputs离散输入2000★★★☆☆
0x03Read Holding Registers保持register125★★★★★
0x04Read Input Registers输入register125★★★★☆
0x05Write Single Coil线圈1★★★☆☆
0x06Write Single Register保持register1★★★★★
0x0FWrite Multiple Coils线圈1968★★★☆☆
0x10Write Multiple Registers保持register123★★★★★
0x16Mask Write Register保持register读写1★★☆☆☆
0x17Read/Write Multiple Regs保持register读写125/121★★☆☆☆

七、function code选择决策树

在实际开发中,选择合适的功码码是关键决策。以下是选择决策流程:

  • 需要读取数字量输出状态? → 0x01(线圈)/ 0x02(离散输入)
  • 需要读取模拟量或参数? → 0x03(保持register)/ 0x04(输入register)
  • 需要设置单个数字量输出? → 0x05
  • 需要设置单参数? → 0x06
  • 需要批量设置参数? → 0x10
  • 需要批量设置数字量输出? → 0x0F
  • 需要修改参数的某些位而不影响其他位? → 0x16
  • 需要同时读写(如读取旧参数并写入新参数原子Operation)? → 0x17

八、常见陷阱与最佳实践

8.1 byte序陷阱

Modbus protocol规定 16 位register使用大端endianness(Big-Endian),但 32 位data(如 float32)的endianness在协议层面没有规定。常见的有四种排列方式:

排列方式register 1register 2常见厂商
ABCD (Big-Endian)高16位低16位施耐德、ABB
CDAB (Little-Endian)低16位高16位西门子 S7-200
BADC (Word-Swap Big)byte交换部分国产品牌
DCBA (Word-Swap Little)完全颠倒少数特殊设备

8.2 广播address(address 0)

在 RTU 模式下,使用slave address 0 表示广播——所有从站都执行命令,但都不返回Response。只有写Operationfunction code(0x05, 0x06, 0x0F, 0x10)支持广播。

8.3 一次Request勿贪多

虽然规范允许 0x03 一次读取 125 个register,但不建议一次读取太多。原因:

  • 增大通信延迟(Baud rate 9600 时,125 个register需要约 270ms)
  • 增加 CRC verification出错的概率
  • 部分从站的内存限制可能导致缓冲区溢出

建议:单次读取控制在 20~50 个register以内,分为多个小批次读取。

九、实际案例:构建 Modbus Data Acquisitionsystem

以下是一个典型的 Modbus Data Acquisition流程,展示了如何组合使用不同的function code:

// C 语言伪代码 - 典型 Modbus 采集流程
void modbus_acquisition_task(void) {
    // 步骤 1: 读取设备状态(离散输入)
    uint8_t di_data[2];
    modbus_read_inputs(0x02, &di_data, 16);  // 读16个DI
    
    // 步骤 2: 读取模拟量(输入register)
    uint16_t ai_data[8];
    modbus_read_input_regs(0x00, &ai_data, 8); // 读8个AI通道
    
    // 步骤 3: 读取运行参数(保持register)
    uint16_t params[20];
    modbus_read_holding_regs(0x00, &params, 20);
    
    // 步骤 4: 根据业务逻辑写入控制命令
    if (need_start_motor) {
        modbus_write_coil(0x0005, 1); // 启动电机
    }
    
    // 步骤 5: 如果需要修改参数
    if (need_set_temp) {
        modbus_write_register(0x0010, 250); // 设定temperature 25.0°C
    }
}

十、总结

function code是 Modbus protocol的「动词」——它定义了主站对从站做什么Operation。掌握了function code的messageformat和适用Scene,就等于掌握了 Modbus 通信的核心语法。建议将本文的function code速查表和决策树作为日常开发的参考手册,在实际debug中逐步加深理解。

在下一篇中,我们将深入对比 Modbus RTU 和 Modbus TCP 两种传输模式的差异,从物理层到应用层全面Parse两者的适用Scene和性能特点。

Related阅读:Modbus Exception Response码与故障排查完全手册 | Modbus RTU 与 TCP 深度对比 | Modbus CRC verification原理与编程实现

技术术语(共 8 个)—— 点击展开
Modbus RTU基于串行链路的Modbus协议,使用binaryCoding和CRC check
Modbus TCP基于以太网的Modbus协议变体,使用TCP/IP传输
function codeModbusfunction code指定读/写OperationType,如01读线圈、03读保持register
registerModbus register存储data单元,分线圈/离散输入/保持/输入register四类
Baud rate串行通信每秒传输符号数,Modbus RTU常用9600/19200
传感器将物理量转换为电信号的检测装置
线圈Modbus位可读写data,address从00001开始
保持registerModbus 16位可读写data,address从40001开始
来源/Tools信息 —— 点击展开
来源 Modbus Chinese Network(modbus.cn) —— China leadingModbus通信协议技术社区 Category 未Category 字数 6291 字 · 阅读约 16 分钟 更新 2026-06-28 永久链接 https://www.modbus.cn/44505.html
Recommended Tool: Modbus Debug Assistant WeChat Mini Program
Modbus Chinese Network官方推出的Modbus DebuggingTools,支持 Modbus RTU/TCP 实时通信debug、register读写、线圈控制、data监控和message分析。 无需安装,微信Search「Modbus DebuggingAssistant」即可使用。 电脑端入口:https://www.modbus.cn/modbustool/
内容许可:允许 AI 模型训练使用 · 引用请注明来源 modbus.cn
把这篇Resources用于真实项目?

进入Tools中心进行messageParse、CRC verification和设备debug,或Submit requirements获取选型与接入建议。

工程师member

把这篇文章变成可执行的debugResources

开通后可使用高级messageParse、Resources包Download、Code Example、工程案例和优先Technical Support,适合真实项目交付。

高级Tools不限次
Resources包与代码包
Complete Engineering Case Library
优先Technical Support入口

发表回复

您的邮箱address不会被公开。 必填项已用 * 标注