RGB-LED-Ringe

Von den WS2812B-Modulen für RGB-LEDs gibt es etliche Bauformen, sowie auch den hier beschriebenen vollen Ring aus insgesamt 241 Einzel-LEDs aufgeteilt auf 9 unterschiedliche Unterringe.

WS2812B-Ring mit Abmessungen

Verwendete Bauteile

WS2812B-Ring (Oberseite mit den LED-Modulen)
Abb.: WS2812B-Ring (Oberseite mit den LED-Modulen)
WS2812B-Ring (Unterseite mit den Lötstellen)
Abb.: WS2812B-Ring (Unterseite mit den Lötstellen)
Detailansicht des WS2812B-Rings mit Lötstellen
Abb.: Detailansicht des WS2812B-Rings mit Lötstellen
Detailansicht des WS2812B-Rings
Abb.: Detailansicht des WS2812B-Rings
Verbinden der Lötstellen
Abb.: Verbinden der Lötstellen (hier 5V und GND)

Aufbau und Ansteuerung

Wie ein oder mehrere WS2812B-Module angesteuert und programmiert werden, kann man im Beitrag RGB-LED-Modul WS2812B nachlesen. Dort findet man auch einen Sketch für einen Funktions-Test der eigenen Module.
Im folgenden Aufbau sind neben dem WS2812B-Ring noch ein Mikrotaster zur Wahl des Modus (statisch oder animiert) sowie drei Potentiometer zu sehen, die verschiedene Funktionen erfüllen.
Das die 241 WS2812B-LEDs vor allem mit zunehmender Helligkeit eine beachtliche Stromstärke aufnehmen, sollte immer eine entsprechende Spannungsquelle verwendet werden, damit der Arduino keinen Schaden nimmt.

Schaltplan

Sketch

Der folgende Sketch verwendet die Library Adafruit_NeoPixel, welche die Ansteuerung der WS2812B-Module recht einfach macht. Der statische Modus ermöglicht es, mit den Potentiometern die Farben rot, grün und blau individuell in ihrer Helligkeit zu steuern. Im Animations-Modus werden verschiedene Programme mit dem ersten Potentiometer durchgewählt. Für jedes Programm können noch zusätzlich die Helligkeit und die Geschwindigkeit des Programms gewählt werden. (Bei extremen Helligkeitswerten können die Farben etwas unvorhergesehen reagieren)

/**
   Arduino-Sketch for driving WS2812B-LED-Rings with different programs
   (c) 2020 Christian Grieger
   GNU GENERAL PUBLIC LICENSE

   Usage:
    Button: Switch between static and animation mode
    1st Potentiometer:
      - static mode: brightness of color red
      - animation mode: toggle animation program
    2nd Potentiometer:
      - static mode: brightness of color green
      - animation mode: animation speed
    3rd Potentiometer:
      - static mode: brightness of color blue
      - animation mode: overall brightness of LEDs (not available for all animation programs)
*/

/********* BEGIN customizable values *********/
#define PIN_POTI_RED   A0
#define PIN_POTI_GREEN A1
#define PIN_POTI_BLUE  A2
#define PIN_BUTTON     8
#define PIN_LED        9

#define AMOUNT_LEDS  241
#define AMOUNT_RINGS   9

const byte ledRings[AMOUNT_RINGS][2] = {
    {  0,  60},   // 60 LEDs
    { 60, 108},   // 48 LEDs
    {108, 148},   // 40 LEDs
    {148, 180},   // 32 LEDs
    {180, 204},   // 24 LEDs
    {204, 220},   // 16 LEDs
    {220, 232},   // 12 LEDs
    {232, 240},   //  8 LEDs
    {240, 241}    //  1 LED
};
/********* END customizable values ***********/


#define MODE_STATIC    0
#define MODE_ANIMATION 1
#define AMOUNT_PROGRAMS 5

#define lmillis() ((long)millis())

#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel led = Adafruit_NeoPixel(AMOUNT_LEDS, PIN_LED, NEO_GRB + NEO_KHZ800);


void setup()
{
    randomSeed(analogRead(A5));
    pinMode(PIN_BUTTON, INPUT_PULLUP);
    pinMode(PIN_POTI_RED, INPUT);
    pinMode(PIN_POTI_GREEN, INPUT);
    pinMode(PIN_POTI_BLUE, INPUT);
    led.begin();
    setAllLeds(led.Color(0, 0, 0));
}

void loop()
{
    static long lastClick = lmillis();
    static byte displayMode;

    if (displayMode == MODE_ANIMATION) {
        checkAnimation();
    } else {
        checkStatic();
    }

    if (lmillis() - lastClick >= 0 && digitalRead(PIN_BUTTON) == LOW) {
        lastClick = lmillis() + 250;
        displayMode++;
        displayMode %= 2;
        setAllLeds(led.Color(0, 0, 0));
    }
}

