Forum: Mikrocontroller und Digitale Elektronik Watchdog 5 Stunden


von T.A. (Gast)


Lesenswert?

Hallo Leute,
Ich hab ein kleines Problem mit dem Watchdog.

Ich würde gerne meinen Atmel 5 Stunden lang schlafen lassen.
Ich hab mir die WDT Tuts schon durchgelesen und es funktioniert auch 
fast alles bis auf, dass er immer zu Früh nach 5 Minuten oder so oder 
noch früher aufwacht.

Der WDT Interrupt läuft wie folgt:
ISR(WDT_vect)
{

  Sleepsekunden++;
  wdt_reset();
  if (Sleepsekunden >= 4500){
  WDT_off();
  sleep_disable();
  for (uint8_t i=0;i<15;i++)
  {



    millisekunden = 0;
    Sleepsekunden=0;



  }
  WDT_RESET();
  uart_init();
  sei();
  }

  else {
  Sleep();

  }
}

Die Unter-Programme Dazu:

void WDT_Init(void)
{
  //disable interrupts
  cli();
  //reset watchdog
  wdt_reset();
  //set up WDT interrupt
  WDTCSR = (1<<WDCE)|(1<<WDE);
  //Start watchdog timer with 4s prescaller
  WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP3)|(0<<WDP2)|(0<<WDP1)|(0<<WDP0);
  //Enable global interrupts
  sei();
}
void WDT_RESET(void)
{
  //disable interrupts
  cli();
  //reset watchdog
  wdt_reset();
  //set up WDT interrupt
  WDTCSR = (1<<WDCE)|(1<<WDE);
  //Start watchdog timer with 4s prescaller
  WDTCSR = (0<<WDIE)|(1<<WDE)|(0<<WDP3) |(1<<WDP2)|(1<<WDP1);
  //Enable global interrupts
  sei();
}


Ich komm gerade nicht ganz mit.

von T.A. (Gast)


Lesenswert?

Das hab ich vergessen:

void Sleep(void) {
 // wdt_enable(7);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 WDT_Init();

  sleep_mode();

}



void WDT_off(void)
{
  cli();
  wdt_reset();
  /* Clear WDRF in MCUSR */
  MCUSR &= ~(1<<WDRF);
  /* Write logical one to WDCE and WDE */
  /* Keep old prescaler setting to prevent unintentional time-out
  */
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  /* Turn off WDT */
  WDTCSR = 0x00;
  sei();
}

von Alex W. (Gast)


Lesenswert?

Der Watchdog beim AVR kann soweit ich weis nur 2048 und 4096mS.

Watchdog ist dafür da, dass dein Programm so und so lange brauchen darf 
um den WDC_Reset auszuführen. Dauert es zu lange, weil z.B.: der uC in 
einer Loop hängt, so kommt der Watchdog und resetet ihn.

von T.A. (Gast)


Lesenswert?

Danke,
Aber ich würde Ihn gern missbrauchen und den UC nach 5 Stunden Reset-en.

Ich erhöhe ja immer ein Incrementenzäher also bis er das erreicht soll 
er immer wieder Schlafen gehen.
Programmtechnisch sollte es passen aber er tut es nicht wirklich :-)

von Jobst M. (jobstens-de)


Lesenswert?

T.A. schrieb:
> Ich würde gerne meinen Atmel 5 Stunden lang schlafen lassen.

Der Watchdog ist dafür da, wenn etwas nicht so funktioniert, wie 
vorgesehen.

Um den Controller absichtlich aus dem Schlaf aufzuwecken ist er das 
falsche Tool. Dafür benutzt man Timer.

Gruß
Jobst

von HildeK (Gast)


Lesenswert?

Erst mal fehlt hier eine ganze Menge:
- welcher Prozessor
- keine Definition der verwendeten Variablen
- kein Hauptprogramm
- unklar, was die 5h sollen, die einzige Abfrage die ich sehe, beziehen 
sich auf 4500s und das wären 1.25h
- die ganze WD-Bearbeitung sieht sehr komplex und umständlich aus.

