Hallo Leute! Ich habe ein Problem mit dem Sleep-Mode bei einem Attiny24. Ich will folgendes machen: Der Attiny24 soll im Schlafmodus verharren und wird durch den Watchdog alle x Sekunden aufgeweckt, um das was zu machen (Messung ...) um anschließend wieder in den Schlafmode geschickt zu werden. Watchdog läuft bereits, habe ich so gelöst: //Bit 7 – WDIF: Watchdog Timeout Interrupt Flag //Bit 6 – WDIE: Watchdog Timeout Interrupt Enable //Bit 5 – WDP Watchdog Timer Prescaler 3 //Bit 4 – WDCE: Watchdog Change Enable //Bit 3 – WDE: Watchdog Enable //Bit 2:0 – WDP Watchdog Timer Prescaler 2, 1, and 0 //----------------------------------- WDTCSR = 0b01000101; Nach der vorgegebenen Zeit wird ISR aufgerufen und eine LED blinkt kurz -- das funktioniert: //-------------------------------------------------------------- // Interruptvector Watchdog Time-out //-------------------------------------------------------------- ISR(WATCHDOG_vect) { PORTB |= (1 << DO_PB0); _delay_ms(1); PORTB &= ~(1 << DO_PB0); WDTCSR |= (1<<WDIE); } Sleep funktioniert nur teilweise - das MCUCR habe ich so beschalten: //Bits 1:0 – ISC01, ISC00: Interrupt Sense Control 0 Bit 1 and Bit 0 //Bit 2 – BODSE: BOD Sleep Enable //Bits 4:3 – SM1, SM0: Sleep Mode Select Bits 1:0 //Bit 5 – SE: Sleep Enable //Bit 6 – PUD: Pull-up Disable //Bit 7 – BODS: BOD Sleep //----------------------------------- MCUCR = 0b10110100; In den Schlafmodus schicke ich den Attiny nach dem ersten ISR-WATCHDOG: //-------------------------------------------------------------- // Interruptvector Watchdog Time-out //-------------------------------------------------------------- ISR(WATCHDOG_vect) { cli(); sleep_disable(); PORTB |= (1 << DO_PB0); _delay_ms(1); PORTB &= ~(1 << DO_PB0); WDTCSR |= (1<<WDIE); set_sleep_mode(SLEEP_MODE_PWR_SAVE); sleep_enable(); sleep_mode(); sei(); } Das ganze verhält sich jetzt so, dass der ISR-WATCHDOG aufgerufen wird, die LED blinkt und der Stromverbrauch sinkt von ca. 4mA auf 1,5mA ab, aber der ISR-WATCHDOG kommt dann nicht mehr. Erst nach einem Reset kommt der ISR-WATCHDOG wieder einmal und strom geht von 4mA auf 1,5mA. Meine Fragen: a) wie kann ich den ISR-WATCHDOG erneut aktivieren? b) warum sinkt der Stromverbrauch nur so gering ab? (Es gibt keine Analogverarbeitung) Danke für eure Hilfe!
Du könntest der Vollständigkeit halber dein ganzes Programm anhängen. Ich habe dir ein funktionierendes Beispiel für den Tiny25/45/85 angehängt, dort habe ich eine Ruhestromaufnahme von <10µA. Ich toggle in der IRQ einen Port, aber genauso kannst du dort ein Flag (volatile!) setzen, um in der main eine Aktion zu starten.
Vielen dank für das Beispiel 'HildeK'! Ich hatte da einen Denkfehler, ich dachte ich muss jedesmal starten und stoppen. Habe es an den Attiny angepasst, dass sieht so aus: // WD-Timer mit Sleep #include <avr/io.h> #include <avr/interrupt.h> #include <avr/sleep.h> #include <avr/wdt.h> #include <util/delay.h> #define WD_PRESCALE 7 // 8:=> 4s ISR(WATCHDOG_vect) { PORTB |= (1 << PB0); _delay_ms(1); PORTB &= ~(1 << PB0); } int main() { uint8_t wdt_flags, wd_timer_prescale; DDRA = 0b00000000; DDRB = 0b00000011; PORTA = 0b00001100; PORTB = 0b10000100; // Strom sparen PRR |= (1 << PRUSI) | (1 << PRTIM1) | (1 << PRTIM0) | (1 << PRADC); // USI, Timer1/0, ADC ungenutzt: abschalten // Power-Down Sleep Mode einstellen set_sleep_mode(SLEEP_MODE_PWR_DOWN); // stromsparend, aufwecken über WD oder INT0 sleep_enable(); // Schlafmodus vorbereiten // Watchdog IRQ vorbereiten wd_timer_prescale = WD_PRESCALE; if (wd_timer_prescale > 9 ) wd_timer_prescale=9; wdt_flags=wd_timer_prescale & 7; if (wd_timer_prescale > 7) wdt_flags|= (1<<5); // wdt_flags enthält den Prescalerwert (0 .. 9) WDTCSR |= (1<<WDCE) | (1<<WDE); // Watchdog aktivieren WDTCSR = wdt_flags | (1<<WDIE); // set watchdog timeout value, start WD-IRQ sei(); while (1) { sleep_mode(); // WD-IRQ weckt, toggelt Ports und schläft weiter. Stromaufnahme: <10µA ohne Last } } Der ISR-WATCHDOG_vect wird alle x-Sekunden aufgerufen. Das einzige was nicht geht ist das mit der Stromreduktion, es werden noch immer 1,5mA aufgenommen. Kann es sein, dass es mit der Quelle des Taktgeben zusammen hängt? Ich verwende den internen RC-8MHz als Taktgeber.
:
Bearbeitet durch User
Rudolf F. schrieb: > Kann es sein, dass es mit der Quelle des Taktgeben zusammen hängt? Nein, das liegt daran, daß du keine ISR für deinen Watchdog Interrupt hast. Lies die Warnings, die sind nicht zum Ignorieren da. Ein Blick ins Datenblatt unter "Interrupt Vectors" ist dann der nächste Schritt.
:
Bearbeitet durch User
Also mit diesem Programm fließen bei meinem ATtiny84A 6.1 uA, in guter Übereinstimmung mit dem Datenblatt.
Hi Zumindest beim ATtiny45 (25, 85) muß das WDIE-Flag nach jedem ISR-Aufruf neu gesetzt werden. Wenn Du zuvor das WDE-Flag gesetzt hast (Dieses wird in der ISR nicht zurück gesetzt), löst der WatchDog beim 2.ten Versuch ein Reset aus - steht auch so im Datenblatt als Sicherheit, falls sich z.B. die ISR festhängt. Selber habe ich den WatchDog bisher auch nur mit WDE + WDIE betrieben - kann mir also vorstellen, daß bei Dir das WDIE-Flag durch den Sprung in die ISR gelöscht wird und danach ist der WatchDog halt aus. MfG
Ich kann nur wiederholen: bei mir wie offenbar auch bei Rudolf F. läuft obiges Programm, und bei mir stimmt auch die Stromaufnahme. Allenfalls könnte ich noch ein etwas kompakteres Programm anbieten:
1 | #define F_CPU 8000000UL
|
2 | #define LED 0
|
3 | |
4 | #include <avr/io.h> |
5 | #include <util/delay.h> |
6 | #include <avr/interrupt.h> |
7 | #include <avr/sleep.h> |
8 | |
9 | ISR(WATCHDOG_vect) |
10 | {
|
11 | PORTB |= (1<<LED); |
12 | _delay_ms(5); |
13 | PORTB &= ~(1<<LED); |
14 | }
|
15 | |
16 | int main (void) |
17 | {
|
18 | DDRB |= (1<<LED); |
19 | PORTA = 0xFF; |
20 | PORTB = 0xFF; |
21 | PRR = 0xFF; |
22 | ACSR = (1<<ACD); |
23 | MCUCR = (1<<SE)+(1<<SM1); // power-down |
24 | WDTCSR = (1<<WDIE)+(1<<WDP3); // 8 s interrupt |
25 | sei(); |
26 | while (1) { |
27 | sleep_mode(); |
28 | };
|
29 | |
30 | return 0; |
31 | }
|
Ich habe einen Tiny25 mit Temperatursensor und IR-Ausgabe so programmiert, dass er mit dem max. WD-Timing alle 8 s aufwacht. Dabei wird die Variable ABLAUF erhöht. ABLAUF = (ABLAUF + 1) & 0x03. ABLAUF = 0, 1, 2, 3, 0, ... 0s: ABLAUF = 0: Temperatur-Messung, (Ablauf += 1) % 4, SLEEP 8s: ABLAUF = 1: (Ablauf += 1) % 4, SLEEP 16s: ABLAUF = 2: Daten senden, (Ablauf += 1) % 4, SLEEP 24s: ABLAUF = 3: (Ablauf += 1) % 4, SLEEP 0s: ... Eckpunkte im ASM-Programm:
1 | RESET: ; * * * Program Start * * * |
2 | wdr |
3 | in Tmp0, WDTCR ; setze W-Dog auf 8 s mit IRQ-Enable |
4 | ori Tmp0, (1 << WDIF) | (1 << WDIE) | (0b00100001 << WDP0) ; 8 s |
5 | out WDTCR, Tmp0 ; Also kein Reset vom W-Dog! |
6 | |
7 | ldi Tmp0, low(RAMEND) |
8 | out SPL,Tmp0 ; Stack Pointer auf RAM-Ende |
9 | |
10 | clr Tmp0 |
11 | rjmp START ; Wichtige Initialisierungen... |
Nach START geht es in die Hauptschleife:
1 | MAIN: |
2 | mn_0: |
3 | ldi Tmp0, 0 |
4 | cp ABLAUF, Tmp0 |
5 | brne mn_1 |
6 | rcall get_temperatur ; t = 0 s: messen |
7 | rjmp mn_nxt |
8 | |
9 | mn_1: ; t = 8 s: weiterschlafen! |
10 | |
11 | mn_2: |
12 | ldi Tmp0, 2 |
13 | cp ABLAUF, Tmp0 |
14 | brne mn_3 |
15 | rcall ir_send ; t = 16 s: ausgeben |
16 | ; rjmp mn_nxt |
17 | |
18 | mn_3: ; t = 24 s: weiterschlafen! |
19 | |
20 | mn_nxt: |
21 | inc ABLAUF |
22 | ldi Tmp0, 4 |
23 | cp ABLAUF, Tmp0 |
24 | brcs mn_rdy |
25 | sub ABLAUF, Tmp0 ; 4 -> 0 Nach 8 s sleep: Neuer Zyklus mit t = 0 |
26 | |
27 | mn_rdy: |
28 | in Tmp0, MCUCR |
29 | ori Tmp0, (1 << SE) | (1 << SM1) | (0 << SM0) ; Sleep-Enable, SleepMode = 2 (PwrDown) |
30 | out MCUCR, Tmp0 |
31 | sleep ; Schlafe bis Wecker vom WatchDog (8 s) |
32 | |
33 | rjmp MAIN |
Die IR-LED pulst mit 120 mA, der Verbrauch über 32 s liegt aber nur bei 55 µA. Das läuft über 2 Jahre mit einer Batterie von 4,5 V / 1 Ah. (3 x AAA)
Rudolf F. schrieb: > Das einzige was nicht geht ist das mit der Stromreduktion, es werden > noch immer 1,5mA aufgenommen. > Kann es sein, dass es mit der Quelle des Taktgeben zusammen hängt? > Ich verwende den internen RC-8MHz als Taktgeber. Auch mein Beispiel wurde mit dem internen Oszillator getestet bei 1MHz (CKDIV8 aktiv). Du hast in dem an meines angepassten Programm insgesamt für vier Portpins (A2, A3, B2, B8) den Pullup aktiv.
1 | DDRA = 0b00000000; |
2 | DDRB = 0b00000011; |
3 | |
4 | PORTA = 0b00001100; |
5 | PORTB = 0b10000100; |
Sind die zugehörigen Eingänge außen beschaltet? So ein interner Pullup hat so um die 30kΩ und wenn da außen ein Pulldown oder hart GND anliegen sollte, dann ist der erhöhte Strom schon möglich. 5V/8k = 0,6mA ... Auch die anderen Eingänge, die keinen Pullup definiert haben: sind die außen auf festem Potential? Wenn nicht, sind es die offene Eingänge, die zu erhöhter Stromaufnahme führen. Ansonsten würde ich mal ein neues Device nehmen.
Der Watch-dog hat seinen eigenen Oszillator, die Erzeugung des Systemtaktes spielt für die Stromaufnahme im Power-down-Modus keine Rolle.
> Wenn nicht, sind es die offene Eingänge, die > zu erhöhter Stromaufnahme führen. Nicht im Power-down-Modus, siehe Datenblatt: "... most of the digital inputs are disabled in the deep sleep modes ...". Diese 1.5 mA müssen anderswo herkommen.
Patrick J. schrieb: > Zumindest beim ATtiny45 (25, 85) muß das WDIE-Flag nach jedem ISR-Aufruf > neu gesetzt werden. Nein. Siehe mein funktionierendes Programm im zweiten Post. Kannst ja testhalber noch ein _delay_ms(1000) an den Anfang setzen, um zu sehen, dass es keinen WD-Reset auslöst. S. Landolt schrieb: > Der Watch-dog hat seinen eigenen Oszillator, die Erzeugung des > Systemtaktes spielt für die Stromaufnahme im Power-down-Modus keine > Rolle. Richtig, der WD läuft mit 128kHz. Aber der Rest des Programms (könnte ja länger sein) läuft mit dem Systemtakt. Der Tiny25 benötigt z.B. während eines _delay_ms-Aufrufs die 1.4mA. Wenn er fast nichts tun muss (wie in meinem Programm nur die Ports toggeln), dann sinkt die Stromaufnahme auf sehr kleine Werte. S. Landolt schrieb: >> Wenn nicht, sind es die offene Eingänge, die >> zu erhöhter Stromaufnahme führen. > Nicht im Power-down-Modus, siehe Datenblatt: > "... most of the digital inputs are disabled in the deep sleep modes > ...". Korrekt, gerade getestet am PB0 - stimmt! :-)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.