Sleep Mode

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

Sleep Mode, auf deutsch Schlafmodus, bezeichnet den Zustand eines Mikrocontrollers, in dem verschiedene Funktionsblöcke wie Timer, UART, AD-Wandler etc. deaktiviert sind, um Strom zu sparen. Das ist vor allem in batteriebetriebenen Geräten wichtig, denn schließlich möchte man eine möglichst lange Laufzeit mit einer möglichst kleinen Batterie erreichen.

Mit dem Sleep Mode eng verknüpft ist das Ultra low power Design. Man muss viele Dinge beachten, um nicht unnötig Strom zu verbrauchen. Z. B. werden in vielen Geräten über lange Zeiträume Daten erfaßt (Datenschreiber). Dabei werden meist relativ wenig Daten in sehr langen Zeitabständen aufgezeichnet und gespeichert. Zwischendurch gibt es für den Mikrocontroller meist nichts zu tun. Dann ist es nicht sinnvoll in Warteschleifen Zeit zu vertrödeln. Das geht wesentlich stromsparender.

Die Ausführungen dieses Wikiartikels beziehen sich auf den AVR ATmega32. Prinzipiell gilt das Gesagte auch für viele andere Mikrocontroller (MSP430, 8051,EFM32 etc.), die Details muss man jedoch in den jeweiligen Datenblättern nachlesen. Bei den verschiedenen AVR Modellen findet man diese Informationen im Datenblatt unter der Überschrift "Power Management and Sleep Modes".

Flussdiagramm zu Anwendung von Sleep Modi

Anwendung

Das Prinzip ist immer gleich: Nach Initialisierung des Mikrocontrollers und eventuell angeschlossener ICs (LCD, I2C-EEPROM etc.) geht der Prozessor in eine Endlosschleife, in welcher die verschiedenen Aufgaben zyklisch bearbeitet werden. Wenn jedoch gerade nichts zu tun ist geht der Prozessor schlafen. Ein Interrupt weckt ihn, der Interrupt wird ausgeführt und er setzt seine Arbeit in der Hauptschleife fort. Das heißt aber auch, daß vor dem Eintritt in den Sleep-Mode die jeweiligen Interrupts freigegeben werden müssen und auch die entsprechenden Interruptroutinen bereitgestellt werden müssen. Sonst gibt es im wahrsten Sinne des Wortes ein böses Erwachen oder einen endlosen Dornröschenschlaf, der nur durch ein Reset beendet werden kann. Kurz bevor der Mikrocontroller schlafen geht, sollte man möglichst alle Module abschalten, welche nicht gebraucht werden, um wertvollen Strom zu sparen. Dazu zählen

Weitere Hinweise zum Stromsparen gibt es im Artikel Ultra low power.

Überblick über alle Sleep Modes der AVRs

Sleep Mode Verfügbare
Module
Strom-
aufnahme
3,3V/1 MHz
[μA]
Weckruf
Aufwach-
zeit
[Takte]
Bemerkung
Active alle 1200 alle 0 -
Idle alle 300 alle 6 -
ADC Noise
Reduction
ADC
Timer 2
ext. Interrupts
TWI
Watchdog
300 ADC
Timer 2
ext. low level Interrupt
TWI Address match
Brown Out Detector
External Reset
Watchdog Reset
PCINT
6 -
Stand By ext. Interrupts
TWI
Watchdog
35 ext. low level Interrupt
TWI Address match
Brown Out Detector
External Reset
Watchdog Reset
PCINT
6 Hauptoszillator aktiv
Power Save Timer 2
ext. Interrupts
TWI
Watchdog
10 Timer 2
ext. low level Interrupt
TWI Address match
Brown Out Detector
External Reset
Watchdog Reset
PCINT
siehe
hier
Timer2 mit 32,768 kHz
Uhrenquarz aktiv
Power Down ext. Interrupts
TWI
Watchdog
0,3 ext. low level Interrupt
TWI Address match
Brown Out Detector
External Reset
Watchdog Reset
PCINT
siehe
hier
-

Die verschiedenen Sleep Modes im Detail

Active Mode

