banner
yono

yono

哈喽~欢迎光临
follow
github

modbus プロトコルの紹介

参考資料#

各ブログサイトは章が欠けていたり、レイアウトが乱れていたり、時折誤りがあるため、参考にしないことをお勧めします。

ここに modbus 中国語サイトの資料があります

MODBUS プロトコル中国語版 / 英語版プレビューおよびダウンロード | Modbus IoT クラウドプラットフォーム

より権威のあるのは公式文書です

MODBUS アプリケーションプロトコル 1 1 b

及び公式の他の文書は、ここで探してください

Modbus 仕様および実施ガイド

もちろん公式文書にもあまり満足していません。彼らの古代の設計構造を維持するために、各フレームセグメントの紹介が直感的でなくなっています。また、少量の誤植もあります。

image

以下は自分が書き直した有効な情報です。

また、私が実装したライブラリもあります

stbanana/modbusX: modbus プロトコルサポート (github.com)

プロトコルの特徴#

全体フレーム構造#

メッセージヘッダーアドレスフィールド機能コードデータフィールドチェックフィールド
RTU1 バイト (スレーブ ID)1 バイトn バイト不定2 バイト (他のすべての内容の CRC-MB16)
TCP6 バイト
(2 バイトトランザクション番号 +
2 バイトプロトコル識別子 - 全て 0+
2 バイト後続バイトの総長 - スレーブ ID を含む)
1 バイト (スレーブ ID)1 バイトn バイト不定

メッセージヘッダーについては、公式文書の全体モデルではアドレスフィールドに分類されていますが、実際のバイトの総長にはスレーブ ID が含まれています。おそらく、初期のシリアルポートプロトコルの時代に全体モデルが定められ、新たに追加された modbusTCP は互換性のために混乱を招いています。

私はここで直接再分類しましたが、標準ではありませんが、私は喜んでいます。

レジスタ属性#

RW 属性bit ビット数
コイル (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-200xCD
出力数量高 8 ビット0x00出力状態 35-280x6B
出力数量低 8 ビット0x13出力状態 38-360x05
チェック 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-1970xAC
出力数量高 8 ビット0x00入力状態 212-2050xDB
出力数量低 8 ビット0x16入力状態 218-2130x35
チェック 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レジスタ値高八位(108)0x02
レジスタ数量高 8 ビット0x00レジスタ値低八位(108)0x2B
レジスタ数量低 8 ビット0x03レジスタ値高八位(109)0x00
チェック CRC 低 8 ビット0x74レジスタ値低八位(109)0x00
チェック CRC 高 8 ビット0x17レジスタ値高八位(110)0x00
レジスタ値低八位(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レジスタ値高八位(9)0x02
レジスタアドレス高 8 ビット0x00レジスタ値低八位(9)0x2B
レジスタアドレス低 8 ビット0x03レジスタ値高八位(10)0x00
チェック CRC 低 8 ビット0xC1レジスタ値低八位(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 バイト (16bit) を書き込む必要があり、6 つの残りのビットをゼロで埋めます(高位端まで)。

コイルアドレス27262524232221202928
対応値1100110100000001

規格に従って埋めた後、実際の設定値セクションは 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-200xCD
出力数量高 8 ビット0x00出力状態 35-280x6B
出力数量低 8 ビット0x13出力状態 38-360x05

他のプロトコルについては省略します

他のプロトコルについては省略します

とにかく modbusTCP は RTU に比べて前のメッセージヘッダーをラッピングしただけで、CRC チェックを削除しました👍。

この文は Mix Space によって xLog に同期更新されました
元のリンクは https://www.yono233.cn/posts/shoot/24_7_26_modbus


読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。