参考資料#
各ブログサイトは欠落や誤りがあり、レイアウトが乱れているため、参考にしないことをお勧めします。
ここに modbus 中国語サイトの資料があります
MODBUS プロトコル中国語版 / 英語版プレビューとダウンロード | Modbus IoT クラウドプラットフォーム
より権威のあるのは公式文書です
および公式の他の文書は、ここで探すことができます
もちろん、公式文書にもあまり満足していません。彼らの古代の設計構造を維持するために、各フレームセグメントの紹介が直感的ではなく、少数の誤字もあります。
以下は自分が書き直した有効な情報です。
また、私自身が実装したライブラリがあります
stbanana/modbusX: modbus プロトコルサポート (github.com)
プロトコルの特徴#
全体フレーム構造#
メッセージヘッダー | アドレスフィールド | 機能コード | データフィールド | チェックフィールド | |
---|---|---|---|---|---|
RTU | 1 バイト (スレーブ ID) | 1 バイト | n バイト不定 | 2 バイト (他のすべての内容の CRC-MB16) | |
TCP | 6 バイト (2 バイトトランザクション番号 + 2 バイトプロトコル識別子 - 全て 0+ 2 バイト後続バイトの総長 - スレーブ ID を含む) | 1 バイト (スレーブ ID) | 1 バイト | n バイト不定 |
メッセージヘッダーについては、公式文書の全体モデルではアドレスフィールドに分類されていますが、実際のバイトの総長にはスレーブ ID も含まれています。おそらく、初期のシリアルプロトコルのみの時に全体モデルが決まったため、新たに追加された modbusTCP は互換性のために無理をしているのでしょう。
私はここで直接再分類しましたが、標準ではありませんが、私はそれを好みます。
レジスタ属性#
RW 属性 | ビット数 | |
---|---|---|
コイル (0x01) | 読み書き可能 | 1 ビット |
離散入力レジスタ (0x02) | 読み取り専用 | 1 ビット |
ホールドレジスタ (0x03) | 読み書き可能 | 16 ビット |
入力レジスタ (0x04) | 読み取り専用 | 16 ビット |
全体モデル#
ソフトウェアを使用してメモリ構造を抽象化し、各アドレスに異なる意味のデータを格納します。FPGA が SRAM をシミュレートするのと同じ原理です。ただし、各レジスタアドレスは必ずしも 16 ビットではなく、1 ビットであることもあります。属性は RO\RW です。
RTU シリーズ#
(0x01) コイルの読み取り#
ホスト要求#
アドレスフィールド | 機能コード | 開始アドレス | コイル数 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 2 バイト | 2 バイト | 2 バイト (CRC-MB16) |
スレーブ応答#
アドレスフィールド | 機能コード | バイト数 | コイル状態 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 1 バイト (計算コイル状態部分のバイト数) | n バイト | 2 バイト (CRC-MB16) |
例#
20〜38 アドレスのコイルデータを読み取る要求をし、返信アドレスは低位から高位に、最終バイトが不足している場合は高位に 0 を埋めます。
[!NOTE]
最終的な出力状態 38-36 の返信バイトは、5 つの残りのビットをゼロで埋めます(高位端まで)。
要求 | 応答 | ||
---|---|---|---|
アドレスフィールド (スレーブ ID) | 0x01 | アドレスフィールド (スレーブ ID) | 0x01 |
機能コード | 0x01 | 機能コード | 0x01 |
開始アドレス高 8 ビット | 0x00 | バイト数 | 0x03 |
開始アドレス低 8 ビット | 0x13 | 出力状態 27-20 | 0xCD |
出力数量高 8 ビット | 0x00 | 出力状態 35-28 | 0x6B |
出力数量低 8 ビット | 0x13 | 出力状態 38-36 | 0x05 |
チェック CRC 低 8 ビット | 0xA9 | チェック CRC 低 8 ビット | 0x42 |
チェック CRC 高 8 ビット | 0xC8 | チェック CRC 高 8 ビット | 0x82 |
(0x02) 離散入力レジスタの読み取り#
ホスト要求#
アドレスフィールド | 機能コード | 開始アドレス | 離散入力数 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 2 バイト | 2 バイト | 2 バイト (CRC-MB16) |
スレーブ応答#
アドレスフィールド | 機能コード | バイト数 | 離散入力状態 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 1 バイト (計算離散入力状態部分のバイト数) | n バイト | 2 バイト (CRC-MB16) |
例#
197〜218 アドレスの離散入力レジスタデータを読み取る要求をし、返信アドレスは低位から高位に、最終バイトが不足している場合は高位に 0 を埋めます。
[!NOTE]
最終的な入力状態 218-213 の返信バイトは、2 つの残りのビットをゼロで埋めます(高位端まで)。
要求 | 応答 | ||
---|---|---|---|
アドレスフィールド (スレーブ ID) | 0x01 | アドレスフィールド (スレーブ ID) | 0x01 |
機能コード | 0x02 | 機能コード | 0x02 |
開始アドレス高 8 ビット | 0x00 | バイト数 | 0x03 |
開始アドレス低 8 ビット | 0xC4 | 入力状態 204-197 | 0xAC |
出力数量高 8 ビット | 0x00 | 入力状態 212-205 | 0xDB |
出力数量低 8 ビット | 0x16 | 入力状態 218-213 | 0x35 |
チェック CRC 低 8 ビット | 0xB8 | チェック CRC 低 8 ビット | 0x22 |
チェック CRC 高 8 ビット | 0x39 | チェック CRC 高 8 ビット | 0x88 |
(0x03) 保持レジスタの読み取り#
ホスト要求#
アドレスフィールド | 機能コード | 開始アドレス | 保持レジスタ数 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 2 バイト | 2 バイト | 2 バイト (CRC-MB16) |
スレーブ応答#
アドレスフィールド | 機能コード | バイト数 | 保持レジスタ状態 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 1 バイト (計算保持レジスタ状態部分のバイト数) | n バイト | 2 バイト (CRC-MB16) |
例#
108〜110 アドレスの保持レジスタデータを読み取る要求をします。
要求 | 応答 | ||
---|---|---|---|
アドレスフィールド (スレーブ ID) | 0x01 | アドレスフィールド (スレーブ ID) | 0x01 |
機能コード | 0x03 | 機能コード | 0x03 |
開始アドレス高 8 ビット | 0x00 | バイト数 | 0x06 |
開始アドレス低 8 ビット | 0x6B | レジスタ値高 8 ビット(108) | 0x02 |
レジスタ数量高 8 ビット | 0x00 | レジスタ値低 8 ビット(108) | 0x2B |
レジスタ数量低 8 ビット | 0x03 | レジスタ値高 8 ビット(109) | 0x00 |
チェック CRC 低 8 ビット | 0x74 | レジスタ値低 8 ビット(109) | 0x00 |
チェック CRC 高 8 ビット | 0x17 | レジスタ値高 8 ビット(110) | 0x00 |
レジスタ値低 8 ビット(110) | 0x64 | ||
チェック CRC 低 8 ビット | 0x05 | ||
チェック CRC 高 8 ビット | 0x7A |
(0x04) 入力レジスタの読み取り#
ホスト要求#
アドレスフィールド | 機能コード | 開始アドレス | 入力レジスタ数 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 2 バイト | 2 バイト | 2 バイト (CRC-MB16) |
スレーブ応答#
アドレスフィールド | 機能コード | バイト数 | 入力レジスタ状態 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 1 バイト (計算入力レジスタ状態部分のバイト数) | n バイト | 2 バイト (CRC-MB16) |
例#
9〜10 アドレスの保持レジスタデータを読み取る要求をします。
要求 | 応答 | ||
---|---|---|---|
アドレスフィールド (スレーブ ID) | 0x01 | アドレスフィールド (スレーブ ID) | 0x01 |
機能コード | 0x04 | 機能コード | 0x04 |
開始アドレス高 8 ビット | 0x00 | バイト数 | 0x06 |
開始アドレス低 8 ビット | 0x6B | レジスタ値高 8 ビット(9) | 0x02 |
レジスタアドレス高 8 ビット | 0x00 | レジスタ値低 8 ビット(9) | 0x2B |
レジスタアドレス低 8 ビット | 0x03 | レジスタ値高 8 ビット(10) | 0x00 |
チェック CRC 低 8 ビット | 0xC1 | レジスタ値低 8 ビット(10) | 0x00 |
チェック CRC 高 8 ビット | 0xD7 | チェック CRC 低 8 ビット | 0xF3 |
チェック CRC 高 8 ビット | 0xF4 |
(0x05) 単一コイルの書き込み#
[!NOTE]
単一コイルの書き込みでは、出力値部分は FF 00 が ON、00 00 が OFF を示すことのみ許可され、他の値は無効です。
ホスト要求#
アドレスフィールド | 機能コード | 出力アドレス | 出力値 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 2 バイト | 2 バイト | 2 バイト (CRC-MB16) |
スレーブ応答#
アドレスフィールド | 機能コード | アドレス | 出力値 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 2 バイト | 2 バイト | 2 バイト (CRC-MB16) |
例#
173 アドレスのコイルデータを ON に書き込む要求をします。
要求 | 応答 | ||
---|---|---|---|
アドレスフィールド (スレーブ ID) | 0x01 | アドレスフィールド (スレーブ ID) | 0x01 |
機能コード | 0x05 | 機能コード | 0x05 |
レジスタアドレス高 8 ビット | 0x00 | レジスタアドレス高 8 ビット | 0x00 |
レジスタアドレス低 8 ビット | 0xAC | レジスタアドレス低 8 ビット | 0xAC |
レジスタ値高 8 ビット | 0xFF | レジスタ値高 8 ビット | 0xFF |
レジスタ値低 8 ビット | 0x00 | レジスタ値低 8 ビット | 0x00 |
チェック CRC 低 8 ビット | 0x4C | チェック CRC 低 8 ビット | 0x4C |
チェック CRC 高 8 ビット | 0x1B | チェック CRC 高 8 ビット | 0x1B |
(0x06) 単一保持レジスタの書き込み#
ホスト要求#
アドレスフィールド | 機能コード | 保持レジスタアドレス | レジスタ値 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 2 バイト | 2 バイト | 2 バイト (CRC-MB16) |
スレーブ応答#
アドレスフィールド | 機能コード | 保持レジスタアドレス | レジスタ値 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 2 バイト | 2 バイト | 2 バイト (CRC-MB16) |
例#
2 アドレスの保持レジスタデータを 0x0003 に書き込む要求をします。
要求 | 応答 | ||
---|---|---|---|
アドレスフィールド (スレーブ ID) | 0x01 | アドレスフィールド (スレーブ ID) | 0x01 |
機能コード | 0x06 | 機能コード | 0x06 |
レジスタアドレス高 8 ビット | 0x00 | レジスタアドレス高 8 ビット | 0x00 |
レジスタアドレス低 8 ビット | 0x02 | レジスタアドレス低 8 ビット | 0x02 |
レジスタ値高 8 ビット | 0x00 | レジスタ値高 8 ビット | 0x00 |
レジスタ値低 8 ビット | 0x03 | レジスタ値低 8 ビット | 0x03 |
チェック CRC 低 8 ビット | 0x2C | チェック CRC 低 8 ビット | 0x2C |
チェック CRC 高 8 ビット | 0x0B | チェック CRC 高 8 ビット | 0x0B |
(0x0F) 複数コイルの書き込み#
ホスト要求#
アドレスフィールド | 機能コード | 開始アドレス | 設定数量 | バイト数 | 設定値 | チェックフィールド |
---|---|---|---|---|---|---|
1 バイト | 1 バイト | 2 バイト | 2 バイト | 1 バイト (計算設定値部分のバイト数) | n バイト | 2 バイト (CRC-MB16) |
スレーブ応答#
アドレスフィールド | 機能コード | 開始アドレス | 設定数量 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 2 バイト | 2 バイト | 2 バイト (CRC-MB16) |
例#
20 アドレスから始まる 10 個のコイルを書き込む要求をします。
[!NOTE]
合計で 2 バイト (16 ビット) を書き込む必要があり、6 つの残りのビットをゼロで埋めます(高位端まで)。
コイルアドレス | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | — | — | — | — | — | — | 29 | 28 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
対応値 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
規格に従って埋めた後、実際の設定値セクションは 0xCD 0x01 であるべきです。
要求 | 応答 | ||
---|---|---|---|
アドレスフィールド (スレーブ ID) | 0x01 | アドレスフィールド (スレーブ ID) | 0x01 |
機能コード | 0x0F | 機能コード | 0x0F |
開始アドレス高 8 ビット | 0x00 | 開始アドレス高 8 ビット | 0x00 |
開始アドレス低 8 ビット | 0x13 | 開始アドレス低 8 ビット | 0x13 |
設定数量高 8 ビット | 0x00 | 設定数量高 8 ビット | 0x00 |
設定数量低 8 ビット | 0x0A | 設定数量低 8 ビット | 0x0A |
バイト数 | 0x02 | チェック CRC 低 8 ビット | 0x24 |
設定値 (27〜20 アドレス) | 0xCD | チェック CRC 高 8 ビット | 0x09 |
設定値 (29〜28 アドレス) | 0x01 | ||
チェック CRC 低 8 ビット | 0x72 | ||
チェック CRC 高 8 ビット | 0xCB |
(0x10) 複数保持レジスタの書き込み#
ホスト要求#
アドレスフィールド | 機能コード | 開始アドレス | 設定数量 | バイト数 | 設定値 | チェックフィールド |
---|---|---|---|---|---|---|
1 バイト | 1 バイト | 2 バイト | 2 バイト | 1 バイト (計算設定値部分のバイト数) | n バイト | 2 バイト (CRC-MB16) |
スレーブ応答#
アドレスフィールド | 機能コード | 開始アドレス | 設定数量 | チェックフィールド |
---|---|---|---|---|
1 バイト | 1 バイト | 2 バイト | 2 バイト | 2 バイト (CRC-MB16) |
例#
34 アドレスから始まる 4 つの保持レジスタを書き込む要求をします。
要求 | 応答 | ||
---|---|---|---|
アドレスフィールド (スレーブ ID) | 0x01 | アドレスフィールド (スレーブ ID) | 0x01 |
機能コード | 0x10 | 機能コード | 0x10 |
開始アドレス高 8 ビット | 0x00 | 開始アドレス高 8 ビット | 0x00 |
開始アドレス低 8 ビット | 0x22 | 開始アドレス低 8 ビット | 0x22 |
設定数量高 8 ビット | 0x00 | 設定数量高 8 ビット | 0x00 |
設定数量低 8 ビット | 0x04 | 設定数量低 8 ビット | 0x04 |
バイト数 | 0x08 | チェック CRC 低 8 ビット | 0x61 |
設定値高 8 ビット (34 アドレス) | 0x00 | チェック CRC 高 8 ビット | 0xC0 |
設定値低 8 ビット (34 アドレス) | 0x40 | ||
設定値高 8 ビット (35 アドレス) | 0x00 | ||
設定値低 8 ビット (35 アドレス) | 0x24 | ||
設定値高 8 ビット (36 アドレス) | 0x00 | ||
設定値低 8 ビット (36 アドレス) | 0x01 | ||
設定値高 8 ビット (37 アドレス) | 0xBF | ||
設定値低 8 ビット (37 アドレス) | 0x52 | ||
チェック CRC 低 8 ビット | 0x5F | ||
チェック CRC 高 8 ビット | 0xCC |
異常応答フレーム#
アドレスフィールド | 機能コード | 異常コード | チェックフィールド |
---|---|---|---|
1 バイト | 1 バイト (機能コード + 0x80) | 1 バイト | 2 バイト (CRC-MB16) |
異常コード | 名称 | 意味 |
---|---|---|
0x01 | 不正な機能コード | 受信した要求命令の機能コードは許可されていない操作です。機能コードがサポートされていないか、エラー状態で要求を処理している可能性があります。 |
0x02 | 不正なデータアドレス | 受信したデータアドレスは許可されていないアドレスです。特に、開始アドレスと転送長の組み合わせが無効です。100 個のレジスタを持つコントローラに対して、開始アドレス 96 と長さ 4 の要求は成功しますが、開始アドレス 96 と長さ 5 の要求は異常コード 0x02 を生成します。 |
0x03 | 不正なデータ値 | 実際にはデータセグメントが不正であることを意味します。たとえば、不正なデータセグメントの長さ、または書き込みまたは読み取りのレジスタ数とデータセグメントが一致しない場合です。レジスタに期待範囲外の値が書き込まれた場合や、実際に書き込みが失敗した場合(この場合は 0x04)を示すものではありません。 |
0x04 | スレーブデバイスの故障 | サーバー(またはスレーブ)がレジスタに対して要求された操作を実行する際にエラーが発生した場合、たとえばレジスタに期待範囲外の値が書き込まれた場合などです。 |
0x05 | 確認 | 実際にはエラーではなく、長時間の指令を受信したことを示し、受信して処理を開始したことを示します。 |
0x06 | 従属デバイスが忙しい | 時間のかかる命令を処理中です(スレーブが空いている場合は、このエラーを引き起こした要求を再送信する必要があります)。 |
0x08 | ストレージのパリティエラー | 記録ファイルを読み取ろうとしましたが、メモリ内でパリティエラーが検出されました。 |
0x0A | 利用できないゲートウェイ経路 | ゲートウェイと一緒に使用され、ゲートウェイが要求を処理するために入力ポートから出力ポートへの内部通信経路を割り当てられないことを示します。通常、ゲートウェイが誤って構成されているか、過負荷であることを意味します。 |
0x0B | ゲートウェイターゲットデバイスの応答失敗 | ゲートウェイと一緒に使用され、ターゲットデバイスからの応答が得られなかったことを示します。通常、デバイスがネットワークに存在しないことを意味します。 |
TCP シリーズ#
要するに、modbusTCP は RTU に比べて前のメッセージヘッダーをラッピングしただけで、CRC チェックを削除しました👍。== なぜなら、TCP 管理層のリンク伝送は非常に堅牢であり、シリアル伝送は堅牢ではないからです ==
メッセージヘッダーのトランザクション番号は、ホスト(TCP クライアント)が要求を開始する際に継続的に加算され、スレーブ(TCP サーバー)が要求に応答する際には、処理している要求を示すために同じトランザクション番号を返信します。したがって、modbusTCP は生まれつきマルチフレームの連続送信をサポートしており、ホストは応答を誤解することはありません👍。
個人的には、このようなスムーズな通信プロトコルがより好きです。|| 情報の正確性は物理リンク層に任せておけば良い、大雲大雲、チェックは依然として必要です ||
(0x01) コイルの読み取り#
ホスト要求#
トランザクション番号 | プロトコル識別子 | バイト総長 | アドレスフィールド | 機能コード | 開始アドレス | コイル数 |
---|---|---|---|---|---|---|
2 バイト | 2 バイト (全 0) | 2 バイト (後続バイト総長) | 1 バイト | 1 バイト | 2 バイト | 2 バイト |
スレーブ応答#
トランザクション番号 | プロトコル識別子 | バイト総長 | アドレスフィールド | 機能コード | バイト数 | コイル状態 |
---|---|---|---|---|---|---|
2 バイト | 2 バイト (全 0) | 2 バイト (後続バイト総長) | 1 バイト | 1 バイト | 1 バイト (計算コイル状態部分のバイト数) | n バイト |
例#
20〜38 アドレスのコイルデータを読み取る要求をし、返信アドレスは低位から高位に、最終バイトが不足している場合は高位に 0 を埋めます。
[!NOTE]
最終的な出力状態 38-36 の返信バイトは、5 つの残りのビットをゼロで埋めます(高位端まで)。
要求 | 応答 | ||
---|---|---|---|
トランザクション番号高 8 ビット | 0x00 | トランザクション番号高 8 ビット | 0x00 |
トランザクション番号低 8 ビット | 0x01 | トランザクション番号低 8 ビット | 0x01 |
プロトコル識別子 16 ビット (全 0) | 0x00 0x00 | プロトコル識別子 16 ビット (全 0) | 0x00 0x00 |
バイト総長高 8 ビット | 0x00 | バイト総長高 8 ビット | 0x00 |
バイト総長低 8 ビット | 0x06 | バイト総長低 8 ビット | 0x06 |
アドレスフィールド (スレーブ ID) | 0x01 | アドレスフィールド (スレーブ ID) | 0x01 |
機能コード | 0x01 | 機能コード | 0x01 |
開始アドレス高 8 ビット | 0x00 | バイト数 | 0x03 |
開始アドレス低 8 ビット | 0x13 | 出力状態 27-20 | 0xCD |
出力数量高 8 ビット | 0x00 | 出力状態 35-28 | 0x6B |
出力数量低 8 ビット | 0x13 | 出力状態 38-36 | 0x05 |
他のプロトコルについては省略します
他のプロトコルについては省略します
要するに、modbusTCP は RTU に比べて前のメッセージヘッダーをラッピングしただけで、CRC チェックを削除しました👍。
この文は Mix Space によって xLog に同期更新されました。原始リンクは https://www.yono233.cn/posts/shoot/24_7_26_modbus