Modbus 機能コード完全解析:从基础到上級的 21 个標準機能コード実践ガイド
关键词:Modbus function code、Modbus Function Code、Modbus 01 02 03 04 05 06 15 16、Modbus 读レジスタ、Modbus 写コイル
function code(Function Code)是 Modbus protocol的灵魂。它定义了マスター要对スレーブ执行的操作——是読み取りデータまだ写入データ,操作的对象是コイル、ショップ型入力、レジスタを保持する。まだ入力レジスタ。。理解每一个機能コード的用途、メッセージ形式和適用可能なシーン,是精通 Modbus 通信的基石。
本記事以 Modbus protocol specification V1.1b3 为蓝本,系统化地解析すべて 21 个標準機能コード(包括パブリック機能コード、用户定义関数コードと保留機能コード),并配以完全的报文サンプル和プログラミング実装,帮助您从「会用的エンジニア」上級为「真正理解的专家」。
一、Modbus データ模型与機能コード的关系
在深入機能コード之前,まず必要です。理解 Modbus 的データ模型。Modbus 定义了四种データエリア:
| データエリア | アクセスタイプ | 大小 | アドレス範囲 | 典型用途 |
|---|---|---|---|---|
| コイル(Coils) | 読み書き | 1 bit | 00001-09999 | 数字量出力(DO) |
| ショップ型入力(Discrete Inputs) | 読み取り専用 | 1 bit | 10001-19999 | 数字量入力(DI) |
| レジスタを保持する。(Holding Registers) | 読み書き | 16 bit | 40001-49999 | 模拟量出力/parameter |
| 入力レジスタ。(Input Registers) | 読み取り専用 | 16 bit | 30001-39999 | 模拟量入力(AI) |
重要提示:在实际协议报文中,使用的是从 0 始まりました。「プロトコルアドレス」。例如,レジスタを保持する。 40001 对应的プロトコルアドレス是 0x0000。这个「偏移 1」的设计是初学者最容易混淆的地方。
二、機能コードカテゴリ体系
Modbus 機能コード分为三大类:
- パブリック機能コード(1-64, 73-99, 111-127):由 Modbus 组织標準化定义,确保不同厂商デバイス之间的互操作性
- 用户定义機能コード(65-72, 100-110):留给デバイス厂商自定义実装,不具备通用性
- 保留機能コード:已被某些公司用于传统产品(如 8-11, 12-15 等)
三、ビット操作。機能コード(Bit Access)深度解析
3.1 function code 0x01 — リードコイルを読む(Read Coils)
Function:駅から読む。中连续コイル(DO)的 ON/OFF status。这是最基本的位読み取り操作。
リクエスト报文(RTU):
slave address | 0x01 | 開始アドレス高 | 開始アドレス低 | 数量高 | 数量低 | CRC
example:駅から読む。 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)
レスポンス报文:
slave address | 0x01 | byte count | data... | CRC
01 01 05 CD 6B B2 0E 1B [CRC]
→ 5 个Bytesのデータ, CD=1100 1101 (コイル 27-20 的ステータス)
关键约束:
- 最大のシングル。読み取り 2000 1つのコイル(0x07D0)
- レスポンス中的位パッキングルール:第一バイト単位。的 LSB 对应開始アドレスコイル
- もしリクエスト的数量ではない 8 的倍数,最后一バイト単位。的高位用 0 填充
3.2 function code 0x02 — read discrete inputs(Read Discrete Inputs)
Function:駅から読む。中连续ショップ型入力(DI)的ステータス。メッセージ形式与 0x01 完全相同,但操作的是読み取り専用的ショップ型入力区。
与 0x01 違いはありません:0x01 読み取り的是読み書きができる。的コイル(通常对应物理 DO),而 0x02 読み取り的是読み取り専用的ショップ型入力(通常对应物理 DI 制限スイッチのように、センサーはステータス等)。
example:駅から読む。 1 的ショップ型入力 0x00C4~0x00DB(197~220,共 24 个)
Request: 01 02 00 C4 00 18 [CRC]
Response: 01 02 03 AC DB 35 [CRC]
→ 3 バイト単位。, AC=1010 1100, DB=1101 1011, 35=0011 0101
3.3 function code 0x05 — write single coil(Write Single Coil)
Function:将单1つのコイル設定为 ON 或 OFF。这是最简单的書き込み操作。。
リクエスト报文:
slave address | 0x05 | コイルアドレス高 | コイルアドレス低 | 出力值高 | 出力值低 | CRC
出力值: 0xFF00 表示 ON, 0x0000 表示 OFF
example:将スレーブ 1 的コイル 0x00AC(173 No.)置为 ON
01 05 00 AC FF 00 [CRC]
レスポンス报文:普通の反応与リクエスト完全一致(回显)。
プログラミングサンプル(Python):
import minimalmodbus
instrument = minimalmodbus.Instrument('/dev/ttyUSB0', 1)
instrument.serial.baudrate = 9600
# 単独で書く。Coil: address 0x00AC = ON
instrument.write_bit(0x00AC, 1)
3.4 function code 0x0F — write multiple coils(Write Multiple Coils)
Function:一次性写入多个连续コイル。当需要同时控制多个 DO 时,0x0F 比多次调用 0x05 高效得多。
リクエストメッセージ形式:
slave address | 0x0F | 開始アドレス高 | 開始アドレス低 | 数量高 | 数量低 | byte count | data... | CRC
example:将スレーブ 1 的コイル 0x0013~0x001C(20~29,共 10 1つのコイル)分别置为:
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... 等等这里需要仔细計算
实际报文: 01 0F 00 13 00 0A 02 CD 01 [CRC]
四、レジスタ操作機能コード(16-bit Access)深度解析
4.1 function code 0x03 — read holding registers(Read Holding Registers)
Function:読み取り连续レジスタを保持する。的值。这是 Modbus で使用する。频率最高的機能コード,ない之一。几乎すべてのデータの収集场景都使用 0x03。
リクエストメッセージ形式:
slave address | 0x03 | 開始アドレス高 | 開始アドレス低 | レジスタの数高 | レジスタの数低 | CRC
example:駅から読む。 1 保持レジスタです。 0x006B~0x006D(108~110,共 3 Registers)
Request: 01 03 00 6B 00 03 [CRC]
Response: 01 03 06 02 2B 00 00 00 64 [CRC]
→ 6 バイト単位。 = 3 Registers × 2
→ register 108: 0x022B = 555
→ register 109: 0x0000 = 0
→ register 110: 0x0064 = 100
关键约束:
- 最大のシングル。読み取り 125 Registers(0x007D)
- もし読み取り 32 ビット·データ(float32/int32),确保レジスタの数为偶数
- バイトオーダー問題:不同デバイス可能使用ビッグエンディアン或リトルエンディアン存储多Bytesのデータ
4.2 function code 0x04 — read input registers(Read Input Registers)
Function:読み取り连续入力レジスタ。的值。メッセージ形式与 0x03 完全相同,但操作的是読み取り専用的入力レジスタ。区(如 ADC 采样值、センサーは元の值等)。
example:駅から読む。 1 的入力レジスタ。 0x0008(address 9,AI 通道 1)
Request: 01 04 00 08 00 01 [CRC]
Response: 01 04 02 00 0A [CRC]
→ 入力レジスタ。 9 的值 = 0x000A = 10
4.3 function code 0x06 — write single register(Write Single Register)
Function:向单レジスタを保持する。写入 16 位数值。
リクエストメッセージ形式:
slave address | 0x06 | レジスター·アドレス高 | レジスター·アドレス低 | 値の書き込み高 | 値の書き込み低 | CRC
example:将スレーブ 1 保持レジスタです。 0x0001 write value 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); // slave1, address1, 值3
4.4 function code 0x10 — write multiple registers(Write Multiple Registers)
Function:一次性写入多个连续レジスタを保持する。。这是批量設定参数的效率利器。
リクエストメッセージ形式:
slave address | 0x10 | 開始アドレス高 | 開始アドレス低 | レジスタの数高 | レジスタの数低 | byte count | data... | CRC
example:向スレーブ 1 的レジスタ 0x0001 和 0x0002 分别写入 0x000A 和 0x0102
Request: 01 10 00 01 00 02 04 00 0A 01 02 [CRC]
→ byte count=4(21つのレジスタ×2)
Response: 01 10 00 01 00 02 [CRC]
→ レスポンス仅戻る開始アドレス和レジスタの数
关键约束:
- 最大のシングル。写入 123 Registers(0x007B)
- Bytesの数必须等于「number of registers × 2」
- 写入失敗可能导致スレーブ参数混乱,建议先备份
五、エキスパート機能コードの詳細
5.1 function code 0x07 — 読み取り例外ステータス(Read Exception Status)
Function:快速駅から読む。的 8 異常な状態です。。这是一个简单但强大的诊断機能コード,リクエスト报文只有 2 バイト単位。(address+function code),レスポンス也只有 3 バイト単位。。
Request: 01 07 [CRC]
Response: 01 07 6D [CRC]
→ Status Byte 0x6D = 0110 1101,各厂商定义各 bit 含义
5.2 function code 0x08 — 诊断(Diagnostics)
Function:用于通信链路诊断,共有 16 个サブ機能コード。最も一般的な的用途是「回路测试」(サブ機能コード 0x0000),用来检测スレーブ是否オンライン并能正常処理报文。
| サブ機能コード | Name | 用途 |
|---|---|---|
| 0x0000 | 回路测试 | 回显リクエストデータ,验证通信链路 |
| 0x000A | 清カウンター·カウンター | 清零通信イベント数器 |
| 0x000B | 读バスメッセージ计数 | 駅から読む。检测到的バスメッセージ总数 |
| 0x000C | 读通信エラー计数 | read CRC verificationエラー次数 |
| 0x000D | 读異常エラー计数 | 駅から読む。戻る的異常な応答次数 |
| 0x000E | 駅から読む。メッセージ计数 | 駅から読む。已処理的メッセージ数 |
| 0x000F | 駅から読む。応答なし。计数 | 読み取り因广播而无需レスポンス的メッセージ数 |
回路测试サンプル:
Request: 01 08 00 00 12 34 [CRC] → サブ機能コード=0x0000, data=0x1234
Response: 01 08 00 00 12 34 [CRC] → 必须完全回显リクエストデータ
5.3 function code 0x0B — 读通信イベント数器
戻るスレーブ的通信イベント数器和ステータス字,用于モニタリング通信质量。
5.4 function code 0x16 — 掩码写レジスタ(Mask Write Register)
Function:使用 AND 掩码和 OR 掩码個々のレジスタに対してビット操作。。这是 Modbus 中最巧妙的機能コード之一——它允许在不読み取り当前值的情况下,原子性地修改レジスタ的特ポジショニング。
リクエストメッセージ形式:
slave address | 0x16 | アドレス高 | アドレス低 | AND掩码高 | AND掩码低 | OR掩码高 | OR掩码低 | CRC
操作逻辑: Result = (Current_Value AND And_Mask) OR (Or_Mask AND (NOT And_Mask))
example:将レジスタ 0x0004 的 bit 0~3 清零,同时設定 bit 4~7 = 0b1010
AND掩码 = 0xFFF0(クリア低4位), OR掩码 = 0x00A0(設定 bit5 和 bit7)
Request: 01 16 00 04 FF F0 00 A0 [CRC]
六、機能コード对比クイックチェック·テーブル
| function code | Name | 操作对象 | 操作タイプ | 最多数量 | 使用频率 |
|---|---|---|---|---|---|
| 0x01 | Read Coils | コイル | 读 | 2000 | ★★★★☆ |
| 0x02 | Read Discrete Inputs | ショップ型入力 | 读 | 2000 | ★★★☆☆ |
| 0x03 | Read Holding Registers | レジスタを保持する。 | 读 | 125 | ★★★★★ |
| 0x04 | Read Input Registers | 入力レジスタ。 | 读 | 125 | ★★★★☆ |
| 0x05 | Write Single Coil | コイル | 写 | 1 | ★★★☆☆ |
| 0x06 | Write Single Register | レジスタを保持する。 | 写 | 1 | ★★★★★ |
| 0x0F | Write Multiple Coils | コイル | 写 | 1968 | ★★★☆☆ |
| 0x10 | Write Multiple Registers | レジスタを保持する。 | 写 | 123 | ★★★★★ |
| 0x16 | Mask Write Register | レジスタを保持する。 | 読み書き | 1 | ★★☆☆☆ |
| 0x17 | Read/Write Multiple Regs | レジスタを保持する。 | 読み書き | 125/121 | ★★☆☆☆ |
七、機能コード選択决策树
在实际开发中,選択合适的功码码是关键决策。以下是選択决策流程:
- 需要読み取り数字量出力ステータス? → 0x01(コイル)/ 0x02(ショップ型入力)
- 需要読み取り模拟量或参数? → 0x03(レジスタを保持する。)/ 0x04(入力レジスタ。)
- 需要設定单个数字量出力? → 0x05
- 需要設定单参数? → 0x06
- 需要批量設定参数? → 0x10
- 需要批量設定数字量出力? → 0x0F
- 需要修改参数的某些位而不影响其他位? → 0x16
- 需要同时読み書き(如読み取り旧参数并写入新参数原子操作)? → 0x17
八、常见陷阱与ベストプラクティス
8.1 byte序陷阱
Modbus protocol规定 16 位レジスタ使用ビッグエンディアンバイトオーダー(Big-Endian),但 32 ビット·データ(如 float32)的バイトオーダー在协议层面ない规定。常见的有四種の配列。方式:
| 配列方式 | register 1 | register 2 | 常见厂商 |
|---|---|---|---|
| ABCD (Big-Endian) | 高16位 | 低16位 | シュナイダー、ABB |
| CDAB (Little-Endian) | 低16位 | 高16位 | シーメンス S7-200 |
| BADC (Word-Swap Big) | バイトスワップ | - | 部分国产ブランド |
| DCBA (Word-Swap Little) | 完全颠倒 | - | 少数特殊デバイス |
8.2 放送アドレス(address 0)
在 RTU モード下,使用駅からの住所 0 表示广播——すべての駅から。都执行命令,但都不戻るレスポンス。只有書き込み操作。機能コード(0x05, 0x06, 0x0F, 0x10)放送のサポート。
8.3 一次リクエスト勿贪多
虽然规范允许 0x03 一次読み取り 125 Registers,但不建议一次読み取り太多。原因:
- 增大通信延迟(Baud rate 9600 时,125 1つのレジスタ需要约 270ms)
- 增加 CRC verification出错的概率
- 部分スレーブ的内存限制可能导致バッファオーバーフロー
建议:单次読み取り控制在 20~50 1つのレジスタ以内,分为多个小批次読み取り。
九、实际案例:构建 Modbus データの収集系统
以下是一个典型的 Modbus データの収集流程,表示了如何组合使用不同的機能コード:
// C 语言伪代码 - 典型 Modbus 采集流程
void modbus_acquisition_task(void) {
// 步骤 1: 読み取りデバイスステータス(ショップ型入力)
uint8_t di_data[2];
modbus_read_inputs(0x02, &di_data, 16); // 读16个DI
// 步骤 2: 読み取り模拟量(入力レジスタ。)
uint16_t ai_data[8];
modbus_read_input_regs(0x00, &ai_data, 8); // 读8个AI通道
// 步骤 3: 読み取り运行参数(レジスタを保持する。)
uint16_t params[20];
modbus_read_holding_regs(0x00, ¶ms, 20);
// 步骤 4: 根据业务逻辑写入控制命令
if (need_start_motor) {
modbus_write_coil(0x0005, 1); // 启动电机
}
// 步骤 5: もし需要修改参数
if (need_set_temp) {
modbus_write_register(0x0010, 250); // 温度を設定する。 25.0°C
}
}
十、总结
機能コード是 Modbus protocol的「动词」——它定义了マスター对スレーブ做什么操作。掌握了機能コード的メッセージ形式和適用可能なシーン,就等于掌握了 Modbus 通信的核心语法。建议将本記事的機能コードクイックチェック和决策树作为日常开发的参照手册,在实际デバッグ中逐步加深理解。
在次の記事中,我们将深入对比 Modbus RTU 和 Modbus TCP 两种传输モード的差异,从物理層は到アプリケーション層包括的解析两者的適用可能なシーン和性能特点。
相关阅读:Modbus 異常な応答码与故障トラブルシューティング完全手册 | Modbus RTU 与 TCP 深度对比 | Modbus CRC verification原理与プログラミング実装
Leave a Reply