Arduinos間の通信オプション

私は5〜10人のArduinosの間でコマンドとデータを送るためにコミュニケーションを探しています。 "Arduino"とは、Arduinoプログラミングフレームワークを使ってプログラムされたATmega328を意味します。

各デバイスは同じPCB上にあります。

私はI2CとSPIがある程度通信できることは知っていますが、実際には、複数のマイクロコントローラを相互に接続するのではなく、マイクロコントローラに接続された周辺機器のデバイスを意味し、通常は一度に数バイトのデータしか送信しません。一方、私はLCDディスプレイがそれらを使用して駆動できることを知っています、そして、私はそれらのケースで転送されているデータがたくさんあると思います。

マイクロコントローラ間の通信にI2C(マルチマスタ、マルチスレーブ、シングルエンド、シリアルコンピュータバス)のようなものがありますか?それぞれのデバイスが任意の他のデバイスにデータを送信することを許可する。たとえば、スイッチがデバイスAで押された場合、デバイスBは、スイッチが押されたときにデバイスBが常にAに尋ねることなく、デバイスBに通知します。およびその逆。

Edit: I found some libraries that may do what I want with RS-485. Is this the only viable option for ~1k bps transmission between 5-10 devices? I would imagine TCP/IP over Ethernet would work as well, but that seems like too much. Are there any I2C libraries that allow sending that amount of data between only master devices?

5
追加された 編集された
ビュー: 1
あなたはRS-485を意味しますか?
追加された 著者 user7461,
@Paul私は懸念の分離をしたい。より多くの割り込みとI/Oを持つより大きなコントローラを手に入れることができるのは分かっていますが、私はむしろデバイスレベルで単純なものを維持したいと思っています。また、各サブシステムを設計したり、独立して構築したり、後で一緒に接続したりできるため、他の人と共同作業するときに役立ちます。単体テストや交換/アップグレードも簡単にできます。
追加された 著者 user7461,
@ frarugi87私は、どのデバイスも他のデバイスと通信して接続を開始すると、バストポロジが最もうまくいくと思います。だから奴隷はいない。
追加された 著者 user7461,
あなたは物理層(ケーブルまたはボード)、RS-485のような電子的な "標準"が必要ですが、5V TTLも良いです。次に、バスアービトレーションのタイプ(ラウンドロビン、マスタースレーブまたはブロードキャストメッセージ)を選択し、おそらくいくつかのアドレッシングまたはエラーチェックを実装する必要があります。
追加された 著者 dotnetengineer,
ブレッドボードでは、トランシーバが必要なのでRS485は使用しません。ロジック1の場合は5V、ロジック0の場合は0Vです。しかしその点から、可能性は無限です。速度要件などにも依存します。
追加された 著者 dotnetengineer,
なぜあなたはそのようなことを作りたいのか述べていません。 IOピンが足りない場合は、IOエキスパンダを使用することができます。より良い解決策があるかもしれません。それが趣味である/概念の証明であれば、そのような他のプロジェクトをチェックして、 "強化/調整"しようとするかもしれません。
追加された 著者 dotnetengineer,
あなたはシリアル接続を見ましたか?
追加された 著者 user67244,
ここでは非常によく似た質問があります:複数のArduinosをRpiで相互接続してホームライト/スイッチを制御する方法 - Rpiの部分を無視する(これは本当に問題とは関係ありませんでした)行う。私は「ローリング・マスター」システムをやっていることについて長い時間をかけて回答しました。他の質問/回答を読み、あなたの考えを見てください。
追加された 著者 Nick Gammon,
別のマイクロは、ホップを作る必要がありますが、それは動作します。最後の解決策はあなたが言ったことです。だから誰もが同じバスで話していますが、あなたは衝突の検出が必要です。この場合は、すでに衝突を処理しているので、CANバスをお勧めします(ただし、コード内で実装する必要があります)。
追加された 著者 Tom Collins,
バストポロジーは大丈夫ですが、バスマスタと他のすべての奴隷を作ることを強くお勧めします。それ以外の場合は衝突が発生し、衝突の検出/防止は「難しい」作業です。もしあなたがただ一つのマスターを持っていれば、彼は話す許可を与えることができるので、これを避けることができます。マスタのTXを各スレーブRXに接続する1本のワイヤとスレーブTXを接続する1本のワイヤ(おそらくは3ステートバッファ)をマスタRXにシリアル(UART)バスで接続することができます。さもなければ、デイジーチェーン接続を作ることができます:TX1はRX2に、TX2はRX3 ... TXnをRX1に接続します。これは少し効率が悪いです
追加された 著者 Tom Collins,
たぶん私はそれを見つけただけではありませんでしたが、基本的な質問は読んでいませんでした。これは「あなたが必要とするトポロジは何ですか?誰もがみんなに話す必要がありますか?集中化されたアクセス(つまり、誰もが話しています)?混合溶液?
追加された 著者 Tom Collins,