Eigentlich ist das kein Sleep Mode, er soll der Vollständigkeit halber aber genannt werden. In diesem Modus sind alle Takte und alle Module aktiv, zumindest die, die man per Programm aktiviert hat. In diesem Modus ist die CPU ständig am arbeiten, auch wenn es nur eine lange Warteschleife ist. Warten kostet genauso viel Strom wie sinnvolle Dinge zu berechnen! Dadurch werden auch ständig Daten aus dem Flash geladen, nämlich das Programm, welches gerade ausgeführt wird. Das kostet natürlich Strom, wenngleich auch die Mikrocontroller von heute sehr wenig brauchen. Bei 1 MHz und 3,3 V braucht der ATmega ca. 1,2 mA; zu finden im Datenblatt unter "ATmega8 Typical Characteristics".

Idle Mode

Hier kann zum ersten mal gespart werden. Wenn nichts berechnet werden soll, der Timer, UART, ADC etc. aber arbeiten sollen, dann ist dieser Modus das Mittel der Wahl. Die CPU bleibt stehen, ebenso der Flash, weil ja kein Programm ausgeführt wird. Das spart schon mal einiges, der Stromverbrauch sinkt auf ca. 0,35 mA, eine Einsparung von 70 %. Aus diesem Modus kann jeder Interrupt die CPU wieder wecken. Sie ist dann bereits nach sechs Takten wieder voll einsatzfähig.

ADC Noise Reduction Mode

Dieser Modus geht einen kleinen Schritt weiter als der Idle Mode. Hier wird zusätzlich der Takt für die IO-Module abgeschaltet. Nur noch der AD-Wandler, die externen Interrupts, das TWI und der Watchdog sind funktionsfähig (wenn man sie nutzen will). Der UART und Timer0 bzw. Timer1 sind nicht mehr nutzbar. Wie der Name des Sleep Mode vermuten lässt, wird das alles getan, um möglichst wenig Störungen mit den internen Modulen zu erzeugen, um die Messung des ADC geringfügig zu verbessern.

Power Save Mode

Hier werden fast alle Oszillatoren gestoppt. Die einzige Ausnahme ist der Timer2, welcher asynchron mit einem 32,768-kHz-Uhrenquarz betrieben werden kann. Ist er entsprechend konfiguriert, dann bleibt er beim Einschalten des Power Save Mode aktiv. Dieser Modus ist einer der wichtigsten. Da alle Oszillatoren gestoppt sind, funktionieren nur noch die asynchronen Module.

Bei neueren AVR-Typen (z. B. ATMega88/ATMega644) kann Timer2 wahlweise auch mit dem internen Oszillator weiterlaufen. In dem Fall braucht es keinen externen Uhrenquarz.

Stand By

Hier werden alle Takte auf dem IC angehalten. ABER! Der ausgewählte Hauptoszillator läuft weiter. Das kostet zwar etwas Strom, hat aber den Riesenvorteil, daß die CPU nach dem Aufwachen nach nur sechs Takten wieder zur Verfügung steht. Das klingt selbstverständlich, ist es aber nicht! Gerade Quarzoszillatoren haben auf Grund ihrer sehr hohen Güte (sehr schmalbandiger Schwingkreis) eine Einschwingzeit von 10...100 ms! Eine kleine Ewigkeit. Dieser Modus ist ideal, wenn ein Quarz verwendet wird und kürzeste Reaktionszeiten nach dem Aufwecken nötig sind. Da alle Takte gestoppt sind, funktionieren nur noch die asynchronen Module.

Power Down Mode

Das ist der "tiefste" Sleep Mode. Dabei werden ALLE außer dem Watchdog-Takt, falls aktiviert) Oszillatoren gestoppt, intern wie extern. Nur asynchrone Module funktionieren jetzt noch und können den schlafenden AVR wecken. Die Stromaufnahme wird nur noch von den Leckströmen bestimmt und liegt typisch bei 300 nA.

Morgenmuffel

