64

2つのデバイス(PCとマイクロコントローラー)間の単純な通信プロトコルが必要です。PCは、いくつかのコマンドとパラメーターをマイクロに送信する必要があります。マイクロはバイトの配列(センサーからのデータ)を送信する必要があります。

データはノイズ保護されている必要があります(パリティチェックの他に、他のデータ修正方法が必要だと思います)。

これを行うための標準的な解決策はありますか?(完全な解決策ではなく、アイデアだけが必要です)。

PSどんなアドバイスも大歓迎です。PPS文法の間違いでごめんなさい、ご理解いただければ幸いです。

編集1.マスター/スレーブプロトコルにするのか、双方が通信を開始できるのかは決めていません。PCは、microがいつジョブを実行し、データを送信できるかを認識している必要があります。データの準備ができている場合はマイクロを継続的にポーリングでき、ジョブが完了するとマイクロはデータを送信できます。どちらが優れていてシンプルかわかりません。

編集2. ハードウェアおよび物理層プロトコル。PCで使用されているRS-232Cシリアル規格なので、非同期通信を使用します。RxD、TxD、GND信号のみを使用します。マイクロコントローラーAFAIKがサポートしていないため、追加のワイヤーを使用できません。ところで、私はAVRATmega128チップを使用しています

したがって、固定ボーレート、8ビットのデータ、2ストップビットをパリティチェックなしで(または?付きで)使用します。

データリンクプロトコル。それが私の質問が主に懸念していることです。HDLCPPPModbusプロトコルを提案していただきありがとうござい調べてみます。

4

12 に答える 12

41

私はHDLCを使用します。私は過去にそれで幸運に恵まれました。ポイントツーポイントシリアルでは、非同期フレーミングを使用し、他のすべての制御機能を忘れてしまいます。おそらくやり過ぎでしょう。

パケットのフレーミングにHDLCを使用することに加えて。パケットを次のようにフォーマットします。これは、802.11を使用してオプションが渡される方法です

U8 cmd;
U8 len;
u8 payload[len];

各コマンドパケットの合計サイズはlen+2です。

次に、次のようなコマンドを定義します

#define TRIGGER_SENSOR 0x01
#define SENSOR_RESPONSE 0x02

もう1つの利点は、新しいコマンドを追加できることです。未定義のコマンドを無視するようにパーサーを正しく設計すると、下位互換性が得られます。

したがって、すべてをまとめると、パケットは次のようになります。

 // total packet length minus flags len+4
 U8 sflag;   //0x7e start of packet end of packet flag from HDLC
 U8 cmd;     //tells the other side what to do.
 U8 len;     // payload length
 U8 payload[len];  // could be zero len
 U16 crc;
 U8 eflag;   //end of frame flag

次に、システムはフラグ0x7eのシリアルストリームを監視し、そこにある場合は、長さをチェックして、それがpklen>=4およびpklen=len + 4であり、crcが有効であるかどうかを確認します。小さなパケットをcrcだけに依存しないように注意してください。多くの誤検知が発生し、長さもチェックされます。長さまたはcrcが一致しない場合は、長さとcrcをリセットして、新しいフレームのデコードを開始します。一致する場合は、パケットを新しいバッファにコピーして、コマンド処理関数に渡します。フラグを受信したときは、常に長さとcrcをリセットしてください。

コマンド処理関数の場合は、cmdとlenを取得し、スイッチを使用して各タイプのコマンドを処理します。また、システムがイベント駆動型のリモートプロシージャコールのように動作するように、特定のイベントが応答を送信する必要があります。

したがって、たとえば、センサーデバイスはタイマーを持っているか、読み取りを行うためのコマンドに応答することができます。次に、パケットをフォーマットしてPCに送信すると、PCはパケットを受信したことを応答します。そうでない場合、センサーデバイスはタイムアウト時に再送する可能性があります。

また、ネットワーク転送を行う場合は、Foredeckerポイントが物理層のものを忘れないように、 OSIモデルのようなネットワークスタックとして設計する必要があります。私のHDLCでの投稿はデータリンク層であり、RPCとコマンド処理はアプリケーション層です。

于 2009-05-02T22:45:56.887 に答える
11

