Der lange Weg zur eigenen RGB-LED-Ansteuerung, Teil 4

Wie zu sehen war kann ein Arduino mit etwas Beschaltung schon etwas an LEDs antreiben. Bis zu LED-RGB-Strips mit 500 – 800 mA pro Farbe fehlt zwar noch etwas an Leistung, aber die Richtung ist schon mal korrekt. Also kommt langsam die Frage des Farbmischens und damit des Dimmens auf. Das kann man relativ einfach halt mit Pulsweitenmodulation (bzw. Pulse Width Modulation / PWM) machen, wobei man die LEDs halt nur eine bestimmte Zeit an- und eine andere Zeit ausschaltet. Zum simplen Überprüfen dieser Theorie schaltet der folgende Code das Signal am Pin 13 an und aus:

int pinId = 13;

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin 13 as an output.
  pinMode(pinId, OUTPUT);

  // initialize serial:
  Serial.begin(9600);
}

// the loop function runs over and over again forever
void loop() {
  for(float i = 1; i < 100; i+=0.1) {
    Serial.println(i);
    digitalWrite(pinId, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay((int)(100/i));         // wait for some time
    digitalWrite(pinId, LOW);    // turn the LED off by making the voltage LOW
    delay((int)(100/(101-i)));   // wait for some time
  }
  for(float i = 100; i > 1; i-=0.1) {
    Serial.println(i);
    digitalWrite(pinId, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay((int)(100/i));         // wait for some time
    digitalWrite(pinId, LOW);    // turn the LED off by making the voltage LOW
    delay((int)(100/(101-i)));   // wait for some time
  }
}

In der setup()-Funktion wird der Pin 13 als Ausgabe geschaltet, dazu noch die serielle Konsole gestartet, damit man auf dem PC mit lesen kann, bei welchem Wert der Arduino gerade ist.
In der Schleife loop() wird dann in sehr simpler Manier das Tastverhältnis gewechselt. Zunächst wird der Pin angeschaltet, und eine relativ lange Zeit (100 Millisekunden) gewartet, bis das Ausschalten kommt, dann wird sehr kurz (1 Millisekunde) gewartet. Da i nur in 0.1er Schritten erhöht wird, wird das Verhältnis von AN nach AUS langsam runter gedreht, bis der Pin schließlich 1 Millisekunde auf AN, und 100 Millisekunden auf AUS steht. Danach wird das dann umgedreht.
Damit werden die angeschlossenen LEDs langsam von fast 100% auf fast 0% und dann wieder auf fast 100% gedimmt.

Das ist schon ganz nett, allerdings ist mir danach aufgefallen, dass der Arduino (bzw. der Atmel-Mikroprozessor) auch Pins hat, die auf dem Board mit „DIGITAL (PWM~)“ markiert sind. Somit sind die Pins 3,5,6,9,10,11 und 13 von Hause aus schon PWM-fähig. Damit kann das Timing des Tastgrads von der Hardware übernommen werden, und ich muss mich damit gar nicht so genau beschäftigen.

Dieser Code dimmt verschiedene Farben von aus nach an und wieder aus. An Pin 9 habe ich da rote, an Pin 10 grüne und an Pin 11 blaue LEDs.

int pinRed = 9;         // Pin 9 is a PWM-'analog'-pin
int pinGreen = 10;      // Pin 10 is a PWM-'analog'-pin
int pinBlue = 11;       // Pin 11 is a PWM-'analog'-pin
int minValue = 0;
int maxValue = 255;
int delayValue = 10;

void setup() {
  // initialize the pins as an output.
  pinMode(pinGreen, OUTPUT);
  pinMode(pinBlue, OUTPUT);
  pinMode(pinRed, OUTPUT);
  analogWrite(pinRed, minValue);
  analogWrite(pinGreen, maxValue);
  analogWrite(pinBlue, minValue);
}

// Fades the PWM output of a pin from the minimum to the maximum
void slowlySwitchOn (int pinId) {
  for(int i = minValue; i <= maxValue; i++) {
    Serial.println(i);
    analogWrite(pinId, i);
    delay(delayValue);
  }  
}

// Fades the PWM output of a pin from the maximum to the minimum
void slowlySwitchOff (int pinId) {
  for(int i = maxValue; i >= minValue; i--) {
    Serial.println(i);
    analogWrite(pinId, i);
    delay(delayValue);
  }
}

// the loop function runs over and over again forever
void loop() {
  // Slowly switch on Green
  slowlySwitchOn(pinGreen);
  
  delay(delayValue * 50);

  // Slowly switch off Green
  slowlySwitchOff(pinGreen);

  delay(delayValue * 50);

  // Slowly switch on Blue  
  slowlySwitchOn(pinBlue);
  
  delay(delayValue * 50);

  // Slowly switch off Blue
  slowlySwitchOff(pinBlue);

  delay(delayValue * 50);

  // Slowly switch on Red  
  slowlySwitchOn(pinRed);
  
  delay(delayValue * 50);
  
  // Slowly switch off Red
  slowlySwitchOff(pinRed);

  delay(delayValue * 50);
}

Ebenso kann man die Farben langsam von einfarbig zu ‚weiß‘ gemischt faden lassen. Der wichtigste Unterschied zum Code davor ist natürlich nicht die Tatsache, dass ich da 3 unterschiedliche Pins und Farben steuer, sondern dass statt digitalWrite(pinId,HIGH|LOW) ein ‚analoger‘ Wert auf die Pins gegeben wird: analogWrite(pinId, value).

Was besonders in diesen beiden Beispielen sichtbar ist, ist der Fakt, dass lineares Dimmen für das menschliche Auge nicht linear ist. Insbesondere wenn es dunkler wird, sieht das Auge zwischen 2 Stufen einen viel größeren Unterschied, als in den helleren Zeiten. Das widerspricht natürlich meinem Wunsch, dass alles langsam und unauffälig passieren soll. Aber dazu dann später. Außerdem müssen die PWM-Signale auch noch an etwas mehr Strom übergeben werden.