Außerdem:
bei den mir bekannten Tinys ist die maximale Watchdogperiode 8s, danach 
wacht er auf jeden Fall erst mal wieder auf.
Hänge mal ein funktionsfähiges Programm an, das deine Wünsche nicht 
erfüllt und nenne diese Wünsche auch genau.
Code als Anhang oder eingebunden in die
1
-Tags, damit man es auch lesen kann. 
2
3
Bei mir sah die Verwendung des WD kürzlich so aus (Wechselblinken an PB3 und PB4 eines Tiny25): 
4
[c]
5
#define F_CPU 1e6
6
7
#include <avr/io.h>
8
#include <avr/interrupt.h> 
9
#include <avr/sleep.h>
10
#include <avr/wdt.h>
11
12
#define WD_PRESCALE 3  //  3:=> 125ms
13
14
ISR(WDT_vect)
15
{
16
  PORTB ^= (1<<PB3) | (1<<PB4);  // Toogle both outputs
17
}
18
19
int main()
20
{
21
  uint8_t wdt_flags, wd_timer_prescale;
22
23
  // PB3, PB4
24
  DDRB = 0xFF;   // outputs
25
  PORTB = 0x08;   // LOW per Default, PB3 auf HIGH
26
27
  // Strom sparen
28
  PRR |= (1 << PRUSI) | (1 << PRTIM1) | (1 << PRTIM0) | (1 << PRADC);   // USI, Timer1/0, ADC ungenutzt: abschalten 
29
30
  // Power-Down Sleep Mode einstellen
31
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // stromsparend, aufwecken über WD oder INT0
32
  sleep_enable();             // Schlafmodus vorbereiten
33
34
  // Watchdog IRQ vorbereiten
35
  wd_timer_prescale = WD_PRESCALE;
36
  if (wd_timer_prescale > 9 ) wd_timer_prescale=9;
37
  wdt_flags=wd_timer_prescale & 7;
38
  if (wd_timer_prescale > 7) wdt_flags|= (1<<5);  // wdt_flags enthält den Prescalerwert (0 .. 9)
39
40
  // Watchdog aktivieren
41
  WDTCR |= (1<<WDCE) | (1<<WDE);
42
  // set watchdog timeout value, start WD-IRQ
43
  WDTCR = wdt_flags | (1<<WDIE);
44
45
  sei();
46
47
  while (1)
48
  {
49
    // WD-IRQ weckt, toggelt Ports und schläft weiter. Stromaufnahme: <10µA ohne Last
50
    sleep_mode(); 
51
  }
52
}

von (prx) A. K. (prx)


Lesenswert?

Bitte keine Files mit TABs drin posten. Sieht scheisse aus.

Deine ISR sieht aber auch sonst höchst seltsam aus. sei() in dort meist 
falsch. Was soll die Schleife bewirken? Sleep() in der ISR sieht 
verdächtig nach Stacküberlauf aus, weil ISR von ISR unterbrochen wird, 
dir von einer ISR unterbochen wird, usw.

von (prx) A. K. (prx)


Lesenswert?

Jobst M. schrieb:
> Um den Controller absichtlich aus dem Schlaf aufzuwecken ist er das
> falsche Tool. Dafür benutzt man Timer.

Der Watchdog-Interrupt ist dafür durchaus geeignet, wenn es auf 
Genauigkeit nicht ankommt. Ein Timer braucht mehr Strom, oder einen 
unabhängigen Takt.

: Bearbeitet durch User
von T.A. (Gast)


Lesenswert?

ATMEGA324PA

Ich glaub auch, dass ich hier etwas falsch mache :-) sonst würde es ja 
gehen.
Du hast recht ein sei(); in ISR ist nicht gut :-)

Die Idee dahinter ist es den INterrupt des WDT so einzustellen, dass er 
alle 4 Sekunden ausgelöst wird.
In diesem Interrupthandler dann eine Variable Hochzählen zu lassen und 
dann wenn die Variable einen bestimmten Wert hat den UC zu reset-en.

von (prx) A. K. (prx)


Lesenswert?

T.A. schrieb:
> Die Idee dahinter ist es den INterrupt des WDT so einzustellen, dass er
> alle 4 Sekunden ausgelöst wird.

