Solar LED-Strahler mit ATtiny

von Stephan Laage-Witt
Elektronik-Labor   Projekte   AVR 




Neulich ist es wieder passiert: Das Warten an der Kasse unseres lokalen Baumarkts führt an den Regalen mit Billig-Artikeln vorbei. Die verkaufsoptimierte Anordnung funktionierte bestens: Wider besseren Wissens landete ein Solar-Strahler für den Garten im Einkaufswagen und wechselte an der Kasse für wenige Euro den Besitzer. Und das nicht zum ersten Mal! Zuhause kam, was kommen musste: Nach einem sonnigen Tag schaltete sich am Abend ein unangenehm kalt-weißes Licht ein, das im Laufe des Abends schnell an Helligkeit verlor und den Rest der Nacht funzelig vor sich hin leuchtete. Nach dem Aufschrauben fand ich eine sehr minimalistische Ausstattung, bestehend aus drei parallel geschaltete 5 mm-LEDs, die über ein vierbeiniges IC mit dem kleinen Solarpanel und einer NiMH-Zelle verbunden waren. Eine Festinduktivität deutete auf eine „joule-thief“-Schaltung hin, die bei abnehmender Spannung des Solarpanels die LED einschaltet und am Morgen bei zunehmender Spannung wieder ausschaltet. Es ist klar, dass für dieses Design der Preisdruck die Oberhand hatte. Insofern macht das Gerät, was es soll, aber mit unbefriedigendem Ergebnis.
Die Frage ist: Wenn ich bereit bin, ein paar mehr Euro zu investieren, wie kann man es besser machen? Auf der Wunschliste stehen: Helleres und warm-weißes Licht mit gleichbleibender Leuchtstärke, begrenzte Brenndauer am Abend zum schonenden Umgang mit der beschränkten Solarenergie und ein pfleglicher Umgang mit dem Akku für eine lange Lebensdauer.
Hier möchte ich einen Vorschlag vorstellen, der diese Kriterien erfüllt – und inzwischen unseren heimischen Garten an verschiedenen Punkten erleuchtet.
 
SMD-LED
Mehr Licht braucht in erster Linie eine andere LED. Die ursprünglichen 5mm-LEDs wurden durch eine SMD-LED ersetzt. Ich habe mich für die STW8Q14C von Seoul Semiconductor entschieden, die für 100mA Dauerleistung bei etwa 3V ausgelegt und für wenig Geld zu habe ist. Jetzt war es auch an der Zeit, eine angemessene Farbe für die Gartenbeleuchtung zu wählen. Ich bevorzuge warm-weißes Licht, das den Ursprüngen jeder Gartenbeleuchtung - Fackeln oder Kerzen - einigermaßen nahekommt. Die LED trotz SMD-Bauform ausreichend groß, dass man sie ohne Probleme auf einer Lochrasterplatine auflöten kann. Zusammen mit einem Vorwiderstand von 10 Ohm auf der Rückseite der Platine kommt die neue LED auf den Reflektor und wird dort mit eine Tropfen Sekundenkleber befestigt. Das Scheinwerfer-Gehäuse vom Baumarkt erfüllt hier gute Dienste. Es zeigte sich, dass diese Anordnung ein sehr schönes und kräftiges Licht produziert.
 

SMD- LED an ihrem Arbeitsplatz

Energieversorgung
Die stärkere LED braucht mehr Strom, was unweigerlich zu einem größeren Solarpanel und einem stärkeren Energiespeicher führt. Von früheren Projekten hatte ich noch ein Panel mit 15 x 8 cm Größe in der Bastelkiste. Das Panel liefert maximal 5.5V und einen Kurzschlussstrom von 150mA. Als Energiespeicher kommen drei NiMH-Zellen, Größe AA, aus dem besagten Baumarkt zum Einsatz. Die Akkus werden in Reihe zu einem „Battery-Pack“ zusammengeschaltet und liefern so eine Ausgangsspannung zwischen 3.0 und etwa 3.8V. Das Solarpanel versorgt den Akku über eine Schottky-Diode (BAT46), die die Batterie vor Entladung schützt. Meine Messungen zeigen einen Ladestrom bei maximalem Sonnenschein zwischen 100mA am leeren und 50mA am vollen Akku. An sehr sonnigen Tagen muss der Akku gegebenenfalls 50mA Dauerladung aushalten, was mir akzeptabel erscheint. Eine Abschaltung bei Vollladung ist also nicht vorgesehen.
 