4 答え

あなたの夢を実現するのに役立ついくつかの概念があります。私は、この答えの中で、あなたが望むものをどのように実装するのかを正確に伝えることはできませんが、実装するのに役立つ概念を示すことができます。

まず、バスマスタというコンセプトがあります。これは必ずしも通信をインスタンス化するデバイスではありません。代わりに、これはバスを所有制御するデバイスです。

バスマスタではないデバイスがバス上で通信したい場合、まずバスマスタからの許可を求めます。古いZ80(まあ、私は「古い」と言っていますが、今日でもいろいろな形でまだ使用されています)は、他のチップがデータバスとアドレスバスを使用できるようにするためにこのコンセプトを使用しました。 BUSRQとBUSACKの2つの信号で構成されています。デバイスはまず、BUSRQまたはBUSACKのいずれかがアクティブであるかどうかを調べ、どちらもアクティブでない場合は、BUSRQをアクティブにします。バスマスタが他のデバイスにバスを放棄しようとしている場合(その時点でそれを使用していない場合)、バスマスタはBUSACKを起動し、他のデバイスはバスを使用できることを認識します。 BUSRQとBUSACKの両方がリリースされるまで、それ以外のものは使用できません。ニースとシンプルでエレガント。

しかし完璧ではない。 2つのデバイスが非常に同じ瞬間にバスを要求すると決定した場合、衝突が発生します。これは、このような共有バスシステムの共通の問題であり、正しく処理する方法がわからない限り、未解決の問題を引き起こします。

listen-while-you-talk のコンセプトを入力します。これは、別の受信機を介してバス上に送信されているものを聴いているバスを送信しているデバイスを含む。その後、バスで送られたものが実際にバスで終わったかどうかを知ることができます。たとえば、2つのデバイスが同時に発言し、1つが 10011001 を送信し、もう1つが 11001100 を送信した場合、バスに表示される結果は実際にはバス信号の作成方法に応じて 11011101 、または 10001000 だからあなたが送ったものが壊れているのを知ったら、あなたは今それについて何かできます。

次のコンセプト:後退。これは、両方の送信者が短期間待ってから再試行して送信する場所です。彼らが両方の時間の異なる時間のために遅延する限り、しようとする最初のものは、バスを取得し、通信することができます。しかし、あなたはどうやって彼らが異なる時間に両方を遅らせることを保証しますか?答えは簡単だと思うかもしれません: rand()random()のような乱数を使用してください。しかし、それも問題である。

Another concept: The pseudo random number generator

Arduinoは乱数を生成しません。複雑な数式を使って、私たちに無作為に見える数列を作成するだけです。彼らはそうではありません。シリアルを通して10の乱数を印刷し、それを複数回実行するための小さなプログラムを書く(リセットボタンを押す)。毎回同じ順序で同じ「ランダム」番号が見つかるでしょう。別のArduinoで試してみて、同じ数字をもう一度得る。いつも同じ。

