06 | 02 Eine LED mit einer for-Schleife regeln

Eine Schleife ist in der Programmierung ein äußerst wichtiges Konstrukt. Wir kennen bereits die sich wiederholende void loop()-Funktion. Es gibt noch weitere Schleifen, die wir für uns nutzen können: die while-Schleife und die for-Schleife. Mit einer for-Schleife können wir bestimmen wie oft ein Block-Code wiederholt wird.

 

Spezifikationen
- Signalart: digital
- Spannung: 3,3V – 5V
- Pinabstand: 2,54mm

Die for-Schleife

Schleifen nehmen uns eine Menge Arbeit ab. Stell dir vor irgendwo in unserem Roboter Master-Code müssten wir an einer Stelle unsere LED 10x blinken lassen. Der untere Ansatz wäre eine ziehmlich unsinnige Arbeit. Das Wiederholen von digitalWrite() und delay() bis zu 10x verbraucht nur wertvollen Speicher und wird sehr unübersichtlich.

void loop() 
{
  ...
  digitalWrite(2, HIGH);  // Turn LED 1 on
  delay(500);             // wait half a second
  digitalWrite(2, LOW);   // Turn LED 1 off
  delay(500);             // wait half a second
  digitalWrite(2, HIGH);  // Turn LED 1 on
  delay(500);             // wait half a second
  digitalWrite(2, LOW);   // Turn LED 1 off
  delay(500);             // wait half a second
  digitalWrite(2, HIGH);  // Turn LED 1 on
  delay(500);             // wait half a second
  digitalWrite(2, LOW);   // Turn LED 1 off
  delay(500);             // wait half a second
  digitalWrite(2, HIGH);  // Turn LED 1 on
  delay(500);             // wait half a second
  digitalWrite(2, LOW);   // Turn LED 1 off
  delay(500);             // wait half a second
  digitalWrite(2, HIGH);  // Turn LED 1 on
  delay(500);             // wait half a second
  digitalWrite(2, LOW);   // Turn LED 1 off
  delay(500);             // wait half a second
  digitalWrite(2, HIGH);  // Turn LED 1 on
  delay(500);             // wait half a second
  digitalWrite(2, LOW);   // Turn LED 1 off
  delay(500);             // wait half a second
  digitalWrite(2, HIGH);  // Turn LED 1 on
  delay(500);             // wait half a second
  digitalWrite(2, LOW);   // Turn LED 1 off
  delay(500);             // wait half a second
  digitalWrite(2, HIGH);  // Turn LED 1 on
  delay(500);             // wait half a second
  digitalWrite(2, LOW);   // Turn LED 1 off
  delay(500);             // wait half a second
  digitalWrite(2, HIGH);  // Turn LED 1 on
  delay(500);             // wait half a second
  digitalWrite(2, LOW);   // Turn LED 1 off
  delay(500);             // wait half a second
  digitalWrite(2, HIGH);  // Turn LED 1 on
  delay(500);             // wait half a second
  digitalWrite(2, LOW);   // Turn LED 1 off
  delay(500);             // wait half a second
  ...
}

Viel eleganter ist z. B. eine for-Schleife, die weitaus weniger Zeilen und Speicher verbraucht. Das untere Beispiel führt die gleiche Aktion aus – mit deutlich weniger Zeichen. Das ist ziehmlich beeindruckend.

void loop() 
{
...
 for(int i = 0; i < 11; x++)
 {
   digitalWrite(2, HIGH);  // Turn LED 1 on
   delay(500);             // wait half a second
   digitalWrite(2, LOW);  // Turn LED 1 on
   delay(500);             // wait half a second
 }
 ...
}

Die Funktionsweise der for-Schleife

Wir nutzen in diesem Beispiel void setup(), der nur einmal durchlaufen wird. Der Sketch läst die Schleife 10x durchlaufen und sendet bei jedem Durchgang die aktuelle Schleifennummer an den seriellen Monitor. Der Code zwischen den geschweiften Klammern wird solange wiederholt, bis die Kondition im Schleifen-Kopf erfüllt ist.