Das Kraftwerk: Solarpanel und NiMh-Akku

Schaltzentrale
Jetzt wird noch eine Steuerung benötigt, um die Komponenten miteinander arbeiten zu lassen. Hier kommt der bewährte ATtiny45 zur Anwendung. Der Mikrocontroller hat 3 Aufgaben.

Erstens schaltet er die LED am Abend abhängig von der Spannung des Solarpanels ein und nach einigen Stunden wieder aus. Schließlich besteht kein Bedarf, die Gartenbeleuchtung die ganze Nacht zu betreiben. Stattdessen sollte eine Akkufüllung auch bei schlechtem Wetter für mehrere Abende reichen.

Zweitens sorgt der ATtiny als Step-Up Wandler mit Hilfe einer Speicherdrossel für eine konstante Spannung an der LED, so dass die Helligkeit immer gleichbleibend und unabhängig vom Ladezustand des Akkus ist.

Und drittens beobachtet der Prozessor die Akkuspannung und schaltet den LED-Verbraucher aus, wenn die Akkuspannung unter den kritischen Wert von 3.0V fällt. So wird eine schädigende Tiefentladung des Akkus vermieden.
 

Schaltplan des Solar-LED Strahlers

Im Zentrum der Schaltung steht der Mikrocontroller. Er bekommt Input von 2 Quellen, die mit Hilfe des ADC ausgelesen werden: ADC-Kanal 2 misst die Spannung am Solarpanel vor der Schottky-Diode, und ADC-Kanal 3 die Akkuspannung. Als Referenz für den ADC wird die die interne Referenz-Spannung von 1.1V verwendet. Deshalb werden die externen Spannungen mit einem Spannungsteiler von 100 versus 33 kOhm auf das passende Niveau reduziert.
Der Ausgang PB1 schaltet die LED mit Hilfe eines P-Kanal FETs (IRLML2244) ein oder aus. Seit einiger Zeit gibt es MOSFETs, die auch mit 3V Steuerspannung durchschalten. Der MOSFET hat gegenüber einem bipolaren Transistor den Vorteil eines sehr kleinen Durchlasswiderstandes in eingeschaltetem Zustand. Dadurch verbessert sich der Wirkungsgrad der Schaltung. Außerdem kann das Gate direkt ohne Vorwiderstand an den Ausgang des Mikroprozessors angeschlossen werden. Nebenbei bemerkt sind die hier verwendeten Power MOSFETs ausgesprochen preisgünstig und in der Tat die billigsten Transistoren, die ich bisher je erworben habe.
Eine Besonderheit dieser Schaltung ist die Spannungserhöhung mit Hilfe eines Step-Up Wandlers. Der Ausgang PB0 produziert ein PWM-Signal von etwa 32kHz, das mit Hilfe eines N-Kanal FETs (IRLML6244) die Speicherdrossel periodisch auf Masse legt. Die Schottky-Diode koppelt die erhöhte Spannung aus, die dann mit dem Elko geglättet wird. Das Ausmaß der Spannungserhöhung kann über das Duty-Verhältnis des PWM-Signals eingestellt werden, was per Software geschieht. Dazu wird der Spannungswert am Ausgang über einen Spannungsteiler auf den ADC-Kanal 1 gegeben. Je nachdem, ob der Wert unter oder über der Zielgröße liegt, wird das Duty-Verhältnis des PWM-Signals angepasst. Diese Regelung klappt sehr gut und funktioniert mit minimaler Hardware. Der Nachteil, dass die Regelung recht langsam von statten geht, ist für diese Anwendung kein Problem. Es geht schließlich nur darum, die Ausgangspannung (und damit den LED-Strom) bei abfallender Akkuleistung konstant zu halten. Und das sind Veränderungen im Minuten- oder Stunden-Bereich.