RS232プロトコルには注意が必要です。HDLCを使用するという提案は良いものですが、ソリューション全体ではありません。あなたが決定する必要がある他の事柄があります:

  • 2つのデバイス間のボーレートはどのように決定されますか?Autobuad?事前定義、または明示的に設定しますか?
  • ソフトウェアまたはハードウェア、あるいはその両方でフロー制御を行いますか?ハードウェアフロー制御を使用する場合は、ケーブルが正しく構築されていることを確認する必要があることに注意してください。
  • ケーブルといえば、これはRS233の大きな苦痛です。デバイスによっては、ストレートケーブル、クロスケーブル、またはそのバリエーションを使用する必要がある場合があります。
  • ソフトウェアベースのフロー制御メカニズムを使用すると、最も単純なケーブル(TX、RX、およびコモン)を3本だけ使用できるため効果的です。
  • 7ビットまたは8ビットのワードを選択しますか?
  • HWパリティまたはソフトウェアエラーチェック。

8データビット、ハードウェアパリティなし、1ストップビットを使用し、ソフトウェアベースのフロー制御を使用することをお勧めします。ハードウェアが自動ボーレートをサポートしている場合は、自動ボーレートを使用する必要があります。そうでない場合、自動ボーレートをソフトウェアで実行するのは非常に困難です。

于 2009-05-03T19:08:46.917 に答える
9

私は数か月前にこの質問を読みましたが、まったく同じ問題がありましたが、RAMの量が少ない小さな8ビットマイクロに十分な効率のあるものは実際には見つかりませんでした。CANとLINに触発されて、私はその仕事をするために何かを作りました。私はそれをMIN(マイクロコントローラー相互接続ネットワーク)と呼び、GitHubにアップロードしました:

https://github.com/min-protocol/min

そこには2つの実装があります。1つは組み込みCで、もう1つはPC用のPythonです。さらに、PCがコマンドを送信し、ファームウェアがLEDを点灯する小さな「HelloWorld」テストプログラム。私はこれをArduinoボードで起動して実行することについてブログに書いています:

https://kentindell.wordpress.com/2015/02/18/micrcontroller-interconnect-network-min-version-1-0/

MINは非常に単純です。レイヤー0の表現(8データビット、1ストップビット、パリティなし)を修正しましたが、ボーレートは開いたままにしました。各フレームは3つの0xAAバイトで始まり、バイナリでは1010101010です。これは、一方の端がもう一方の端に動的に適応したい場合に自動ボーレート検出を行うための優れたパルストレインです。フレームは0〜15バイトのペイロードであり、16ビットのフレッチャーのチェックサムと制御バイトおよび8ビットの識別子(ペイロードデータに含まれるものをアプリケーションに通知するため)が含まれます。

プロトコルは文字スタッフィングを使用するため、0xAA0xAA0xAAは常にフレームの開始を示します。これは、デバイスがリセットから抜け出した場合、常に次のフレームの開始と同期することを意味します(MINの設計目標は、不完全または誤ったフレームを渡すことではありませんでした)。これは、特定のバイト間およびフレーム間のタイミング制約を設定する必要がないことも意味します。プロトコルの詳細は、GitHubレポジトリwikiにあります。

MINには将来の改善の余地があります。ブロックメッセージパッシング(制御バイトの4ビットが予約されている)と機能の高レベルのネゴシエーション(識別子0xFFが予約されている)のためにいくつかのフックを残しているので、一般的に必要な機能のサポートを追加するための十分な余地があります。

于 2015-02-18T16:51:00.517 に答える
8

ここにはいくつかの良い答えがあります、ここにいくつかの有用なポインタがあります:

パケットが時間で区切られていない場合でも、同期バイトは、パケットの作成を試みる必要のある場所の数を減らすための重要な方法です。多くの場合、デバイスは大量のジャンクデータ(つまり、電源がオンになったときの飛行中のパケットの終わり、またはハードウェアの衝突の結果)を処理する必要があります。同期バイトがないと、受信したすべてのバイトからパケットを作成する必要があります。同期バイトは、1/255バイトのランダムノイズのみがパケットの最初のバイトになる可能性があることを意味します。また、プロトコルをスヌープしたい場合はFANTASTICです。

パケットにアドレスを設定したり、マスター/スレーブまたはPC /デバイスを少しだけ言ったりすることは、何らかの種類のスヌープツールを介してパケットを確認するときに役立ちます。これを行うには、PC用にDEVICEとは異なる同期バイトを使用します。また、これは、デバイスがそれ自体のエコーに応答しないことを意味します。

エラー訂正(ハミングなど)を調べることをお勧めします。8ビットのデータを12ビットで保護されたバイトにパッケージ化します。これらの12ビットのいずれかを途中で反転して元の8ビットを取得できます。データストレージ(CDで使用)またはデバイスが簡単に再送信できない場合(衛星リンク、一方向RF)に便利です。