Der Hauptfehler ist, dann in der ISR auf den nächsten Interrupt zu 
warten. Damit stapeln sich die Interrupts auf dem Stack und irgendwann 
läuft der über.

Das muss im Hauptprogramm passieren, nicht in der ISR. Die ISR zählt 
bloss die Zeit hoch. Das Hauptprogramm pennt so lange immer wieder ein, 
bis die Stunden rum sind.

: Bearbeitet durch User
von Sascha W. (sascha-w)


Lesenswert?

T.A. schrieb:
> Die Idee dahinter ist es den INterrupt des WDT so einzustellen, dass er
> alle 4 Sekunden ausgelöst wird..
Ok
> In diesem Interrupthandler dann eine Variable Hochzählen zu lassen
Ok
> und dann wenn die Variable einen bestimmten Wert hat den UC zu reset-en.
Warum willst du dann ein Reset machen? Ein Sprung nach 0x0000 würde es 
auch tun. Ansonsten musst den den WDT am Ende wieder so konfigurieren 
das beim nächsten Durchlauf der Reset ausgelöst wird.
In der ISR brauchst du eigentlich nur die Variable hochzählen.
In der Hauptschleife prüfst du ob die 4500 Durchläufe um sind, wenn 
nicht dann wieder Sleep.

Sascha

von T.A. (Gast)


Lesenswert?

Wird die Hauptschleife überhaupt durchgelaufen wenn ich den MCU auf 
Power_Down Schlafen lasse?

von (prx) A. K. (prx)


Lesenswert?

T.A. schrieb:
> Wird die Hauptschleife überhaupt durchgelaufen wenn ich den MCU auf
> Power_Down Schlafen lasse?

Der Watchdog-Interrupt weckt den Prozessor auf und der läuft dann so 
lange weiter, bis du ihn wieder schlafen legst. Er beendet also ganz 
normal die ISR, landet dann im Hauptprogramm und macht dort direkt nach 
dem Sleep weiter.

von S. Landolt (Gast)


Lesenswert?

> Ich würde gerne meinen Atmel 5 Stunden lang schlafen lassen.
Geht es um den Lerneffekt oder um eine konkrekte Anwendung?
  Bei Letzterem wäre vielleicht Timer2 mit 32 KiHz-Quarz die 
stromsparendere Lösung, vorausgesetzt, der Systemtakt muss nicht 
quarzgenau sein.

von T.A. (Gast)


Lesenswert?

Konkreten Anwendungsfall aber ich brauch die Mhz für die UART!

von S. Landolt (Gast)


Lesenswert?

Würde auch noch gehen, ist aber trickreich & aufwändig, und lohnte sich 
wohl nur, wenn es auf das letzte uA ankommt: OSCCAL per 32 KiHz-Quarz 
justieren.

von Thomas E. (picalic)


Lesenswert?

S. Landolt schrieb:
> KiHz

Was, bitte sind denn "KiHz"? 1024 Hz oder was?

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Ja, ist irgendwo auf Wikipedia zu finden.

von S. Landolt (Gast)


Lesenswert?

Zu C kann&will ich nichts sagen, aber in Assembler sieht es fast noch 
einfacher aus als der Vorschlag von HildeK:
1
.org $0000
2
    rjmp    reset
3
4
.org WDTaddr
5
    reti
6
;*******************************************************
7
8
main:
9
    sbi     DDR_LED,LED
10
    ldi     tmp0,(1<<SE)+(1<<SM1)                       ; power-down
11
    out     SMCR,tmp0
12
    ldi     tmp0,(1<<WDCE)+(1<<WDE)
13
    sts     WDTCSR,tmp0
14
    ldi     tmp0,(1<<WDIE)+(1<<WDP3)+(1<<WDP0)          ; 8 s
15
    sts     WDTCSR,tmp0
16
    sei
17
main_loop:
18
    sleep
19
    sbi     PIN_LED,LED
20
21
; hier auf 2250 = 5*3600 / 8  zaehlen
22
23
  rjmp      main_loop
24
;*******************************************************
25
reset:
26
...

