3.7 MPPT (Maximum Power Point Tracking) bei Gartenleuchten-Zeug? (🚧)
Ein Paket mit Werbegeschenken von Würth-Solar: Solar-Ladegerät für 2 NiMH Zellen brachte mich auf die (Schnaps-) Idee.
Für viele (IoT-) Projekte brauche ich eine leistungsstarke Spannungsversorgung im Aussenbereich mit ordentlicher Gangreserve. LiIon-Akkus aus Mobiltelefonen oder Akkupacks ohne Balancer usw. liegen in der Bastelkiste. Solarmodule aus defekten Gartenleuchten ebenso. Könnte man diese Reste nicht sinnvoll weiter verwenden?
Solarzellenspannung für LiIon-Zelle erhöhen
Gute Gartenleuchten und auch das Würth-Solar-Ladegerät laden 2 NiMH Zellen und haben 8 Solarzellen in Reihe, was max. ca. 4V ergibt, ist zu wenig einen LiIon-Akku zu laden. Die Spannung muss erhöht werden mit einem Schaltwandler. Dabei könnte auch gleich der beste Arbeitspunkt für einen maximalen Ladestrom automatisch eingestellt werden: Maximum Power Point Tracking📖
Testaufbau mit ATtiny84
Völlig bekloppt diesen veralteten Chip zu verwenden?
- Lagen noch 10 Stück im Regal rum
- Funktioniert schmerzfrei von 2,7..5,5V
- Hat genug freie Anschlüsse mit 10 Bit AD-Wandlung für Messungen
- Hat einen AD-Wandler, der auch Spannungsdifferenzen kann und dabei 20 fach verstärken mag!
- Hat keinen USART!
Mit Arduino programmieren
Library laden: github.com/SpenceKonde/ATTinyCore🔗
Programmer z.B. AVRISP mkII verwenden

| Beschaltung | Funktion | Arduino | Bez | Pin | Pin | Bez | Arduino | Funktion | Beschaltung |
|---|---|---|---|---|---|---|---|---|---|
| VCC | 1 | 14 | GND | ||||||
| P_LCD | XTAL1 | D10 | PB0 | 2 | 13 | PA0 | D0 | ADC0/AREF | P_VCC |
| P_TASTER | XTAL2 | D9 | PB1 | 3 | 12 | PA1 | D1 | ADC1/AIN0 | P_UBATT |
| RESET | RESET | D11 | PB3 | 4 | 11 | PA2 | D2 | ADC2/AIN1 | P_POTI |
| P_POTI_LED | INT0/OC0A | D8 | PB2 | 5 | 10 | PA3 | D3 | ADC3/T0 | P_SOLAR |
| P_LED | OC0B/ADC7 | D7 | PA7 | 6 | 9 | PA4 | D4 | ADC4/USCK/SCL/T1 | USCK / SCL |
| SDA / MOSI | OC1A/SDA/MOSI/ADC6 | D6 | PA6 | 7 | 8 | PA5 | D5 | ADC5/DO/MISO/OC1B | MISO / P_PWM |
Schaltplan

Die Solarzellenspannung (nur Solarzellen zur Landung von 2 NiMH-Akkus mit 8 Streifen, Zellen verwenden) wird mit einem Aufwärtswandler (10 kHz) an die Batteriespannung angepasst. Der Akkustrom wird über einen 2,2Ω Widerstand gemessen. Zum Einstellen bei der Entwicklung wurde ein Poti verbaut, seine Referenzspannung wird mit einer roten LED (D3) erzeugt. Nachts sollen LEDs aus einer Weihnachsbeleuchtung leuchten, dafür wird ein Abwärtswandler (497 Hz) verwendet.
Eine prima Dimensionierungshilfe für die Induktionen: Dimensionierung von Schaltnetzteilen🔗
Für die Spannungmessungen wird der 10Bit-AD-Wandler mit der internen Referenzspannung von 1,1V betrieben, daher müssen die zu messenden Spannungen geteilt werden. Zur Messglättung dienen 100nF Keramikkondensatoren.

