Forum: Mikrocontroller und Digitale Elektronik Arduino UNO Power Safe mit Watchdog


von poertner (Gast)


Lesenswert?

Hallo zusammen,

wie oben schon geschrieben habe ich Probleme mit dem Watchdog bei meinem 
Arduino UNO. Ich google und probiere jetzt schon eine ganze Weile, finde 
den bug aber nicht.
Vielleicht kann einer helfen?

Ich möchte meinen Arduino UNO für 20 sek. in den PWR_DOWN Mode schicken. 
Bei meinem Sketch scheinen es aber nur 2 sek zu sein. Und startet immer 
mit dem Setup neu :-(.

Gruß poertner



void setup() {
  Serial.begin(57600);     // Set console baud rate
  Serial.println ("Setup... ");
  wdt_enable(WDTO_2S); // WDT 2s
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // den tiefsten Schlaf auswählen 
PWR_DOWN
  Serial.println ("Setup wird beendet.");
}

void loop() {

  Serial.println ("Hauptschleife wird durchlaufen ");
  for (int i = 0; i < 10; i++) {
    Serial.println ("enter sleep-Funktion ");
    Serial.println (i);
    delay(1000); //delay, für serial monitor
    sleep_enable(); // sleep mode einschalten
    sleep_mode(); // in den sleep mode gehen
    sleep_disable(); // hier nach dem sleep weiter machen
  }
  Serial.println ("nach der Schalfdauer???");
  wdt_disable();
}

von arduino-fan (Gast)


Lesenswert?

Hej,

zum ersten Problem:

was verlangt denn der Code

       wdt_enable(WDTO_2S); // WDT 2s

vom Arduino?

Gruß

von Frank E. (Firma: Q3) (qualidat)


Lesenswert?

Ich glaube (weiss aber nicht genau), dass mit dem Watchdog so lange 
Zeiten wie 20s wg. inermem Zählerüberlauf garnicht machbar sind. Bereits 
2s sind für einen Mikrocontroller quasi Äonen ...

Lösung (so ungefähr): Immer mal kurz aufwachen und zusätzlichen Zähler 
hochsetzen. Wenn Soll-Zählerstand noch nicht erreicht, wieder schlafen 
legen.

von Ulrich F. (Gast)


Lesenswert?

poertner schrieb:
> Und startet immer
> mit dem Setup neu :-(.

Ich sehe keine ISR für den WDT!

Und dann geht es zwangsläufig nach 2S über Los

von chris (Gast)


Lesenswert?

WDT auf 4 Sec einstellen, und 5x sleep in einem Loop durchlaufen.
Beispiel:

void sleep(unsigned int times) {
//  wdt init
    wdt_reset();
    MCUSR &= ~(1<<WDRF);
    WDTCSR &= ~(1<<WDIE); // Disable watchdog timer.
    WDTCSR |= (1<<WDIF); // disable interrupt flag
    WDTCSR |= (1<<WDCE) | (1<<WDE) | 8;
    wdt_reset();

  do {
    digitalWrite(13, LOW);
    WDTCSR |= (1<<WDIE);
    set_sleep_mode(SLEEP_MODE_PWR_DOWN); // den tiefsten Schlaf 
auswählen
    sleep_enable(); // sleep mode einschalten
    sleep_mode(); // in den sleep mode gehen
    sleep_disable(); // hier nach dem sleep weiter machen
    digitalWrite(13, HIGH);
  } while(--times);

}

  ISR(WDT_vect) // Watchdog timer ISR
  {
    WDTCSR &= ~(1<<WDIE); // Disable watchdog timer.
  }

von chris (Gast)


Lesenswert?

Hier die bessere Version, times ist jetzt in Sekunden.

void sleep(unsigned int times) {
    unsigned char t=6;
    if(!(times&1)) { times>>=1; t++; }
    if(!(times&1)) { times>>=1; t++; }
    if(!(times&1)) { times>>=1; t++; }

//  wdt init
    wdt_reset();
    MCUSR &= ~(1<<WDRF);
    WDTCSR &= ~(1<<WDIE); // Disable watchdog timer.
    WDTCSR |= (1<<WDIF); // disable interrupt flag
    WDTCSR |= (1<<WDCE) | (1<<WDE) | t;
    wdt_reset();

  do {
    digitalWrite(13, LOW);
    WDTCSR |= (1<<WDIE);
    set_sleep_mode(SLEEP_MODE_PWR_DOWN); // den tiefsten Schlaf
auswählen
    sleep_enable(); // sleep mode einschalten
    sleep_mode(); // in den sleep mode gehen
    sleep_disable(); // hier nach dem sleep weiter machen
    digitalWrite(13, HIGH);
  } while(--times);

}

  ISR(WDT_vect) // Watchdog timer ISR
  {
    WDTCSR &= ~(1<<WDIE); // Disable watchdog timer.
  }

von poertner (Gast)


Lesenswert?

@arduino-fan

wdt_enable(WDTO_2S); // WDT 2s aktiviert meinem Verständis nach den 
Watchdog mit 2 sekunden-Zeit.

@Frank Esselbach
Der Controller auf dem Arduino UNO kann bis 8s.
Darüber hinaus schwebt mir eine Lösung wie von dir vorgeschlagen vor. 
Habe ich mit der for - Schleife versucht zu realisieren.

von Ulrich F. (Gast)


Lesenswert?

poertner schrieb:
> Habe ich mit der for - Schleife versucht zu realisieren.
Kann man tun....

Du hast vergessen die WDT Interrupts zu aktivieren und keine ISR im 
Programm. Daran solltest du vermutlich noch etwas arbeiten.


Zusätzlich könnte man noch die millis() Zählvariable um die 
entsprechende Sekunden Anzahl hoch setzen. Wird nicht sonderlich genau, 
aber vielleicht reichts ja...

von poertner (Gast)


Lesenswert?

@chris
Danke für den Code-Vorschlag, der leider auch immer in der 
Setup-Funktion startet.
Für mein besseres Verständnis habe ich den Code kommentiert. Und meine 
Fragen in fett eingefügt.


Hier der komplette Code:

// libraries
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

void setup() {
  Serial.begin(57600);     // Set console baud rate
  Serial.println ("Setup... ");
  delay(1000);
  }

void loop() {

  Serial.println ("Hauptschleife wird durchlaufen ");
  delay(500);
  sleep(20); /Aufrufen der sleep-Funktion - Wert in Sekunden eintragen
  Serial.println ("20 sec gewartet???");
}


void sleep(unsigned int times) {
    unsigned char t=6;

    // Umbau von Sekunden in WDP2 WDP1 WDP0 (timer prescaler bits)
    if(!(times&1)) { times>>=1; t++; }
    if(!(times&1)) { times>>=1; t++; }
    if(!(times&1)) { times>>=1; t++; }


//  wdt init
    wdt_reset();
    MCUSR &= ~(1<<WDRF); //reset flag leeren
    WDTCSR &= ~(1<<WDIE); // Disable watchdog timer.
    WDTCSR |= (1<<WDIF); // disable interrupt flag
    WDTCSR |= (1<<WDCE) | (1<<WDE) | t; //WDCE um prescaler setzen zu 
können 4 takte!
    wdt_reset();

  do {
    digitalWrite(13, LOW);
    WDTCSR |= (1<<WDIE); // Enable the WD interrupt (note no reset)
    set_sleep_mode(SLEEP_MODE_PWR_DOWN); // den tiefsten Schlaf 
auswählen
    sleep_enable(); // sleep mode einschalten
    sleep_mode(); // in den sleep mode gehen
    sleep_disable(); // hier nach dem sleep weiter machen
    digitalWrite(13, HIGH);
  } while(--times); // *???*

} //Sleep Funktion Ende

  ISR(WDT_vect) // Watchdog timer ISR
  {
    WDTCSR &= ~(1<<WDIE); // Disable watchdog timer. // *Warum steht 
diese Zeile nicht in der sleep Funktion?*
  }

von Ulrich F. (Gast)


Lesenswert?

Aus meiner Wühlkiste, leicht für dich modifiziert:
1
#include <avr/wdt.h>
2
#include <avr/sleep.h>
3
4
extern volatile unsigned long timer0_millis;
5
const byte LED = 13;
6
7
8
void sleep(uint16_t seconds)
9
{
10
  wdt_enable(WDTO_1S);
11
  WDTCSR |= _BV(WDIE);
12
  while(seconds--)
13
  {
14
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);// SLEEP_MODE_PWR_SAVE
15
    sleep_enable(); 
16
    sleep_mode(); 
17
    // sleeping
18
    sleep_disable();
19
    WDTCSR |= _BV(WDIE);
20
  }
21
  wdt_disable();
22
}
23
24
25
void setup() 
26
{
27
  pinMode(LED,OUTPUT);
28
}
29
30
void loop() 
31
{
32
  sleep(3);
33
  digitalWrite(LED,!digitalRead(LED));
34
}
35
36
37
38
ISR(WDT_vect) // Watchdog timer ISR
39
{
40
    timer0_millis += 1000; // atomic
41
}

von poertner (Gast)


Lesenswert?

@Ulrich F.

Danke Danke.

Mit dem Code läuft es, ohne das der Arduino regelmäßig in den Reset 
geht. :-)
Ich werde morgen mal probieren den Code in mein Programm zu 
implementieren.

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.