PCに接続することになっている独自のCPU(AVR Mega8)を備えた小さなデバイスを構築しています。物理的な接続とバイトの受け渡しが完了したと仮定すると、これらのバイトに加えて使用するのに最適なプロトコルは何ですか? コンピュータは、デバイスに特定の電圧を設定し、他の特定の電圧を読み取ることができる必要があります。
現時点では、完全にホスト主導の同期プロトコルを考えています。つまり、コンピューターが要求を送信し、組み込みの CPU が応答します。他のアイデアはありますか?
PCに接続することになっている独自のCPU(AVR Mega8)を備えた小さなデバイスを構築しています。物理的な接続とバイトの受け渡しが完了したと仮定すると、これらのバイトに加えて使用するのに最適なプロトコルは何ですか? コンピュータは、デバイスに特定の電圧を設定し、他の特定の電圧を読み取ることができる必要があります。
現時点では、完全にホスト主導の同期プロトコルを考えています。つまり、コンピューターが要求を送信し、組み込みの CPU が応答します。他のアイデアはありますか?
Modbusはあなたが探しているものかもしれません。それはまさにあなたが抱えている問題のタイプのために設計されました。そこにはたくさんのコード/ツールがあり、標準に準拠することは後で簡単に再利用できることを意味します。また、人間が読めるASCIIもサポートしているため、理解/テストも簡単です。
ウィンドウと埋め込みソースについては、 FreeModBusを参照してください。
クライアント/サーバー アーキテクチャと同期プロトコルについては、言いたいことがたくさんあります。まず、シンプルさと堅牢性。速度が問題にならない場合は、コンパクトで人間が判読できるプロトコルを検討して、デバッグに役立てることができます。私は、モデム AT コマンドの行に沿って考えています。「ウェイクアップ」シーケンスの後に 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 float を使用し (PC の場合)、エンディアンが同じであることが確実な場合は、float をデータ型として使用できます。それ以外の場合は、生の A/D ビットまたはプリセット スケールのいずれかの整数を使用する方が安全です (つまり、1 ビット = .001V で +/-32.267 V の範囲が得られます)。
Adam Liss は多くの素晴らしい点を挙げています。シンプルさと堅牢性に重点を置く必要があります。人間が読める ASCII 転送は、デバッグ中に大いに役立ちます。素晴らしい提案。
それらはあなたのニーズには過剰かもしれませんが、HDLC や PPP は、データ リンク層の概念と、データ リンク層に伴うすべての利点 (およびコスト) を追加します。リンク管理、フレーミング、チェックサム、シーケンス番号、再送信などはすべて、堅牢な通信を確保するのに役立ちますが、複雑さ、処理、およびコード サイズが追加され、特定のアプリケーションには必要ない場合があります。
プロトコルに直接誘導するものではないすべての応答から、あなた自身のアプローチが最善の選択であるとすでに判断しているかもしれません。
それで、これは私に考えさせられました、そして、ここに私の考えのいくつかがあります-
このチップに 6 つの ADC チャネルがあることを考えると、Rs-232 シリアル通信を使用している可能性が最も高く (質問からの推測)、もちろんコード スペースが限られているため、Adam が指摘するように、単純なコマンド構造を定義することが役立ちます。チップでの入力処理を最小限に抑えたい場合があるため、バイナリは魅力的に聞こえますが、トレードオフは開発とサービスの容易さです (今から 6 か月後にデッド入力のトラブルシューティングが必要になる場合があります) -- ハイパーターミナルは強力ですデバッグ ツール -- それで、信頼性の高いシンプルなコマンド構造を実装する方法を考えるようになりました。
いくつかの一般的な考慮事項 --
コマンドを同じサイズに保つ -- デコードが容易になります。
Adam が指摘するように、コマンドとオプションのチェックサムをフレーミングすると、コマンドを簡単にラップできます。(小さなコマンドを使用すると、単純な XOR/ADD チェックサムがすばやく簡単に実行できます)
リセット時にファームウェア バージョンをホストに起動アナウンスすることをお勧めします。たとえば、"HELLO; Firmware Version 1.00z" は、ターゲットが起動したばかりで、何が実行されているかをホストに伝えます。
主に監視している場合は、ターゲットがアナログとデジタルの読み取り値を単純に循環する「フリーラン」モードを検討することをお勧めします。もちろん、これは連続的である必要はありません。 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)。または、外部参照テーブルを追加します。データ バイトがルックアップ テーブルへのインデックスである場合、値は線形である必要さえありません。 .
私が言いたいように; そうでない場合を除き、通常はシンプルな方が良いです。
これが少し役立つことを願っています。
再読中に別の考えがありました。「*」コマンドを追加すると、html タグでラップされたデータを要求でき、ホスト アプリは出力を micro からブラウザにリダイレクトするだけで済み、wala、ブラウザ対応 -
:)
効率的なバイナリ転送を行う必要があるとは思わなかった場合は、既に提案されているターミナル スタイルのインターフェイスを使用します。
バイナリ パケット形式を使用したい場合は、PPP バイト asnc HDLC 形式に基づいた大まかな形式を使用する傾向があります。これは、基本的に、非常にシンプルで送受信が簡単です。
パケットは 0x7e で始まり、0x7e で終わる 0x7d を前に付け、ビット 5 をトグルする (つまり、0x20 で xor) ことにより、char をエスケープします。
0x7e が表示されるたびに、データが保存されていれば、それを処理できます。
特別な理由がない限り、通常はホスト主導の同期処理を行います。これは、簡単なポイントツーポイント RS232 からマルチドロップ RS422/485 まで手間をかけずに拡張できる手法です。
USB バスは、すべての要件に対応します。デバイスにリクエストを送信するための制御パイプのみを備えた非常に単純な USB デバイスの場合もあれば、デバイスの変更をホストに通知できるようにする割り込みパイプを追加することもできます。CypressやMicrochipなど、使用できるシンプルな USB コントローラが多数あります。
転送上のプロトコルは、実際には要件に関するものです。あなたの説明から、単純な同期プロトコルで間違いなく十分であるようです。他の方法を探して迷う理由は何ですか? あなたの疑問を共有してください。私たちは助けようとします:)。