Frage:
Optionen für die Kommunikation zwischen Arduinos
waspinator
2016-03-18 01:22:41 UTC
view on stackexchange narkive permalink

Ich möchte zwischen ~ 5-10 Arduinos kommunizieren, um Befehle und Daten zwischen ihnen zu senden. Mit "Arduino" meine ich den ATmega328, der mit dem Arduino-Programmierframework programmiert wurde.

Jedes der Geräte befindet sich auf derselben Platine.

Ich weiß, dass I2C und SPI bis zu einem gewissen Grad kommunizieren können , aber dass sie wirklich für Peripheriegeräte gedacht sind, die an einen Mikrocontroller angeschlossen sind, anstatt mehrere Mikrocontroller miteinander zu verbinden, und dass sie normalerweise nur wenige Datenbytes gleichzeitig senden. Andererseits weiß ich, dass LCD-Displays mit ihnen betrieben werden können, und ich würde mir vorstellen, dass in diesen Fällen viele Daten übertragen werden.

Gibt es so etwas wie I2C (Multi-Master, Multi-Master)? Slave, Single-Ended, Serial Computer Bus) für die Kommunikation zwischen Mikrocontrollern? Zulassen, dass jedes Gerät unaufgefordert Daten an das andere Gerät sendet. Wenn beispielsweise ein Schalter an Gerät A gedrückt wird, teilt dies Gerät B mit, ohne dass Gerät B ständig A fragt, ob ein Schalter gedrückt wurde. und umgekehrt.

Bearbeiten : Ich habe einige Bibliotheken gefunden, die mit RS-485 das tun können, was ich will. Ist dies die einzig praktikable Option für eine Übertragung von ~ 1k bps zwischen 5-10 Geräten? Ich würde mir vorstellen, dass TCP / IP über Ethernet auch funktionieren würde, aber das scheint zu viel zu sein. Gibt es I2C-Bibliotheken, mit denen diese Datenmenge nur zwischen Master-Geräten gesendet werden kann?