Im Power Save und Power Down Mode ist der Oszillator für die CPU gestoppt. Wird der AVR nun geweckt, kann er leider nicht sofort loslegen. Warum? Weil der Oszillator erst anlaufen und sich stabil einschwingen muß. Während dieser Zeit darf die CPU noch nicht loslaufen, sonst kann es passieren, daß sie abstürzt (weil ein noch instabiler Oszillator ultrakurze Taktpulse erzeugen kann, an denen sich die CPU "verschluckt".) Wie bereits oben gesagt, kann das Anschwingen eines Quarzoszillators sehr lange dauern. Je niedriger die Frequenz um so länger. Keramikresonatoren sind ca. zehn mal so schnell. Auch das ist ganz einfach physikalisch durch die Güte bestimmt. Sie sind breitbandiger, dadurch zwar ungenauer aber schwingen schneller an. Am schnellsten sind RC-Oszillatoren, leider sind sie aber auch die ungenauesten. Um nun die entsprechende Zeit zu warten wird der Watchdog-Oszillator verwendet. Darum muß man sich nicht direkt kümmern, das macht der AVR allein. Aber man muß mittels der AVR Fuses festlegen, wieviele Takte gewartet werden soll. Die Frequenz des Watchdogoszillators beträgt ca. 1,15 MHz bei 3,3 V Versorgungsspannung.

Taktquelle Wartezeit
[Takte]
Wartezeit
[μs]
typische
Einschwingzeit
externer Quarz (1) 16384
32768
14200
28400
10 ms, Uhrenquarze 100 ms
externer Resonator (1) 1024
16384
890
14200
1 ms
externer Takt 6 5 Takt liegt konstant an
externer RC-Oszillator 6
18
5
15
1...3 Takte
interner RC-Oszillator 6 5 1...3 Takte

(1) Es können für den Quarz bzw. Resonator auch niedigere Wartezeiten verwendet werden. Das ist jedoch nicht empfehlenswert. Näheres siehe Datenblatt.

Ermittlung des Stromverbrauchs

Bei der Messung des Stromverbrauchs haben wir jedoch ein kleines Problem. Die Stromaufnahme eines Mikrocontrollers schwankt bei der Verwendung des Sleep Mode gewaltig. Denn oft wartet der Mikrocontroller im Schlafmodus auf ein Ereignis, z. B. einen Tastendruck. Wird eine Taste gedrückt arbeitet der Mikrocontroller beispielsweise für 100ms und geht dann wieder für Sekunden bis Tage schlafen. Die stoßartige Arbeitsweise (Burst) gleicht einer PWM. Das Problem ist dabei, dass man theoretisch mit einem Tiefpass diese PWM filtern (glätten) muss um sie anschließend mit einem Multimeter zu messen. Aber wer will schon einen Tiefpass mit einer Zeitkonstante von mehreren Minuten bis Tagen bauen und damit messen? Das Problem muss anders gelöst werden. Und das ist recht leicht.

  • Mit einem Multimeter misst man die Stromaufnahme im Sleep Mode (Mikroampere)
  • Mit einem Reihenwiderstand von 10..100 Ω in der Vcc Leitung des Mikrocontrollers und einem Oszilloskop kann die Stromaufnahme des Mikrocontrollers während der kurzen aktiven Arbeitsphase gemessen werden. Dazu braucht man nur das ohmsche Gesetz, I = U / R. Dabei nutzt man einen 1:1 Tastkopf, um eine maximale Spannungsauflösung zu erreichen. Ausserdem schaltet man den Eingang auf AC-Kopplung, da ja nur Pulse gemessen werden, keine Gleichspannungen. Damit kann man vor allem den Spannungsmessbereich sehr weit runter drehen.
  • Der mittlere Stromverbrauch wird wie folgt berechnet:
[math]\displaystyle{ I_m = \frac {I_\text{sleep} \cdot t_\text{sleep} + I_\text{aktiv} \cdot t_\text{aktiv}}{t_\text{sleep} + t_\text{aktiv}} }[/math]

Batterielebensdauer

