組み込みCPUとPCの間の通信に使用されるプロトコル
-
10-07-2019 - |
質問
私は、PCに接続することになっている独自のCPU(AVR Mega8)を備えた小さなデバイスを構築しています。物理的な接続とバイトの受け渡しが完了したと仮定すると、それらのバイトの上で使用するのに最適なプロトコルは何でしょうか?コンピューターは、デバイスに特定の電圧を設定し、他の特定の電圧を読み戻すことができる必要があります。
現時点では、コンピューターが要求を送信し、組み込みのCPUが応答する、完全にホスト主導の同期プロトコルを考えています。他のアイデアはありますか?
解決
Modbus が探しているものです。まさにあなたが抱えている問題のタイプに合わせて設計されました。そこには多くのコード/ツールがあり、標準に準拠することは後で簡単に再利用できることを意味します。また、人間が読めるASCIIもサポートしているため、理解/テストが容易です。
Windowsおよび埋め込みソースについては、 FreeModBus を参照してください。
他のヒント
クライアント/サーバーアーキテクチャと同期プロトコルについて多くのことが言われています。シンプルさと堅牢性、開始する。速度が問題にならない場合は、デバッグに役立つコンパクトで人間が読み取れるプロトコルを検討してください。私はモデムのATコマンドのラインに沿って考えています:" wakeup"シーケンスの後にset / getコマンドが続き、その後にターミネータが続きます。
Host --> [V02?] // Request voltage #2
AVR --> [V02=2.34] // Reply with voltage #2
Host --> [V06=3.12] // Set voltage #6
AVR --> [V06=3.15] // Reply with voltage #6
閉じ括弧が表示されない場合、各側はタイムアウトする可能性があり、メッセージ自体には表示できない次の開いている括弧で再同期します。
速度と信頼性の要件に応じて、コマンドを1バイトまたは2バイトにエンコードし、チェックサムを追加します。
コマンドを単にエコーするのではなく、実際の電圧で返信することをお勧めします。後続の読み取り操作が保存されるためです。
デバッグが必要な場合に備えて、エラーメッセージの定義にも役立ちます。
私の投票は、人間が読める形式のものです。
ただし、バイナリを使用する場合は、先頭にヘッダーバイトを配置して、パケットの先頭をマークしてください。シリアルプロトコルが同期しなくなるのはいつも不運でした。ヘッダーバイトにより、組み込みシステムはPCと再同期できます。また、最後にチェックサムを追加します。
単純なバイナリ形式でこのようなことをしました
struct PacketHdr
{
char syncByte1;
char syncByte2;
char packetType;
char bytesToFollow; //-or- totalPacketSize
};
struct VoltageSet
{
struct PacketHdr;
int16 channelId;
int16 voltageLevel;
uint16 crc;
};
struct VoltageResponse
{
struct PacketHdr;
int16 data[N]; //Num channels are fixed
uint16 crc;
}
同期バイトは、非同期プロトコルよりも同期プロトコルではそれほど重要ではありませんが、特に組み込みシステムの最初の電源投入時に役立ちます。また、最初のバイトが真ん中かどうかはわかりませんメッセージかどうか。
タイプは、パケットの解釈方法を示す列挙型である必要があります。サイズは型から推測できますが、明示的に送信すると、受信者は窒息することなく未知の型を処理できます。 「合計パケットサイズ」または「従うべきバイト」を使用できます。後者は、受信者コードを少しきれいにすることができます。
最後のCRCは、有効なデータがあることの保証を追加します。ときどき、ヘッダーのCRCを見たことがあります。これにより、構造の宣言が簡単になりますが、最後に配置することで、メッセージを送信するときに余分なデータの受け渡しを回避できます。
送信者と受信者は、バイトがドロップされた場合に備えて、パケットの最初のバイトが受信された後にタイムアウトを開始する必要があります。また、PC側では、組み込みシステムが接続されておらず、応答がない場合を処理するためのタイムアウトが必要です。
両方のプラットフォームでIEEE-754浮動小数点数(PCの浮動小数点数)が使用され、エンディアンネスが同じであることが確実な場合、データ型として浮動小数点数を使用できます。それ以外の場合は、生のA / Dビット、またはプリセットスケール(つまり、1ビット= .001Vが+/- 32.267 V範囲を与える)のいずれかの整数を使用する方が安全です
アダム・リスは多くの素晴らしい点を挙げています。シンプルさと堅牢性に焦点を当てる必要があります。人間が読めるASCII転送は、デバッグ中にLOTに役立ちます。素晴らしい提案。
これらはあなたのニーズに対してはやり過ぎかもしれませんが、HDLCやPPPはデータリンク層の概念と、データリンク層に付随するすべての利点(およびコスト)を追加します。リンク管理、フレーミング、チェックサム、シーケンス番号、再送信などはすべて、堅牢な通信を保証するのに役立ちますが、複雑さ、処理、およびコードサイズが追加され、特定のアプリケーションには必要ない場合があります。
効率的なバイナリ転送を行う必要がないと思っていた場合は、すでに提案されている端末スタイルのインターフェイスを使用します。
バイナリパケット形式を使用する場合、PPP byte-asnc HDLC形式に基づいた緩やかなものを使用する傾向があります。
パケットは0x7eで開始および終了します 0x7dを前に付けてビット5を切り替えることで、charをエスケープします(つまり、xorに0x20を付けます) 0x7eは0x7d 0x5eになります 0x7dは0x7d 0x5dになります
0x7eが表示されるたびに、データが保存されている場合は、それを処理できます。
通常、ホスト駆動の同期処理は、特に理由がない限り実行します。これは、単純なポイントポイントRS232からマルチドロップRS422 / 485まで、手間をかけずに拡張する手法です。多くの場合、ボーナスです。
プロトコルに直接誘導されないすべての応答から既に決定している可能性があるため、独自のアプローチを選択することが最善の選択であると判断します。
だから、これは私に考えさせてくれました、そして、ここに私の考えのいくつかがあります-
このチップに6つのADCチャンネルがあることを考えると、おそらくあなたはRs-232シリアル通信(あなたの質問からの推測)を使用していること、そしてもちろん限られたコードスペース、単純なコマンド構造を定義することはAdamが指摘するように役立ちます-チップで入力処理を最小限に抑えることをお勧めしますので、バイナリは魅力的に聞こえますが、トレードオフは開発とサービスの容易さです(6か月後にデッド入力を撃つ必要があるかもしれません)-ハイパーターミナルは強力なデバッグツールです。そのため、信頼性の高い単純なコマンド構造を実装する方法を考えました。
いくつかの一般的な考慮事項-
同じサイズのコマンドを保持-デコードを容易にします。
コマンドとオプションのチェックサムのフレーム化。Adamが指摘しているように、コマンドを簡単にラップできます。 (小さなコマンドでは、単純なXOR / ADDチェックサムは迅速で簡単です)
リセット時のファームウェアバージョンを含むホストへの起動アナウンスメントをお勧めします-例:" HELLO;ファームウェアバージョン1.00z" -ターゲットが開始したばかりで実行中のものをホストに伝えます。
主に監視している場合、「フリーラン」を検討することをお勧めします。ターゲットは単にアナログとデジタルの読み取り値を循環するモードです-もちろん、これは連続している必要はなく、1、5、10秒、またはコマンドで間隔を空けることができます。マイクロは常にリッスンしているため、更新された値の送信は独立したタスクです。
各出力行をCR(または他の文字)で終了すると、ホストでの同期が簡単になります。
たとえば、マイクロは単に文字列を出力できます。
V0=3.20
V1=3.21
V2= ...
D1=0
D2=1
D3=...
and then start over --
また、コマンドは本当にシンプルかもしれません-
? -すべての値を読み取ります-それほど多くはないので、すべて取得します。
X = 12.34-値を設定するには、最初のバイトがポート、次に電圧です。" ="を維持することをお勧めします。および「。」チェックサムを忘れた場合に有効なパケットを確保するためのフレーミングとして。
別の可能性として、出力が設定範囲内にある場合は、事前にスケールすることができます。たとえば、出力が正確である必要がない場合、次のようなものを送信できます
5=0
6=9
2=5
ポート5をオフ、ポート6をフルオン、ポート2をハーフ値に設定する-このアプローチでは、マイクロでの計算/デコードリソースに関して、asciiとバイナリデータはほぼ同じ位置にあります。または、より正確にするには、出力を2バイトにします。たとえば、2 = 54-OR、外部参照テーブルを追加します。データバイトがルックアップテーブルへのインデックスである場合、値は線形である必要さえありません。 。
私が言いたいように。そうでない場合を除き、通常はsimpleの方が優れています。
これが少し役立つことを願っています。
再読中に別の考えがありました。 " *"を追加するコマンドはhtmlタグでラップされたデータを要求することができ、ホストアプリは出力をmicroからブラウザーとwala、ブラウザー対応に単純にリダイレクトできるようになりました-
:)