MINT lernen

Textaufgaben: Mikrocontroller programmieren

Ein blinkendes Fahrradrücklicht mit Taster und eine Bewässerung für den Schulgarten, die nicht zu viel gießen darf.

Dein Fortschritt:
0 / 0 Aufgaben
1

Ein Rücklicht fürs Fahrrad

AFB I–II

Tim baut für sein Fahrrad ein Rücklicht mit einem Arduino Uno. Normalerweise soll die rote LED blitzen; solange der Taster am Lenker gedrückt ist, soll sie dauerhaft leuchten. Die Schaltung und der Sketch sehen so aus:

Arduino · ruecklicht.ino
const int LED = 9;
const int TASTER = 2;

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(TASTER, INPUT_PULLUP);
}

void loop() {
  if (digitalRead(TASTER) == LOW) {   // Dauerlicht
    digitalWrite(LED, HIGH);
  } else {                            // Blinklicht
    digitalWrite(LED, HIGH);
    delay(100);
    digitalWrite(LED, LOW);
    delay(400);
  }
}
Schaltskizze des Rücklichts
ArduinoUnoPin 9Pin 2GND220 ΩLEDTaster
Der Taster verbindet Pin 2 beim Drücken mit GND; einen eigenen Widerstand braucht er wegen INPUT_PULLUP nicht.
  1. Nennen Sie die Pins, die der Sketch als Ausgang bzw. als Eingang benutzt, wie oft setup() und loop() jeweils ausgeführt werden und den Speicher, in dem das übersetzte Programm auf dem Board liegt.
  2. Berechnen Sie für das Blinklicht die Periodendauer \(T\), die Frequenz \(f\) und die Anzahl der Blitze in einer Minute.
  3. Erläutern Sie, warum der Sketch einen gedrückten Taster an LOW erkennt und warum die LED nach dem Drücken manchmal erst mit Verzögerung dauerhaft leuchtet.

Hinweise

Hinweis zu Aufgabe a)
Schauen Sie auf die pinMode-Aufrufe. Welcher Speicher des Mikrocontrollers behält das Programm auch ohne Strom?
Hinweis zu Aufgabe b)
Eine Periode besteht aus der Leuchtzeit und der Pause. Rechnen Sie Millisekunden in Sekunden um, bevor Sie \(f = \frac{1}{T}\) bilden. Die Laufzeit der übrigen Befehle ist gegenüber den Wartezeiten vernachlässigbar.
Hinweis zu Aufgabe c)
Was misst Pin 2, wenn der Taster offen ist und der interne Pull-up-Widerstand ihn mit 5 V verbindet — und was, wenn der Taster ihn mit GND verbindet? Wann wird digitalRead in loop() überhaupt aufgerufen?

Erwartungshorizont

Erwartungshorizont zu Aufgabe a)

Ausgang: Pin 9 (LED). Eingang: Pin 2 (Taster, mit internem Pull-up-Widerstand).

setup() läuft einmal nach dem Einschalten bzw. Reset, loop() danach immer wieder, solange Strom anliegt.

Das Programm wird auf dem PC übersetzt und beim Hochladen in den Flash-Speicher (32 KB beim ATmega328P) geschrieben; dort bleibt es auch ohne Strom erhalten.

Erwartungshorizont zu Aufgabe b)

\(T = t_{an} + t_{aus} = 100\,\text{ms} + 400\,\text{ms} = 500\,\text{ms} = 0{,}5\,\text{s}\)

\(f = \frac{1}{T} = \frac{1}{0{,}5\,\text{s}} = 2\,\text{Hz}\)

\(N = f \cdot t = 2\,\tfrac{1}{\text{s}} \cdot 60\,\text{s} = 120\)

Die LED blitzt zweimal pro Sekunde, also 120-mal in einer Minute.

Erwartungshorizont zu Aufgabe c)

Mit INPUT_PULLUP ist Pin 2 intern über einen Widerstand mit 5 V verbunden: Offener Taster ergibt HIGH. Drückt Tim, verbindet der Taster den Pin direkt mit GND, der Pin liest LOW. Deshalb bedeutet hier „gedrückt = LOW“.

Der Taster wird nur einmal am Anfang jedes loop()-Durchlaufs abgefragt. Läuft gerade der Blinkzweig, wartet der Mikrocontroller in delay(100) und delay(400) und reagiert währenddessen nicht. Drückt Tim z. B. kurz nach dem Aufblitzen, leuchtet die LED erst nach dem Ende der Pause dauerhaft — im ungünstigsten Fall rund 0,5 s später (eine ganze Periode). Beispiel aus einem Test: Drücken ab 1,2 s, Dauerlicht erst ab 1,5 s. Ein sehr kurzer Druck mitten in der Pause wird sogar ganz übersehen.

2

Gießen im Schulgarten

AFB II–III

Die Schulgarten-AG möchte ihre Tomatenpflanzen im Gewächshaus automatisch gießen. Aylin schließt an einen Arduino einen Feuchtesensor an (Pin 4 meldet HIGH, wenn die Erde trocken ist) sowie über ein Relais eine kleine Pumpe an Pin 7. Die Pumpe fördert 25 ml Wasser pro Sekunde.

