In diesem Video geht es um Arduino-Programmierung. Das Beispiel mit der blinkenden LED am Arduino ist schnell verstanden. Bei komplexeren Projekten bekommt man aber schnell mit dem delay() - Befehl Probleme. 'Schau dir Blinken ohne Delay oder Interrupts an', das sind die guten Ratschläge, die man dann erhält. Hat schon jemand versucht, das Beispiel mit 5 oder 10 unabhängig voneinander blinkenden LED's umzusetzen? Das wird recht kompliziert und man verliert sich leicht in den vielen globalen Variablen. Hier ein Vorschlag, wie man das etwas übersichtlicher gestalten kann.


Einige Tipps zur Vereinfachung des Programmcodes

Schaut euch das Video an! Hier gebe ich nur eine Zusammenfassung einiger Tipps. Die Details erfährt ihr im Video. Ich weiss, dass man über einzelne Tipps stundenlang diskutieren könnte. Gewisse Stilfragen muss aber jeder für sich entscheiden. Ich gebe diese Tipps aber hier nicht als Informatiker, sondern als Hobbyelektroniker, der nur auf möglichst einfache Art und Weise das gewünschte Ergebnis erzielen möchte.

Deklariert Pinnummern, Verzögerungszeiten usw. in Konstanten. Ich bevorzuge die Deklaration mit const anstelle von define, da const Teil der Sprache C ist, während define ein Konstrukt des preprocessors ist.

Die Arduino-Boards habe eine eingebaute LED. Wenn ihr nicht wisst, was für eine Pinnummer diese hat, könnt ihr die Konstante LED_BUILTIN verwenden.

Haltet die loop() - Funktion schlank und verwendet eigene Funktionen, die ihr aus loop() aufruft.

Anstelle von
if (state == HIGH) {
state = LOW;
} else {
state = HIGH;
}

könnt ihr auch schreiben
state = !state;

Output-Pins können auch gelesen werden. Durch digitalRead() werden sie aber nicht zu Input-Pins. Sie geben lediglich den zuvor mit digitalWrite() gesetzten Wert zurück.

Input-Pins brauchen immer einen PULL-UP oder PULL-DOWN Widerstand um in unbeschaltetem Zustand einen eindeutigen Wert zu haben. Im Adruino ist ein PULL_UP schon eingebaut und kann mit pinMode(x,INPUT_PULLUP) aktiviert werden.

Analoge Pins können auch digital verwendet werden. Man setzt einfach wie gewohnt den Pin-Mode (z. Bsp. pinMode(A1,INPUT_PULLUP)).


Die Verwendung von Interrupts

Während ein delay() ausgeführt wird, reagiert das Programm auf keine Eingaben von Input-Pins. Mit einer Ausnahme: Interrupts können das laufende Programm auch innerhalb von delays unterbrechen. Sie führen dann ihren Code aus und geben danach die Kontrolle an den unterbrochenen Programmteil zurück.

Stacks Image 37739

Led 2 wird durch den Taster gesteuert. Dafür ist die Funktion led2() zuständig. led2() wird aber in loop() gar nicht mehr aufgerufen. Stattdessen wird mit attachInterrupt in setup() definiert, dass bei jedem Wechsel des Zustandes an Pin 2 (Taster wird gedrückt oder losgelassen) die Funktion led2() aufgerufen werden soll.

Der Arduino UNO erlaubt Interrupts auf Pin 2 und 3.

const int ledPin = LED_BUILTIN;  // Eingebaute LED
const int delayTime = 1000;
const int led2Pin = 7;
const int tasterPin = 2; // interrupts nur auf Pin 2 oder 3

void setup() {
  pinMode(ledPin, OUTPUT);  
  pinMode(led2Pin, OUTPUT);      
  pinMode(tasterPin,INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(tasterPin), led2, CHANGE);
  // LOW, CHANGE, RISING, FALLING
}

