Schritt 5: Jetzt wird es bunt

Mein Ziel ist es, diese Einführung so einfach als auch kostengünstig zu gestalten. Bislang haben wir knapp 20 Euro für ein Board investiert. Für die nächsten Schritte möchte ich mich der dreifarbigen LED zuwenden, der RGB-LED, die so heist, da sie einen roten (R), grünen (G) und blauen (B) Farbkanal hat und somit 16 Millionen Farben darstellen kann, da jeder Kanal Werte zwischen 0 und 255 annehmen kann.

Um die Sache zu vereinfachen, benutze ich eine RGB-LED vom Typ NeoPixel, der von Adafruit angeboten wird. Es gibt diese LEDs einzeln oder als Streifen, Ringe oder Matrix. Ein Streifen von 8 LEDs kostet ca € 5.66 (exp-tech.de) oder CHF 7.55 (boxtec.ch), ist also vergleichsweise günstig. Ausserdem kann man an diesen Streifen sehr einfach eine Stiftleiste anlöten und daran Kabel aufstecken um den Streifen mit dem Arduino zu verbinden.

Das Besondere an diesen NeoPixeln ist, dass man sie über einen einzelnen Draht ansteuern kann. Wie das genau funktioniert soll uns erst einmal nicht interessieren. Dazu gibt es eine ausführliche Beschreibung bei Adafruit, die ich hier nicht wiederholen möchte. Ausserdem will ich die LEDs benutzen und nicht en Detail selbst programmieren: Darin liegt übrigens eine der Stärken der Arduino Platform: Man kann Dinge benutzen und erhält dafür alle notwenigen Bebliotheken bereit gestellt (Adafruit und Sparkfun tun sich hier besonders gut hervor). Wenn ich das Gleiche auf einer anderen Platform versuche, muss ich im schlimmsten Fall die Steruerung der LEDs selbst schreiben.

Also ist der Anschluss des NeoPixel Streifens sehr einfach: GND an Masse, 4-7VDC an +5V und Din an einen freien Pin, z.B. den Pin 6. Diese LEDs zeihen recht viel Strom, wenn man einen langen Streifen verwendet. Bei unserem Streifen mit 8 LEDs sollte es keine Probleme geben.

Von Adafruit erhalte ich also eine Bibliothek (library) für den NeoPixel welche ich sehr einfach in mein Arduino IDE einbinden kann. Es gibt in der Arduino IDE zwei Verzeichnisse, in der Libraries abgelegt werden: Im Installationsverzeichniss der IDE liegen die STandardlibraries der IDE, bei mir also:

c:\opt\arduino-1.5.6-r2\libraries\

Hier sollten nur die Libraries abgelegt werden, die mit der IDE geliefert werden oder die für diese IDE spezifisch geschrieben sind. Alle anderen Libraries, also auch unsere NeoPixel Library gehören in der Benutzerveizeichnis, wo auch alle meine Sketches abgelegt werden. Bei mir ist das:

c:\data\Arduino\libraries\

und dementsprechend:

c:\data\Arduino\libraries\Adafruit_NeoPixel\

Leider benennt Adafruit ihr Library-Verzeichnis Adafruit_NeoPixel-master was der IDE überhaupt nicht gefällt. Generell mag die IDE keine Leerzeichen im Namen und auch keine Sonderzeichen als auch keine Namen, welche mit eine Zahl anfangen. Am Besten ist es, das Verzeichnis mit dem gleichen Namen zu bezeichnen wie das .ccp File in diesem Verzeichnis, welches den Code der Library enthält.

Die Libraries werden nur beim Start der IDE geladen, was man manchmal vergisst und sich dann wundert, warum die Library nicht gefunden wird. Erhält man beim Übersetzen eines Sketches eine lange Liste an unbekannten Klassenelementen, sollte man immer an den Anfang der Lsite gehen und schauen, ob die Library überhaupt geladen wurde.

Nach dem Start der IDE taucht nun die Adafruit Neopixel Library unter den Beispielen auf. Um unseren NeoPixel Streifen zu nutzen, braucht es nun nur noch ein paar kleine Schritte. Dazu schauen wir uns der Beispiel "strandtest" an:

