ソース:Modbus China Network(modbus.cn) -中国をリードするModbus通信プロトコル技術コミュニティ
この記事:Modbus通信エラーの検出と診断:パリティから異常コードまでの完全なシステム·著者:modbus Technical Team·公開日:2026- 0 7 - 0 1
Modbusプロトコルのエラー検出は、文字レベルのパリティチェック、フレームレベルのLRC/CRCチェック、アプリケーションレベルの例外応答コードとタイムアウトメカニズムの3つのレベルに分かれています。この記事では、各検出方法の動作原理、アルゴリズム実装(実行可能なC/Pythonコードを含む)、および実際のデバッグ用途を分解し、完全な例外コードのクイックチェックテーブルと障害物除去プロセスを提供します。キーワード:Modbus CRC、LRCチェック、パリティ、Modbus例外コード、Modbusエラー検出、CRC16 Modbus
RS-485バスでModbusフレームを送信することは、騒々しいワークショップで叫ぶようなものです。01 03 00 00 00 01最後に受け取ったものは01 03 00 00 00 03。ビットが反転すると、温度が25°Cから26°Cに変化したり、バルブの“なぜ動かないのか”がここに埋もれたりします。
Modbusは1979 年から階層的なエラー検出メカニズムを持って生まれました。各文字はパリティによってビットエラーをブロックし、フレーム全体はCRC(RTUモード)またはLRC(ASCIIモード)によってバックストップされ、アプリケーション層は例外応答コードによってマスターに“要求に問題があります”と伝えます。この3層メカニズムとタイムアウト再送信戦略は、Modbusが産業現場で50年近い信頼性の基盤を形成しています。
率直に言って、Modbusのエラー検出は暗号レベルではなく、CRC16は耐タンパー性がなく、LRCは連続偶数ビットのエラーを見逃す可能性がある。しかし、9600bps、数十メートルのRS-485バスを持つ物理環境では、これらのメカニズムで十分です。その価値は理論的な完璧さにあるのではなく、実装のシンプルさと計算オーバーヘッドの低さにあります。8ビットマイクロコントローラは100バイト未満のコードでCRC16の計算を実行できます。
エラー検出のための3つのレベル
Modbusシリアル通信のエラー検出は、通信スタック全体を上から下までカバーする3つのレベルに分かれています。
アプリケーション層:例外応答コード+タイムアウト再送
↓ ↓ ↓
フレームレイヤCRC-16またはLRC ASCII
↓ ↓ ↓
文字レイヤパリティEven/Odd/文字レイヤ各バイト転送の正確性を保護します。UARTフレーム内の8データビットと、ハードウェアが自動的に検証を行う1つのパリティビット。
フレームレイヤステーションアドレスから最後のデータバイトまで、Modbusメッセージ全体の完全性を保護します。フレームチェックに失敗すると、スレーブデバイスはメッセージをサイレントに破棄し、何も返信しません。
アプリケーション層要求したファンクションコードデバイスがサポートされていない、レジスタアドレスが存在しない、データ値が範囲外であるなど、“物理層は大丈夫ですが、論理的に問題があります”状況に対処します。これらのエラーは、異常応答コードでマスターに通知されます。
3つの層はすべて機能しますが、デバッグ時にエンジニアはアプリケーション層の例外コードを見やすくなり、物理層のパリティエラーは無視されます。パリティエラーはデバイスハードウェアレベルで破棄されるため、まったく見えません。
二、文字层:パリティ検査
2.1原理原理は
パリティは、各UART文字フレームに1つのチェックビットを追加し、フレーム全体の“1”の合計が奇数(奇数)または偶数(偶数)になるようにします。
Modbusの文字フレームの定義はモードによって異なる。
| モデルは | スタート地点。 | データ·ビット | チェックビット | ストップ·ビット | 合計桁数 |
|---|---|---|---|---|---|
| RTU(検証済み) | 1 | 8 | 1 | 1 | 11 |
| RTU(無検証) | 1 | 8 | 02 | 11 | |
| ASCII | 1 | 7 | 1 | 1 | 10 |
RTUは検証なしで2つのストップビットを使用して合計ビット数を集めることに注意してください-これはハード要件であり、シリアルパラメータの設定で多くの人がNo Parityを選択しましたが、ストップビットを1から2に変更するのを忘れてしまい、結果は通信が不安定ですが、完全に接続されていない、非常に確認が困難です。
2.2計算の例
1バイトを取る:11000101。1の数は4(偶数)です。
- 偶数チェック→チェックビット= 0、1を保持する総数は偶数(4個)
- 奇数チェック→チェックビット= 1、1の総数が奇数(5個)になるように
ハードウェアUARTは、送信時に自動的にチェックビットを計算し、入力時にチェックします。受信側のチェックが失敗した場合、UARTハードウェアはパリティエラー Parity Errorをマークしますが、データを自動的に破棄するわけではありません。破棄するかどうかはソフトウェアによって決まります。
2.3パリティの限界
パリティは検出のみ可能奇数ビットエラー。送信中にちょうど2ビットが反転した場合、パリティは変化せず、チェックはパスしますが、データは間違っています。RS-485では、電磁干渉によって単一ビットが反転する確率が複数ビットが同時に反転する確率よりもはるかに高いため、パリティは実用的には有用ですが、万能ではありません。
デバッグの推奨事項ライン品質に問題があると思われる場合は、ロジックアナライザを使用してUARTフレームをキャプチャし、各文字のパリティエラーフラグを確認します。シリアルアシスタント(SSCOMなど)はパリティエラーの数を表示することができます。カウンタが上昇し続けている場合は、物理ラインに電磁干渉の問題があることを示します。ケーブルがシールドされていない、周波数コンバータがブリッジに入っている、または端子抵抗が信号の反射を引き起こす可能性があります。
フレーム層(1):LRCチェック-Modbus ASCIIモード
3.1 LRCとは?
LRC(Longitudinal Redundancy Check、LRC)はModbus ASCIIモードで使用されるフレームチェックアルゴリズムである。これは8ビット(1バイト)のチェックコードであり、フレームの最後に設定され、チェック範囲は局アドレスからデータ領域までのすべてのバイトであり、フレームヘッダ(コロン)を除く。:)とフレーム末尾(改行CR/LF)。
3.2 Modbus ASCIIフレーム構造
: 0 1 0 3 21 0 2 0 0 0 2 D 7 CR LF
│ │ │ └─────────┬────────────┘ │ │ │
フレームヘッド LRC検証範囲 LRCコード完全なModbus ASCIIリクエストフレーム:
:0103020002F8rn3.3 LRCアルゴリズム
非常に簡単です-3ステップ:
- データゾーンへのアドレスコードのすべてのバイトの合計
- 和の下位8ビット(modulo 256)
- その補数を取る(256からこの値を引くか、ビット単位で逆に1を加える)。
例:例::メッセージ: 01 03 21 02 00 02
合計0 x 0 1 + 0 x 0 3 + 0 x 21 + 0 x 0 2 + 0 x 0 0 + 0 x 0 2 = 0 x 29
下位8ビット0 x 29
補数:256 - 0 x 29 = 0 x D 7
LRCチェックコード= D7フルフレームは:: 01 03 21 02 00 02 D7 rn
3.4 LRCのC言語実装
/**
* Modbus ASCII LRCチェックコードの計算
* buf:検証が必要なデータ(アドレスコードからデータゾーンまでのすべてのバイト)
* len:バイト数
* 戻り値1バイトのLRCチェックコード
*/
uned LRC uned *buf uned
{
符号なしchar lrc = 0;
while len--{
lrc += *buf++;
}
//補数256-lrc-lrcと等価
return uned-lrc;
}Pythonでの検証:
calc_lrc
"""Modbus ASCII LRCチェックコードの計算"""
return 256-sum data 0xFF 0xFF
#テストは
msg = b [0x01 0x03 0x21 0x02 0x00 0x02]
lrc = calc_lrc msg
print f"LRC 0x{lrc 02X}"#出力LRC 0xD73.5 LRCの限界
LRCはエラーの一定割合しか検出できません。2つのバイトの同じビットが同時に反転した場合(例えば、バイトAの3番目のビットが0から1に、バイトBの3番目のビットが1から0に)、合計は変更されず、LRCチェックは合格します。そのため、Modbus RTUはバイナリデータ伝送にLRC-RTUモードよりも強力なCRC-16を使用し、信頼性が要求されますが、ASCI Iモードは主にデバッグと古いデバイスとの互換性に使用されます。
フレーム層(2):CRC-16チェック-Modbus RTUモード
4.1 CRC-16 Modbusの定義
Modbus RTUはCRC-16アルゴリズムを以下のパラメータで使用する。
| パラメータ | 価値観は |
|---|---|
| 幅の幅 | 16 位。 |
| 多項式の生成 | 0x8005(x¹⁶ + x¹⁵ + x² + 1) |
| 実演算多項式 | 0 x A 001(0 x 80 0 5ビット反転形式) |
| 初期値は | 0xFFFF |
| 入力バイト反射 | いいえ、いいえ |
| 出力CRC 反射 | はい最終結果の高低バイトスワップ |
| 出力差または値 | 0x0000 |
ここでの“ビット反転”は、CRCパラメータ体系では紛らわしい概念である。Modbusの計算は実際にはビット単位で処理され、LSB 方向からシフトされ、反転多項式0 xA 001を使用して計算結果は自然に反転するため、最終的にはグローバル反転は必要ありません。ハイバイトとハイバイトの交換。送信時にはローバイトが前、ハイバイトが後になります。
4.2 CRC-16 Modbusアルゴリズムフロー(ビット単位計算)
ビット単位の計算は遅いが、各ステップで何が起こっているかを見ることができる。
- プリセット16ビットCRCレジスタは
0xFFFF - メッセージの最初のバイトをCRCレジスタの下位8ビットと区別し、結果をCRCレジスタに格納します。
- CRCレジスタは右に1ビットシフトし、最上位ビットは0になり、最下位ビットがチェックされます。
- シフト= 1 → CRCレジスタと0 x A 0 01の排他的和;シフト= 0 →動作しない
- 手順3~4を8回繰り返す(1バイトの8ビットを処理した後)
- ステップ2~5を繰り返して、メッセージの次のバイトを処理します。
- すべてのバイト処理が完了すると、CRCレジスタの下位バイトが前にあり、上位バイトが後にあり、CRC-16チェックコードとなります。
4.3 CRC-16 Modbus C言語の実装
/**
* Modbus RTU CRC-16チェックコードの計算(ビット単位)
* buf:検証が必要なデータ(アドレスコードからデータゾーンまでのすべてのバイト)
* len:バイト数
* 戻り値16ビットCRC値下位バイトが前
*/
uned CRC16_uned *buf uned
{
unsigned short crc = 0 x FFFF;
uned i j;
for i = 0; i len; i++{
crc ^= buf[i]; ステップ2/STEP 2
for j = 0; j 8; j++{ //ステップ3~5サイクル8回
if crc 0x0001 {
crc =(crc 1)^0 xA 001; //1への移動
(エルゼ)
CRC = 1; 0に移動します。
}
}
}
// 注意:Modbus CRCは下位バイトが前に送信される
CRCに戻る
}4.4ルックアップテーブル-組み込み機器の標準実装
ビット単位の計算は1バイトあたり8サイクル必要であり、組み込みMCUにはオーバーヘッドが大きすぎます。プロジェクトでは、ルックアップテーブル法を使用して、256バイトのCRC値を事前に計算し、バイトごとにルックアップテーブル+1つの例外または+1つのシフトを行います。
ハイテーブルルックアップテーブル(最も一般的):
/* CRCハイテーブル */
static const unsigned char aucchr [] = {
0x00 0xC1 0x81 0x40 0x01 0xC0 0x80 0x41 0x01 0xC0
0x80 0x41 0x00 0xC1 0x81 0x40 0x01 0xC0 0x80 0x41
0x00 0xC1 0x81 0x40 0x00 0xC1 0x81 0x40 0x01 0xC0
/* ...全256項目(省略)
};
/* CRCローテーブル */
static const unsigned char aucchar [] = {
0x00 0xC0 0xC1 0x01 0xC3 0x03 0x02 0xC2 0xC6 0x06
0x07 0xC7 0x05 0xC5 0xC4 0x04 0xCC 0x0C 0x0D 0xCD
0 x 0 F、0 x CF、0 x CE、0 x 0 E、0 x 0 A、0 x CA、0 x CB、0 x 0 B、0 x C 9、0 x 0 9、
/* ...全256項目(省略)
};
uned CRC16_Modbus_Table uned *buf uned
{
unsigned char crcHi = 0 xFF;
unsigned char crcLo = 0 xFF;
符号なしの短いインデックス;
while len--{
index = crc ^ *buf++;
crc = crc ^ auchCRCHi[index];
crc = auchCRCLo[index];
}
return<< crcHi8| CRCLO;
}512バイトの完全なハイビットとハイビットのテーブルはModbusプロトコル仕様の付録から直接コピーすることができ、完全なサンプルテーブルはModbus.org V 1.1 b 3仕様の40ページにあります。
4.5 CRCの実装を確認する
既知のメッセージでテストする:
メッセージ01 03 00 00 01
正しいCRC 84 0A(下位バイトが上位)
検証手順
crc = 0 x FFFF
crc ^= 0 x 01 → 0 x FFFE
bit0=0 crc 1 → 0x7FFF
bit1=1 0x3FFF ^ 0xA001 → 0x9FFE
...
最終crc = 0 x 0 a 84
送信時に下位バイトが上位84 0Aメッセージ送信シーケンス全体:01 03 00 00 00 01 84 0A
Modbus PollやModbusアプレットを使用してCRCを計算し、コードとクロスバリデーションを実装することもできます。
4.6 CRCのCentera機能
CRC-16では、以下のエラータイプを検出できます。
- すべての単一ビットエラー
- すべての2ビットエラー(32,767ビット以下の場合)
- すべての奇数ビットエラー
- すべてのバーストエラー、長さ≤ 16ビット
- 99.998%の長いバーストエラー
簡単に言えば、Modbusフレームは通常256バイトを超えないため、CRC-16は物理層のほぼすべての伝送エラーをキャプチャすることができます。CRCチェックで通過したデータフレームは、基本的に信頼できます。
V.アプリケーション層:異常応答コード
物理層とフレーム検証の両方がパスし、デバイスから完全に有効なModbusフレームが受信されますが、論理的に間違っています。この時点で、スレーブデバイスは沈黙していませんが、異常応答を返し、マスターステーションに“あなたが私にさせたことはできません”と伝えます。
5.1例外応答のフレーム形式
通常の応答と例外応答の違いは1つだけです。関数コードの最高位。
- 通常の応答:関数コード= raw関数コード(例:0 x 0 3リードホールドレジスタ)
- 例外応答:関数コード=元の関数コード+0 x 80(例:0 x 83)に続く1バイトの例外コード
例:例:マスターがレジスタをリードするよう要求する01 03 00 00 00 01 84 0A
通常の反応:01 03 02 00 7B F9 8D(2バイトのデータを返す)00 7B)
例外応答(レジスタが存在しないと仮定):01 83 02 C0 F1
83= 0 x 0 3(旧機能コード)+0 x 8002例外コードは“不正なデータアドレス”を示します。
5.2標準異常コードクイックチェック表
| 異常コード。 | 名前は | 意味の意味 | よくある原因 |
|---|---|---|---|
| 0x01 | Illegal Function | 違法な機能コード | デバイスが機能コードをサポートしていない(読み取り専用デバイスへの書き込みなど) |
| 0x02 | Illegal Data Address | 違法なデータアドレス | レジスタアドレスが範囲外、または開始アドレス+数量外 |
| 0x03 | Illegal Data Value | 違法なデータ値 | 書き込みされた値がレジスタの許容範囲を超えています |
| 0x04 | Slave Device Failure | 機器の故障。 | スレーブデバイスで操作の実行中に回復不能なエラーが発生しました |
| 0x05 | Acknowledge | ( | リクエストは受け入れられましたが処理に時間がかかります。プライマリ局は待機してください。 |
| 0x06 | Slave Device Busy | 設備から忙しい。 | デバイスは別のコマンドを処理中で、一時的に応答できません |
| 0x07 | Negative Acknowledge | 否定的な確認 | スレーブデバイスで機能を実行できない(通常は不特定エラー) |
| 0x08 | Memory Parity Error | メモリパリティエラー | 拡张ファイルエクストの整合性検证にしました |
0 x 0 1から0 x 0 4が最も一般的ですが、0 x 0 5から0 x 0 8は通常のModbusデバイスではまれです。多くのデバイスメーカーは最初の4つの例外コードしか実装していません。
5.3例外コードの実際のデバッグ使用法
“なぜデータが返されないのか?”物理層とCRCの問題を除外した後、例外コードを参照してください。
受信0 x 0 1(不正な機能)デバイスがサポートしていない機能コードを送信しました。最も一般的なシナリオは、0 x 0 3(読み取り保持レジスタ)を使用して、0 x 0 4(読み取り入力レジスタ)を介してのみアクセス可能なアナログ入力を読み取る場合です。デバイスマニュアルのレジスタマップテーブルを開き、アドレスに対応するアクセス機能コードを確認します。
受信0 x 0 2(不正アドレス)開始アドレスとリクエスト数がデバイスがサポートするアドレス範囲を超えています。たとえば、デバイスに10個の保持レジスタ(アドレス0-9)しかない場合、アドレス0から始まる12個のレジスタを要求します。回避策:リクエストあたりのレジスタ数を減らすか、読み込む前にデバイスタイプを0 x 11(スレーブIDを報告)で確認してください。
受信0 x 0 3(不正なデータ値)書き込みたい値はデバイスには意味がありません。たとえば、デバイスが0-100のデータ範囲をサポートしている場合、200を書き込みます。または書き込み時のデータバイト数が機能コード要求の長さと一致しない。
全く応答なし。異常ではなく、何もない。考えられる原因:CRCエラー(デバイスからのサイレントドロップ)、フレーム間隔(3.5文字の時間)が正しく実装されていない、デバイスアドレスの不一致。この場合、ロジックアナライザを使用してバスをキャッチし、デバイスから受信したものとUARTハードウェアにパリティエラーフラグがあるかどうかを確認する必要があります。
6、タイムアウトメカニズム:メインステーションの最後の防衛線
Modbus仕様ではマスターステーションにタイムアウト時間を設定する必要がある。タイムアウトは、次の場合にトリガーされます。
- マスタが要求を出した後、スレーブ局は所定時間内に何の応答もない
- スレーブ局がフレームエラーを検出し(CRC/LRC失敗)、フレームをサイレントに破棄し、マスタ局が応答を受信しない
- スレーブアドレスが存在しない-メッセージは空のアドレスに送信されます。
タイムアウト時間の設定には制約があります。スレーブデバイスの可能な最大応答時間よりも大きい必要があります。計算方法は:
タイムアウト時間伝送遅延× 2 +スレーブ処理時間9600bpsでは、典型的なModbus RTUリクエスト(1レジスタの読み取り)は約8バイト= 64ビットであり、転送時間= 64 / 9600 ≈ 6.7 msである。応答は約7バイト= 56ビット,転送時間≈ 5.8 msである.スレーブ処理時間(最低50msを仮定)を加えると、双方向の合計時間は約6.7 + 50 + 5.8 ≈ 62.5 msになります。マージンを2倍にして、タイムアウトは100-200msに設定する方が合理的です。
バス上に複数のスレーブがある場合は、ポーリングが最も遅いデバイスを考慮してください(例えば、古いPLCはリクエストを処理するのに100msかかる)。Modbus仕様で推奨されているデフォルトのタイムアウトは1 秒です。これは最新のデバイスでは大きすぎますが、デバッグを開始する初期値としてセキュリティです。
7.完全な障害物除去プロセス
“Modbus 通信障害”が発生した場合は、次の順序でレイヤーをチェックします。
| 層の層 | チェック項目 | ツール·ツール | 判断の方法 |
|---|---|---|---|
| 物理層は | RS-485配線(A/B、コモングランド、終端抵抗) | マルチメータ | オン、バスアイドルレベル≥ 200mV |
| 文字レイヤ | シリアルパラメータボーレート、データビット、チェックビット、ストップビット | ロジックアナライザ | 実测ビット幅= 1/baud |
| 文字レイヤ | パリティエラー | ロジックアナライザ/シリアルアシスタント | パリティエラー数= 0 |
| フレームレイヤ | CRCチェック | Modbusアプレット/自己記述コード | 受信CRC =計算CRC |
| フレームレイヤ | フレーム間隔(3.5文字以上) | ロジックアナライザ | フレーム間の空き時間≥ 3.6 ms @ 9600bps |
| アプリケーション層 | 駅からの住所 | 機器マニュアル/ダイヤルスイッチ | 要求アドレス=スレーブの実際のアドレス |
| アプリケーション層 | 機能コード+アドレス範囲 | デバイスレジスタマップテーブル | 機能コードとレジスタアドレスはデバイスのサポート範囲内 |
| アプリケーション層 | 異常応答コード | シリアルアシスタント/バッグ | 機能コードの上位ビットが1の場合に例外コードをチェック |
| アプリケーション層 | タイムアウト | タイムスリップをチェック。 | レスポンス時間のタイムアウト設定 |
特別な注意点“0 1 0 3 0 0 0 0 0 0 0 1”のような標準的なModbusリクエストを使用して対話する場合、ASCII文字列を直接送信するのではなく、バイナリフレームを送信する必要があります。初心者は、シリアルアシスタントでASCIIモードを使用しています。0x31 0x30 0x33 0x30 0x30 0x30 0x30 0x30 0x30 0x31ASCII文字列の“010300000001”01 03 00 00 00 01この6バイト。Modbusを学ぶほとんどの人がこの間違いを犯す。
CRCチェックコードの正しい計算は、Modbus 通信の信頼性の礎です。しかし、エンジニアリング現場での問題の90%はCRC自体ではありません。配線、パラメータ、アドレス範囲外、機能コードの選択の誤りです。CRCはセーフティネットのようなもので、“データは正しいはずだ”と言えば自信を与えます。データが本当に間違っている場合は、最初のレイヤーをチェックします。
この記事のコードをプロジェクトに入れてクロスバリデーションし、CRCコードをオンラインでコピーしてもすぐに使用できるとは思わないでください。バイトオーダーの反転のためにCRCが決してチェックされないケースをたくさん見てきました。Modbus.org V 1.1 b 3仕様の付録をご覧ください。CRCルックアップテーブルの完全なデータと高と低の両方の実装の公式例があります。
再び話す問題がある。
1