Arduino · giessen.ino
const int SENSOR = 4;   // Feuchtesensor: HIGH = Erde trocken
const int PUMPE = 7;    // Relais der Pumpe

void setup() {
  pinMode(SENSOR, INPUT);
  pinMode(PUMPE, OUTPUT);
}

void loop() {
  if (digitalRead(SENSOR) == HIGH) {
    digitalWrite(PUMPE, HIGH);
    delay(3000);
    digitalWrite(PUMPE, LOW);
    delay(60000);          // Wasser einsickern lassen
  }
}

Lehrer Herr Brandt wünscht sich zusätzlich einen Taster an Pin 2 für „Gießen von Hand“ (2 Sekunden Pumpe) und eine LED an Pin 12, die leuchtet, solange die Erde als trocken gemeldet wird. Außerdem fragt er, was passiert, wenn der Sensor einmal defekt ist und dauerhaft „trocken“ meldet.

  1. Stellen Sie den Ablauf von loop() in Aylins Sketch als Struktogramm dar.
  2. Erweitern Sie den Sketch um den Taster und die LED nach Herrn Brandts Wunsch.
  3. Diskutieren Sie, ob delay(60000) für diese Anlage geeignet ist. Gehen Sie dabei auf den Handbetrieb und auf einen defekten Sensor ein.

Hinweise

Hinweis zu Aufgabe a)
Ein Struktogramm hat für die Wiederholung einen Block mit Balken links und für das if einen Block mit Dreieck und den Spalten „ja“ und „nein“. Ein else fehlt im Sketch — was steht dann in der „nein“-Spalte?
Hinweis zu Aufgabe b)
Beide Bauteile brauchen einen pinMode in setup(); beim Taster bietet sich INPUT_PULLUP an (gedrückt = LOW). Die LED braucht auch einen Zweig, in dem sie wieder ausgeht.
Hinweis zu Aufgabe c)
Was kann der Mikrocontroller während eines delay tun? Berechnen Sie für den defekten Sensor, wie viele Gießvorgänge in eine Stunde passen und wie viel Wasser das ist.

Erwartungshorizont

Erwartungshorizont zu Aufgabe a)
Struktogramm zu loop()
wiederhole endlos (loop)Erde trocken?janeinPumpe an (Pin 7 HIGH)warte 3000 msPumpe aus (Pin 7 LOW)warte 60000 ms–
Der „nein“-Zweig ist leer; loop() beginnt dann sofort von vorn.

Bewertet werden: Endloswiederholung als äußerer Block, Verzweigung mit Bedingung, vier Anweisungen in der richtigen Reihenfolge im „ja“-Zweig, leerer „nein“-Zweig.

Erwartungshorizont zu Aufgabe b)
Arduino · giessen.ino (erweitert)
const int SENSOR = 4;   // HIGH = Erde trocken
const int PUMPE = 7;
const int TASTER = 2;   // gedrueckt = LOW
const int LED = 12;     // leuchtet bei trockener Erde

void setup() {
  pinMode(SENSOR, INPUT);
  pinMode(PUMPE, OUTPUT);
  pinMode(TASTER, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
}

void loop() {
  if (digitalRead(SENSOR) == HIGH) {
    digitalWrite(LED, HIGH);
    digitalWrite(PUMPE, HIGH);
    delay(3000);
    digitalWrite(PUMPE, LOW);
    delay(60000);
  } else {
    digitalWrite(LED, LOW);
  }
  if (digitalRead(TASTER) == LOW) {   // Handbetrieb
    digitalWrite(PUMPE, HIGH);
    delay(2000);
    digitalWrite(PUMPE, LOW);
  }
}

Bewertet werden: pinMode für beide neuen Pins, LED an im trockenen und aus im feuchten Fall (else), Tasterabfrage mit LOW, Pumpe 2 s an und wieder aus. Ebenfalls richtig: die Tasterabfrage vor die Sensorabfrage setzen.

Erwartungshorizont zu Aufgabe c)

Pro: Die Pause ist fachlich sinnvoll — das Wasser braucht Zeit zum Einsickern, sonst würde gegossen, bis der Sensor reagiert, und der Topf liefe über. Der Code bleibt kurz und für Anfänger gut lesbar.

Contra: Während delay tut der Mikrocontroller nichts anderes. Ein Tastendruck in den 63 Sekunden eines Gießvorgangs wird nicht bemerkt; der Handbetrieb wirkt „kaputt“. Bei einem defekten Sensor wiederholt sich der Ablauf ungebremst: \(3600\,\text{s} : 63\,\text{s} \approx 57\) Gießvorgänge pro Stunde, also \(57 \cdot 3\,\text{s} \cdot 25\,\tfrac{\text{ml}}{\text{s}} = 4275\,\text{ml} \approx 4{,}3\,\text{l}\) Wasser pro Stunde.

Ergebnis: Die Pause selbst ist nötig, aber ein einziger langer delay macht die Anlage träge und bietet keinen Schutz. Sinnvoll wären eine Obergrenze für Gießvorgänge (Zähler) und eine Wartezeit ohne Blockieren, z. B. mit millis(), die den Taster weiter abfragt. Eine vollständige Antwort wägt mindestens ein Pro- und zwei Contra-Argumente (mit Rechnung) ab und kommt zu einem begründeten Ergebnis.