void blinkLED(int pin) {
  digitalWrite(pin,!digitalRead(pin));  
}

void led2() {
  digitalWrite(led2Pin,!digitalRead(tasterPin));
}

void loop() {
  blinkLED(ledPin);     // Zustand wechseln
  delay(delayTime);  // warten
}

Viele Leuchtdioden

Jetzt arbeiten wir mit millis()! Da wir aber viele Leuchtdioden ansteuern möchten, müssen wir uns etwas einfallen lassen, damit wir die Übersicht nicht verlieren. Da wir uns hier nicht mit Klassen herumschlagen möchten, erstellen wir 'Objekte' mit der Copy / Paste - Methode.

Jede LED erhält eine eigene Funktion. In dieser Funktion wird möglichst alles definiert, was diese LED betrifft. Wenn weitere LED's benötigt werden, wird die Funktion einfach kopiert und Pinnummer und Blinkfrequenz angepasst.



Stacks Image 37758

Die einzige verbleibende globale Variable ist currentMillis. Das ist der Zeittakt, der von jeder Funktion verwendet wird. Es ist auch möglich auf currentMillis zu verzichten und den aktuellen Wert in jeder Funktion direkt über millis() zu ermitteln.

setup() bleibt leer, da alle Initialisierungen in den Funktionen vorgenommen werden.

led2() definiert das Verhalten der LED an Pin 2.
In Konstanten werden die Pinnummer (pin) und die Verzögerungszeit (delayTime) festgelegt.
previousMillis wird als static Variable definiert, damit sie ihren Inhalt zwischen den Aufrufen nicht verliert.
Bei ersten Aufruf der Funktion wird previousMillis auf 0 gesetzt. Das können wir verwenden, um den pinMode zu setzen.
Danach wird geblinkt, falls bereits genügen Zeit set dem letzten Mal vergangen ist.

Für die LED an Pin 3 wird einfach die Funktion led2() kopiert und in led3() umbenannt. Pin und delayTime werden entsprechen gesetzt. Jetzt muss led3() nur noch aus loop() aufgerufen werden.

So ist es einfach eine beliebige Anzahl von LED's blinken zu lassen.

unsigned long currentMillis;

void setup() {
}

void blinkLED(int pin) {
  digitalWrite(pin,!digitalRead(pin));  
}

void led2() {
  const int pin = 2;
  const int delayTime = 1000;
  static unsigned long previousMillis = 0;
  if (previousMillis == 0) pinMode(pin, OUTPUT);
  if (currentMillis - previousMillis >= delayTime) {
    previousMillis = currentMillis;
    blinkLED(pin);
  }
}

void led3() {
  const int pin = 3;
  const int delayTime = 500;
  static unsigned long previousMillis = 0;
  if (previousMillis == 0) pinMode(pin, OUTPUT);
  if (currentMillis - previousMillis >= delayTime) {
    previousMillis = currentMillis;
    blinkLED(pin);
  }
}

void led4() {
  const int pin = 4;
  const int delayTime = 250;
  static unsigned long previousMillis = 0;
  if (previousMillis == 0) pinMode(pin, OUTPUT);
  if (currentMillis - previousMillis >= delayTime) {
    previousMillis = currentMillis;
    blinkLED(pin);
  }
}

void led5() {
  const int pin = 5;
  const int delayTime = 125;
  static unsigned long previousMillis = 0;
  if (previousMillis == 0) pinMode(pin, OUTPUT);
  if (currentMillis - previousMillis >= delayTime) {
    previousMillis = currentMillis;
    blinkLED(pin);
  }
}

void led8() {
  const int pin = 8;
  static boolean initialized = false;
  if (!initialized) {
    pinMode(pin,OUTPUT);
    initialized = true;
  }
  digitalWrite(pin,digitalRead(1) && digitalRead(2));
}

void loop() {
  currentMillis = millis();
  led2();
  led3();
  led4();
  led5();
  led8();
}