Wie übersetzen sich nun diese Zahlen in eine Batterielebensdauer? Versorgt man den AVR über drei in Reihe geschaltete AAA Batterien, kann man etwa folgende Abschätzung machen. Eine AAA Batterie (Micro) hat eine Kapazität von ca. 1200mAh. D.H. Sie kann für 1200 Stunden (50 Tage) 1mA liefern. Oder für 12000 Stunden 0,1mA, das sind immerhin schon 500 Tage, also über sechzehn Monate! Nutzt man den Power Save Mode (10µA), dann reichen die Batterien bereits 120.000 Stunden, das sind theoretisch 13,7 Jahre! Natürlich sinkt während der Entladung die Batteriespannung, aber der ATmega32 kann ja mit 2,7V betrieben werden, einige AVR-Typen sogar mit nur 1,8V. Ebenso wird es in 13 Jahren zu einer merklichen Selbstentladung der Batterien kommen, so daß die hier berechnete Zeit nicht erreicht wird. Real kann eher mit drei bis sieben Jahren gerechnet werden. Um eine hohe Lebensdauer zu erreichen müssen dann Lithiumbatterien verwendet werden, welche eine extrem geringe Selbstentladung haben und eine Lebensdauer von 10 Jahren erreichen.

Wenn man wirklich das allerletzte Mikroampere einsparen will und dennoch quarzgenau eine Zeitbasis benötigt, dann verwendet man eine Real Time Clock (RTC, Echtzeituhr), wie z. B. DS1371 oder RV-3029-C2. Diese Bausteine arbeiten auch mit einem 32,768 kHz Uhrenquarz (ggf. auch intern), sind aber extrem auf Stromsparen optimiert (Stromverbrauch 800..1100nA). Gleichzeitig ist eine Uhr und Weckfunktion eingebaut. Ausgelesen werden kann sie über den I2C-Bus. Diese RTC können den Mikrocontroller periodisch nach einer bestimmten Zeit (Sekunden bis Tage) über einen externen Interrupt wecken. Damit kann der Mikrocontroller in den Power Down Mode gehen und maximal Strom sparen. So eine Kombination aus AVR und RTC verbraucht dann nur noch ca. 1400nA! Eine kleine 3V Lithiumzelle mit 100mAh reicht dann unglaubliche 71.400 Stunden = 8 Jahre!

Allgemein gilt:

[math]\displaystyle{ \text{Lebensdauer} [h] = \frac {\mathrm{Kapazit\ddot at} [Ah] }{\text{Strom} [A]} }[/math]

Zu beachten ist, daß diese Formel nur für relativ geringe Entladeströme gilt, typisch bei einer Entladung über 20 Stunden oder länger. Will man hohe Ströme in einer kurzen Zeit entnehmen, sinkt die verfügbare Kapazität. Genaueres findet man dazu hier und im Datenblatt der Batterien.

Beispiele

Die Beispiele sind mit WINAVR 20060421 compiliert und getestet worden. Zur Nutzung des Sleep Mode werden zwei C-Funktionen zur Verfügung gestellt, set_sleep_mode() und sleep_mode(). Genaueres hierzu findet man in der Dokumentation der libc im WINAVR. Alle Programme wurden mit Optimierungsstufe -Os compiliert.

UART Terminal

Soll der UART verwendet werden kommt nur der Idle Mode in Frage. In diesem Beispiel wird der AVR genutzt um Zeichen von der RS232 Schnittstelle zu empfangen und per Morsezeichen auszugeben. Als Hauptoszillator wird ein 3,6864 MHz Quarz eingesetzt, wie für eine zuverlässige UART-Kommunikation notwendig ist. Siehe auch AVR-Tutorial, AVR Checkliste und AVR-GCC-Tutorial. Im Sleepmode verbraucht der AVR ca. 1,9mA, im aktiven Zustand mit eingeschalteter LED ca. 7,3mA.

/*
************************************************************************
*
* Sleep Mode Demo, Idle Mode
*
* ATmega32 mit externem 3,6864 MHz Quarz an XTAL1/XTAL2
*
* LOW Fuse Byte = 0xFF
*
* An PD5 muss eine LED mit 1 kOhm Vorwiderstand angeschlossen werden
* An PD0 ist ein MAX232 angeschlosssen, um Daten vom PC zu empfangen
*
************************************************************************
*/

#define F_CPU 3686400       // Taktfrequenz des Quarzes

#define BAUD 9600L          // Baudrate, das L am Ende ist wichtig, NICHT UL verwenden!
 