void setup()
{ 
  Serial.begin(9600);

  for(int i = 1; i <= 10; i++)
  { 
    Serial.println(i);
  } 
  delay(500);
  Serial.println("All done!");
} 


void loop() 
{
  //leer
}

Der Schleifenkopf beinhaltet drei Elemente: Initialisierung, Bedingung und Iteration. Diese drei bestimmen, wie gezählt werden soll. Alle drei Elemente werde durch ein Strich-Punkt-Symbol von einander getrennt. Die Initialisierung markiert den Startpunkt von wo an gezählt werden soll. Da dieser eine Variable ist, müssen wir sie mit einer Interger-Variablen deklarieren und ihm einen Startwert zuweisen. Du könntest hier beliebige Buchstaben vergeben. Meistens wird der Buchstabe i benutzt, der für index steht. Übrigens ist die Variable i nur innerhalb der Schleife gültig. Falls du im Sketch eine Variable gleichen Namen hast, haben beide nichts mit einander zu tun.

In unserem Beispiel startet i bei 1.

int i = 1;

Die Bedingung bestimmt, wann die for-Schleifen beendet werden soll. Im Beispiel soll sie stoppen, wenn der Wert kleiner gleich 10 ist.

i <= 10)


Die Iteration gibt an, in welchen Schritten bei jedem Schleifendurchgang erhöht werden soll. Die untere Zeile stellt eine Kurzschreibweise dar. In Wirklichkeit verbirgt sich folgende Formel dahinter: i = i + 1. Das bedeutet, dass bei jedem Durchgang die Variable i um eins erhöht wird.

i++

Wollten wir beispielsweise nur 5 Durchgänge anstatt 10 realisieren, können wir i = i +2 schreiben. Damit Springen wir gleich zwei Schritte statt einem:

for(int i = 1; i <= 10; i = i+2)

Zoomen wir unseren Fokus noch mal herraus und sehen uns den Gesamtablauf an. Der Sketch landet bei der for-Schleife, sieht sich an wo er starten soll (int = 1), springt zur Kondition (i <= 10) und schaut sich an, ob bereits 10 Schleifen durchlaufen sind (wenn ja wird gestoppt), springt dann weiter zur Steigerung (i++) und addiert 1 zu i (dieser Wert bei jeder Schleife größer). Nun wird die Variable i mit dem Wert 1 in den Schleifenkörper übertragen und an den seriellen Monitor gesendet.

for(int i = 1; i <= 10; i++)
  { 
    Serial.println(i);
  }

Schleife 1: (Start bei 1 ; Ende bei 10 ; beginnt bei 1 ) >>> i = 1 Ergebnis: 1
Schleife 2: (Start bei 1 ; Ende bei 10 ; Steigerung um 1) >>> i = 1 +1 Ergebnis: 2
Schleife 3: (Start bei 1 ; Ende bei 10 ; Steigerung um 1) >>> i = 2 + 1 Ergebnis: 3
Schleife 4: (Start bei 1 ; Ende bei 10 ; Steigerung um 1) >>> i = 3 +1 Ergebnis: 4
Schleife 5: (Start bei 1 ; Ende bei 10 ; Steigerung um 1) >>> i = 4 + 1 Ergebnis: 5
Schleife 6: (Start bei 1 ; Ende bei 10 ; Steigerung um 1) >>> i = 5 + 1 Ergebnis: 6
Schleife 7: (Start bei 1 ; Ende bei 10 ; Steigerung um 1) >>> i = 6 + 1 Ergebnis: 7
Schleife 8: (Start bei 1 ; Ende bei 10 ; Steigerung um 1) >>> i = 7 + 1 Ergebnis: 8
Schleife 9: (Start bei 1 ; Ende bei 10 ; Steigerung um 1) >>> i = 8 + 1 Ergebnis: 9
Schleife 10: (Start bei 1 ; Ende bei 10 ; Steigerung um 1) >>> i = 9 + 1 Ergebnis: 10