Haben Sie sich die serielle Verbindung angesehen?
meinst du RS-485?
Hier gibt es eine sehr ähnliche Frage: [Wie man mehrere Arduinos mit einem RPI verbindet, um Home-Lights / Schalter zu steuern] (http://arduino.stackexchange.com/questions/15834/how-to-interconnect-multiple-arduinos- mit-einem-RPI-zu-steuern-Home-Licht-Schalter) - Ignorieren des RPI-Teils (es war nicht wirklich relevant für die Frage) Ich zähle das als praktisch identisch mit dem, was Sie tun möchten. Ich habe dort lange geantwortet, dass ich ein "Rolling Master" -System machen soll. Bitte lesen Sie die andere Frage / Antwort und sehen Sie, was Sie denken.
Sie benötigen eine physikalische Schicht (Verkabelung oder Platine), einen elektronischen "Standard" wie RS-485, aber 5V TTL ist auch gut. Dann müssen Sie auswählen, welche Art von Bus-Arbitrierung (Round-Robin-, Master-Slave- oder Broadcast-Nachrichten) und wahrscheinlich eine Adressierung oder Fehlerprüfung durchführen.
Auf einem Steckbrett würde ich RS485 nicht verwenden, da es Transceiver benötigt. Nur 5 V für eine logische 1 und 0 V für eine logische 0. Von diesem Punkt an sind die Möglichkeiten endlos. Dies hängt auch von den Geschwindigkeitsanforderungen usw. ab.
Sie haben nicht angegeben, warum Sie so etwas erstellen möchten. Wenn Ihnen die E / A-Pins fehlen, können Sie E / A-Expander verwenden. Es könnte bessere Lösungen geben. Wenn es sich um ein Hobby / Proof of Concept handelt, können Sie andere Projekte wie dieses ausprobieren und versuchen, es zu "verbessern / anpassen".
@Paul Ich möchte eine Trennung der Bedenken haben. Ich weiß, ich könnte einfach einen größeren Controller mit mehr Interrupts und E / A bekommen, aber ich möchte die Dinge lieber auf Geräteebene einfach halten. Dies hilft auch bei der Zusammenarbeit mit anderen, da jedes Subsystem unabhängig entworfen und sogar konstruiert und später miteinander verbunden werden kann. Kann auch einfacher zu testen und zu ersetzen / zu aktualisieren sein.
Vielleicht habe ich es nicht nur gefunden, sondern auch nicht die grundlegende Frage gelesen: "Welche Topologie benötigen Sie?" Müssen alle mit allen reden? Zentraler Zugang (d. H. Alle sprechen mit einem)? Eine gemischte Lösung?
@frarugi87 Ich denke, eine Bustopologie würde am besten funktionieren, wenn jedes Gerät mit einem anderen Gerät kommuniziert und die Verbindung herstellt. Also keine Sklaven.
Gut, für die Bustopologie in Ordnung, aber ich empfehle Ihnen dringend, einen Busmaster und alle anderen Slaves zu machen. Andernfalls kommt es zu Kollisionen, und das Erkennen / Verhindern von Kollisionen ist eine "schwierige" Aufgabe. Wenn Sie nur einen Meister haben, können Sie dies vermeiden, da nur er die Erlaubnis zum Sprechen geben kann. Sie können einen seriellen (UART) Bus herstellen, bei dem ein Draht den Master-TX mit jedem Slave-RX und ein Draht den Slave-TX (möglicherweise mit einem 3-Status-Puffer) mit dem Master-RX verbindet. Andernfalls können Sie eine Verkettung durchführen: TX1 an RX2, TX2 an RX3 ... TXn an RX1. Dies ist etwas weniger effizient, da mit zu sprechen
ein anderes Mikro muss man n Hopfen machen, aber es funktioniert. Die letzte Lösung ist die, die Sie gesagt haben, also sprechen alle im selben Bus, aber Sie benötigen eine Kollisionserkennung. In diesem Fall empfehle ich Ihnen den CAN-Bus, da er bereits die Kollisionen behandelt (aber Sie müssen ihn in Ihren Code implementieren).
Vier antworten:
Majenko
2016-03-18 04:01:36 UTC
view on stackexchange narkive permalink

Es gibt eine Reihe von Konzepten, mit denen Sie Ihren Traum verwirklichen können. Ich kann Ihnen im Rahmen dieser Antwort nicht genau sagen, wie Sie das umsetzen sollen, was Sie wollen, aber ich kann Ihnen die Konzepte zeigen, die Ihnen bei der Umsetzung helfen.

Zunächst einmal gibt es das Konzept von der Busmaster . Dies ist nicht unbedingt das Gerät, das die Kommunikation instanziiert. Stattdessen ist dies das Gerät, das besitzt und den Bus steuert.

Wenn ein Gerät nicht vorhanden ist. Wenn der Busmaster auf dem Bus kommunizieren möchte, bittet er zuerst den Busmaster um Erlaubnis. Der alte Z80 (nun, ich sage "alt", aber sie werden heute noch in vielen Formen verwendet) verwendete dieses Konzept, um anderen Chips die Verwendung der Daten- und Adressbusse zu ermöglichen. Es besteht aus zwei Signalen - BUSRQ und BUSACK. Ein Gerät prüft zunächst, ob BUSRQ oder BUSACK aktiv sind, und aktiviert BUSRQ, wenn dies nicht der Fall ist. Wenn der Busmaster bereit ist, den Bus an das andere Gerät abzugeben (er verwendet ihn derzeit nicht), aktiviert er BUSACK und das andere Gerät weiß dann, dass es den Bus verwenden kann. Nichts anderes kann es verwenden, bis BUSRQ und BUSACK beide veröffentlicht wurden. Schön und einfach und elegant.

Aber nicht perfekt. Wenn zwei Geräte im selben Moment nach dem Bus fragen, erhalten Sie eine Kollision . Dies ist ein häufiges Problem bei gemeinsam genutzten Bussystemen wie diesem und verursacht unzählige Probleme, es sei denn, Sie wissen, wie Sie richtig damit umgehen.

Geben Sie das Konzept zuhören, während Sie sprechen . Dies beinhaltet, dass das Gerät, das auf dem Bus sendet, auch hört, was auf dem Bus über einen separaten Empfänger gesendet wird. Es kann dann wissen, ob das, was es im Bus gesendet hat, tatsächlich im Bus gelandet ist. Wenn beispielsweise zwei Geräte gleichzeitig kommunizieren und eines 10011001 und das andere 11001100 sendet, wird das Ergebnis, das auf dem Bus angezeigt wird, möglicherweise als etwas anderes angezeigt, z 11011101 oder möglicherweise 10001000 , je nachdem, wie die Bussignale erzeugt werden. Wenn Sie also wissen, dass das, was Sie gesendet haben, beschädigt wurde, können Sie jetzt etwas dagegen tun.

Nächstes Konzept: Zurücksetzen . Hier warten beide Absender kurz und versuchen erneut zu senden. Solange beide unterschiedlich lange warten, erhält der erste, der es versucht, den Bus und kann kommunizieren. Aber wie garantieren Sie, dass sich beide um unterschiedliche Zeiten verzögern? Sie denken vielleicht, die Antwort ist einfach: Verwenden Sie eine Zufallszahl wie rand () oder random () . Das ist aber auch problematisch:

Ein anderes Konzept: Der Pseudo Zufallszahlengenerator

Der Arduino generiert keine Zufallszahlen . Es wird lediglich eine komplexe mathematische Formel verwendet, um eine Folge von Zahlen zu erstellen, die für uns zufällig aussehen . Sie sind es aber nicht. Schreiben Sie ein kleines Programm, um 10 Zufallszahlen seriell zu drucken, und führen Sie es mehrmals aus (drücken Sie die Reset-Taste). Sie finden jedes Mal die gleichen "Zufallszahlen" in der gleichen Reihenfolge. Versuchen Sie es auf einem anderen Arduino und Sie erhalten wieder die gleichen Zahlen. Immer gleich.

Also, was tun? Die Antwort heißt Seeding des Zufallszahlengenerators. Die nächste von rand () et al. Generierte Nummer hängt von der zuletzt generierten Nummer ab. Ändern Sie also die erste Nummer und alle anderen Nummern ändern sich. Sie haben jedoch eine Catch-22-Situation. Sie benötigen eine Zufallszahl, um den Zufallszahlengenerator zu setzen, damit er zufällig eine Zufallszahl generiert, um den Zufallszahlengenerator zu setzen ... ad infinitum. Siehst du, wohin das führt? Sie können nicht aus rand () säen, da rand () nicht zufällig ist, bis Sie aus einer zufälligen Quelle gesät haben. Sie müssen also eine zufällige Quelle finden.

Und das ist keine leichte Aufgabe. Die beste Quelle für Entropie , wie sie genannt wird, ist weißes Rauschen . Dies kann auf verschiedene Weise mit verschiedenen Schaltkreisen erzeugt werden - vom Durchbruch eines Diodenübergangs bis zur Verstärkung der thermischen Schwankungen in einem Widerstand mit sehr hoher Verstärkung.

Alle sind ziemlich komplex für das, was Sie wirklich wollen, aber es gibt eine einfachere, wenn auch etwas weniger zufällige Methode - lesen Sie einen analogen Eingang, der mit nichts verbunden ist. Es hat nicht so viel Reichweite wie ein geeigneter Entropiegenerator, sollte jedoch genügend Zufälligkeit bieten, um eine vernünftige Chance zu bieten, dass jedes Gerät einen anderen Startwert erhält.

Ein weiteres nützliches Konzept ist der Interrupt.

Dies ist gut in einer Situation, in der Sie nicht die Komplexität eines Multi-Master-Busses mit all den Kollisionen usw. wollen. Sie haben einen einzelnen Master, der die gesamte Arbeit am Bus erledigt, und wenn Sie ein Slave sind Das Gerät hat etwas Wichtiges zu sagen, es stupst den Master mit einem Interrupt an. Der Meister sagt dann "Ja? Was willst du?" worauf der Sklave antwortet "Jemand hat meinen Knopf gedrückt".

Auf diese Weise fragt der Master den Slave nicht ständig ab, um festzustellen, ob die Taste gedrückt wurde. Es wird häufig in Busanordnungen wie SPI verwendet, und es gibt viele Chips, wie z. B. IO-Expander-Chips, die einen Interrupt auslösen können, wenn einer ihrer Eingangspins den Status ändert.

Wenn Sie jedoch 20 Geräte haben, ist dies der Fall meine du hast 20 Interrupt Pins? Nicht unbedingt. Neues Konzept: verdrahtet ODER .

Es ist durchaus möglich, mehrere verschiedene Slaves mit demselben Interrupt-Pin zu haben. Der Pin wird normalerweise mit einem Widerstand auf HIGH gehalten (es könnte sich um einen internen Pullup-Widerstand handeln), und jeder Slave verfügt über einen Open Drain -Ausgang, der mit diesem Pin verbunden ist. Ein Open-Drain-Ausgang ist, wenn er ausgeschaltet ist, mit nichts verbunden - es ist, als ob sich der Pin im Eingangsmodus befindet (tatsächlich kann er durch Umschalten zwischen Eingangs- und Ausgangsmodus auf Chips emuliert werden, die keinen offenen Drain haben). Wenn der Ausgang eingeschaltet ist, verbindet er den Pin mit Masse und zieht den E / A-Pin nach unten, genau wie es eine Taste tun würde.

Es ist dann Sache des Masters, sich um die ihm bekannten Slaves zu bewegen an diesen Interrupt gebunden, um zu sehen, wer Aufmerksamkeit braucht. Sie können natürlich eine Reihe verschiedener Interrupt-Pins mit jeweils unterschiedlichen Gruppen von Slaves implementieren - möglicherweise einen mit hoher Priorität mit nur einem Gerät und einen mit niedrigerer Priorität mit jeweils mehreren Geräten.

Das gleiche Konzept von verkabeltem ODER und offenem Abfluss kann verwendet werden, damit mehrere Geräte alle dieselben physischen Kabel gemeinsam nutzen können. Genau so funktioniert I2C - die beiden Busleitungen werden von Widerständen hochgezogen, und die darauf befindlichen Geräte verwenden Open-Drain-Ausgänge, um die Leitung auf Low zu bringen und wieder auf High zu bringen, um die verschiedenen Logikpegel zu erzeugen. Wenn zwei Geräte beide zusammen ziehen, ist es nur niedrig. Ohne die Open-Drain-Methode würden Sie, wenn ein Gerät eine 1 und ein anderes eine 0 ausgeben würde, grundsätzlich einen Kurzschluss zwischen den beiden erhalten und die Chips beschädigen.

Und dann haben Sie natürlich das Konzept der synchronen versus asynchronen Kommunikation, aber das ist ein ganz anderer Fischkessel. Einfach gesagt, Protokolle mit einer Uhr wie SPI und I2C, bei denen ein Master diese Uhr erzeugt, sind synchron. Protokolle wie UART und RS-232, RS-485 usw. sind asynchron - sie beruhen auf beiden Enden, die sich darauf einigen, wie schnell Daten gesendet werden (Baudrate), damit sie wissen, wie die Signale bei ihrem Eintreffen zu interpretieren sind.

Ich möchte nur hinzufügen, dass I2C theoretisch Multi-Master-fähig ist und ein Arbitrierungsschema hat, das keine Zufallszahlen benötigt. Es scheint jedoch ein Problem mit der Implementierung von Atmel zu geben. C.f. Zum Beispiel [TWI-Modul scheint in der Multi-Master-Kommunikation fehlerhaft zu sein] (http://www.avrfreaks.net/forum/twi-module-seems-buggy-multi-master-communications) und [Multiple Master-Problem mit Atmel AVR-Mikrocontrollern] (http://www.robotroom.com/Atmel-AVR-TWI-I2C-Multi-Master-Problem.html). Single Master + Interrupts scheinen mir die einfachste Lösung zu sein.
@EdgarBonet Nahezu alle Protokolle können als Multi-Master-Protokolle erstellt werden, wenn eine Art Bus-Arbitrierungssystem implementiert ist. Einige sind dafür besser geeignet als andere, und einige, wie I2C, haben "offizielle" Methoden, von denen einige besser funktionieren als andere. Der zuverlässigste Weg ist natürlich, überhaupt kein Multi-Master-System zu benötigen :)
@EdgarBonet wissen Sie, ob die Drahtbibliothek Multi-Master unterstützt? Ist es so einfach wie dieses https://michael.bouvy.net/blog/de/2013/05/25/arduino-multi-master-to-master-i2c/
@waspinator: kann ich nicht sagen, da ich es nie versucht habe. Es scheint, dass [die Wire-Bibliothek die Bus-Schiedsgerichtsbarkeit übernimmt] (https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/libraries/Wire/src/utility/twi.c#L439), aber Ich weiß nicht, ob es mit den Problemen fertig wird, auf die ich zuvor hingewiesen habe.
EllisGL
2016-04-15 09:34:53 UTC
view on stackexchange narkive permalink

Schauen Sie sich PJON an - https://github.com/gioblu/PJON. Es ist eine Ein-Draht-Alternative.

Bitte können Sie auf Ihre Antwort ein Beispiel für die Verwendung oder Vor- und Nachteile erläutern, da dies im Moment wirklich nur eine Linkantwort ist.
Bitte fügen Sie einige Informationen hinzu, warum es besser ist als die Alternativen / was es auszeichnet. Vielen Dank!
PJON wurde für mehrere Plattformen verfügbar gemacht, nicht nur für Arduino. Es ist einfacher als I2C / One-Wire. Es geht besser mit Lärm um. Es hat Multi-Master-Unterstützung. Lesen Sie das Wiki über den Link.
AMADANON Inc.
2016-03-18 08:37:35 UTC
view on stackexchange narkive permalink

Zusätzlich zu der hervorragenden Antwort von @ Majenko müssen Sie sich überlegen, was Sie kommunizieren.

Es hört sich so an, als ob Sie ein einziges Bit kommunizieren möchten - vielleicht können Sie mit einzelnen Pins davonkommen? Wenn Sie einen Master und bis zu 13 Slaves haben, können Sie einen Pin am Master mit einem Pin an jedem der Slaves verbinden (über einen Widerstand). Wenn Slave A sein Signal signalisieren wollte, würde er den Pin anheben; Der Master könnte dann nacheinander jeden Pin abfragen, um herauszufinden, wer was gesagt hat.

Entschuldigung, das letzte Bit war nur ein Beispiel dafür, wie Geräte Daten untereinander "pushen" sollen, anstatt danach abzufragen. Ich möchte tatsächlich mehr Daten senden. ~ 100 Bytes 10 mal pro Sekunde.
AMADANON Inc.
2016-03-18 09:09:12 UTC
view on stackexchange narkive permalink

Eine weitere Option ist SPI.

SPI kann mit einer beliebigen Anzahl von Geräten in einem Ring verwendet werden. Es wurde mir wie folgt erklärt: Jeder Teilnehmer kann die Taktleitung 8 Mal umschalten, um das Byte in seinem eigenen Puffer in einem Ring in den Puffer des nächsten Geräts zu verschieben; Das Gerät erhält ein Byte vom vorherigen Gerät. Wenn jemand anderes die Uhr achtmal umschaltet, werden Sie benachrichtigt, dass das neue Byte bereit ist (dies erfolgt in Hardware).

Sie müssen sorgfältig über ein Protokoll nachdenken - eine "Adresse", " Länge "," Befehl "und dann eine beliebige Anzahl von Parametern. Der Absender sendet das "Adress" -Byte, setzt das "Längen" -Byte im Puffer und hält den Rest bereit. Das nächste Gerät hat das "Adress" -Byte empfangen und prüft, ob es der beabsichtigte Empfänger ist. Wenn dies nicht der Fall ist, wird dies notiert und die Kette herumgeschoben, die Länge notiert und gewartet, bis jemand anderes so viele Bytes herumgeschoben hat. Wenn es Ihnen gehört, lesen Sie den Rest der Daten, schieben Sie die Daten herum und löschen Sie sie, während Sie gehen (um zu verhindern, dass sie zurückkommen). Eine leere Adresse (z. B. 0) wäre reserviert, was bedeutet, "nichts damit zu tun, darauf zu warten, dass jemand anderes sie herumschiebt, und das nächste Byte als nächste Adresse zu lesen". Alle Geräte müssten beim Start auf 0 initialisiert werden.

Wenn Sie Adressen dynamisch festlegen müssen, setzen Sie ein spezielles Byte "alle Stationen" mit einem Befehl, der bedeutet, dass Ihre Gerätenummer X ist, und teilen Sie dies mit Das nächste Gerät, dessen Gerätenummer X + 1 "ist. Natürlich müsste dies jemand einleiten.

Sie laufen auch Gefahr, kollidiert zu werden, wenn zwei Geräte gleichzeitig senden oder wenn etwas nicht weitergibt, was es soll (z. B. ein Chip) ist ausgeschaltet). Sie müssen darüber nachdenken, wie Sie dies erkennen / beheben können.



Diese Fragen und Antworten wurden automatisch aus der englischen Sprache übersetzt.Der ursprüngliche Inhalt ist auf stackexchange verfügbar. Wir danken ihm für die cc by-sa 3.0-Lizenz, unter der er vertrieben wird.
Loading...