Tinkercad - Projekt 3 - 2 Arduinos miteinander kommunizieren lassen

RX und TX

Der Zustand des Schalters an Arduino 1 steuert den Zustand der LED an Arduino 2.

Schwierigkeitsgrad: mittelschwer

Starte die Simulation, verstelle die Position des Schalters links (darauf klicken), warte ein wenig und der Zustand der LED rechts sollte sich verändern:
Richte dich darauf ein, dass die Simulation nicht in Echtzeit, sondern sehr viel langsamer laufen wird. Das siehst du an der Zeitanzeige oben.
(Falles es hier nicht lädt: Hier ist der Link.)


Für dieses Projekt musst du folgendes können:

Hardware

In der Demo-Schaltung gibt es 2 Arduinos:
  • Arduino 1 (links): Schalter angeschlossen an Pin A0. Dieser hat 2 Positionen: Entweder er verbindet Pin A0 mit GND (LOW) oder mit 5V (HIGH).
  • Arduino 2 (rechts): LED mit Vorwiderstand angeschlossen an Pin A1.
Die beiden Arduinos haben jeweils unterschiedliche Programme. Du kannst im "Code"-Editor oben rechts zwischen Arduino "1" und Arduino "2" umschalten oder einfach auf den jeweiligen Arduino klicken.
Abbildung 1 - zwischen Programmen der beiden Arduinos umschalten

Verbunden sind beide Arduinos jeweils an den Pins 0 und 1. Diese sind mit TX und RX beschriftet.
  • TX steht für transmit (senden)
  • RX steht für receive (empfangen)
Will Arduino 1 also eine Information an Arduino 2 senden, kommt diese Information aus TX (Arduino 1) heraus und geht in RX (Arduino 2) hinein und umgekehrt.

Damit die beiden Arduinos sich verstehen, müssen sie sich auf eine "Sprache" einigen. Das nennt man Kommunikations-Protokoll. Das hier verwendete Protokoll heißt UART.

Der Text wird dabei Zeichen für Zeichen in eine Zahl umgewandelt. Diese Zahl kann man binär, also durch 0 und 1 darstellen (in Bits) und die Bits werden nacheinander übertragen. Die verwendete Zuordnung zwischen Buchstaben und Zahlen heißt ASCII.

Solch eine Zuordnung nennt man Kodierung. Es gibt noch viele andere Kodierungen, zum Beispiel UTF-8, welche auch Umlaute und ß beherrschen und somit besser für die deutsche Sprache geeignet sind. Für chinesische Schriftzeichen benötigt man wieder eine ganz andere Kodierung. Abbildung 2 zeigt einen Teil der ASCII-Kodierung - welches Zeichen welcher Folge von Bits entspricht:
Abbildung 2 - Ausschnitt ASCII-Kodierung binär

  • TX Pin wird als Ausgang konfiguriert und HIGH (5V) getrieben → Bit 1 → von RX auf der anderen Seite als HIGH empfangen, was 1 entspricht.
  • TX Pin wird LOW (0V) getrieben → Bit 0 → von RX auf der anderen Seite als LOW empfangen, was 0 entspricht.
Damit das klappt, müssen die GND-Pins beider Arduinos auch miteinander verbunden sein, denn eine Spannung existiert immer nur zwischen 2 Leitungen. Es muss ja irgendwie ein Strom im Kreis fließen können.

Das UART-Protokoll ist ein serielles Protokoll. Das bedeutet, dass die einzelnen Zeichen nacheinander übertragen werden. Das S in USB steht z.B. auch für seriell. In Projekt 6 wirst du ein paralleles Protokoll kennen lernen, bei dem wesentlich mehr Kommunikationsleitungen verwendet werden als nur ein TX-RX-Pärchen. Auf jeder Leitung wird dann seriell kommuniziert. Aber da es mehrere gibt, kann man mehr Information gleichzeitig übertragen und die Übertragung wird schneller. Abbildung 3 zeigt einen Frame (ein Zeichen) im UART-Protokoll:
Abbildung 3 - ein Zeichen im UART Protokoll

Bei der in Abbildung 3 abgebildeten Signalform ist -15V LOW und +15V HIGH. Beim Arduino ist das nicht so.

Diese Kommunikation kannst du in den 2 Oszilloskopen in der Demo beobachten.

Zwischen den beiden Arduinos befinden sich jeweils in den Kommunikationsleitungen (Datenleitungen) Widerstände in Serie.
Abbildung 4 - Widerstände in Serie in den Datenleitungen zwischen RX und TX

Deren strombegrenzende Funktion wird dazu genutzt Kurzschlüssen vorzubeugen. Die können passieren, wenn zum Beispiel sowohl TX (Arduino 1) und RX (Arduino 2) auf Ausgang konfiguriert sind. Beide Seiten versuchen dann das Signal zu treiben. Sowas sollte man generell vermeiden. Setzt Arduino 1 sein TX dann auf HIGH und Arduino 2 sein RX auf LOW, passiert ein Kurzschluss, da beide Arduinos auch über GND miteinander verbunden sind. Dabei können beide Arduinos kaputt gehen.
Abbildung 5 - Kurzschluss zwischen 2 Arduinos

