Verschiedene Wege
Bislang laufen deine Programme stur Zeile für Zeile durch – das soll sich nun ändern.
Eine Verzweigung sagt deinem Programm, dass es unter bestimmten Bedingungen Unterschiedliches tun soll. Das ist mit einer Entscheidung vergleichbar, die du triffst: Je nach Situation tust du verschiedene Dinge.
In C++/Arduino erstellst du eine Verzweigung mit der „if“-Anweisung. Sie prüft eine Bedingung und führt einen Abschnitt nur dann aus, wenn die Bedingung erfüllt ist. Ist sie nicht erfüllt, wird der Abschnitt übersprungen.
Grün, wenn der Joystick gedrückt ist: if
#define LEDR 5 // rote LED an Pin 5
#define LEDG 7 // grüne LED an Pin 7
#define KEY_CENTER 0 // Druck auf die Mitte des Joysticks
void setup(void) {
pinMode(KEY_CENTER, INPUT_PULLUP); // Eingang: Der Taster wird gelesen.
pinMode(LEDR, OUTPUT); // Ausgang: Er schaltet eine LED.
pinMode(LEDG, OUTPUT); // Ausgang: Er schaltet eine LED.
digitalWrite(LEDG, LOW); // Schaltet die grüne LED aus.
digitalWrite(LEDR, HIGH); // Schaltet die rote LED ein.
if (digitalRead(KEY_CENTER) == LOW) { // Falls die Mitte gedrückt ist ...
digitalWrite(LEDG, HIGH); // ... schalte die grüne LED ein ...
digitalWrite(LEDR, LOW); // ... und die rote LED aus.
}
}
void loop() {}
Anmerkungen
- Dieses Programm steht komplett in
setup()und wird daher nur ein einziges Mal durchlaufen – und das sehr schnell. Du merkst einen Unterschied also nur, wenn du den Joystick gedrückt hältst, während du den PicoBoy mit der Taste „RES“ neu startest. Keine Bange, du siehst bald, wie es besser geht. - Durch
INPUT_PULLUPliegt der Pin im Ruhezustand auf HIGH. Gedrückt ist der Taster also dann, wenndigitalRead()den WertLOWliefert – das wirkt zunächst verdreht, ist aber bei Tastern der Normalfall. - Beachte die zusätzlichen geschweiften Klammern „{ … }“. Sie begrenzen den Codeabschnitt, der bei erfüllter Bedingung ausgeführt wird.
- Die Vergleichsoperatoren in C++ sind „<“ (kleiner), „>“ (größer), „<=“ (kleiner oder gleich), „>=“ (größer oder gleich), „==“ (gleich) und „!=“ (ungleich).
- Ein doppeltes „==“ vergleicht, ein einfaches „=“ weist zu. Das zu verwechseln ist der häufigste Anfängerfehler in C++.

Soll bei erfüllter Bedingung ein Teil des Quelltextes ausgeführt werden und bei nicht erfüllter Bedingung ein anderer, kannst du eine „else“-Anweisung hinzufügen.
Immer genau eine LED: if … else
#define LEDR 5
#define LEDG 7
#define KEY_CENTER 0
void setup(void) {
pinMode(KEY_CENTER, INPUT_PULLUP);
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
if (digitalRead(KEY_CENTER) == LOW) {
digitalWrite(LEDG, HIGH);
digitalWrite(LEDR, LOW);
} else {
digitalWrite(LEDG, LOW);
digitalWrite(LEDR, HIGH);
}
}
void loop() {}
Anmerkungen
- Während der Ausführung zeigt sich kein sichtbarer Unterschied zum ersten Programm. Der Unterschied steckt im Aufbau und geht aus dem Programmablaufplan hervor: Hier wird immer genau einer der beiden Abschnitte ausgeführt.

