RGB-LED-Blinker

Dieses Experiment unterscheidet sich insofern von LED-Blinker, LED-Blitzer für 9V und LED-Blitzer II., weil hierbei ein ATtiny-Mikrocontroller die Blink-Steuerung übernimmt. Dafür blitzt die LED in vielen verschiedenen Farben.

Verwendete Bauteile

Aufbau der Schaltung

Zum Ausprobieren der RGB-LED wird zunächst eine Schaltung für einen Arduino UNO aufgebaut und programmiert. Hierbei wird die LED langsam durch die einzelnen Farben rotieren:

Aufbau der Schaltung mit dem Arduino UNO

In der Schaltung ist zu beachten, dass eine RGB-LED mit gemeinsamer Kathode (-) verwendet wurde.

Sketch

#define PIN_RED    9
#define PIN_GREEN 10
#define PIN_BLUE  11

int rVal = 254, gVal = 1, bVal = 127;
int rDir = -1, gDir = 1, bDir = -1;

void setup()
{
    pinMode(PIN_RED, OUTPUT);
    pinMode(PIN_GREEN, OUTPUT);
    pinMode(PIN_BLUE, OUTPUT);
}

void loop()
{
    analogWrite(PIN_RED, rVal);
    analogWrite(PIN_GREEN, gVal);
    analogWrite(PIN_BLUE, bVal);

    rVal += rDir;
    gVal += gDir;
    bVal += bDir;

    if (rVal >= 255 || rVal <= 0) {
        rDir *= -1;
    }
    if (gVal >= 255 || gVal <= 0) {
        gDir *= -1;
    }
    if (bVal >= 255 || bVal <= 0) {
        bDir *= -1;
    }

    delay(100);
}

Aufbau mit dem ATtiny85

Für den fertigen Aufbau mit dem ATtiny85 wird ein kleiner LiPo mit 100mAh verwendet. Diese Akkus werden auch gerne für kleine Spielzeug-Drohnen (Quadkopter) verwendet.

Aufbau der Schaltung mit dem ATtiny85

Sketch für den ATtiny85

Dies ist der eigentliche Blink-Sketch, der die RGB-LED mit einer zufälligen Farbe (und Helligkeit) für 200ms aufblinken lässt und dann wieder erlischt. Während dieser Zeit wird der ATtiny in den Sleep-Modus versetzt und dann durch den Watchdog-Timer nach 4 Sekunden wieder erwacht und die LED erneut blinken lässt.
(Das Programmieren des ATtiny wird in einem anderen Beitrag ausführlich beschrieben)

#include <avr/sleep.h>
#include <avr/wdt.h>

#define PIN_RED   PCINT0
#define PIN_GREEN PCINT1
#define PIN_BLUE  PCINT4

ISR(WDT_vect) {}

void setup()
{
    pinMode(PIN_RED, OUTPUT);
    pinMode(PIN_GREEN, OUTPUT);
    pinMode(PIN_BLUE, OUTPUT);

    // setup of the WDT
    cli();
    wdt_reset(); // reset watchdog timer
    MCUSR &= ~(1 << WDRF); // remove reset flag
    WDTCR = (1 << WDCE); // set WDCE, access prescaler
    WDTCR = 1 << WDP3; // set prescaler bits to to 4s
    WDTCR |= (1 << WDIE); // access WDT interrupt
    sei();
}

void loop()
{
    analogWrite(PIN_RED, random(0, 255));
    analogWrite(PIN_GREEN, random(0, 255));
    analogWrite(PIN_BLUE, random(0, 255));
    delay(200);
    resetLeds();
}

void resetLeds()
{
    digitalWrite(PIN_RED, LOW);
    digitalWrite(PIN_GREEN, LOW);
    digitalWrite(PIN_BLUE, LOW);
    enterSleepMode();
}

void enterSleepMode()
{
    byte adcsra;

    adcsra = ADCSRA; // save ADC control and status register A
    ADCSRA &= ~(1 << ADEN); // disable ADC

    MCUCR |= (1 << SM1) & ~(1 << SM0); // Sleep-Modus = Power Down
    MCUCR |= (1 << SE); // set sleep enable
    sleep_cpu(); // sleep
    MCUCR &= ~(1 << SE); // reset sleep enable

    ADCSRA = adcsra; // restore ADC control and status register A
}
3,7V LiPo-Akku (100mAh) mit Lademodul TP4056
Abb.: 3,7V LiPo-Akku (100mAh) mit Lademodul TP4056; Das Laden mit einer Powerbank dauert ca. 20min.
Aufbau auf dem Breadboard
Abb.: Aufbau auf dem Breadboard
Aufbau auf dem Breadboard
Abb.: Aufbau auf dem Breadboard; Ein rosa Blitz wurde mit der Kamera aufgenommen

