ASCIIから高度なシリアルプロトコルにいつ切り替える必要がありますか?


28

UARTを介してPCと通信するすべてのマイクロコントローラーデバイスは、コマンドの送信とデータの受信にArduinoで実装されているASCII文字列を使用します。それは電子機器を掘り始めたときに学んだことであり、私は常に裸の弦を送るだけで十分であることがわかりました。しかし、私が遭遇したほとんどのデバイスは、機能コード、アドレス、CRCエラーチェックを含む洗練されたバイナリプロトコルを使用していることに気付きました。

基本的なASCII通信はいつ受け入れられ、Modbusのようなより高度なものを検討する必要がありますか?商用デバイスはそのようなASCIIを使用しますか?産業用?


3
簡単な答え:アプリケーションで必要なとき。はい、商用デバイスはASCIIを使用します。GPS NMEAを例に取ります。(また、ここで自分の質問を参照します
ユージン・シュ。

1
ModbusにはASCIIモードがあります。参照のModicon Modbusプロトコルリファレンスガイド
ツタンカーメン

@EugeneSh .: NMEAにはチェックサムフィールドがあることに注意してください。チェックサムの失敗(考えられるよりも頻繁に発生する)による単一のサンプルバーストのドロップは、一般に重大な失敗ではありません。それは他のプロトコルには当てはまらないかもしれません... そして、それが実際に重要であるかもしれないアプリケーション(または1Hzより高いサンプルレートであるアプリケーションのために使用中のバイナリGPSプロトコルがたくさんあります(例えばGarmin) NMEAは冗長すぎる)これは本当にあなたのポイントを固めるだけです。
ライトネスレースとモニカ

回答:


28
  1. ASCIIとCRCは相互に排他的ではありません。ASCIIはエンコードであり、CRCはエラーチェック用です。

  2. 何でもASCIIとして送信できます。私たちの老人は、UUEncodingを覚えています。これは、何でもASCII文字列に変換します。

  3. A)私にとっては、通常、速度と効率の問題です。ASCIIによる大きな32ビット数の送信には長い時間がかかりますが、シリアルプロトコル経由でバイナリとして送信するのに4バイトしかかかりません。

    B)ASCIIを介してNUMBERSを送信することは、番号をASCIIに変換する必要があることを意味します。これは明確な追加手順です(これは "printf"の一部です)。

  4. どうにかして場所を失ったり、台無しにしたり、フォーマットを失ったり、間違ったエンディアンを取得したりすると、バイナリ通信プロトコルが確実に台無しになります。ASCIIを送信している場合は、データストリームにアクセスして検索するだけで、混乱から簡単に回復できます。


12
「ASCIIはエンコーディングです」の場合は+1。プロトコルではありません。プロトコルはASCIIの上に構築できます。
ピートベッカー

8
ねじ込みからの自動回復は、バイナリベースのテキストベースのプロトコルにとって本質的に簡単ではありませんが、検査とデバッグは確かに可能です。
ニックジョンソン

1
@NickJohnson-絶対に。あなたが回復できるかを確認するバイナリエディタでファイルを開くの地点にいるならば、あなたはこれまでのSOPが行くようFUBARですでにしている
スコットサイドマン

1
@nickjohnsonそれは本当に真実ではありません。ASCIIは、帯域外フレーミング/デリミタオプションを多数提供して、同期と回復を支援します。これには、チャネルが全幅バイナリデータに使用される場合、追加のエスケープ、ビットスタッフィング、時間間隔またはその他のトリックが必要になります。
クリスストラットン

2
すべての明らかな利点(読みやすさ、ログ可能性など)のためにプロトコルを書くとき、私は常にASCIIを好みます。バイナリのほうが理にかなっているのは2つの場合があります。1つは速度が問題で、ストリームにできるだけ多くのデータを詰め込む必要がある場合、2つ目はデータを意図的に難読化または暗号化しようとする場合です。リバースエンジニアリングを妨害または防止するためのストリーム。その時点で、バイナリプロトコルをリバースエンジニアリングしましたが、実際にこの行為を妨げた以上に、大部分がイライラさせられました。
J ...

10

ここにいくつかの考えがあります:

  • ASCIIは、シリアルモニターを使用して送信内容を手動で確認できるため便利です。
  • 接続が信頼できない場合、送信エラーを予期する必要があり、CRCを使用して各受信メッセージの整合性をチェックする必要があります。これは、ASCIIメッセージでも実行できます。
  • 接続が遅すぎる場合は、バイナリ形式に切り替えることでメッセージのサイズを減らすことができます
  • 特殊なバイナリ形式は、ASCIIよりも受信側でデコードする方が簡単な場合があります

7

最も単純なレベルでは、単純な通信プロトコルには、物理​​、トランスポート、およびアプリケーションの3つの層があります。(7のOSIや4のTCP / IPなど、より多くのモデルがあります。この質問のコンテキストでは、レイヤーの数はそれほど重要ではありません。)

アプリケーション層は、コードで直接扱う層であり、質問の焦点です。トランスポートレイヤーに関する限り、send_dataで渡したバイトは単なるバイナリパターンですが、アプリケーションコードでは文字「A」として解釈できます。CRCまたはチェックサムの計算は、バイトを「A」、0x41、または0b01000001のいずれであるとみなしても同じです。

トランスポート層はパケットレベルであり、メッセージヘッダーがあり、CRCでも基本チェックサムでもエラーチェックを行います。ファームウェアのコンテキストでは、送信するバイトを渡すsend_dataなどの関数を使用できます。その関数内で、「これは通常のメッセージです。確認応答が必要で、チェックサムは0x47、現在の時間はXです」というパケットに入れられます。このパケットは、物理層を介して受信ノードに送信されます。