じゃあ何をすればいいの?答えは乱数ジェネレータをシードすると呼ばれます。 rand()などが生成する次の数字は、最後に生成された番号に依存します。 最初のの数字を変更すると、残りの数字はすべて変更されます。しかし、キャッチ22の状況があります。乱数ジェネレータをシードする乱数が必要です。乱数を生成して乱数ジェネレータ...無限にシードするには、乱数ジェネレータを乱数にする必要があります。あなたはそれがどこにあるのかを見ますか? rand()はランダムなソースからシードされるまでランダムではないので、 rand()からシードすることはできません。だからあなたはランダムな情報源を見つける必要があります。

それは簡単なことではありません。知られているエントロピーの最良のソースはホワイトノイズです。これは、ダイオード接合部の破壊から、抵抗器の熱変動の非常に高い利得増幅まで、さまざまな回路を使用してさまざまな方法で生成することができます。

すべてはあなたが本当に望むものにはかなり複雑ですが、何かに接続されていないアナログ入力を読み込む方が、ほんの僅かでランダムな方法では簡単です。適切なエントロピージェネレータほどの範囲はありませんが、各デバイスが異なるシードを取得する妥当な確率を与えるのに十分なランダム性を提供する必要があります。

もう一つの便利な概念は割り込みです。

これは、すべての衝突などを伴うマルチマスターバスの複雑さを望まない状況では有効です。バス上のすべての作業を行う単一のマスターがあり、スレーブデバイスが何か重要なことを言うときは割り込みでマスタをナッジします。マスターは次に「はい、あなたは何をしたいですか?スレーブが「誰かが私のボタンを押した」と返答します。

そうすれば、マスターはスレーブを常にポーリングして、ボタンが押されたかどうかを確認することはありません。これはSPIのようなバス構成でよく使用され、入力ピンの1つが変化したときに割り込みをアサートできるIO拡張チップなどのチップが多数あります。

しかし、20個のデバイスを持っていると、20個の割り込みピンがあることになりますか?必ずしも。新しいコンセプト:有線OR

複数の異なるスレーブがすべて同じ割り込みピンを使用することは完全に可能です。このピンは通常、抵抗(内部プルアップ抵抗でも可)でHIGHに保持され、各スレーブにはそのピンに接続されたオープンドレイン出力があります。オープンドレイン出力は、「オフ」のときは何も接続されていません。ピンが入力モードにあるようなものです(実際には入力モードと出力モードを切り替えることでオープンドレインのないチップでエミュレートできます)。出力が「オン」のときは、ピンと同じようにピンをグランドに接続し、IOピンをプルダウンします。

それから、誰が注意を必要としているかを見るために、その中断に付随していることを知っている奴隷の周りを回るのは、主人までです。もちろん、それぞれのスレーブの異なるグループを持つ複数の異なる割り込みピンを実装することができます。たとえば、デバイスが1つの場合は優先度が高く、それぞれのデバイスが複数ある場合は優先度が低くなります。

wired ORopen drain という同じ概念を使用して、複数のデバイスがすべて同じ物理配線を共有できるようにすることができます。つまり、2つのバスラインは抵抗によってプルアップされ、その上のデバイスはオープンドレイン出力を使用してラインをローにプルダウンし、ハイレベルに戻して異なるロジックレベルを作り出します。 2つのデバイスが共に低くなると、それはちょうど低くなります。オープンドレイン方式がなければ、1つのデバイスが1を出力し、もう1つが0を出力すると、基本的に2つの間の短絡が発生し、破損したチップになります。

もちろん、同期と非同期のコミュニケーションのコンセプトはありますが、それはまったく異なる魚です。簡単に言えば、そのクロックを生成するマスタを持つSPIやI2Cのようなクロックを持つプロトコルは同期しています。 UARTやRS-232、RS-485などのプロトコルは非同期です。信号の到着時に信号をどのように解釈するかを知るために、データの転送速度(ボーレート)を両者が頼りにしています。