Software
Die Software ist recht überschaubar und passt in eine kurze Datei (solar_led.c). Das Programm ist um 3 verschiedene Systemzustände herum organisiert:
•    STATE_DAY ist der Betrieb am Tag. Der Akku wird geladen und die LED ist ausgeschaltet.
•    STATE_NIGHT nach Einbruch der Dämmerung. Wenn die Spannung an der Solarzelle unter einen Grenzwert absinkt, wird die LED eingeschaltet.
•    STATE_BAT_LOW nach Absinken der Akku-Spannung unter 3.0V, und STATE_TIME_OUT nach Ablauf der geplanten Leuchtdauer sind eigentlich zwei verschiedene Zustände, die aber identische Eigenschaften haben. In beiden Fällen ist die LED ausgeschaltet. Das System wartet auf den nächsten Morgen mit einer ansteigenden Spannung am Solarpanel.
 

System-Zustände und ihre Übergänge

Zur Verwaltung der Zustände wird ein regelmäßiger Timer-Interrupt verwendet, der die CPU einmal pro Sekunde aus dem Sleep-Modus weckt. Hier kommt der Watchdog-Timer zum Einsatz, der im Gegensatz zu den anderen Timern den Vorteil eines sehr geringen Strombedarfs. Außerdem erlaubt er die Verwendung des „PWR_DOWN“ Sleep-Mode, was den Chip auf minimal Stromverbrauch trimmt. Tatsächlich verbraucht die Schaltung bei abgeschalteter LED nur 30 µA. Der Watchdog-Timer hat den Nachteil, dass seine Frequenz etwas ungenauer ist im Vergleich zu Timer0 und Timer1. Bei dieser Anwendung kommt es aber nicht auf exaktes Timing an.
Für den Step-Up Wandler produziert der ATtiny ein PWM-Signal, dessen Duty-Verhältnis über OCR0A eingestellt wird. Der Wert 255 entspricht dem kleinsten Duty-Cycle. Kleinere OCR0A-Werte erhöhen den Duty-Cycle und damit die Ausgangsspannung. Die Routine zur Regelung wird einmal pro Sekunde aufgerufen und ist sehr minimalistisch. Mit jedem Durchlauf wird OCR0A um den Wert 1 erhöht oder vermindert. Wie schon gesagt ergibt das eine sehr langsame Regelung. Natürlich könnte man einen effizienteren Regelalgorithmus implementieren, aber für diese Anwendung ist die Langsamkeit eine sehr sympathische Eigenschaft. Aus einer nostalgischen Perspektive ist es schön zu sehen, dass die Lampe nach dem Einschalten 30 oder 40 Sekunden benötigt, um volle Helligkeit zu erreichen, ganz wie die alten Natriumdampflampen in früheren Straßenlaternen …
Die Konstante TIME_OUT definiert die Brenndauer der LED in Sekunden. Im Programm-Listing ist der Wert von 14400 vorgegeben, was 4 Stunden entspricht. Hier sind natürlich beliebige andere Werte möglich.
Das Programm verwendet eine Umschaltverzögerung von 5 Minuten. Ohne diese Verzögerung besteht die Gefahr, dass in der Nacht eine kurzeitige Beleuchtung der Solarzelle (z.B. ein vorbeifahrendes Auto) den Prozess neu startet. Die Dauer der Verzögerung kann über die Konstante SWITCH_DELAY eingestellt werden.
Der ATtiny arbeitet in dieser Anwendung mit dem internen 8MHz Taktgenerator. Dazu muss die CKDIV8-Fuse gelöscht werden. Alle anderen Fuse-Einstellungen bleiben unverändert.