パケット番号は生​​活を楽にします。送信されたパケットには番号が付けられ、応答には同じ番号と「応答」というフラグが付けられます。これは、到着したことのないパケット(たとえば、同期が破損している)が送信者によって簡単に検出され、低速リンクの全二重モードでは、最初の応答が受信される前に2つのコマンドを送信できることを意味します。これにより、プロトコル分析も容易になります(サードパーティは、基盤となるプロトコルを知らなくても、どのパケットが受信されたかを理解できます)。

単一のマスターを持つことは素晴らしい単純化です。とはいえ、全二重環境では、それはまったく問題ではありません。電力を節約しようとしている場合や、デバイス側でイベント駆動型のイベントを実行している場合(入力状態が変更され、サンプルの準備ができている場合)を除いて、常に実行する必要があると言えば十分です。

于 2009-06-21T04:29:49.467 に答える
5

私の提案はmodbusです。これは、センサーとパラメーターを備えたデバイス(PLCなど)と通信するための効率的で簡単な標準プロトコルです。仕様はhttp://www.modbus.orgで入手できます。1979年から登場し、人気が高まっています。例やライブラリを見つけるのに問題はありません。

于 2009-05-04T21:51:06.160 に答える
4

別のプロトコルは次のとおりです。

u8  Sync          // A constant value which always marks the start of a packet
u16 Length        // Number of bytes in payload
u8  Data[Length]  // The payload
u16 Crc           // CRC

PC(シリアルポート)とプロセッサ(UART)は、最小限の手間ですでにそれを処理できるため、RS232 / UARTを使用します(レベルシフトを行うには、 MAX232チップなどが必要です)。

また、RS232 / UARTを使用すると、関連性がない場合でもマスター/スレーブについて心配する必要はありません。必要に応じてフロー制御を利用できます。

推奨されるPCソフトウェア:独自に作成するか、Docklightを使用して簡単に監視および制御できます(評価バージョンは無料です)。

エラーチェックを強化するには、パリティチェックが最も簡単です。より強力なものが必要な場合は、たたみ込み符号化を使用します。

いずれにせよ、あなたが何をするにしても、それをシンプルにしてください!

編集: PCでRS232を使用することは、以前よりもさらに簡単になりました。これにより、USBからRS232/TTLへのコンバーターを入手できるようになりました。一方の端はPCのUSBソケットに入り、通常のシリアルポートとして表示されます。もう1つは、レベルシフトを必要とせずにプロセッサに直接接続できる5Vまたは3.3Vの信号に出力されます。

FDTIチップのTTL-232R-3V3を使用しました。これは、この種のアプリケーションに最適です。

于 2009-05-03T14:02:34.220 に答える
3

パリティチェックについて(ここで数回出てきます):

それらはほとんど役に立たない。1つのビットが誤って変更される可能性があることが懸念される場合は、2番目のビットも変更される可能性が高く、パリティチェックから誤検知が発生します。

ルックアップテーブルでCRC16のような軽量のものを使用します。これは、各バイトが受信されるときに計算でき、基本的には単なるXORです。Steve Melnikoffの提案は、小さなマイクロに最適です。

また、生のバイナリではなく、人間が読める形式のデータを送信することをお勧めします(パフォーマンスが最優先事項でない場合)。これにより、デバッグファイルとログファイルがはるかに快適になります。

于 2009-05-14T12:23:50.470 に答える
2

私の唯一の提案は、耐ノイズ性が必要な場合は全二重RS-422/485を使用することをお勧めします。AVR側でこれに似たICを使用し、次に485PTBRのようにPC側でRS- 232->RS-422コンバーターを使用できます。シールドケーブル(2つのツイストシールドペア)を見つけたり作成したりできる場合は、さらに保護が強化されます。そして、これらすべてはマイクロとPCには見えません-ソフトウェアの変更はありません。

何をするにしても、全二重システムを使用していることを確認し、読み取り/書き込みイネーブルラインがICにアサートされていることを確認してください。

于 2009-05-06T02:35:12.647 に答える
2

TelemetryPythonでのデスクトップ実装とそれに関連するものを見ることができますPytelemetry

主な特徴

これはPubSubベースのプロトコルですが、MQTTとは異なり、ポイントツーポイントプロトコルであり、ブローカーはありません

他のpubsubプロトコルと同様に、一方の端からaで公開topicし、もう一方の端でそのトピックについて通知を受けることができます。

