[[uc-welt:gscheiduino:03-blinklicht|← Kapitel 3: Blinklicht]] | [[uc-welt:gscheiduino:00-uebersicht|↑ Übersicht]] | [[uc-welt:gscheiduino:05-eingaenge|Kapitel 5: Eingänge →]]
====== Kapitel 4: Übungsaufgabe Ampelsteuerung ======
===== Schaltung =====
Wir ändern unseren ersten Versuchsaufbau um eine gelbe und eine grüne LED:
{{:uc-welt:gscheiduino:gscheiduino_breadboard_kap4-ampel.png?direct&300|Aufbau Ampel}}
Die Pinbelegungen sind wie folgt:
Drei 120R-Widerstände:
* D3 und G3
* D6 und G6
* D9 und G9
Die rote LED: Plus auf J3, Minus auf die Masseschiene
Die gelbe LED: Plus auf J6, Minus auf die Masseschiene
Die grüne LED: Plus auf J9, Minus auf die Masseschiene
Die Kabel:
blau: GND und Masseschiene
rot: 13 und A3
gelb: 12 und A6
grün: 11 und A9
Wir erhalten dadurch folgenden Schaltplan:
{{:uc-welt:gscheiduino:004-schaltung.png?direct&200|}}
===== Definitionssache =====
Um den ganzen Code ein wenig übersichtlicher zu gestalten lernen wir vor der Übung noch eine wichitge Componente der Programmiersprache: //Defines//
Mit diesen Defines können wir den Code deutlich lesbarer machen. Das funktioniert so:
#define KONSTANTENNAME Wert
Jetzt wenden wir diese Definition auf unser erstes Beispiel mit der LED an:
#define LED_ROT 13
Soweit so gut. Jetzt passiert vorerst nichts, wir verwenden also unsere Definition:
digitalWrite(LED_ROT, HIGH);
Was nun passiert ist folgendes:
Der Compiler (Das war das Teil, das unseren Code in Maschinensprache übersetzt) arbeitet den Code von oben nach unten ab. Ganz oben schreiben wir unser //#define// hin. Wenn der Compiler zu dieser Stelle kommt weiß er "Ah, LED_ROT bedeutet in Wirklichkeit 13".
Nun arbeitet er den Code weiter ab und macht dabei etwas geniales: An jeder Stelle, an der //LED_ROT// steht, schreibt der Compiler //13// hin.
Um solche #defines schnell zu erkennen, werden sie in der Regel mit Großbuchstaben geschrieben. Wir erkennen jetzt also, dass zum Beispiel //HIGH// auch eine Konstante ist, die von Arduino bereits definiert wurde.
Warum definieren wir das aber? Ganz einfach: Wenn wir die rote LED mehrfach in unserem Code verwenden müssen, können wir jedesmal LED_ROT schreiben. Sollte sich irgendwann der Pin ändern (Und jeder der jetzt denkt: "Warum sollte sich ein Pin ändern?" sei gewarnt: Das passiert sehr häufig, meistens aus Bequemlichkeit) kann diese Anpassung am Anfang des Codes in der Definition gemacht werden. Einmal und nicht X-mal im gesamten Quellcode.
===== Programmablauf =====
Das Ziel dieser Aufgabe ist es, eine Ampelsteuerung zu simulieren. Das Timing dieser Steuerung soll wie folgt aussehen:
* Die Ampel startet rot
* Nach 2 Sekunden rot wird gelb eingeschaltet
* Nach 1 Sekunde erlischt rot und gelb, grün leuchtet
* Nach 3 Sekunden schaltet die Ampel von grün auf gelb
* Nach 1 Sekunde erlischt gelb und der Zyklus beginnt von vorne
===== Kleine Hilfestellung =====
Da die Defines noch neu sind gibt es hier das Grundgerüst des Codes, der erweitert werden soll:
#define LED_ROT 13
#define LED_GELB 12
#define LED_GRUEN 11
void setup()
{
pinMode(LED_ROT, OUTPUT);
}
void loop()
{
digitalWrite(LED_ROT, HIGH);
}
Die Aufgabe besteht nun darin, den Code an den entsprechenden Stellen so zu erweitern, dass die Ampelsteuerung wie oben beschrieben, funktioniert.
Als Vergleich zur selbst erstellten Lösung gibt es [[uc-welt:gscheiduino:04-ampelsteuerung-loesung|hier die Musterlösung]], die aber natürlich nicht benötigt wird!
Jetzt wo wir wissen, wie Ausgänge funktionieren, kommen wir logischerweise zur anderen Richtung:
[[uc-welt:gscheiduino:05-eingaenge|Kapitel 5: Eingänge]]