Am Anfang wird die Library durch den Aufruf

#include <Adafruit_NeoPixel.h>

eingebungen. die Klammern "<" und ">" weisen den Compiler an, die Datei im Verzeichnisbaum des Benutzers und der IDE zu suchen. Daher sollten die Namen der Dateien eindeutig sein. Druch diesen Aufruf wird auch dei Datei Adafruit_NeoPixel.cpp eingelesen und alles das definiert, was wir zum Steuern der NeoPixel brauchen.

#define PIN 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(8, PIN, NEO_GRB + NEO_KHZ800);

Mit #define PIN 6 wird wie in der vorherigen Beispielen ein Pin definiert, an den wir den Neopixel angeschlossen haben. Die zweite Zeile definiert ein Objekt namens strip, welches wir für unseren Streifen benutzen wollen. Ein Objekt ist vereinfacht dargestellt die Zusammenfassung von allem, was ich brauche, um etwas zu verwenden, also

  • die Speicherplätze
  • die Routinen, um diese zu erstellen
  • die Routinen, um diese zu bearbeiten
  • die Routinen, um mit der Hardware zu reden

Hier wird also ein Objekt erzeugt, welches einen NeoPixel-Streifen mit 8 LEDs steuert. Bei dem Beispiel müssen wir also nur den Pin ändern, wenn wir einen anderen Pin als den Pin 6 verwenden und die Anzahl der Pixel anpassen, wenn wir wie hier nur 8 statt der vorgegebenen 60 pixel haben.

An dieser Stelle empfehle ich, das Sketch zu kompilieren und auf den Arduino zu laden. Sonnenbrille auf und einfach mal nur bewundern...

NeoPixel programmieren

Nun versuche ich mal, den NeoPixel Streifen zu programmieren:

In setup() müssen wir das Objekt initialisieren:

strip.begin();
strip.show();

Mit strip.begin() wird der Streifen initialisiert, mit strip.show() angezeigt. Da im Streifen noch nichts geladen ist, bleibt er also dunkel.

Die LEDs werden von links nach rechts durchnummeriert, wobei man bei 0 anfängt. Die Routine strip.setPixelColor( index, color) setzt die Farbe für einen Pixel. Die Farbe wird dabei in Form eines 32-bit langes Wortes angegeben. Die Kodierung nimmt uns aber eine Routine der Library ab: strip.Color( r,g,b) wobei r, g und b die jeweiligen Farbanteile für Rot, Grün und Blau der gewünschten Farbe angeben. Die Werte können dabei zwischen 0 und 255 liegen. Das Triplet (0,0,0) ist also Schwarz, (255,0,0) Rot, )0,255,0) Grün und (0,0,255) Blau. (255,255,255) ist demnach Weis.

In dem Beispiel von Adafruit ist eine Routine angegeben, welche uns die RGB Werte für einen Farbkreis errechnet, der in 255 Farben geteilt ist. Wie beim Arduino üblich, bedienen wir uns gerne solcher Codeschnipsel und bauen sie in unseren Sketch ein.

Im loop() will ich nun einen Lichtpunkt von einer Seite des Streifens zu der anderen wandern lassen und wieder zurück. Dazu baue ich folgende for-Schleife:

for (int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, Wheel(wc));
    t = i - 1;
    if (t < 0) t = strip.numPixels() - 1;
    strip.setPixelColor(t, strip.Color( 0, 0, 0));
strip.show();
    delay(50);
  }

Die Funktion strip.numPixels() gibt mir die Anzahl der Pixel, die ich bei der Definition des Objekts angegeben habe. Das ist praktisch, da ich so den Sketch für Streifen beliebiger Länge programmieren kann. In der ersten Anweisung in der Schleife setze ich die Farbe des jeweiligen Pixels. Dann errechne ich mir den letzten Pixel. Wenn ich unter Null gerate, sete ich diesen Index auf die höchste Pixelnummer. Diesem Pixel gebe ich nun die Frabe Schwarz, lösche also das Licht an der Stelle des letzten Schleifendurchlaufs. Dann zeige ich das Ergebnis meiner Bemühungen an und warte 50 Millisekunden um mich dem nächsten Pixel zu widmen.