Praktisches
Mit etwas Geduld und einer ruhigen Hand kann man die Schaltung auf einem recht kleinen Stück doppelseitiger Lochraster-Platine zusammenbauen. Das folgende Bild zeigt ein mögliches Layout.
 

Layout auf einer doppelseitigen Lochrasterplatine. Schwarze Linien zeigen Verbindungen auf der Unterseite, und roten Linien Drahtbrücken auf der Oberseite. Die Speicherdrossel L wird senkrecht gestellt. Die Anschlüsse für Akku, Solar-Panel und LED werden mit flexiblen Kabeln herausgeführt.

Die FETs sind kleine SMD-Bauteile, die aber mit dem Lötkolben noch einigermaßen handhabbar sind. Es hat sich bewährt, sie ziemlich am Anfang der Lötarbeiten einzubauen. Dafür lasse ich kurze versilberte Kupferdrähte auf der Oberseite der Platine passend herausstehen, auf die die FETs dann aufgelötet werden. Dasselbe gilt für die SMD-Speicherdrossel, die aber erfreulicherweise wesentlich grösser ist.
 

Montage der SMD FETs. Zuerst schauen kurze versilberte Kupferdrähte aus der Oberseite der Platine (oben links), auf denen die Transistoren dann Platz finden (oben Mitte). Entsprechend wird auch die SMD-Speicherdrossel eingebaut (oben rechts). Unten: Fertig bestückte Platine mit Anschlussdrähten

Vor dem Einbau in das Gehäuse muss der gewünschte LED-Strom über den Trimmer eingestellt werden. Dazu kommt ein Amperemeter in die Leitung zur LED. Nach dem Anschluss des geladenen Akkus, jetzt noch ohne Solarzelle, sollte die LED kurz aufleuchten als Funktionskontrolle und dann erst einmal dunkel bleiben. Jetzt heißt es Warten auf den verzögerten Zustandswechsel. Nach 5 Minuten sollte sich die LED einschalten. Damit beginnt die Regelung der Ausgangsspannung. Im Sekunden-Rhythmus steigt der LED-Strom langsam an, um dann bei einem Maximalwert zu verharren. Am Trimmer lässt sich dieser Wert verändern. Sinnvolle Werte liegen zwischen 80 und 100 mA. Allerdings braucht der Einstellprozess etwas Geduld, da die Software auf jede Änderung in kleinen Schritten reagiert.
Das Gehäuse besteht aus der um etwa 45 Grad schräg gestellten Solarzelle und Plastikteilen für Boden, Seiten und Rückwand, die aus einer Kunststoffplatte aus dem Bastelbedarf zugeschnitten werden. Kleine Holzleisten dienen zur Stabilisierung. Die Teile werden mit 5-Minuten Epoxy verklebt, der auch als Dichtung gegen Spritzwasser dient. Die Solar-LED ist für den längerfristigen Einsatz im Garten gedacht. Deshalb braucht ein angemessener Schutz vor Regen etwas Aufmerksamkeit. Dazu werden Elektronik und Akku in Schrumpfschlauch untergebracht. Der Einbau sollte aber nicht komplett luftdicht sein, um Kondenswasser zu vermeiden. Zum Schluss wird die Rückwand aufgeschraubt.
 

Gehäuse mit geöffneter (links) und verschraubter (rechts) Rückwand

Dem Einsatz im Garten steht jetzt nichts mehr im Wege. Es ist erstaunlich, wieviel Licht diese kleine LED produziert. Das Schöne an Solar-getriebenen Leuchten ist, dass sie (hoffentlich) täglich und klaglos ihren Dienst leisten, ohne weitere Aufmerksamkeit zu benötigen. Ich wünsche viel Freude mit dem Solar-LED Strahler.
 

Solar-LED Strahler im Einsatz
 

Download: solar_led.c