| 3890 | B 394 | V 397 |
| Solarspannung in mV: 3,890V | Batteriespannung in cV: 3,94V | VCC in cV: 3,97V |
| PW 11 | 11 | 74% |
| Pulsweite 11µs | Strom in Akku 11mA | Ladezustand Akku 74% |
Probleme mit AD-Differenzmessung bei ATtiny84
Diesen µC habe ich u.a. gewählt weil er die Möglichkeit bieten soll die Differenzspannung von zwei AD-Eingängen zu messen und diese sogar 20fach verstärken kann.
Ich wollte den Strom-Messwiderstand R6 möglichst klein machen (zunächst 1Ω) um keine Energie zu verschwenden. In der aktuellen ATTinyCore🔗-Lib 1.5.2 von SpenceKonde kann noch nicht differnzielle Messung eingestellt werden. Auf seiner Github-Seite stellt er eine Beta-Lib 2.0 zur Diskussion: Für ATtiny84 lesen🔗
Ich habe zunächst versucht mit der alten Lib und eigenem Code die Strommessung durch zu führen und bin gescheitert. Mit seiner neuen Lib hat es nicht besser funktioniert: Beim ATtiny84 kann bei Differenzmessung wohl nur VCC als Referenzspannung eingestellt werden, weder die interne 1,1V Referenz noch eine externe Referenz sind dafür verwendbar. Auch der Bipolar-Modus hat bei mir nicht sinnvoll funktioniert.
Bin letztlich von der Differenzmessung abgerückt und habe R6 durch 2,2Ω ersetzt um aussagekräftige Spannungsdifferenzen ermitteln zu können. Auch in Hinblick auf ESP32, dessen AD-Wandler keine Differenz-Messung hat?
sbi(ADCSRB,7); // Bipolarmode im Setup setzen
int readIbatt(){ // Differenzwert von PA0 und PA1
ADMUX = 0b00001001; // siehe S129 Datenblatt
delay(2);
ADCSRA |= (1 << ADSC);
while(ADCSRA & (1<<ADSC)); // warten Messung fertig
return ADCW;
}
Stromsparorgie
Letztlich soll die Schaltung mehr einbringen als sie verbraucht.
- LCD Hintergrundbeuchtung ausschalten
- LCD Power-LED abklemmen
- LCD Spannungsversorgung abschalten
- µC schlafen schicken, er wacht allerdings ca. 494 mal in der Sekunde durch den Timer0 Overflow-Interrupt wieder auf, dieser ist für millis() verantwortlich.
Bin von ca. 7mA bei 0,7mA bei ausgeschalteter LCD und 2,7mA mit LCD-Anzeige gelandet.