2
追加された
@EdgarBonetワイヤライブラリがマルチマスターをサポートしているかどうか知っていますか?このように簡単ですか? michael.bouvy.net/blog/en/2013/05/25/…
追加された 著者 user7461,
追加された 著者 Sprogz,
私は単なるI2Cが理論的にはマルチマスタ対応であり、乱数を必要としない調停方式があると付け加えたいと思います。しかし、Atmelの実装に問題があるようです。 C.f。たとえば、 TWIモジュールはマルチマスター通信でバグがあるようですAtmel AVRマイクロコントローラの複数マスタ問題。単一のマスター+割り込みは私にとっては最も簡単な解決策のようです。
追加された 著者 Sprogz,
@EdgarBonet何らかの形のバス調停システムが実装されていれば、ほとんどすべてのプロトコルをマルチマスターにすることができます。これには他よりも適しているものもあれば、I2Cなど一部のものでは「公式」な方法がありますが、その中のいくつかは他のものより優れています。もちろん、最も信頼性の高い方法は、マルチマスターシステムがまったく必要ないことです。
追加された 著者 Majenko,

PJONをチェックしてください - https://github.com/gioblu/PJON これは単線の代替品です。

1
追加された
代替案よりも優れている理由/それが目立つ理由についていくつかの情報を追加してください。ありがとう!
追加された 著者 hintbw,
PJONはArduinoだけでなく、複数のプラットフォームで利用できるようになりました。これはI2C/one-wireより簡単です。それはより良い騒音を処理します。マルチマスターをサポートしています。リンクからwikiを読んでください。
追加された 著者 Peter Green,
あなたは現時点で実際にはリンクのみの回答であるため、あなたの答えを多分使い方や賛否両論の例を詳しく説明してください。
追加された 著者 RSM,

@ Majenkoの優れた答えに加えて、あなたはコミュニケーションしているものについて考える必要があります。

それはあなたが単一のビットを伝えたいと思うように聞こえる - おそらくあなたは個々のピンで逃げることができますか?マスターと最大13台のスレーブがある場合は、スレーブ上の1つのピンに(抵抗を介して)接続されたマスター上の1つのピンを持つことができます。スレーブAが信号を送りたいと思ったら、ピンを上げるでしょう。マスタは次に各ピンを順番にポーリングして、誰が何を言ったかを理解することができます。

0
追加された
申し訳ありませんが、その最後のビットは、デバイスがポーリングする代わりにデータをお互いに「プッシュ」できるようにする方法の一例です。私は実際には、より多くのデータを送信したいと思います。 10秒間に100バイト〜100バイト。
追加された 著者 user7461,

別のオプションはSPIです。

SPIは、リング内の任意の数のデバイスで使用できます。それは私に次のように説明されました:どの参加者もクロックラインを8回トグルして自分のバッファ内のバイトをリング内の次のデバイスのバッファに移動できます。デバイスは前のデバイスからバイトを取得します。他の誰かがクロックを8回トグルすると、新しいバイトが準備完了であることが通知されます(これはハードウェアで行われます)。

あなたは、 "アドレス"、 "長さ"、 "コマンド"、そして任意の数のパラメータのためのプロトコルについて注意深く考える必要があります。送信側は "アドレス"バイトを送信し、バッファ内の "長さ"バイトを設定し、残りを準備します。次のデバイスは「アドレス」バイトを受信し、それが意図された受信者であるかどうかを見る。そうでない場合は、これをメモし、チェーンを丸めて、長さをメモし、ELSEがそのバイト数をプッシュするまで待つ。それがあなたのものであれば、残りのデータを読んで、データをプッシュして行きます(戻るのを止めるために)。空白のアドレス(例えば0)は予約されている。つまり、「これで何もしないで、誰かがそれを押して、次のバイトを次のアドレスとして読む」。すべてのデバイスは、起動時に0に初期化する必要があります。

アドレスを動的に設定する必要がある場合は、「あなたのデバイス番号がXで、次のデバイスにデバイス番号がX + 1であることを通知する」というコマンドで、特別なバイト「すべてのステーション」を設定します。もちろん、誰かがこれを開始する必要があります。

2つの端末が同時に送信を開始した場合や、何かが中継されていない場合(たとえば、チップの電源が切れているなど)、衝突の危険性があります。あなたはこれをどのように検出/回復するかについて考える必要があります。

0
追加された