/*
* solar_led.c : Solar LED with ATtiny45
*
* Fuse: CKDIV8 cleared. All other fuses remain at default.
*
* Pin assignment:
* PB0 - pin 5: output controls the power to the solar lamp
* ADC3 (PB3) - pin 2: input from battery pack
* ADC2 (PB4) - pin 3: input from solar panel
* ADC1 (PB2) - pin 7: input from output power
*
* First version: 31-Oct-2016
* Last update: 29-Jul-2017
* Author : Stephan Laage-Witt
*/

#define F_CPU 8000000

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <util/delay.h>

// ADC channels
#define ADC_BATTERY 3
#define ADC_SOLAR 2
#define ADC_OUT 1

// pin definitions
#define BIT_POWER_SWITCH 1

// ADC threshold values. Calulation: ADC value = target_voltage * (33 / 133) * (1024 / 1100)
#define BATT_LOW 692 // threshold to switch LED off: 3.0V
#define BATT_HIGH 808 // threshold to re-enable LED: 3.5V
#define SOL_LOW 230 // solar panel threshold to switch LED on: 1.0V
#define SOL_HIGH 808 // solar panel threshold to switch LED off: 3,5V

#define VOUT_TARGET 650 // approx. 4.5 V

#define ON 255
#define OFF 0

// state definitions
#define STATE_DAY 1
#define STATE_NIGHT 2
#define STATE_BAT_LOW 3
#define STATE_TIME_OUT 4

// timing parameters
#define TIME_OUT 14400 // 4 hours * 60 min * 60 sec
#define SWITCH_DELAY 300 // 5 min * 60 sec

// global variables ----------------------------------------------------------------------------------
volatile uint8_t interrupt_cnt = 0; // interrupt counter

/* interrupt service handler for watchdog timer ------------------------------------------------------*/
ISR(WDT_vect) {
WDTCR |= (1 << WDIE); // wake up CPU and re-enable watchdog interrupt - that's all
}

/* switch_lamp -----------------------------------------------------------------------*
* Switches LED output on or off. Sets OCR0A and PortB / BIT_POWER_SWITCH
* Changes sleep mode: "idle" for lamp on, "power down" for lamp off
* Input: mode (ON or OFF)
*/
void switch_lamp(const uint8_t mode) {
if (mode == ON) {
TCCR0A = (1 << COM0A0) | (1 << COM0A1) | (0 << COM0B0) | (0 << COM0B1); // connect OC0A to compare match, OC0B disconnected (p. 78)
TCCR0A |= (1 << WGM01) | (1 << WGM00); // set OC0A on compare match (data sheet page 101)
TCCR0B = (0 << CS02) | (0 << CS01) | (1 << CS00); // no pre-scaling
OCR0A = 255; // begin without voltage step-up, and increase it from here
PORTB &= ~(1 << BIT_POWER_SWITCH); // switch LED power on
set_sleep_mode(SLEEP_MODE_IDLE); // set sleep mode to "idle", keep timer for PWM running
return;
};
if (mode == OFF) {
PORTB |= (1 << BIT_POWER_SWITCH); // switch power off
TCCR0A = 0; // stop PWM on OCR0A
TCCR0B = 0;
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // set sleep mode to "power down"
};
}

/* adjust_vout -----------------------------------------------------------------------*
* Sets OCR0A depending on adc_out
* Iterative calls ensure approximation to targeted output voltage
* Input: adc_out - measurement of current output voltage
*/
void adjust_vout(const uint16_t adc_out) {
if (adc_out < VOUT_TARGET) {
if (OCR0A > 120)
OCR0A = OCR0A - 1;
};
if (adc_out > VOUT_TARGET) {
if (OCR0A < 255)
OCR0A = OCR0A + 1;
};
}

/* get_adc --------------------------------------------------------------------------------*
* Reads ADC
* Input: ADC channel
* Returns: ADC value (16 bit, right adjusted)
*/
uint16_t get_adc(const uint8_t adc_channel) {
ADMUX = (1<<REFS1) | adc_channel; // set channel
ADCSRA |= (1<<ADSC); // start ADC conversion
while ((ADCSRA & (1 << ADSC)) > 0); // wait for the end of the conversion
return(ADCW); // return result
}

