Am Beispiel eines Würfel-Spiels konstruieren wir jetzt eine Schaltung, in der drei Arduinos miteinander seriell
kommunizieren. Alle drei Mikrocontroller müssen über die serielle Schnittstelle Daten senden und empfangen.
Die Spielregeln halten wir einfach. Zwei Spieler, Tom (links) und Jerry (rechts), würfeln pro ein Spiel fünfmal um ihr
Glück. Die Augenzahlen werden summiert. Wer mehr angesammelt hat, hat gewonnen.
Die Spieler werden von zwei Arduino Nanos repräsentiert. Die Rolle des Schiedsrichters, der das Spiel leitet, übernimmt
Arduino Mega. Nachdem das Spiel gestartet wurde, entscheidet der Schiedsrichter, welcher Spieler an der Reihe ist. Die Spieler
würfeln nach dem Prinzip einer Zufallszahl. Anschließend übergeben sie das erreichte Ergebnis an den Schiedsrichter. Er summiert
die Punkte und zeigt den aktuellen Spielstand auf einer Infotafel. Zum Schluss zeigt er auch an, welcher der beiden Spieler
erfolgreicher war.
Die Mikrocontroller
An dem Spiel nehmen drei Arduinos (2 x Arduino Nano und 1 x Arduino Mega) teil. Arduino Mega verfügt über mehrere
serielle Schnittstellen. Arduino Nano hat nur eine.
Die Würfelaugen werden mithilfe zweier Matrix (8x8) angezeigt. Sie werden von dem Anzeigentreiber Max7219 gesteuert.
Die Kommunikation des Treibers mit dem Arduino Nano erfolgt hier über die Pins D2, D3 und D4. Um die 64 Digits der Matrix anzusteuern,
werden also nur drei
Leitungen verwendet. Es werden auch keine Vorwiderstände gebraucht. Die Matrix wird auf das Modul mit MAX7219 einfach
aufgesteckt.
Um die Anzahl der notwendigen Verbindungen zu reduzieren, wird an das LCD ein I2C-Adapter (FC-113) angeschlossen
(hier fest angelötet). Damit kann das Display über I2C-Bus angesprochen werden. Das reduziert die Anzahl der Verbindungen auf
zwei. Die für den I2C-Bus zuständigen Pins am Arduino Mega – Board sind die Pins 20 (SDA)
und 21 (SCL).
Beide Arduino Nanos werden mit dem gleichen Programm ausgestattet. In der Vorbereitungsphase muss an das Programm
die Bibliothek "LedControl.h" (von Eberhard Fahle, 2007) eingebunden werden. Sie übernimmt die Kommunikation mit der Matrix,
an der die Würfelaugen angezeigt werden. Für diese Kommunikation müssen wir drei digitale Pins des Arduino aufopfern, es sind
die Pins D2, D3 und D4. Für die Einbindung der Bibliothek kann der Bibliothekenverwalter verwendet werden.
Die beiden Nanos arbeiten mit Zufallszahlen. Ohne weitere Vorkehrungen generiert der Mikrocontroller bei jedem Neustart
die gleichen Zufallszahlen. Das kann den Spaß an einem Glückspiel ein wenig verderben. Um dem Problem vorzubeugen, kommt in dem
Programm die Funktion randomSeed(analogRead(A0) zum Einsatz. Sie bestimmt den Startwert des Zufallsgenerators. Den
Startwert holen wir von dem analogen Eingang A0. An den Eingang ist ein Kondensator angeschlossen, der sich über den Widerstand R1
auflädt. Bei Betätigen des Tasters S1 erfolgt über den Widerstand R2 eine kurze Entladung des Kondensators. Da nicht vorhersehbar ist,
wie lange ein
Mensch einen Taster drückt, kann man davon ausgehen, dass an dem analogen Eingang jeweils ein anderer Spannungswert ausgelesen wird.
Damit wird sichergestellt, dass bei jedem Neustart
andere Zufallszahlen generiert werden.
Viel zu tun haben die Nanos nicht. Es wird zunächst darauf gewartet, ob der Befehl Start von dem Arduino Mega,
der in dem Spiel als Schiedsrichter fungiert, über die serielle Schnittstelle angekommen ist. Sobald dies geschieht, wird eine
kleine Matrix-Show gestartet. Gleich danach wird eine Würfel-Augenzahl zwischen 1 und 6 via Zufall generiert. Die Augenzahl wird
dann auf der Matrix angezeigt und über die serielle Schnittstelle dem Schiedsrichter mitgeteilt.
Damit es ein wenig persönlicher wird, bekamen die Arduinos statt Nummern eigene Namen. In der Testschaltung spielt auf der
linken Seite Tom. Jerry positionierte sich auf der rechten Seite.
// *************************************************************************************
// Tom und Jerry Würfelspiel
// Serielle Kommunikation drei Arduinos
// Sketch Arduino Nano
// Arduino IDE 1.8.19
// *************************************************************************************
Der Schiedsrichter (Arduino Mega) koordiniert das Spiel. Er bestimmt, welcher der Spieler gerade am Zug ist.
Mit Serial.print("Start") wird Tom aufgefordert, den Würfel zu werfen. Mit Serial1.print("Start") wird
der Jerry angesprochen. Nach jedem Aufruf wartet Arduino Mega auf Antwort des jeweiligen Spielers. Die vom Spieler mitgeteilte
Augenzahl wird dann auf dem Display angezeigt. Zusätzlich wird die gesamte Punktezahl errechnet und ebenfalls angezeigt. Ein Spiel
besteht aus fünf Runden. Wenn man weiter machen will, muss erneut der Startknopf betätigt werden.
Auch in diesem Programm wird eine Bibliothek verwendet. Sie ist für die Kommunikation mit dem Display notwendig.
Die Bibliothek LiquidCrystal_I2C.h kann ebenfalls über den Bibliothekenverwalter installiert werden.
Die Funktionen, die sich auf serielle Schnittstelle beziehen, sind:
Serial.available() – Prüfung, ob Daten vorhanden sind
Serial.print () – Daten senden
Serial.parseInt() – lese die nächste gültige ganze Zahl
// ******************************************************************************
// Tom und Jerry Würfelspiel
// Serielle Kommunikation drei Arduinos
// Sketch Arduino Mega
// Arduino IDE 1.8.19
// ******************************************************************************
#include<LiquidCrystal_I2C.h> // Bibliothek Display I2C-Bus
LiquidCrystal_I2C lcd(0x27,20,4); // Adresse, Zeichen, Zeilen
int Taster_Start = 13; // Taster Spiel Start
int Punkte_Tom [2];
int Punkte_Jerry [2];
void setup() {
lcd.init(); // Display initialisieren
lcd.backlight(); // Hintergrundbeleuchtung
pinMode (Taster_Start, INPUT_PULLUP);
Serial.begin (9600); // Schnittstelle Tom
Serial1.begin (9600); // Schnittstelle Jerry
}
// ******************************************************************************
void loop() {
lcd.setCursor(1,1); // Start Text auf dem Display
lcd.print("Druecke den Knopf,");
lcd.setCursor(3,2);
lcd.print("um zu beginnen.");
if (digitalRead (Taster_Start) == LOW) { // Taster betätigt?
Punkte_Tom [0] = 0; Punkte_Tom [1] = 0; // Punkte nullen
Punkte_Jerry [0] = 0; Punkte_Jerry [1] = 0;
Ergebnisse();
for (int i=0; i<5; i++) { // 5 Durchläufe pro Spiel
lcd.setCursor(0,0);
lcd.print("Tom - Du bist dran"); // Tom beginnt
Serial.print ("Start"); // Seriell zu Nano "Start"
while (Serial.available() <= 0); // Auf Antwort warten
Punkte_Tom [0] = Serial.parseInt(); // Ergebnis als Zahl
Punkte_Tom [1] = Punkte_Tom [1] + Punkte_Tom [0]; // Punkte addieren
Ergebnisse(); // Punkte anzeigen
lcd.setCursor(0,0);
lcd.print("Jerry - Du bist dran"); // Jerry folgt
Serial1.print ("Start"); // Jerry, du bist dran
while (Serial1.available() <= 0); // Auf Antwort warten
Punkte_Jerry [0] = Serial1.parseInt(); // Ergebnis als Zahl
Punkte_Jerry [1] = Punkte_Jerry [1] + Punkte_Jerry [0]; // Punkte addieren
Ergebnisse(); // Punkte anzeigen
}
Spiel_Ende();
}
}
// ******************************************************************************
void Ergebnisse() { // Spielstand anzeigen
lcd.clear();
lcd.setCursor(1,1);
lcd.print("Tom");
lcd.setCursor(9,1);
lcd.print(Punkte_Tom [0]);
lcd.setCursor(14,1);
lcd.print(Punkte_Tom [1]);
lcd.setCursor(1,2);
lcd.print("Jerry");
lcd.setCursor(9,2);
lcd.print(Punkte_Jerry [0]);
lcd.setCursor(14,2);
lcd.print(Punkte_Jerry [1]);
}
// ******************************************************************************
void Spiel_Ende() { // Gewinner ermitteln
lcd.setCursor(1,3);
if (Punkte_Tom [1] == Punkte_Jerry [1]) {
lcd.print("REMIS");
}
if (Punkte_Tom [1] > Punkte_Jerry [1]) {
lcd.print("Tom hat gewonnen!");
}
if (Punkte_Tom [1] < Punkte_Jerry [1]) {
lcd.print("Jerry war besser!");
}
delay(5000);
lcd.clear();
}