Den Arduino in den Schlaf Modus setzen und wieder aufwecken.

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.

Hier die minimale Beschaltung

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.

Register

Register

Prescaler

Prescaler

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

14 Gedanken zu „Den Arduino in den Schlaf Modus setzen und wieder aufwecken.

  1. Pingback: Vergleich der Stromaufnahme von Arduino Schaltungen, vom Uno bis zum IC im Schlafmodus auf dem Steckbrett | Shelvin – Elektronik ausprobiert und erläutert

  2. Roland

    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!

    Antworten
  3. Sebastian

    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?

    Antworten
      1. Jens

        Hallo,

        wenn ich den Code überprüfe bekomme ich einen Fehler :

        ‚watchdogOn‘ was not declared in this scope

        Was mache ich falsch ?
        Jens

        Antworten
  4. Rafael

    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.

    Antworten
  5. Johannes

    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

    Antworten
    1. admin Beitragsautor

      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

      Antworten
  6. Florian

    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

    Antworten
  7. 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

    Antworten
  8. 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

    Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.