Bin ich einmal den Streifen entlang gelaufen, so geht es jetzt wieder in die andere Richtung:

for (int i = strip.numPixels()-1; i >= 0; i--) {
    strip.setPixelColor(i, Wheel(wc));
    t = i + 1;
    if (t >= strip.numPixels()) t = 0;
    strip.setPixelColor(t, strip.Color( 0, 0, 0));
    strip.show();
    delay(50);
  }

 

Zum Schluss zähle ich noch den Zähler hoch, den ich für die Routine Wheel() verwende und wir sind fertig. Hier der gesamte Code:

#include <Adafruit_NeoPixel.h>
#define PIN 10
Adafruit_NeoPixel strip = Adafruit_NeoPixel(8, PIN, NEO_GRB + NEO_KHZ800);
int wc = 0;

void setup() {
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

void loop() {
  // knight rider LEDs
  int t;
  for (int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, Wheel(wc));
    t = i - 1;
    if (t < 0) t = strip.numPixels() - 1;
    strip.setPixelColor(t, strip.Color( 0, 0, 0));
    strip.show();
    delay(50);
  }
  for (int i = strip.numPixels()-1; i >= 0; i--) {
    strip.setPixelColor(i, Wheel(wc));
    t = i + 1;
    if (t >= strip.numPixels()) t = 0;
    strip.setPixelColor(t, strip.Color( 0, 0, 0));
    strip.show();
    delay(50);
  }
  wc++;
  if (wc>255) wc=0;
}

uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

Eigentlich hindert uns jetzt nichts, mit den Pixelstrip herum zu spielen. Ich habe mir zum Beispiel aus den Erfahrungen der vorherigen Seiten drei SLider im Dashboard definiert und kann damit die Farbanteile meiners Streifens steuern. Viel Vergnügen!

Details

Der Vollständigkeit halber hier noch ein paar Details:

Weitere Routinen

Es gibt zwei Routinen, die auch noch interessant sind:

  • setBrightness(uint8_t b) - setzt einen generellen Skalierungsfaktor b (0 .. b .. 255) für alle Farben und damit eine Helligkeit
  • getPixelColor(uint16_t n) - liest die zuletzt gesetzte Farbe eine Pixels aus.

Die Farbinformation für alle Pixel wird in einem Array gespeichert und beim Aufruf der Routine show() in einem Schwung an die seriell verbundenen Pixel geschickt. Damit hat man also die jeweiligen Pixelwerte immer parat und kann sie entsprechend abfragen und muss sie nicht selbst zwischenspeichern.

WS2801, WS2811, WS2812, WS2812S, WS2812B - was nun?

Ich habe hier die RGB-LEDs des Neopixel Produkts von Adafruit besprochen. Diese basieren auf den WS2812 LEDs bzw. WS2811 Treibern. Den Streifen, welchen ich gekauft habe, verwenden den WS2812S, neuere verwenden den WS2812B. Was ist denn nun der Unterschied:

  • WS2811 - das ist der Treiberchip
  • WS2812S - ältere Version, besteht aus einer 5050-RGB-LED und dem WS2811 treiber in einem kompakten Gehäuse, hat 6 Pins
  • WS2812B - neuere Version, Aufbau wie WS2812S, aber nur 4 Pins

Die LED WS2801 wird komplett anders angesprochen und ist nicht mit den hier beschriebenen LEDs kompatibel.

RGB-LED - eine dreifach LED

Genau genommen hat man hier keine RGB-LED sondern eine LED, welche drei Einzel-LED in enem Gehäuse vereint. Das erkennt man ganz gut, wenn man sich eine klassische RGB-LED kauft, welche 4 Pins hat, drei für die jeweiligen Farben und eine gemeinsame Anode oder Kathode. Wenn man die NeoPixel mit sehr geringer Lichtstärke ansteuert, kann man die einzelnen LEDs auf dem Chip sehen.