Software (🚧)
Ist noch nicht ordentlich getestet, das “Nachtlicht” ist langweilig.
#include <Wire.h> // Wire Bibliothek einbinden
#include "wiring_private.h"
#include <LiquidCrystal_PCF8574.h>
#include <avr/sleep.h>
#define P_VCC 0 // D0 Spannungsteiler Spannung VCC
#define P_UBATT 1 // D1 Spannungsteiler Spannung Akku
#define P_POTI 2 // D2 Einstell-Poti
#define P_SOLAR 3 // D3 Spannungsteiler Spannung Solarzelle
#define P_PWM 5 // D5 PWM-Signal für Wandler
#define P_LED 7 // D7 LED
#define P_POTI_LED 8 // D8 Spannung für Poti
#define P_TASTER 9 // D9 Taster gegen GND zur Steuerung
#define P_LCD 10 // D10 LCD-Spannung schalten
#define PWM_MIN 6 // minimale Pulsbreite in us
#define PWM_MAX 40 // maximale Pulsbreite in us
#define ANZ_MESSUNG 10 // Anzahl Messungen fürs Mitteln
LiquidCrystal_PCF8574 lcd (0x27); // LCD-Adresse auf 0x27 für 16 Zeichen und 2 Zeilen ein
enum zustandstyp {RUHE_ENTRY,RUHE,LADEN_ENTRY,LADEN,VOLL,NACHT}; // Aufzaehlungstyp
enum zustandstyp zustand = RUHE_ENTRY; // Startzustand
void setup() {
pinMode(P_LCD,OUTPUT);
pinMode(P_LED,OUTPUT);
pinMode(P_POTI_LED,OUTPUT);
pinMode(P_TASTER,INPUT_PULLUP);
analogReference(INTERNAL); // 1,1V intern
//digitalWrite(P_POTI_LED,1); // Poti für Einstellungen einschalten
TCCR1A = 0b00100011; // Ausgang OC1B bei 0 setzen und bei OCR1B loeschen
TCCR1B = 0b00011001; // Waveform Generation Mode: Fast PWM it OCR1A als Top, Timer mit CPU-CLK
OCR1A = 100; // Timer 10kHz
set_sleep_mode(SLEEP_MODE_IDLE);
}
int a,ladung;
uint8_t pwm=0,messungen=0,nachtlicht=0;
int8_t richtung = 1,nlRichtung=2; // Suchrichtung für PWM
int32_t uSolar,uSolarGlatt,uBatt,vcc,iBatt,iBattSum=0,iBattSumAkt=0,iBattSumAlt=0;
uint32_t oldmillis=0;
bool messungFertig=false;
bool oldTaster=false;
bool lcdAn=false;
bool taster(){ // Taste gedrückt?
bool ausgabe = false;
bool test = !digitalRead(P_TASTER); // Taster ist low aktiv
if (oldTaster != test){ // hat sich was getan?
delay(10); // 10 ms warten
test=!digitalRead(P_TASTER); // noch mal einlesen
if (oldTaster != test){ // immer noch anders?
ausgabe = !oldTaster & test; // steigende:fallende Flanke
oldTaster = test;
}
}
return ausgabe;
}
void einschaltenLCD(){
digitalWrite(P_LCD,1);
delay(100);
lcd.begin(16, 2); // LCD initialisieren
lcd.clear(); // Displaypuffer löschen
lcd.setBacklight(0); // Hintergrundbeleuchtung aus
lcd.setCursor(0,0); // Cursor auf erstes Zeichen, erste Zeile setzen
}
void lcdAusgabe(){
lcd.setCursor(0,0);
uSolarGlatt=(uSolarGlatt*9+uSolar)/10;
lcd.printf("%4d ",uSolarGlatt); // mehr als 1 Parameter scheint nicht zu funktionieren
lcd.printf("B %3d ",uBatt/10);
lcd.printf("V %3d",vcc/10);
ladung=(uBatt-3200)/10;
lcd.setCursor(0,1);
lcd.printf("PW %2d ",pwm); //pwm
lcd.printf("%4d ",iBatt);
lcd.printf(" %3d%%",ladung);
}
void messung(){
//digitalWrite(P_LED,!digitalRead(P_LED));
uSolar=analogRead(P_SOLAR);
uSolar=uSolar*3933/928;
uBatt=analogRead(P_UBATT);
uBatt=uBatt*3820/902;
vcc=analogRead(P_VCC);
vcc=vcc*3783/888;
//a=analogRead(P_POTI)/4;
iBattSum+=vcc-uBatt;
messungen++;
if(messungen>=ANZ_MESSUNG){
messungFertig=true;
iBattSumAkt=iBattSum;
iBatt=iBattSum*28/58/ANZ_MESSUNG;
messungen=0;
iBattSum=0;
}
if(lcdAn){
lcdAusgabe();
if(taster()){
lcdAn=false;
digitalWrite(P_LCD,0);
}
}
else{
if(taster()){
lcdAn=true;
einschaltenLCD();
}
}
switch(zustand){
case RUHE_ENTRY:
pinMode(P_PWM,INPUT); // PWM abschalten
pwm=0;
analogWrite(P_LED,0);
nachtlicht=10;
zustand = RUHE;
break;
case RUHE:
if(uSolar>3000) zustand = LADEN_ENTRY;
if(uSolar<1000&&uBatt>3500) zustand = NACHT;
break;
case LADEN_ENTRY:
pwm=PWM_MIN;
OCR1B = pwm;
pinMode(P_PWM,OUTPUT); // PWM einschalten
richtung=1; // nach oben
messungen = 0;
iBattSum=0;
iBattSumAlt=0;
zustand = LADEN;
break;
case LADEN:
if(messungFertig){
if(iBattSumAkt>iBattSumAlt){
pwm+=richtung;
}
else{
richtung = (richtung>0)?-1:1;
pwm+=richtung;
}
messungFertig=false;
iBattSumAlt=iBattSumAkt;
if(pwm<PWM_MIN)pwm=PWM_MIN;
if(pwm>PWM_MAX)pwm=PWM_MAX;
OCR1B = pwm;
}
if(uSolar<2500) zustand=RUHE_ENTRY; // wenn es dunkel wird
if(uBatt>4100){ // bei 90%
zustand=VOLL;
OCR1B = pwm = 1;
}
break;
case VOLL:
if(uSolar<2500) zustand=RUHE_ENTRY; // wenn es dunkel wird
if(uBatt<4000) zustand=LADEN_ENTRY;
break;
case NACHT:
if(uBatt<3600||uSolar>1000) zustand=RUHE_ENTRY;
if(nachtlicht>220) nlRichtung=-rand()%4-2;
else if(nachtlicht<10) nlRichtung=rand()%32+3;
nachtlicht+=nlRichtung;
analogWrite(P_LED,nachtlicht);
break;
}
}
void loop() {
if(millis()>oldmillis+500){
oldmillis=millis();
messung();
}
sleep_mode(); // enter sleep, wakes on interrupt
}
Fazit
Immense Materialschlacht für zwar großen Erkenntnis- aber kleinen Praxisgewinn? Problem war die Strom-Messung.
Ein Vergleich der Ladeleistung mit Würth-Solarladegerät für 2 NiHM-Zellen: NiHM: 2,5V * 50mA = 140mW. LiIon: 4,0V * 33mA = 132mW
Sieht doch gut aus! Betrachtet man den wesentlich besseren Wirkungsgrad beim LiIon-Laden holt die Schaltung wirklich viel Energie aus den ollen Solar-Zellen raus.
Lohnt es sich?
Wenn die Teile rumliegen, ein Aufwärtswandler notwendig ist und Entwicklungs- bzw. Bastel-Zeit keine Rolle spielen ist es eine prima Reste-Verwertung.
Wenn neu beschafft wird, können auch gleich passende Solarmodule besorgt werden.
Wie viele µC Port-Pins? Usolar, Uvcc, Ubatt, PWM -> 4
Ausblick ohne MPPT
Bei Ziel IoT mit ESP32 sind die freien Ports beschränkt.
Für 1,70 pro Stück habe ich 5V 60mA Solarmodule (68mmx37mm) bestellt🔗. Der Ladestrom eines LiIon-Akkus war heute 21mA, der Zellen-Fläche angemessen.
Wie viele µC Port-Pins ohne MPPT? Usolar, Uvcc, Laden -> 3
