Forum: Mikrocontroller und Digitale Elektronik Warum funktioniert mein Watchdog Timer-Interrupt nicht?


von Peter K. (peter_k575)


Lesenswert?

Hallo zusammen,

ich versuche gerade, meinen uC (Attiny 84A) in einen deep Sleep Modus 
(Power Down) zu versetzen und ihn nur alle 8s aufzuwecken. Laut 
Datenblatt ist das ja möglich und das mit dem deep Sleep scheint auch zu 
funktionieren, jedenfalls fließen jetzt nur noch 0,3mA statt 3mA. Mehr 
als erwartet, aber schon mal ein Fortschritt.

Jedoch scheint meine ISR nicht zu funktionieren, jedenfalls wird die 
hier nur testweise implementierte Funktion nie ausgeführt. Weiß da 
jemand hier weiter?

Viele Grüße!
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <avr/interrupt.h>
5
#include <avr/sleep.h>
6
#include <avr/wdt.h>
7
#include <stdbool.h>
8
9
volatile bool flag = 0;
10
11
ISR(WDT_vect)
12
{
13
  sleep_disable();
14
  flag = 1;
15
  sleep_mode();
16
  reti();
17
}
18
19
void WDtimerInit()
20
{
21
  cli();
22
  wdt_reset();
23
  WDTCSR |= (1 << WDIE) | (1 << WDCE) | (1 << WDP3) | (1 << WDP0);
24
  sei();
25
}
26
27
int main(void)
28
{
29
  DDRB = 0xff; // 0000 0111 = 0x07
30
  DDRA = 0xc7; // 1100 0111 = 0xc7
31
  
32
  WDtimerInit();
33
  
34
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
35
  sleep_mode();
36
37
  while(1)
38
  {  
39
    if ( flag == 1) 
40
    {  
41
      sleep_disable();
42
            PORTA = 0x01;
43
                  _delay_ms(1000);
44
                  PORTA = 0x00;
45
46
      WDtimerInit();
47
      flag = 0;
48
      sleep_mode();
49
    }
50
    
51
  }
52
}

von Peter D. (peda)


Lesenswert?

Du mußt im WDT-Handler schon die Sequenz lt. Datenblatt ausführen, sonst 
macht der nächste WDT-Überlauf ein Reset.

Und sleep im Interrupt ist verboten, da Du dann nicht mehr aufwachen 
kannst.
Und reti auch, da Absturz (Epilog wird nicht ausgeführt).
sleep_disable ist eine sinnlose Funktion (bewirkt nichts).

: Bearbeitet durch User
von Peter K. (peter_k575)


Lesenswert?

Danke für die schnelle Antwort!

Also die ISR sollte einfach nur so aussehen:

ISR(WDT_vect)
{ flag = 1; }

Ich dachte aber, dann würde der if-Vergleich in der main nie ausgeführt 
werden? Brauch ich denn nicht doch noch ein sleep_disable in der ISR?

Peter D. schrieb:
> Du mußt im WDT-Handler schon die Sequenz lt. Datenblatt ausführen, sonst
> macht der nächste WDT-Überlauf ein Reset.

Hab ich dich so richtig verstanden, dass ich meine WDtimerInit Funktion 
noch um _WDR() und MCUSR = 0x00 erweitern muss?

von Peter D. (peda)


Lesenswert?

Siehe:
https://www.instructables.com/AVR-Watchdog-as-timed-interrupt/
1
ISR(WDT_vect)
2
{
3
/* ReEnable the watchdog interrupt, as this gets reset when entering this ISR and automatically enables the WDE signal that resets the MCU the next time the  timer overflows */
4
  WDTCR |= (1<<WDIE);
5
}

Ein Flag brauchst Du nicht, die CPU wartet nach jedem Sleep, bis der 
Interrupt ausgeführt wurde.

von Georg M. (g_m)


Lesenswert?

Hier ist ein funktionierendes Beispiel:
1
// ATtiny84A
2
// LED: PA2 (Pin 11): ~1s ON, ~8s OFF 
3
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include <avr/sleep.h>
7
8
ISR(WATCHDOG_vect)
9
{
10
11
}
12
13
int main(void)
14
{
15
  DDRA |= (1<<DDA2);                             // set PA2 as output
16
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);           // set sleep mode
17
  sei();                                         // enable interrupts
18
19
  while(1)
20
  {
21
    PORTA |= (1<<PORTA2);                        // LED on
22
    WDTCSR = (1<<WDCE) | (1<<WDE);               // enable WDT time-out change
23
    WDTCSR = (1<<WDIE) | (1<<WDP2) | (1<<WDP1);  // enable WDT interrupts, set time-out 1s
24
    sleep_mode();                                // sleep
25
26
    PORTA &= ~(1<<PORTA2);                       // LED off
27
    WDTCSR = (1<<WDCE) | (1<<WDE);               // enable WDT time-out change
28
    WDTCSR = (1<<WDIE) | (1<<WDP3) | (1<<WDP0);  // enable WDT interrupts, set time-out 8s
29
    sleep_mode();                                // sleep
30
  }
31
}

Stromverbrauch ohne LED ca. 5µA @ 3.8V.

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
Noch kein Account? Hier anmelden.