// Berechnungen
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000) // Fehler in Promille 

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

// globale Variablen

volatile uint8_t uart_flag;
volatile uint8_t uart_data;

// lange, variable Wartezeit, Einheit in Millisekunden

void long_delay(uint16_t ms) {
    for (; ms>0; ms--) _delay_ms(1);
}

// Ein Byte als "Morsezeichen" auf eine LED ausgeben

void morse(uint8_t data) {
    uint8_t i,j;
    
    for(i=0; i<8; i++) {
        if (data & 0x01)        // Prüfe Bit #0
            j=250;              // Bit ist 1
        else
            j=100;              // Bit ist 0

        PORTD |= (1 << PD5);    // LED an
        long_delay(j);
        PORTD &= ~(1 << PD5);   // LED aus
        long_delay(1000-j);
        data >>= 1;             // nächstes Bit auf Bit #0 schieben
    }
}


int main (void) {

// IO konfigurieren

    DDRA = 0xFF;
    DDRB = 0xFF;
    DDRC = 0xFF;
    DDRD = 0xFF;

// UART konfigurieren

    UBRRH = UBRR_VAL >> 8;
    UBRRL = UBRR_VAL & 0xFF;
    UCSRB = (1<<RXCIE) | (1<<RXEN); 

// Interrupts freigeben

    sei();
    
// Endlose Hauptschleife

    while(1) {
        set_sleep_mode(SLEEP_MODE_IDLE);
        sleep_mode();                   // in den Schlafmodus wechseln

        // hier wachen wir wieder auf
        if (uart_flag==1) {
            uart_flag =0;
            morse(uart_data);
        }
    }
}

// UART RX complete interrupt

ISR(USART_RXC_vect) {
    uart_flag = 1;              // signalisiere neue Daten
    uart_data = UDR;            // Daten auslesen, dadurch wird auch der Interrupt gelöscht
}

Quarzgenaue Zeitbasis

Hier kommt der Power Save Mode zum Einsatz. Als Zeitbasis dient ein externer 32,768 kHz Uhrenquarz, welcher asynchron den Timer 2 taktet. Das ist zwar nur ein 8 Bit Zähler, der schon nach 256 Takten überläuft, aber es gibt ja zum Glück noch den Vorteiler (Prescaler). Dieser kann die Teilerverhältnisse 1/8/32/256/1024 annehmen, daraus ergeben sich Überlaufzeiten von 7,8125ms/62,5ms/250ms/2s/8s. Werden längere Zeiten benötigt muß man diese in Software nachbilden. Z. B. kann man mit einem zwei Sekunden Intervall in einer Variable bis 30 zählen um exakt eine Minute zu erhalten. Die 30 mal aufwachen, Variable hochzählen und wieder in den Sleep Mode schalten fallen praktisch nicht ins Gewicht, das dauert nur einige Dutzend Mikrosekunden.

Das hier gezeigte Beispiel ist sehr einfach gehalten, zeigt aber deutlich die Vorgehensweise. Im quarzgenauen Zeitraster von einer Minute wird eine LED für zwei Sekunden eingeschaltet. In den realen Anwendungen wird natürliche eine Messung etc. gemacht.

/*
************************************************************************
*
* Sleep Mode Demo, Power Save Mode
*
* ATmega32 mit internem 1 MHz Oszillator + 32 kHz Quarz
*
* LOW Fuse Byte = 0xE1
*
* An PD5 muss eine LED mit 1 kOhm Vorwiderstand angeschlossen werden
* An TOSC1/TOSC2 muss ein 32,768 kHz Quarz angeschlossen sein
*
************************************************************************
*/

#define F_CPU 1000000

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

// globale Variablen

volatile uint8_t flag;

// lange, variable Wartezeit, Einheit in Millisekunden

void long_delay(uint16_t ms) {
    for (; ms>0; ms--) _delay_ms(1);
}