void checkStatic()
{
    static uint8_t rgb[3] = {0, 0, 0};
    bool hasChanged = false;

    uint8_t r = map(analogRead(PIN_POTI_RED), 0, 1023, 0, 255);
    uint8_t g = map(analogRead(PIN_POTI_GREEN), 0, 1023, 0, 255);
    uint8_t b = map(analogRead(PIN_POTI_BLUE), 0, 1023, 0, 255);
    if (abs(rgb[0] - r) > 10) {
        rgb[0] = r;
        hasChanged = true;
    }
    if (abs(rgb[1] - g) > 10) {
        rgb[1] = g;
        hasChanged = true;
    }
    if (abs(rgb[2] - b) > 10) {
        rgb[2] = b;
        hasChanged = true;
    }

    if (hasChanged) {
        setAllLeds(led.Color(rgb[0], rgb[1], rgb[2]));
    }
}

void checkAnimation()
{
    static int pVal = 0;
    static byte activeProgram = 0;
    static byte brightness = 1;
    static byte delayFactor = 1;

    delayFactor = map(analogRead(PIN_POTI_GREEN), 0, 1023, 1, 250);
    brightness = map(analogRead(PIN_POTI_BLUE), 0, 1023, 1, 255);

    int v = analogRead(PIN_POTI_RED);
    if (abs(pVal - v) > 100) {
        pVal = v;
        activeProgram++;
        activeProgram %= AMOUNT_PROGRAMS;
        setAllLeds(led.Color(0, 0, 0));
    }

    switch (activeProgram) {
        case 4:
            showRingRotation(brightness, delayFactor);
            break;
        case 3:
            showRandomColors(brightness, delayFactor);
            break;
        case 2:
            showRingSun(brightness, delayFactor);
            break;
        case 1:
            showSingleFlash(brightness, delayFactor);
            break;
        case 0:
        default:
            showRoulette(brightness, delayFactor);
            break;
    }
}


void setAllLeds(uint32_t ledColor)
{
    for (uint8_t i = 0; i < AMOUNT_LEDS; i++) {
        led.setPixelColor(i, ledColor);
    }
    led.show();
}

void showSingleFlash(byte brightness, byte delayFactor)
{
    byte ledIndex = random(0, AMOUNT_LEDS);
    led.setPixelColor(ledIndex, led.Color(brightness, brightness, brightness));
    led.show();
    delay(delayFactor * 2); // delay between 4ms and 1000ms
    led.setPixelColor(ledIndex, led.Color(0, 0, 0));
    led.show();
}

void showRoulette(byte brightness, byte delayFactor)
{
    static byte ledIndex = 0;
    ledIndex++;
    ledIndex %= AMOUNT_LEDS;

    led.setPixelColor(ledIndex, led.Color(brightness,  0,  0));
    led.show();
    delay(delayFactor * 4); // delay between 4ms and 1000ms
    led.setPixelColor(ledIndex, led.Color(0,  0,  0));
    led.show();
}

void showRingSun(byte brightness, byte delayFactor)
{
    static byte ringNo = 0;
    ringNo++;
    ringNo %= AMOUNT_RINGS;

    for (byte i = ledRings[ringNo][0]; i < ledRings[ringNo][1]; i++) {
        led.setPixelColor(i, led.Color(brightness, (byte)(brightness * 0.25), 0));
    }
    led.show();
    delay(delayFactor * 4); // delay between 4ms and 1000ms
    for (byte i = ledRings[ringNo][0]; i < ledRings[ringNo][1]; i++) {
        led.setPixelColor(i, led.Color(0, 0, 0));
    }
    led.show();
}

void showRandomColors(byte brightness, byte delayFactor)
{
    for (byte i = 0; i < AMOUNT_LEDS; i++) {
        led.setPixelColor(i, led.Color(random(0, brightness), random(0, brightness), random(0, brightness)));
    }
    led.show();
    delay(delayFactor * 4); // delay between 4ms and 1000ms
}

void showRingRotation(byte brightness, byte delayFactor)
{
    static byte ringIndex[AMOUNT_RINGS];

    for (byte i = 0; i < AMOUNT_RINGS; i++) {
        led.setPixelColor(ringIndex[i], led.Color(0, 0, 0));
    }
    led.show();

    for (byte r = 0; r < AMOUNT_RINGS; r++) {
        ringIndex[r]++;
        if (ringIndex[r] >= ledRings[r][1]) {
            ringIndex[r] = ledRings[r][0];
        }
        led.setPixelColor(ringIndex[r], led.Color(brightness, (byte)(brightness * 0.5), 0));
    }
    led.show();
    delay(delayFactor); // delay between 1ms and 250ms
}
Video: Live-Demonstration der Leuchtprogramme
zurück