Mein Arduino Uno soll für eine stromsparende Anwendung in den SLEEP_MODE_PWR_DOWN Modus gesetzt werden um Strom aus dem Akku zu sparen und so eine möglichst lange Akkulaufzeit zu bekommen.
In einer normale loop() Schleife mit delay() liegt der Stromverbrauch bei gemessenen 54mA.
Im Schlaf Modus geht er auf 38mA zurück. Das ist immer noch erstaunlich viel Verbrauch, liegt aber an den zusätzlichen Elementen auf der Uno Platine. Die Power LED nimmt gut 10 mA und die USB Schnittstelle nimmt auch einiges auf.
Um wirklich Strom zu sparen macht es Sinn den Microcontroller einzeln auf einer Platine zu haben mit einer minimalen Beschaltung. Im Sleep Modus geht er dann auf unter 0,1 mA Stromaufnahme. Zum Testen nehme ich aber vorerst die Uno Platine.
Als erstes werden ein paar nicht benötigte Funktionen des Controllers abgeschaltet, das bringt gut 1mA Ersparniss im normalen Betrieb.
ADCSRA = ADCSRA & B01111111; // ADC abschalten, ADEN bit7 zu 0 ACSR = B10000000; // Analogen Comparator abschalten, ACD bit7 zu 1 DIDR0 = DIDR0 | B00111111; // Digitale Eingangspuffer ausschalten, analoge Eingangs Pins 0-5 auf 1
Dann wird der Watchdog Timer auf eine Sekunde eingestellt. Das WDTSCR Register wird mit dem Prescaler Wert 128k für 1 Sekunde gesetzt.
void watchdogOn() { MCUSR = MCUSR & B11110111; // Reset flag ausschalten, WDRF bit3 vom MCUSR. WDTCSR = WDTCSR | B00011000; // Bit 3+4 um danach den Prescaler setzen zu können WDTCSR = B00000110; // Watchdog Prescaler auf 128k setzen > ergibt ca. 1 Sekunde WDTCSR = WDTCSR | B01000000; // Watchdog Interrupt einschalten MCUSR = MCUSR & B11110111; }
Für den Power Down Modus gibt es noch die Funktion zum schlafen legen für mehrere Sekunden.
void pwrDown(int sekunden) { set_sleep_mode(SLEEP_MODE_PWR_DOWN); // den tiefsten Schlaf auswählen PWR_DOWN for(int i=0; i < sekunden; i++) { sleep_enable(); // sleep mode einschalten sleep_mode(); // in den sleep mode gehen sleep_disable(); // sleep mode ausschalten nach dem Erwachen } }
Und hier das komplette Programm.
Im Hauptprogramm wird die LED 13 für 1 Sekunde eingeschaltet, der Zähler k wird seriell ausgegeben und dann geht der Uno 10 Sekunden schlafen.
// Arduino Uno runter fahren und wieder aufwecken. // // Matthias Busse 7.9.2014 Version 1.0 #include < avr/sleep.h> volatile int sleepcounter = 0; // Schlafzyklen mitzählen int k=0, led=13; void setup() { Serial.begin(115200); pinMode(led, OUTPUT); watchdogOn(); // Watchdog timer einschalten. ADCSRA = ADCSRA & B01111111; // ADC abschalten, ADEN bit7 zu 0 ACSR = B10000000; // Analogen Comparator abschalten, ACD bit7 zu 1 DIDR0 = DIDR0 | B00111111; // Digitale Eingangspuffer ausschalten, analoge Eingangs Pins 0-5 auf 1 } void loop(){ digitalWrite(led, HIGH); delay(100); // delay für serielle Ausgabe Serial.println(k); k++; delay(900); // delay für serielle Ausgabe beenden digitalWrite(led, LOW); pwrDown(10); // ATmega328 fährt runter für 10 Sekunden; } void pwrDown(int sekunden) { set_sleep_mode(SLEEP_MODE_PWR_DOWN); // den tiefsten Schlaf auswählen PWR_DOWN for(int i=0; i < sekunden; i++) { sleep_enable(); // sleep mode einschalten sleep_mode(); // in den sleep mode gehen sleep_disable(); // sleep mode ausschalten nach dem Erwachen } } void watchdogOn() { MCUSR = MCUSR & B11110111; // Reset flag ausschalten, WDRF bit3 vom MCUSR. WDTCSR = WDTCSR | B00011000; // Bit 3+4 um danach den Prescaler setzen zu können WDTCSR = B00000110; // Watchdog Prescaler auf 128k setzen > ergibt ca. 1 Sekunde WDTCSR = WDTCSR | B01000000; // Watchdog Interrupt einschalten MCUSR = MCUSR & B11110111; } ISR(WDT_vect) { sleepcounter ++; // Schlafzyklen mitzählen }
Hier gibt es ein paar Alternativen und Erläuterungen zum Thema.
Und hier eine Minimalbeschaltung des ATMEGA168.
von Matthias Busse
Pingback: Vergleich der Stromaufnahme von Arduino Schaltungen, vom Uno bis zum IC im Schlafmodus auf dem Steckbrett | Shelvin – Elektronik ausprobiert und erläutert
Hallo, ich komme mit der avr/sleep Library nicht zurecht. Auf Github habe ich diese gefunden, aber wie kann ich diese downloaden bzw. installieren?
Vielen Dank im voraus!
Hi, danke für den Artikel.
Ist sehr hilfreich und macht bei mir ca ~40mA aus (60mA -> 20mA)
Hallo,
bei mir bleibt nach der Programmierung wie oben beschrieben der Arduino Uno in der void Setup () hängen. Was mache ich denn hier bitte falsch?
Vor avr muss das Leerzeichen weg.
Habe ich gemacht…
Hallo,
wenn ich den Code überprüfe bekomme ich einen Fehler :
‚watchdogOn‘ was not declared in this scope
Was mache ich falsch ?
Jens
Das klappt ja Prima. Ich verwende statt WDT eine Steigende Flanke an INT0 zum aufwecken.
//attachInterrupt(digitalPinToInterrupt(2), erfassung, RISING);
//void erfassung() { }
Die reduzierte Stromaufnahme von < 0.1mA kann ich bestätigten.
Im Power Down nahm mein externer Aufbau nur noch 63µA auf.
Mich Irritierten die Angaben im Datenblatt des µC da diese noch tiefer lagen.
Nachdem ich in den FUSEBITs bei Brownout Detection von 2.7V auf deaktiviert umgestellt hatte
lag der Strom bei mir sogar < 1µA wie im Datenblatt beschrieben.
Wo gibt es die Library die du eingebunden hast?
#include
Ich finde keine Website wo man es runterladen kann.
Und was für ein Modul hast du für den Watchdog gekauft?
Über eine Antwort wäre ich sehr dankbar.
Grüße Johannes
Die Library avr/sleep.h wurde bei mir mit dem Arduino Programm installiert.
Der Watchdog Timer ist im Arduino und kein extra Teil, die Tabellen sind aus dem Datenblatt des verbauten ATmega328P.
Grüße, Matthias
Hallo zusammen,
vielen Dank für das bereitgestellte Programm, funktioniert bei mir am Arduino Nano super.
Ich verwende es um alle ca. 15 min. einen Dämmerungssensor über einen DI auszulesen.
Allerdings möchte ich jetzt auf das fertige Modul des Dämmerungssensors verzichten und direkt einen Fotowiderstand einlöten und über einen AI auslesen.
Mein Problem dabei ist, dass die Analogeingänge nicht ausgelesen werden können was an den Zeilen im Programm:
ADCSRA = ADCSRA & B01111111; // ADC abschalten, ADEN bit7 zu 0
ACSR = B10000000; // Analogen Comparator abschalten, ACD bit7 zu 1
DIDR0 = DIDR0 | B00111111; // Digitale Eingangspuffer ausschalten, analoge Eingangs Pins 0-5 auf 1
liegt.
Wie würdet ihr dies im Programm am besten umsetzen da ich ohne diese Zeilen ca. 0,2 mA mehr Strom benötige und deshalb nicht darauf verzichten möchte.
Können die Analogen Eingänge jedes mal vor dem Auslesen aktiviert werden und danach ca. 1s später wieder deaktiviert?
Vielen Dank im Voraus für Eure Antwort.
Gruß
Florian
Hallo,
verwende das Programm funktioniert super
Hallo,
verwende das Beispielprogramm um das Signal eines Dämmerungssensor alle 15min. auszulesen.
Soweit funktioniert das Programm super und der Stromverbrauch meines mini pro liegt bei 1,5mA.
Allerdings möchte ich nun den Dämmerungssensor direkt durch einen Fotowiderstand ersetzen.
Dabei habe ich Probleme beim Auslesen des Analogen Eingangs was denke ich an den Zeilen liegt:
ADCSRA = ADCSRA & B01111111; // ADC abschalten, ADEN bit7 zu 0
ACSR = B10000000; // Analogen Comparator abschalten, ACD bit7 zu 1
DIDR0 = DIDR0 | B00111111; // Digitale Eingangspuffer ausschalten, analoge Eingangs Pins 0-5 auf 1
Wie würdet Ihr mein Problem lösen ist es möglich alle 15min. vor dem Auslesen die analogen Funktionen zu aktivieren und danach wieder zu deaktivieren?
Gruß
Florian
Hallo,
verwende das Beispielprogramm um das Signal eines Dämmerungssensor alle 15min. auszulesen.
Soweit funktioniert das Programm super und der Stromverbrauch meines mini pro liegt bei 1,5mA.
Allerdings möchte ich nun den Dämmerungssensor direkt durch einen Fotowiderstand ersetzen.
Dabei habe ich Probleme beim Auslesen des Analogen Eingangs was denke ich an den Zeilen liegt:
ADCSRA = ADCSRA & B01111111; // ADC abschalten, ADEN bit7 zu 0
ACSR = B10000000; // Analogen Comparator abschalten, ACD bit7 zu 1
DIDR0 = DIDR0 | B00111111; // Digitale Eingangspuffer ausschalten, analoge Eingangs Pins 0-5 auf 1
Wie würdet Ihr mein Problem lösen ist es möglich alle 15min. vor dem Auslesen die analogen Funktionen zu aktivieren und danach wieder zu deaktivieren?
Gruß
Florian
Pingback: Funk – Temperatursensoren mit dem Arduino - Programmieren und mehr...