Verzweigungen in loop()
Natürlich lassen sich Verzweigungen auch mit den Grafikbefehlen kombinieren. Im nächsten Beispiel stehen sie in der Funktion loop() und werden daher unentwegt wiederholt, nachdem setup() abgearbeitet ist. So kannst du den Joystick endlich wirklich benutzen: Du steuerst einen Punkt über das Display.
Einen Punkt mit dem Joystick bewegen
#include <U8g2lib.h>
#include <SPI.h>
#define KEY_RIGHT 2
#define KEY_DOWN 3
#define KEY_LEFT 4
#define KEY_UP 1
#define KEY_CENTER 0
U8G2_SH1106_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, 10, 8, 9);
// Diese beiden Variablen stehen außerhalb der Funktionen,
// damit setup() und loop() sie gemeinsam nutzen können.
int xPos;
int yPos;
void setup(void) {
u8g2.begin();
u8g2.clearBuffer();
u8g2.sendBuffer();
pinMode(KEY_RIGHT, INPUT_PULLUP);
pinMode(KEY_DOWN, INPUT_PULLUP);
pinMode(KEY_LEFT, INPUT_PULLUP);
pinMode(KEY_UP, INPUT_PULLUP);
pinMode(KEY_CENTER, INPUT_PULLUP);
xPos = 64; // Startposition: Mitte des Displays
yPos = 32;
}
void loop() {
if (digitalRead(KEY_UP) == LOW) { // nach oben: y um 1 kleiner
yPos = yPos - 1;
}
if (digitalRead(KEY_DOWN) == LOW) { // nach unten: y um 1 größer
yPos = yPos + 1;
}
if (digitalRead(KEY_LEFT) == LOW) {
xPos = xPos - 1;
}
if (digitalRead(KEY_RIGHT) == LOW) {
xPos = xPos + 1;
}
if (digitalRead(KEY_CENTER) == LOW) { // Mitte: löschen, zurück zum Start
u8g2.clearBuffer();
xPos = 64;
yPos = 32;
}
delay(50);
u8g2.drawPixel(xPos, yPos); // Punkt an der aktuellen Position
u8g2.sendBuffer();
}
Anmerkungen
- Der Displayspeicher wird nur beim Druck auf die Mitte geleert. Deshalb bleiben die gezeichneten Punkte stehen und du malst eine Linie – wie bei einer Zaubertafel.
- Die fünf Abfragen sind voneinander unabhängig. Drückst du den Joystick schräg, treffen zwei davon gleichzeitig zu und der Punkt wandert diagonal.
delay(),drawPixel()undsendBuffer()sollen auf jeden Fall ausgeführt werden und stehen daher außerhalb der geschweiften Klammern. Sie laufen, nachdem alle if-Blöcke durchlaufen sind.- Das
delay(50)bremst den Punkt. Ohne diese Pause würdeloop()so oft pro Sekunde durchlaufen, dass der Punkt sofort am Rand wäre.
Logische Operatoren
Führst du das Programm mit dem Punkt aus, zeigt sich ein Problem: Du kannst aus dem Display „herauszeichnen“. Der Punkt wandert über den Rand hinaus und ist nicht mehr zu sehen, weil seine Koordinaten außerhalb des Displays liegen.
Mit sogenannten logischen Operatoren lässt sich das verhindern. Eine Bedingung für einen Schritt nach rechts könnte lauten: Gehe nach rechts, wenn der Joystick nach rechts gedrückt wird und die aktuelle Position noch mindestens einen Schritt von der rechten Kante entfernt ist. Das „und“ schreibt man in C++ als „&&“.
Am Rand stoppen: &&
#include <U8g2lib.h>
#include <SPI.h>
#define KEY_RIGHT 2
#define KEY_DOWN 3
#define KEY_LEFT 4
#define KEY_UP 1
#define KEY_CENTER 0
U8G2_SH1106_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, 10, 8, 9);
int xPos;
int yPos;
void setup(void) {
u8g2.begin();
u8g2.clearBuffer();
u8g2.sendBuffer();
pinMode(KEY_RIGHT, INPUT_PULLUP);
pinMode(KEY_DOWN, INPUT_PULLUP);
pinMode(KEY_LEFT, INPUT_PULLUP);
pinMode(KEY_UP, INPUT_PULLUP);
pinMode(KEY_CENTER, INPUT_PULLUP);
xPos = 64;
yPos = 32;
}
void loop() {
if (digitalRead(KEY_UP) == LOW && yPos > 0) { // noch Platz nach oben?
yPos = yPos - 1;
}
if (digitalRead(KEY_DOWN) == LOW && yPos < 63) { // 63: unterste Zeile
yPos = yPos + 1;
}
if (digitalRead(KEY_LEFT) == LOW && xPos > 0) {
xPos = xPos - 1;
}
if (digitalRead(KEY_RIGHT) == LOW && xPos < 127) { // 127: rechte Spalte
xPos = xPos + 1;
}
if (digitalRead(KEY_CENTER) == LOW) {
u8g2.clearBuffer();
xPos = 64;
yPos = 32;
}
delay(50);
u8g2.drawPixel(xPos, yPos);
u8g2.sendBuffer();
}
Der Schritt wird nur ausgeführt, wenn beide Bedingungen gelten. Steht der Punkt bei y = 0, ist yPos > 0 nicht mehr erfüllt, und nach oben geht es nicht weiter, egal wie du am Joystick drückst.
Neben dem Und gibt es weitere Operatoren, um logische Aussagen zu verknüpfen. Hier ein Überblick – in den Tabellen steht, was bei welcher Kombination herauskommt:
UND (&&)
Nur wahr, wenn beide Aussagen wahr sind.
| a | b | a && b |
|---|---|---|
| false | false | false |
| false | true | false |
| true | false | false |
| true | true | true |
ODER (||)
Wahr, wenn mindestens eine der beiden Aussagen wahr ist.
| a | b | a || b |
|---|---|---|
| false | false | false |
| false | true | true |
| true | false | true |
| true | true | true |
NICHT (!)
Dreht eine Aussage um: aus wahr wird falsch und umgekehrt.
| a | not a |
|---|---|
| false | true |
| frue | false |
ODER und NICHT im Programm
Das nächste Programm benutzt beide. Die gelbe LED leuchtet, solange du den Joystick nach links oder rechts drückst. Die grüne LED leuchtet, solange er nicht nach links gedrückt ist.
#define LEDY 6
#define LEDG 7
#define KEY_RIGHT 2
#define KEY_LEFT 4
void setup(void) {
pinMode(KEY_RIGHT, INPUT_PULLUP);
pinMode(KEY_LEFT, INPUT_PULLUP);
pinMode(LEDY, OUTPUT);
pinMode(LEDG, OUTPUT);
}
void loop() {
// Ein Vergleich ergibt true oder false, das passt in eine boolean-Variable.
boolean links = digitalRead(KEY_LEFT) == LOW;
boolean rechts = digitalRead(KEY_RIGHT) == LOW;
if (links || rechts) { // ODER: mindestens eine der beiden Richtungen
digitalWrite(LEDY, HIGH);
} else {
digitalWrite(LEDY, LOW);
}
if (!links) { // NICHT: solange links NICHT gedrückt ist
digitalWrite(LEDG, HIGH);
} else {
digitalWrite(LEDG, LOW);
}
delay(20);
}
Anmerkungen
- Ein Vergleich liefert
trueoderfalse. Dieses Ergebnis kannst du in einerboolean-Variablen aufheben, wie hier inlinksundrechts. Die Bedingungen darunter werden dadurch kürzer und lesen sich fast wie ein Satz. - Links und rechts von
&&und||muss je eine vollständige Bedingung stehen.xPos > 0 && < 127versteht der Compiler nicht, und0 < xPos < 127tut nicht, was es in der Mathematik bedeutet. Richtig istxPos > 0 && xPos < 127. - Hinter die Klammer von
ifgehört kein Semikolon.if (xPos > 0);beendet die Verzweigung sofort, und der Abschnitt in den geschweiften Klammern läuft dann immer.
Mehrere Fälle: else if
Schließen sich mehrere Fälle gegenseitig aus, hängst du sie mit else if aneinander. Das Programm prüft von oben nach unten und führt nur den ersten Abschnitt aus, dessen Bedingung erfüllt ist. Alle weiteren werden übersprungen.
if (punkte >= 100) { // ab 100 Punkten: grün
digitalWrite(LEDG, HIGH);
} else if (punkte >= 50) { // sonst ab 50 Punkten: gelb
digitalWrite(LEDY, HIGH);
} else { // alles andere: rot
digitalWrite(LEDR, HIGH);
}
Bei 120 Punkten leuchtet also nur die grüne LED, obwohl auch die zweite Bedingung erfüllt wäre.
Übung
Schreibe ein Programm, das den Joystick in loop() abfragt: Nach oben leuchtet die rote LED, nach links oder rechts die gelbe und nach unten die grüne. Lässt du los, gehen alle LEDs aus. Tipp: Schalte am Anfang von loop() alle drei LEDs aus und danach die passende wieder ein.