Stromsparen & Laufzeit

Durch den Einsatz des Sleep-Modus kann während Zeit, in der die LED nicht leuchtet, eine Menge Energie eingespart werden. Mit einem Multimeter habe ich ~3,5mA im aktiven Zustand des ATtiny inkl. des Leuchten der LED gemessen. Allerdings dauert dies nur 200ms. In den darauffolgenden 4 Sekunden fährt der ATtiny in den Sleep-Modus und die gesamte Schaltung verbraucht dabei nur noch ca. ~2µA. Rein rechnerisch wäre dies ein durchschnittlicher Verbrauch von ca. 0,2mAh. Damit sollte der 100mAh-Akku ausreichend sein, den Blinker für ca. 20 Tage durchgehend zu betreiben.

Variation mit LDR

Da es eigentlich nicht sinnvoll ist, die Schaltung in heller Umgebung blinken zu lassen, habe ich noch einen LDR GL5516 verwendet, um die Helligkeit zu erkennen. Jetzt blinkt die LED nur, wenn die Umgebung dunkel ist. Allerdings ist bei der üblichen LDR-Schaltung der Fotowiderstand permanent unter Strom, was die Akku-Haltbarkeit deutlich herabsenken würde. Daher habe ich mir einen kleinen Trick zu Nutze gemacht, d.h. der LDR wird bei der Messung durch einen anderen digitalen Pin mit Strom (also einem HIGH-Signal) versorgt und misst dann über einen zweiten analogen Pin. Somit ist zwar ein zusätzlicher Pin belegt, aber dafür kann der Sleep-Modus wieder voll ausgenutzt werden.

Aufbau der Schaltung

Aufbau der Schaltung mit einem zusätzlichen LDR

Sketch

#include <avr/sleep.h>
#include <avr/wdt.h>

#define PIN_RED        PCINT0
#define PIN_GREEN      PCINT1
#define PIN_BLUE       PCINT4
#define PIN_LDR_SENSOR PCINT3
#define PIN_LDR_POWER  PCINT2

ISR(WDT_vect) {}

void setup()
{
    pinMode(PIN_LDR_SENSOR, INPUT);
    pinMode(PIN_LDR_POWER, OUTPUT);
    pinMode(PIN_RED, OUTPUT);
    pinMode(PIN_GREEN, OUTPUT);
    pinMode(PIN_BLUE, OUTPUT);

    // setup of the WDT
    cli();
    wdt_reset(); // reset watchdog timer
    MCUSR &= ~(1 << WDRF); // remove reset flag
    WDTCR = (1 << WDCE); // set WDCE, access prescaler
    WDTCR = 1 << WDP3; // set prescaler bits to to 4s
    WDTCR |= (1 << WDIE); // access WDT interrupt
    sei();
}

void loop()
{
    digitalWrite(PIN_LDR_POWER, HIGH);
    if (analogRead(PIN_LDR_SENSOR) < 300) {
        analogWrite(PIN_RED, random(0, 255));
        analogWrite(PIN_GREEN, random(0, 255));
        analogWrite(PIN_BLUE, random(0, 255));
        delay(200);
        resetLeds();
    }
    digitalWrite(PIN_LDR_POWER, LOW);
    enterSleepMode();
}

void resetLeds()
{
    digitalWrite(PIN_RED, LOW);
    digitalWrite(PIN_GREEN, LOW);
    digitalWrite(PIN_BLUE, LOW);
}

void enterSleepMode()
{
    byte adcsra;

    adcsra = ADCSRA; // save ADC control and status register A
    ADCSRA &= ~(1 << ADEN); // disable ADC

    MCUCR |= (1 << SM1) & ~(1 << SM0); // Sleep-Modus = Power Down
    MCUCR |= (1 << SE); // set sleep enable
    sleep_cpu(); // sleep
    MCUCR &= ~(1 << SE); // reset sleep enable

    ADCSRA = adcsra; // restore ADC control and status register A
}
zurück