int main (void) {

// IO konfigurieren

    DDRA = 0xFF;
    DDRB = 0xFF;
    DDRC = 0xFF;
    DDRD = 0xFF;

// Analogcomparator ausschalten

    ACSR = 0x80;

// Timer2 konfigurieren

    ASSR  = (1<< AS2);              // Timer2 asynchron takten
    long_delay(1000);               // Einschwingzeit des 32kHz Quarzes
    TCCR2  = 6;                     // Vorteiler 256 -> 2s Überlaufperiode
    while((ASSR & (1<< TCR2UB)));   // Warte auf das Ende des Zugriffs
    TIFR   = (1<<TOV2);             // Interrupts löschen (*)
    TIMSK |= (1<<TOIE2);            // Timer overflow Interrupt freischalten
// (*) "Alternatively, TOV2 is cleared by writing a logic one to the flag."

// Interrupts freigeben

    sei();

// Endlose Hauptschleife

    while(1) {

        // WICHTIG!
        // Wenn der Timer2 im asynchronen Modus periodisch zum Wecken aus dem Sleep Mode
        // genutzt wird, dann muss vor dem Wiedereintritt mindestens
        // 1 Oszillatortakt des Timers abgewartet werden (~30us), um die Interruptlogik 
        // wieder zu aktivieren, anderenfalls wacht der AVR nicht mehr auf.
        // Die folgenden zwei Zeilen tun dies.
        // Nur wenn sichergestellt ist, dass der Interrupt + Hauptschleife länger als 30µs dauern,
        // kann man den Test weglassen

        OCR2 = 0;                       // Dummyzugriff
        while((ASSR & (1<< OCR2UB)));   // Warte auf das Ende des Zugriffs

        set_sleep_mode(SLEEP_MODE_PWR_SAVE);
        sleep_mode();                   // in den Schlafmodus wechseln

        // hier wachen wir wieder auf, nach Ausführung des Interrupts

        if (flag==1) {                  // Neues Messintervall ?
            flag =0;
            PORTD |= (1 << PD5);        // LED für 2 Sekunden anschalten
        }
    }
}

// Timer2 overflow Interrupt

ISR(TIMER2_OVF_vect) {
    static uint8_t ticks;               // Hilfsvariable für Messintervall

    ticks++;
    if (ticks==30) {                    // neues Messintervall ?
        ticks=0;
        flag=1;
    }
    PORTD &= ~(1 << PD5);               // LED ausschalten
}

Im Sleep Mode beträgt die Stromaufnahme des AVR ca. 10μA, während der zwei Sekunden LED Leuchtdauer 2,3mA. Dadurch ergibt sich ein mittlerer Stromverbrauch von

[math]\displaystyle{ I_m = \frac {10 \mu A \cdot 58s + 2,3mA \cdot 2s}{60s} = 86,3 \mu A }[/math]

Korrekterweise müßte man jedoch noch den Stromverbrauch berücksichtigen, welcher bei jedem Timerüberlauf alle zwei Sekunden entsteht. Dabei wird einmal der Timerinterrupt durchlaufen sowie einmal die Hauptschleife. Das dauert hier ca. 50 Takte, bei 1 MHz somit 50μs. Zusätzlich wird noch bis zu 30µs gewartet, um garantiert einen Takt im Timer 2 vergehen zu lassen. Das passiert pro Minute 30 mal, somit erhöht sich der mittlere Stromverbrauch um

[math]\displaystyle{ \frac {30 \cdot 80 \mu s \cdot 1,2mA}{60s}= 48nA }[/math] , was somit praktisch vollkommen vernachlässigbar ist.

Aufwachen per Tastendruck

Maximale Einsparung an Energie bringt der Power Down Modus. Das Aufwecken muß dann aber durch eine externen Interrupt erfolgen. Auch hier blinkt eine LED.

/*
************************************************************************
*
* Sleep Mode Demo, Power Down Mode
*
* ATmega32 mit internem 1 MHz Oszillator
*
* LOW Fuse Byte = 0xE1
*
* An PD5 muss eine LED mit 1 kOhm Vorwiderstand angeschlossen werden
* An PD2 muss ein Taster gegen GND angeschlossen sein
*
************************************************************************
*/

#define F_CPU 1000000

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

// lange, variable Wartezeit, Einheit in Millisekunden

void long_delay(uint16_t ms) {
    for (; ms>0; ms--) _delay_ms(1);
}