von F. F. (foldi)


Lesenswert?

A. K. schrieb:
> Jobst M. schrieb:
>> Um den Controller absichtlich aus dem Schlaf aufzuwecken ist er das
>> falsche Tool. Dafür benutzt man Timer.
>
> Der Watchdog-Interrupt ist dafür durchaus geeignet, wenn es auf
> Genauigkeit nicht ankommt. Ein Timer braucht mehr Strom, oder einen
> unabhängigen Takt.

Hätte Jobst jetzt zu 100% zugestimmt. Immer wieder interessant auch mal 
andere Ansätze zu lesen.
Danke für deinen Einwurf dieser Art!

von T.A. (Gast)


Lesenswert?

habs geknackt.

Danke

Der Hinweis dass nach dem Interrupt das Programm dort weiterläut wo er 
im Sleep geschickt wurde war der Bringer. Danke Dir/Euch

von T.A. (Gast)


Lesenswert?

Zum Stromverbrauch:

Timer 2 oder WDT Timer unterscheiden sich im uA Bereich.
Ich glaube es kommt darauf an ob man den WDT noch für Programmsicherheit 
benötigt oder nicht.

von (prx) A. K. (prx)


Lesenswert?

T.A. schrieb:
> Timer 2 oder WDT Timer unterscheiden sich im uA Bereich.
> Ich glaube es kommt darauf an ob man den WDT noch für Programmsicherheit
> benötigt oder nicht.

Der WDT ist nicht verbrannt, wenn man den "Interrupt and System Reset 
Mode" verwendet. Denn der WDT-Interrupt schaltet sich automatisch bei 
Ablauf ab. Wenn man den also nicht wieder einschaltet, dann gibts beim 
zweiten Ablauf einen Reset.

Man muss also den WDT-Interrupt jedesmal neu einschalten. Wichtig ist 
hier, dass man das nicht in der WDT-ISR macht, sondern in der Mainloop. 
Wenn diese Mainloop nicht läuft, dann gibts trotz erfolgtem 
WDT-Interrupt nach zweimaligem Ablauf einen Reset.

: Bearbeitet durch User
von F. F. (foldi)


Lesenswert?

A. K. schrieb:
> Wichtig ist
> hier, dass man das nicht in der WDT-ISR macht, sondern in der Mainloop.

Steht ja in so ziemlich jedem Buch, wenn man anfängt µC zu 
programmieren, dass man in der ISR nur das absolut Notwendige machen 
sollte und dann wieder in die Hauptroutine springen soll.

von T.A. (Gast)


Lesenswert?

Danke! Wie gesagt ich bin ja jetzt wieder gescheiter geworden. Also 
Danke Euch

von (prx) A. K. (prx)


Lesenswert?

T.A. schrieb:
> Zum Stromverbrauch:

Der grössere Unterschied dürfte im Hauptoszillator liegen. Im Power Down 
ist der abgeschaltet. Wenn das ein Quarzoszillator ist, dann dauert es 
verdammt lang, bis der sauber läuft. In dieser Zeit frisst der µC 
deutlich Strom. Und das macht der alle 4 Sekunden.

Wenn man als Hauptoszillator den internen R/C-Oszillator verwendet kann, 
dann entfällt dieser Startup und die Gesamtlaufzeit des alle 4 Sekunden 
auftretenden WDT-Interrupts ist viel kürzer.

Ein Kompromiss ist ein Keramikoszillator. Für UART reicht er und der 
Startup ist viel schneller.

Das Optimum bei genauem Haupttakt ist der interne R/C-Oszillator als 
Haupttaktquelle zusammen mit einem asynchronen quarzgenauen 32kHz Timer. 
Um den Haupttakt hinreichend genau zu kriegen stellt man das 
Kalibrier-Register des R/C-Oszillators anhand gemessener Takte für ein 
paar Perioden des 32kHz Timers immer wieder neu ein. Das dürfte den 
minimal möglichen Verbrauch ergeben. Den WDT-Interrupt braucht man dann 
nicht und der 32kHz Osz ist sparsamer als der WDT.

: Bearbeitet durch User
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.