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

9 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
  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

Schreibe einen Kommentar

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.