Mit Serial.println(), außerhalb von der for-Schleife, lassen wir uns noch einmal bestätigen, das sie Schleife so eben verlassen wurde.

Serial.println("All done!");

Der Sketch - Dimmen einer LED mit for-Schleifen

void setup()
{
  pinMode(3, OUTPUT);
}

void loop() 
{
  for (int i=0; i<256; i++)
  {
    analogWrite(3, i);
    delay(5);
  }
  for (int i=255 ; i>=0 ; i-- )
  {
    analogWrite(3, i);
    delay(5); 
  }
  delay(200);
}

Im Detail

Das Dimmen der LED erfolgt in zwei for-Schleifen. Der erste läst sie hoch dimmen und der zweite runter dimmen.
Da wir zum Dimmen ein PWM-Pin benutzen, zählen wir von 0 auf 256. Sobald die LED das Maximum von 256 erreicht, wird die Schleife verlassen. Der delay()-Befehl sorgt für eine winzige Verzögerung, damit wir das Dimmen überhaupt wahrnehmen können. Natürlich ist es auch möglich durch den delay()-Wert einfluss auf das Dimmverhalten zu nehmen.

for (int i=0; i<256; i++)
  {
    analogWrite(3, i);
    delay(5);
  }

Das besondere der zweiten Schleife ist die Verkleinerung der Variable i. Wir können mit der for-Schleife auch runter zählen, in dem wir die Operatoren umkehren. Anstatt i<=0 benutzen wir i>=0 und anstatt i++ wird i-- eingesetzt.

for (int i=255 ; i>=0 ; i-- )
  {
    analogWrite(3, i);
    delay(5); 
  }

Bei der Steigerung können wir alle Kurzschreibweisen aus dem letzten Kapitel einfügen: +=, –=, *= und /=.

i = i / 500  //ist das gleiche wie:  i /= 500

Inkrementierung – Zusatz zu i++

Das ++ in Kombination mit einer Variabel (z.B. i++) erhöht deren Wert um 1. Das gleiche gilt für das –– Zeichen, die den Wert um -1 verringert. Dabei macht es einen Unterschied ob es vor der Variable ++i oder nach der Variable i++ platziert ist.

Das Setzen des ++ hinter dem Variablennamen i++ ist eine Post-Inkrement-Operation. Das bedeutet, dass die Variable in der Anweisung verwendet und erst danach inkrementiert wird. Sehen wir uns das obere Beispiel der ersten Schleife noch einmal an:

Schleife 1: (Start bei 1 ; Ende bei 10 ; beginnt bei 1 ) >>> i = 1 Ergebnis: 1

Eigentlich müsste diese Zeile schon bei der ersten Schleife das Ergebnis 2 hervorbringen müssen, da wir ja mit 1 Starten und nicht bei 0. Doch wie oben schon erwähnt wird zunächst der Wert 1 (Start bei 1) genommen und erst in der nächsten Schleife incrementiert.

Schleife 1: (Start bei 1 ; Ende bei 10 ; beginnt bei 1 ) >>> i = 1+1 Ergebnis: 2 //nicht richtig


Folgende zwei Sketche treten den Beweis an. Die Variable count hat einen initialen Wert von 1. Im post-increment Sketch werden folgende Ergebnisse im seriellen Monitor angezeigt: 1, 2, 3. Hier wird der initiale Wert von count übernommen und erst im nächsten Schleifendurchgang erhöht.

Hingegen zeigt der pre-increment Sketch ein anderes Ergebnis: 2, 3, 4. Hier wird schon beim ersten ++count um 1 inkrementiert.

//post-increment i++
void setup() 
{
  int count = 1;
  
  Serial.begin(9600);
  
  Serial.println(count++);
  
  Serial.println(count++);

  Serial.println(count++);
  
  Serial.println();
}


void loop() 
{
  //leer
}

//pre-increment --i

void setup() 
{
  int count = 1;
  
  Serial.begin(9600);
  
  Serial.println(++count);
  
  Serial.println(++count);

  Serial.println(++count);
  
  Serial.println();
}


void loop() 
{
  //leer
}