埋め込み側では、トピックへの公開は次のように簡単です。

publish("someTopic","someMessage")

数字の場合:

publish_f32("foo",1.23e-4)
publish_u32("bar",56789)

変数を送信するこの方法は制限されているように見えるかもしれませんが、次のマイルストーンは、次のようなことを行うことで、トピックの解析に特別な意味を追加することを目的としています。

// Add an indexing meaning to the topic
publish("foo:1",45) // foo with index = 1
publish("foo:2",56) // foo with index = 2

// Add a grouping meaning to the topic
publish("bar/foo",67) // foo is under group 'bar'

// Combine
publish("bar/foo:45",54)

これは、配列や複雑なデータ構造などを送信する必要がある場合に適しています。

また、PubSubパターンは、その柔軟性のために優れています。マスター/スレーブアプリケーション、デバイス間などを構築できます。

CライブラリGitHubバージョン

Cライブラリは、適切なUARTライブラリがあれば、新しいデバイスに簡単に追加できます。

TM_transport(で定義された)というデータ構造をインスタンス化しTelemetry、4つの関数ポインタを割り当てるだけread readable write writeableです。

// your device's uart library function signatures (usually you already have them)
int32_t read(void * buf, uint32_t sizeToRead);
int32_t readable();
int32_t write(void * buf, uint32_t sizeToWrite);
int32_t writeable();

テレメトリを使用するには、次のコードを追加する必要があります

// At the beginning of main function, this is the ONLY code you have to add to support a new device with telemetry
TM_transport transport;
transport.read = read;
transport.write = write;
transport.readable = readable;
transport.writeable = writeable;

// Init telemetry with the transport structure
init_telemetry(&transport);  

// and you're good to start publishing
publish_i32("foobar",...

PythonライブラリPyPIバージョン

デスクトップ側にはpytelemetry、プロトコルを実装するモジュールがあります。

Pythonを知っている場合、次のコードはシリアルポートに接続し、トピックについて1回公開し、foo受信したすべてのトピックを3秒間印刷してから、終了します。

import runner
import pytelemetry.pytelemetry as tm
import pytelemetry.transports.serialtransport as transports
import time

transport = transports.SerialTransport()
telemetry = tm.pytelemetry(transport)
app = runner.Runner(transport,telemetry)

def printer(topic, data):
    print(topic," : ", data)

options = dict()
options['port'] = "COM20"
options['baudrate'] = 9600

app.connect(options)

telemetry.subscribe(None, printer)
telemetry.publish('bar',1354,'int32')
time.sleep(3)

app.terminate()

Pythonがわからない場合は、コマンドラインインターフェイスを使用できます

ピテレメトリーCLIPyPIバージョン

コマンドラインはで開始できます

pytlm

次に、受信したトピック、トピックで受信したデータを(一覧表示)、トピックでconnectls公開)、またはトピックでを開いて、受信したデータをリアルタイムで表示できます。printpubplot

ここに画像の説明を入力してください

ここに画像の説明を入力してください

于 2016-02-10T08:07:26.693 に答える
1

この質問は完全にばかげているかもしれませんが、X / Y / Zモデムプロトコルの1つを使用することを検討した人はいますか?

上記のプロトコルのいずれかを使用する主な利点は、さまざまなプログラミング環境ですぐに使用できる実装の優れた可用性です。

于 2009-05-07T13:25:48.143 に答える
0

マイクロコントローラーの動作を正確に指定していませんが、マイクロコントローラーから送信されるものはすべて、PCからのコマンドに対する直接の応答になりますか?もしそうなら、あなたはある種のマスター/スレーブプロトコルを使うことができるようです(これは通常最も簡単な解決策です)。双方が通信を開始できる場合は、より一般的なデータリンク層プロトコルが必要です。HDLCは、このための古典的なプロトコルです。完全なプロトコルはおそらくあなたのニーズには行き過ぎですが、例えば、少なくとも同じフレームフォーマットを使用することができます。また、PPPを調べて、有用な部分があるかどうかを確認することもできます。

于 2009-05-02T22:59:40.240 に答える
-1

SLIPとUDP。真剣に。

すべてのPCおよび同様のデバイスがそれを話します。

TCPリーンからの良い本と例があり ます

Jeremy Benthamは、TCP/IPの動作を行うPICをこっそりと入手しました。AVRはPICと同じくらい良いですか?

代わりにUDPをお勧めします。とても簡単です。

于 2009-12-01T03:46:52.763 に答える