int main (void) {

// IO konfigurieren

    DDRA = 0xFF;
    DDRB = 0xFF;
    DDRC = 0xFF;
    DDRD = 0xFB;        // PD2 = INT0 = Eingang
    PORTD = 0x04;       // Pull Up aktivieren

// Analogcomparator ausschalten

    ACSR = 0x80;

// Interrupt konfigurieren

    MCUCR &= ~0x3;              // levelgesteuerter Interrupt an INT0

// Interrupts freigeben

    sei();
    
// Endlose Hauptschleife

    while(1) {

        GICR |= (1 << INT0);            // externen Interrupt freigeben

        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
        sleep_mode();                   // in den Schlafmodus wechseln

        // hier wachen wir wieder auf
        GICR &= ~(1 << INT0);           // externen Interrupt sperren
                                        // WICHTIG! falls der externe LOW Puls an INT0
                                        // sehr lange dauert

        PORTD |= (1 << PD5);            // LED für eine Sekunde anschalten
        long_delay(1000);
        PORTD &= ~(1 << PD5);
    }
}

// externer Interrupt INT0 

// Die Interruptroutine kann leer sein, ABER sie muss existieren!
// Sonst springt der AVR nach dem Aufwachen zum Reset, weil kein sinnvoller
// Interruptvektor eingetragen ist!

ISR(INT0_vect) {
}

Im Power Down Mode beträgt die Stromaufnahme des AVR weniger als 1μA (weniger konnte mit dem verfügbaren Messgerät nicht gemessen werden), laut Datenblatt ca. 0,3µA. Während der einen Sekunde LED Leuchtdauer werden 3,8mA verbraucht. Wird einmal pro Minute die Taste gedrückt, ergibt sich ein mittlerer Stromverbrauch von

[math]\displaystyle{ I_m = \frac {0,3 \mu A \cdot 59s + 3,8mA \cdot 1s}{60s} = 63,6 \mu A }[/math]

Wird nur einmal pro Stunde die Taste gedrückt, ergibt sich ein mittlerer Stromverbrauch von

[math]\displaystyle{ I_m = \frac {0,3 \mu A \cdot 3599s + 3,8mA \cdot 1s}{3600s} = 1,3 \mu A }[/math]

Hinweise

JTAG Fuse

Aus einem Beitrag im Forum:

Wenn ich in den Power Down mode schalte bleibt die Stromaufnahme trotzdem gleich.
ATmega128 8MHz 3,3V = 8mA entspricht auch dem Datenblatt.

Datenblatt, Seite 49:

If the On-chip debug system is enabled by the OCDEN Fuse and the chip enter Power down or Power save sleep mode, the main clock source remains enabled. In these sleep modes, this will contribute significantly to the total current consumption. There are three alternative ways to avoid this:
  • Disable OCDEN Fuse.
  • Disable JTAGEN Fuse.
  • Write one to the JTD bit in MCUCSR.

PS. Ich habe gestern den ganzen Tag dran mit dem ATmega128 im Sleep-Modus gesessen, man musste einfach JTAG abschalten, dann läuft der Hauptoszillator nicht mehr und der Stromverbrauch sinkt drastisch ab.

TWI-Nutzung nach Power-Save

Problem: Nach dem Aufwachen aus dem Power-Save-Mode funktioniert das I2C/TWI-Interface nicht richtig. Abhilfe: Zurücksetzen des TWI-Registers im entsprechenden Interrupt.

   TWCR &= ~((1 << TWSTO) | (1 << TWEN));
   TWCR |= (1 << TWEN);

Bauteile

  • DS1371, Echtzeituhr mit 1000nA Stromverbrauch
  • PCF2123, Echtzeituhr mit 200nA Stromverbrauch
  • AB18XX, Echtzeituhr extrem niedrigem Stromverbrauch
    • Quarz: 2ppm, 55nA
    • Autokalibrierung: 3ppm/Jahr, 22nA
    • RC-Oszilator: 16ppm, 14nA

Weblinks

  • Arduino Sleep_Watchdog_Battery von Martin Nawrath
  • Arduino Sleep.How to let your Arduino go to sleep and wake up on an external event.