/* main -----------------------------------------------------------------------------------*/
int main(void)
{
uint8_t current_state = STATE_DAY;
uint16_t time_count = 0, switch_count = 0;

DDRB = 0b11100011; // set OC0A and PB1 to output, and ADC channels to input
PORTB = 0b11100010; // switch off power and pull up resisters

// show that we are alive
_delay_ms(1000);
PORTB &= ~(1 << BIT_POWER_SWITCH); // switch power on
_delay_ms(2000); // keep it on for 2 seconds
switch_lamp(OFF); // initial status: lamp off

// setup watchdog timer
cli(); // disable all interrupts
MCUSR = 0; // clear MCU status register
WDTCR = 0;
WDTCR = (1 << WDIE) | (0 << WDP3) | (1 << WDP2) | (1 << WDP1) | (0 << WDP0); // setup watchdog for interrupt (not reset), 1 sec cycle time
sei(); // enable interrupts - system is up and running

while (1) {

// initialize ADC
ADMUX = (1<<REFS1) | (1<<REFS0) | (0<<ADLAR); // 10 bit, right adjusted, internal reference 1.1V
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (0<<ADPS1) | (0<<ADPS0); // scaling factor: 16 -> 62500 kHz
get_adc(ADC_SOLAR); // run the ADC, but ignore the result of the first conversion

switch (current_state) {

case STATE_DAY:
if (get_adc(ADC_SOLAR) < SOL_LOW) {
++switch_count;
if (switch_count >= SWITCH_DELAY) {
current_state = STATE_NIGHT;
time_count = 0;
switch_count = 0;
switch_lamp(ON);
};
} else {
switch_count = 0;
};
break;

case STATE_NIGHT:
if (time_count >= TIME_OUT) {
current_state = STATE_TIME_OUT;
switch_count = 0;
switch_lamp(OFF);
} else if (get_adc(ADC_BATTERY) < BATT_LOW) {
current_state = STATE_BAT_LOW;
switch_count = 0;
switch_lamp(OFF);
} else if (get_adc(ADC_SOLAR) > SOL_HIGH) {
++switch_count;
if (switch_count >= SWITCH_DELAY) {
current_state = STATE_DAY;
switch_count = 0;
switch_lamp(OFF);
};
} else {
switch_count = 0;
};
adjust_vout(get_adc(ADC_OUT));
++time_count;
break;

case STATE_TIME_OUT:
case STATE_BAT_LOW:
if (get_adc(ADC_SOLAR) > SOL_HIGH) {
++switch_count;
if (switch_count >= SWITCH_DELAY) {
current_state = STATE_DAY;
};
} else {
switch_count = 0;
};
break;
};

// shut down ADC to save energy
ADCSRA = (0<<ADEN); // switch off ADC
ADMUX = (0<<REFS1) | (0<<REFS0) | (0<<ADLAR); // switch off internal reference 1.1V

// good night (for one second)
sleep_mode();
}
}


Messung der Batteriespannung von Juergen Schimmer

Ein sehr hübsches Design - ich hatte jetzt noch eine Idee, den Ruhestrombedarf noch weiter zu reduzieren und noch einen Pin freizubekommen - was lassen sich mit einem übrig gebliebenen Pin alles für Zusatzfunktionen hinzubasteln...). Bei den ATinys lässt sich der Kehrwert der Versorgungsspannung dadurch messen, dass die Versorgungsspannung als Referenz verwendet wird ( REFS[2:0] = 000 ) und die Referenzspannung über den Multiplexer an den Eingang des ADC gelegt wird. ( Mux[3:0] = 1100 ). Damit wird der Pin2 ( ADC3  ) frei, und je ein 33k und 100k Widerstand können entfallen. Damit sinkt der Ruhestrombedarf nochmals um fast 3uA. Jetzt ergibt sich nur noch das Problem - was machen mit dem freien Portpin - er ruft ja geradezu nach einer Aufgabe...





Elektronik-Labor   Projekte   AVR