Software

Kommuniziert wird mit der Serial Bibliothek:
  • Serial.print() sendet etwas aus Pin TX heraus. Diese Daten werden am anderen Arduino an Pin RX empfangen und der Warteschlange hinzugefügt.
  • Serial.read() liest die Daten dann aus der Warteschlange aus.
Du kannst dich erstmal herantasten, indem du für Arduino 1 ein Programm schreibst, dass den Zustand des Schalters ausliest und im Serial Monitor ausgibt. Das wird dann genau so auch an Arduino 2 gesendet. Das machst du regelmäßig in loop().

Vergiss nicht, eine Verzögerung mit einzubauen, damit du nicht schneller Zeichen an Arduino 2 sendest als Arduino 2 diese auslesen kann. Jetzt kann es dir immer noch passieren, dass der Programmcode in loop() schneller ausgeführt wird als die Daten übertragen werden können. Wenn du dich erinnerst, mit Serial.begin() konnte man die Übertragungsgeschwindigkeit einstellen in Bits/Sekunde. Meist wird dort 9600 Bits/Sekunde (Baud) verwendet. In der Realität kann man mit dem Arduino maximal 11200 Baud verwenden und es funktioniert noch (schneller und es fangen an sich Übertragungsfehler einzuschleichen). Wenn man jetzt eine sehr langsame Übertragungsgeschwindigkeit wählt, kann es passieren, dass gar nicht alle Daten über den Serial Monitor rausgehen, da das Programm schneller ist als die UART-Kommunikation.

Beide Arduinos müssen übrigens dieselbe Übertragungsgeschwindigkeit verwenden, um sich gegenseitig zu verstehen.

Es gibt dafür aber eine Funktion, die einem zurückgibt wie viele Zeichen man noch ohne Probleme senden kann:

int Serial.availableForWrite()

Wenn diese Funktion einem nicht 0 zurück gibt, darf man noch Daten senden. Du kannst also entweder eine Verzögerung einbauen oder nur Daten senden, wenn Serial.availableForWrite() größer 0 zurück gibt.

Das kann so hier aussehen. In diesem Beispiel ist es doppelt gemoppelt, da beides gemacht wird. Aber sicher ist sicher:

void loop()
{
  if (Serial.availableForWrite() >= 1) {
    // Schalter auslesen und im Serial Monitor ausgeben
  }
  delay(100);
}

Wenn das funktioniert, kannst du für Arduino 2 ein Programm schreiben, dass Zeichen vom Serial Monitor wieder ausliest. Zeige dir diese im Serial Monitor in Arduino 2 an, sodass
  1. in Arduino 1 der Taster ausgelesen und per Serial.print() and Arduino 2 übertragen wird,
  2. in Arduino 2 per Serial.read() der Zustand des Tasters wieder ausgelesen und per Serial.print() wieder ausgegeben wird.
  3. (Streng genommen sendet Serial.print() in Arduino 2 die Daten wieder an Arduino 1 zurück; gewissermaßen wie ein Echo. Aber du wertest diese Antwort in Arduino 1 ja nie aus.)
Achte dabei darauf, dass du nur Daten aus der Warteschlange auslesen kannst, wenn auch welche zur Verfügung stehen. Wenn du dich erinnerst, kannst du dies mit Serial.available() prüfen.

Wenn das funktioniert und der Schalter-Zustand in Arduino 2 ankommt, kannst du damit die LED steuern.

Du liest mit Serial.read() ein Zeichen aus. Das ist vom Typ char. Wenn du also auf einen bestimmten Wert testen willst, kannst du etwas schreiben wie:

// ein Zeichen steht immer in einfachen Anführungszeichen (')
if (Serial.read() == '1') {
  // LED einschalten
}

Du kannst den char allerdings auch in eine Zahl (z.B. int) umwandeln mit dieser Funktion:

// bei einer Zahl benötigt man keine Anführungszeichen
if (Serial.parseInt() == 1) {
  // LED einschalten
}

Jetzt ist es allerdings wichtig, dass die Ziffern irgendwie voneinander getrennt sind, damit die Zeichenfolge '1''1''1' nicht als Zahl 111 gelesen wird. Dafür reicht es aus die Zeichen in Arduino 1 mit Serial.println() anstatt Serial.print() zu versenden, da der Zeilenumbruch (neue Zeile) keine Ziffer ist.

'1'
'1'
'1'

wird dann als drei Einsen interpretiert.

Na dann los!

Richte dich darauf ein, dass die Simulation nicht in Echtzeit, sondern sehr viel langsamer laufen wird.

Falls du die Schaltung nicht selbst aufbauen willst, hier der Starter:

Du kannst natürlich auch andere Dinge an die beiden Arduinos anschließen, um das Projekt ein bisschen interessanter zu machen. Lass deiner Fantasie freien Lauf!

Kommentare

Beliebte Posts aus diesem Blog

Tinkercad Übung 6 - LED mit Taster ansteuern

Tinkercad Übung 11 - LED dimmen

Tinkercad Übung 15 - Ultraschallsensor auslesen