物理層は、コネクタと電圧レベル、タイミングなど、電子機器とインターフェースが定義される場所です。この層は、PCB上の基本的なUARTのTTL信号を実行するいくつかのトレースから、一部のCAN実装。

受信ノードでは、パケットは物理層に到着し、トランスポート層で展開され、アプリケーション層でバイナリパターンが利用可能になります。そのパターンを「A」、0x41、または0b01000001として解釈する必要があるかどうか、およびそれをどう処理するかを知るのは、受信ノードのアプリケーションレイヤー次第です。

結論として、もしそれがアプリケーションが要求するものであれば、ASCII文字を送信することはほとんど常に受け入れられます。重要なことは、通信スキームを理解し、エラーチェックメカニズムを含めることです。


Asciiプロトコルにもチェックサムを組み込むことができます。数字のアスキー表現を使用した16進数としての16進数のバリエーションに遭遇しました。
ユージーンSh。

しゅう その点を明確化
マットヤング

ひとくくりにする必要はありませんが、TCPは4つの層ではありません。OSIモデルのレイヤー4に適合すると見なされます。シリアル通信は、OSIモデルに実際にはあまり適していません。
batsplatsterson

@batsplatstersonそれはちょっとした選択であり、私が作成しているポイントとはかなり無関係です。
マットヤング

5

まだ言及されていない点は、ASCIIまたはバイナリプロトコルを使用しているかどうか、各パケットの前に消しゴムを送信すると、パケットの開始前にラインノイズやフレーミングエラーが表示されても、さらなるノイズがない場合、outは正しくフレーム化されます。そうしないと、パケットを継続的に送信し、再同期を保証する文字が含まれていない場合、1つのグリッチが送信の次の一時停止まで続くすべてを破損する可能性があります。0xFF文字は、すべての受信者が次の文字で再同期できることを保証するので便利です。

(*)0xFF-ラブアウトと呼ばれますほとんどの受信者に無視されます)。


2

ASCII文字列を送信する利点の1つは、制御コードを使用してメッセージの開始/終了を通知できることです。たとえば、STX(char 2)およびETX(char 3)は、送信の開始と送信の終了を通知できます。または、単純なラインフィードを追加して、送信の終了を示すことができます。

有効なデータバイトが同じパターンを持っている可能性があるため、バイナリコードを送信するとき、特定のビットパターンを制御コード用に予約することができないため、これはより複雑になります。


3
多くのバイナリプロトコルは、1つ以上のビットパターンを制御コードとして予約していますが、データに表示されるときにそれらのコードを処理するエスケープメカニズムも含まれています。
デイブツイード

任意のパターンを予約して、バイナリで必要なものにフラグを付けることができます。たとえば、同じデータを高速データストリームと低速データストリームで送信するプロジェクトに取り組んでいます。最大の負のint32を低速データのフラグとして予約し、負のデータを最大の負の+ 1で飽和させるだけです。
Scott Seidman

同意した。編集した回答でこれを明確にしたいと思います。
トランジスタ

2

ASCIIは大丈夫です。私はほぼすべてのプロジェクトでそれを使用しています。ポートを監視するためのデバッグがはるかに簡単になり、送信するデータが大量にある場合にのみ問題になります。

もう1つのボーナスは、arduino間でメッセージを取得するためにシリアル無線デバイスを使用し、ラップトップに接続されたシリアルモニターを使用してメッセージを挿入して特定の処理を実行できることです。テストに最適です。

また、バイナリとして送信することはデバッグが不可能ではなく、ツールによっては、バイナリを抽出して人間が読める形式に変換することができます。または、探しているものがわかっている場合は、データストリームを視覚的に検査し、値がどこにあるべきかを認識し、そうではないにしても、その方法を見つけることができます。つまり、バイトのパターンを認識し、期待される値を認識します


2

Modbusの代わりにHDLCを検討してください。エラー検出を取得します(ノイズの多いシリアル回線で重要です)。同期は堅牢で、エスケープは堅牢です。

RS-485ネットワークでHDLCを問題なく使用しましたが、PPPもHDLCを使用しています。


2
Modbusで提案する理由を指摘していただければ幸いです。
何をしているかわからない

1

UARTを介したASCIIが最も人気のある理由の1つは次のとおりです。

  • デバッグ時に人間が読める形式です(ASCIIをデコードしないロジックアナライザーはまだ見ていません)。

  • 実装は非常に簡単で、標準化されたクイックGoogleを介してASCIIテーブルを取得できます。

  • スタート/ストップビットとの同期が組み込まれています。

  • 趣味の世界全体がASCIIをシリアルで設定しているので、新しいメソッドはそれを処理する必要があり、それは決して簡単なことではありません。

その後、特定のエンコードの送信を開始すると、フロートをASCIIに変換するのと比較してフロートのメモリ内表現を送信し、4バイトを超える可能性のあるシリアルで送信し、それを元に戻すなどの状況になりますホスト上のメモリ内表現に。代わりに、毎回4バイト表現を送信するだけです。もちろん、自分でエンコーディングの処理を開始できますが、開始/終了タグ、順序などを設定する必要があります。

代わりに、Protobufなどを使用できます。これは実際に私が取り組んでいるプロジェクトで使用され、非常に有益でした。可変長メッセージを処理し、エンディアンを処理し、他のいくつかのクールな機能を備えています。また、コードサイズはそれほど大きくありません。また、起動時に静的に割り当てるすべてを指定できます。ただし、必要な場合は、自分でチェックサムを挿入する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.