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.
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:
In der Schaltung ist zu beachten, dass eine RGB-LED mit gemeinsamer Kathode (-) verwendet wurde.
#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);
}
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.
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
}
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.
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.
#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