Forum: Mikrocontroller und Digitale Elektronik Atmega328p in Sleep und mit Watchdog wecken


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Peter (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

ich hab hier ein kleines Testprogramm geschrieben, was mir meinen 
Atmega328p der mit dem internen 1 Mhz Takt und 3,3V betrieben wird alle 
8 Sekunden aufwecken soll und Daten per Funk versenden soll. Nur sendet 
dieser nur genau einmal beim einschalten. Irgendwie stehe ich auf dem 
Schlauch. Weiß jemand wieso er nur einmal sendet?
//  Atmega328p intern 1 Mhz
#define    F_CPU        1000000UL
#include  <avr/io.h>
#include   <util/delay.h>
#include   <avr/interrupt.h>
#include   <avr/power.h>
#include   <avr/wdt.h>
#include   <avr/sleep.h>
#include   "rfm69.c"

uint8_t array[MAX_ARRAYSIZE + 1];
uint8_t tx_length;

volatile uint8_t sekunden=0;

void sleep_now() 
{
    power_all_disable();
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_mode();
}

void todo()
{
  //Daten auswerten und senden
  sekunden++;
  array[0]=sekunden;
  array[1]++;
  tx_length=2;
  rfm_transmit(array, tx_length);  
}

int main( void )
{
  wdt_enable(WDTO_8S);
  rfm_init();
  while(1)
  {
    todo();
    sleep_now();
  }
}

von derjaeger (Gast)


Bewertung
0 lesenswert
nicht lesenswert
http://www.avrfreaks.net/forum/difference-between-sleepcpu-and-sleepmode

With sleep_mode() you select the sleep mode you like to enter.
With sleep_cpu() you enter the sleep mode you have selected by calling 
sleep_mode().

von Peter (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Heißt soviel wie das ein "sleep_cpu();" hinter mein "sleep_mode();" 
kommen muss?

Wobei das ja eigentlich egal wäre weil der Watchdog Reset alle 8 
Sekunden käme oder?

von Thomas E. (Firma: Thomas Eckmann Informationst.) (thomase)


Bewertung
1 lesenswert
nicht lesenswert
Peter schrieb:
> Wobei das ja eigentlich egal wäre weil der Watchdog Reset alle 8
> Sekunden käme oder?

Ja, das ist es wohl.

Aber was hält der initialisierte RFM davon, wenn er mit einem Init 
einfach nochmal übergebügelt wird? Oder bekommt der vorher noch einen 
Reset? Beim Einschalten bekommt er den ja auf jeden Fall(Power On).

Oder ist er falsch initialisiert und hängt sich nach dem ersten Senden 
auf?

Teste das einfach mal in einer Schleife: Senden - Delay - Senden usw...
Und wenn das geht, packst du ein Init in die Schleife. Dann siehst du, 
ob er das mag oder nicht.

Allerdings ist ein Reset zum Beenden des Sleep nun wahrlich nicht der 
Weisheit letzter Schluß. Weniger nett ausgedrückt, könnte man auch 
sagen, daß das totaler Mist ist.

Den WD kann man auch als Timer benutzen, sowohl mit als auch ohne Reset.

Grundsätzlich bringt man das erstmal ohne Sleep zum Laufen und erst wenn 
alles funktioniert, baut man den Sleep ein.

von M. K. (sylaina)


Bewertung
-1 lesenswert
nicht lesenswert
Hast du den Watchdog auch entsprechend eingestellt damit er nicht im 
Watchdog-Reset kleben bleibt? Mit der wdt.h kenne ich mich nicht aus, 
würde aber sagen der AVR bleibt da im Watchdog-Reset kleben.

Versuche mal deinen Code umzubauen und zwar so:
//  Atmega328p intern 1 Mhz
#define    F_CPU        1000000UL
#include  <avr/io.h>
#include   <util/delay.h>
#include   <avr/interrupt.h>
#include   <avr/power.h>
#include   <avr/sleep.h>
#include   "rfm69.c"

uint8_t array[MAX_ARRAYSIZE + 1];
uint8_t tx_length;

volatile uint8_t sekunden=0;

void sleep_now() 
{
    power_all_disable();
    sleep_mode();
}

void todo()
{
  //Daten auswerten und senden
  sekunden++;
  array[0]=sekunden;
  array[1]++;
  tx_length=2;
  rfm_transmit(array, tx_length);  
}

int main( void )
{
  // watchdog konfigurieren
  // zunaechst Schutz des Registers aufheben gemaess Datasheet
  WDTCSR = (1 << WDCE)|(1 << WDE);
  // Interruptmode an, Zeit auf 8s einstellen
  WDTCSR = (1 << WDIE)|(1 << WDP3)|(1 << WDP0);

  rfm_init();
  
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);

  // globale Interrupts einschalten
  sei();
  while(1)
  {
    sleep_now();
  }
}
ISR(WDT_vect){
  // watchdog interrupt
  todo();
}

Das sollte alle 8s die todo() aufrufen.

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Das eingangs gezeigte Programm funktioniert als solches schon irgendwie: 
wenn ich, in Ermangelung dieses Funkteils, in todo eine LED kurz 
einschalte, dann blinkt diese im 8 s-Rhythmus. Also hat wohl Thomas 
Eckmann mit seiner Vermutung Recht.

von S. Landolt (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Was allerdings das Konzept betrifft, so würde ich auf jeden Fall einen 
32 KiHz-Quarz als Zeitgeber vorziehen, vorausgesetzt, die beiden Pins 
sind frei; ist genauer und stromsparender als der Watchdog.

von batman (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Quarzbetrieb stromsparender als der interne Watchdog-Timer? Das hab ich 
mal anders gelesen, wenn auch nicht nachgemessen.

von S. Landolt (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Nachmessen ist immer gut, man kann es aber auch nachlesen.

von batman (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Da les ich jetzt aber nicht, was der WDT im Power-Down zieht. Obwohl 
alles unter 1µA sowieso meistens egal ist.

von S. Landolt (Gast)


Angehängte Dateien:

Bewertung
-1 lesenswert
nicht lesenswert
Ich dachte, es sei klar, dass der RC-Oszillator des Watchdog nicht unter 
1 uA kommt.

von batman (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Ja dann haste Recht und mein Amperemeter lügt. Gut zu wissen.

von M. K. (sylaina)


Bewertung
0 lesenswert
nicht lesenswert
batman schrieb:
> Ja dann haste Recht und mein Amperemeter lügt. Gut zu wissen.

Naja, um so 1/2/3 uA mit nem Amperemeter wirklich zu messen braucht man 
schon ein relativ Gutes. Die 08/15-Dinger schätzen in dem Bereich ja 
schon irgendwie mehr als dass sie wirklich messen, ich trau da ja nicht 
mal meinem Agilent U1253B wobei das kein schlechtes MM ist.

von Thomas E. (Firma: Thomas Eckmann Informationst.) (thomase)


Bewertung
0 lesenswert
nicht lesenswert
M. K. schrieb:
> würde aber sagen der AVR bleibt da im Watchdog-Reset kleben.

Wie klebt ein AVR im WD-Reset?

von M. K. (sylaina)


Bewertung
0 lesenswert
nicht lesenswert
Thomas E. schrieb:
> M. K. schrieb:
>> würde aber sagen der AVR bleibt da im Watchdog-Reset kleben.
>
> Wie klebt ein AVR im WD-Reset?

Mit "kleben" meinte ich, dass der AVR vielleicht ständig nur resetet und 
zu nix anderem mehr kommt. Deshalb "kleben" ;)

von Thomas E. (Firma: Thomas Eckmann Informationst.) (thomase)


Bewertung
1 lesenswert
nicht lesenswert
M. K. schrieb:
> Mit "kleben" meinte ich, dass der AVR vielleicht ständig nur resetet und
> zu nix anderem mehr kommt. Deshalb "kleben"

Und warum sollte er das tun?

von M. K. (sylaina)


Bewertung
1 lesenswert
nicht lesenswert
Thomas E. schrieb:
> Und warum sollte er das tun?

Ist ja schon gut, ich habs ja verstanden, dass das wohl ne blöde Idee 
war...

von Thomas E. (Firma: Thomas Eckmann Informationst.) (thomase)


Bewertung
2 lesenswert
nicht lesenswert
M. K. schrieb:
> Ist ja schon gut, ich habs ja verstanden, dass das wohl ne blöde Idee
> war...

Grundsätzlich ist die Idee gar nicht blöd. Das kann nämlich dann 
passieren, wenn man die Einschaltung und das Setzen des Timeouts des WD 
irgendwo in einer Init versteckt und dies nicht als erstes in der Main 
durchführt. Denn bei einem WD-Reset werden zwar die Register mit den 
Default-Werten geladen, nicht aber der WD abgeschaltet. Und dann muß man 
sich u.U. einigermaßen beeilen, den Timeout wieder zu verlängern, da 
dieser nach Reset auf der kürzesten Zeit steht. Der WD wird erst mit 
Power Off abgeschaltet.

Ist aber in dem Programm des TO richtig:
int main( void )
{
  wdt_enable(WDTO_8S);

: Bearbeitet durch User
von Ralph G. (rhg)


Bewertung
1 lesenswert
nicht lesenswert
Moin,

aus dem Datasheet 15.9.2:

Executing the corresponding interrupt vector will clear WDIE and WDIF 
automatically by hardware (the Watchdog goes to System Reset Mode).
This is useful for keeping the Watchdog Timer security while using the 
interrupt. To stay in Interrupt and System Reset Mode, WDIE must be set 
after each interrupt.

Du musst den WDInt nach jedem auslösen neu setzen.
int main( void )
{
  wdt_enable(WDTO_8S);
  rfm_init();
  while(1)
  {
    todo();
    sleep_now();
    wdt_enable(WDTO_8S);
  }
}

von Stefan E. (sternst)


Bewertung
0 lesenswert
nicht lesenswert
Thomas E. schrieb:
> Das kann nämlich dann
> passieren, wenn man die Einschaltung und das Setzen des Timeouts des WD
> irgendwo in einer Init versteckt und dies nicht als erstes in der Main
> durchführt.

Auch wenn es direkt das Erste in main() ist, kann es passieren, nämlich 
dann, wenn .data und .bss groß genug sind und deren Initialisierung 
entsprechend lange dauert. Der Default nach dem Reset liegt bei ca 16ms, 
also bei 1 MHz gerade mal 16000 Takte. Wir wissen nicht, was 
MAX_ARRAYSIZE genau ist und welche weiteren Buffer sich vielleicht in 
rfm69.c verstecken. Es ist also nicht ganz abwegig, dass das sein 
Problem sein könnte.

von batman (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ralph G. schrieb:
> Du musst den WDInt nach jedem auslösen neu setzen.

Das gilt aber nicht für den reinen System-Reset-Mode, der anfangs 
benutzt wurde und so schon funktionierte. Da muß man nur einmal WDE 
setzen.

Wenn man dagegen nur den Timer des WD nutzt, sollte man WDE und 
wdt_enable() gar nicht verwenden. Hier mal meine sleep-Routine:
/--------------------------------------------------------------------------------------------
#define WDTIME 4


// WDT ISR
ISR(WDT_vect) {}


void sleep_long(u16 sleeptime)
// sleep seconds, interrruptable by any active irq
{

  // --- perform sleep cycles ---
#if WDTIME==1
  WDTCR |=  0<<WDP3 | 1<<WDP2 | 1<<WDP1 | 0<<WDP0;  // prescale for 1s
#elif WDTIME==4
  WDTCR |=  1<<WDP3 | 0<<WDP2 | 0<<WDP1 | 0<<WDP0;  // prescale for 4s
#elif WDTIME==8
  WDTCR |=  1<<WDP3 | 0<<WDP2 | 0<<WDP1 | 1<<WDP0;  // prescale for 8s
#else
#error NO WDTIME!
#endif

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  SBIT(WDTCR,WDIE)=1;            // enable watchdog IRQ
  for(u16 elapsed=0; elapsed<sleeptime; elapsed+=WDTIME)  {
    sleep_mode();            // in den Schlafmodus wechseln
    // --- wake up ---
  }
  SBIT(WDTCR,WDIE)=0;    // disable watchdog IRQ

}

//--------------------------------------------------------------------------------------------

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Thomas E. schrieb:
> Denn bei einem WD-Reset werden zwar die Register mit den
> Default-Werten geladen, nicht aber der WD abgeschaltet.

Du vergißt, daß er noch seine ATmega8 Schätzchen aufbrauchen will.
Und die schalten den Watchdog ab, wenn er nicht per Fusebit permanent an 
ist.
Es hilft also nichts, aus dem ATmega88 Datenblatt zu zitieren.

von M. K. (sylaina)


Bewertung
0 lesenswert
nicht lesenswert
batman schrieb:
> Hier mal meine sleep-Routine:

Funktioniert das sicher? Gemäß Datenblatt zum Atmega328p muss man, um 
den Prescaler wechseln zu können, doch zunächst das WDCE und WDE Bit 
setzen. Das vermisse ich irgendwie bei dir.

von Thomas E. (Firma: Thomas Eckmann Informationst.) (thomase)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Du vergißt, daß er noch seine ATmega8 Schätzchen aufbrauchen will.

???:

Peter schrieb:
> ich hab hier ein kleines Testprogramm geschrieben, was mir meinen
> Atmega328p

von derjaeger (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Bisher hat es nur Peter Dannegger angesprochen:

Hast du das Fusebit gesetzt beim Mikrocontroller: Watch-dog Timer always 
on; [WDTON=0] ?

von batman (Gast)


Bewertung
0 lesenswert
nicht lesenswert
M. K. schrieb:
> batman schrieb:
>> Hier mal meine sleep-Routine:
>
> Funktioniert das sicher? Gemäß Datenblatt zum Atmega328p muss man, um
> den Prescaler wechseln zu können, doch zunächst das WDCE und WDE Bit
> setzen. Das vermisse ich irgendwie bei dir.

Bezieht sich das vielleicht exklusiv auf den System-Reset-Mode?
Meine Sleep-Funktion läuft so auf mehreren  m328p, mega8 und tinys.

von M. K. (sylaina)


Bewertung
0 lesenswert
nicht lesenswert
Ich habs nicht probiert aber im Datasheet steht halt auch drin, dass zum 
ändern der Zeit zunächst WDCE und WDE gesetzt werden müssen und man dann 
vier Zyklen Zeit hat zum Einstellen der neuen Zeit. Vielleicht gilt das 
auch nur wenn das WDTON-Fuse gesetzt ist. Das hab ich jetzt nicht auf 
dem Schirm.

von batman (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Für mich nicht ganz eindeutig. Die Prozedur würde jedenfalls keinen Sinn 
machen, wenn man den Timer nur als Trigger für die ISR nutzt. Bei diesen 
Datenblättern muß man manchmal zwischen den Zeilen lesen. :)

von Peter (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Also, der 328er soll eigentlich nur alle 30-60 Sekunden Aufwachen, 
Temperatur und relative Luftfeuchtigkeit eines sht21(der noch unterwegs 
ist) einlesen und über das RFM69CW Modul senden. Das alles sollte 
Natürlich so sparsam wie möglich betrieben werden. Wollte zwar eine 
14500 Trustfire 800mAh als Versorgung benutzten, aber man will ja so 
lange wie möglich damit kommen.

Ich muss auch ehrlich dazu sagen, dass ist mein erstes Projekt wo ich 
mich überhaupt mit Low Power bzw Sleep Modus aber auch Watchdog 
beschäftige.

Den internen Watchdog wollte ich verwenden um weniger Bauteile zu haben.

Bin aber über Tips Tricks dankbar und hab jetzt schon neue Sachen hier 
gelernt.

von derjaeger (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Kannst du deine FUSE-Konfiguration  zeigen?

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Thomas E. schrieb:
> Peter D. schrieb:
>> Du vergißt, daß er noch seine ATmega8 Schätzchen aufbrauchen will.
>
> ???:

Sorry, war gedanklich im falschen Thread.

von M. K. (sylaina)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
batman schrieb:
> Für mich nicht ganz eindeutig. Die Prozedur würde jedenfalls
> keinen Sinn
> machen, wenn man den Timer nur als Trigger für die ISR nutzt. Bei diesen
> Datenblättern muß man manchmal zwischen den Zeilen lesen. :)

Warum sollte die Prozedure keinen Sinn machen? Das ist eine 
Fail-Safe-Procedure, die verhindern soll, dass die Time-Out aus 
versehen/zufällig geändert werden kann.
Im Anhang der Beispiel-Code dazu. Da wird u.a. auch empfohlen, den 
Watchdog zu reseten bevor man die Zeit ändert da es sonst zum Reset 
kommen kann was auch irgendwie logisch ist, in deiner Funktion fehlt das 
aber auch. ;)

Peter schrieb:
> Also, der 328er soll eigentlich nur alle 30-60 Sekunden Aufwachen,

Würde ich im Watchdog-Interrupt-Mode machen, also so wie schon oben 
gezeigt. Hierzu einfach eine Variable nehmen, die die Interupts zählt 
und sowie eine gewisse Anzahl erreicht ist das todo() ausführen lassen. 
Die ISR könnte so aussehen:
volatile uint8_t myWatchDogInterrupts = 0;
...
ISR(WDT_vect){
  myWatchDogInterrupts++;
  if(myWatchDogInterrupts > 5){
    // ist der Watchdog auf 8 Sekunden eingestellt 
    // so tritt dies hier alle 6*8s = 48s auf
    todo();
    myWatchDogInterrupts=0;
  }
}
...

von batman (Gast)


Bewertung
0 lesenswert
nicht lesenswert
M. K. schrieb:
> Warum sollte die Prozedure keinen Sinn machen? Das ist eine
> Fail-Safe-Procedure, die verhindern soll, dass die Time-Out aus
> versehen/zufällig geändert werden kann.

Schön, und die Frage war, welchen Sinn das hier machen sollte.

> Im Anhang der Beispiel-Code dazu. Da wird u.a. auch empfohlen, den
> Watchdog zu reseten bevor man die Zeit ändert da es sonst zum Reset
> kommen kann was auch irgendwie logisch ist, in deiner Funktion fehlt das
> aber auch. ;)

Nein, das fehlt nicht. Durch das Löschen des WDIE-Flag wird der WD 
deaktiviert und startet dann neu bei Null. Einen Reset kann der Timer in 
meiner Sleep-Funktion aber gar nicht auslösen. Das ist völlig falscher 
Kontext.

von HildeK (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
> Also, der 328er soll eigentlich nur alle 30-60 Sekunden Aufwachen,

Aufwachen an sich geht längstens im 8s-Intervall mit dem WD. Natürlich 
kannst du bei jedem Aufwachen in der WD-ISR einen Zähler nehmen und dann 
beim Stand 4 ... 7 (32s ... 56s) nur senden.

Welche Besonderheiten der 328 enthält, weiß ich nicht.
Bei Tiny x5 braucht man jedenfalls die WDTON Fuse nicht aktivieren, um 
zyklische WD-Interupts zu generieren und so den WD-Timer zu nutzen.
WDTON ist bei Atmel der "safety level 2", bei dem der WD vom Power-On an 
aktiv ist und der per Programm auch nicht abgeschaltet werden kann.
Um die WD-Zeiten zu ändern, braucht man im Level 2 die 'Timed sequence', 
ohne WDTON-Fuse jedoch nicht. Für Level 1 kann die selbe Funktion auch 
per SW aktiviert werden, nur dass der WD dann auch unterwegs 
abgeschaltet werden kann.
Wenn auf die Sicherheitsfunktion des WD verzichtet werden will (kein 
WD-Reset bei wild gewordenem Prog, sondern nur Nutzung des WD-Timers), 
dann braucht man WDE nicht setzen, nur WDIE für den Interrupt.

Wie gesagt, das gilt für die Tinys und auch für den 164A, 324A, 644A und 
1284, ich vermute aber, dass der 328 auch so arbeitet. Genaueres weiß 
das Datenblatt.

von M. K. (sylaina)


Bewertung
0 lesenswert
nicht lesenswert
batman schrieb:
> Schön, und die Frage war, welchen Sinn das hier machen sollte.

Default ist der Watchdog auf 16 ms eingestellt, hier soll er nun auf 8 s 
geändert werden und das ist die dazu, lt. Datenblatt, nötige Procedure 
um die Time-Out zu ändern. Mag sein, dass es auch anders geht, ich würde 
mich aber definitiv ans Datenblatt halten.

batman schrieb:
> Nein, das fehlt nicht. Durch das Löschen des WDIE-Flag wird der WD
> deaktiviert und startet dann neu bei Null.

Wo hast du denn das raus gelesen? Im Datenblatt steht das auf jeden Fall 
nicht oder ich bin blind.
Ist aber auch egal erstmal, deine sleep-Funktion wird aufgerufen und 
soll nun starten, das WDIE löscht sie aber erst zum Schluss, nicht zu 
Beginn. Und wenn der Watchdog nun schon läuft? Deine sleep-Funktionn ist 
schön und gut, hat aber ein paar Randbedingungen, die man beachten 
sollte ;)

von Thomas E. (Firma: Thomas Eckmann Informationst.) (thomase)


Bewertung
0 lesenswert
nicht lesenswert
M. K. schrieb:
> Wo hast du denn das raus gelesen? Im Datenblatt steht das auf jeden Fall
> nicht oder ich bin blind.

Doch das steht da. Da hat der Fledermausmann teilweise recht. Aber seine 
Rückschlüsse sind auch nicht ganz richtig.

Wenn sowohl WD-Reset als auch WD-Timer aktiv sind, wird nach Ablauf des 
ersten Timeout die ISR ausgeführt und nach einem weiteren Timeout der 
Reset.

Damit das in dieser Reihenfolge passiert, wird bei gesetztem WDIE-Bit 
die ISR ausgeführt und nicht nur das WDIF-Flag sondern auch das WDIE-Bit 
gelöscht. Dann erfolgt beim nächsten Timeout der Reset.

Möchte man diesen Reset verhindern, muß das WDIE-Bit wieder gesetzt 
werden. Dann wird beim nächsten Timeout wieder die ISR ausgeführt.

Das ist der Sinn und Zweck dieser Prozedur. Der WD-Timercounter wird 
dabei nicht zurück gesetzt. Auch ist das wiederholte Setzen des WDIE-Bit 
im reinen Timer-Mode nicht erforderlich, da dieses nur bei gesetztem WDE 
gelöscht wird. Also im kombinierten Mode.

: Bearbeitet durch User
von batman (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
Thomas E. schrieb:
> Wenn sowohl WD-Reset als auch WD-Timer aktiv sind, wird nach Ablauf des
> ersten Timeout die ISR ausgeführt und nach einem weiteren Timeout der
> Reset.

Tja wenn das Wörtchen wenn nicht wär, ne. Worum ging es hier denn 
gleich.

von M. K. (sylaina)


Bewertung
0 lesenswert
nicht lesenswert
Thomas E. schrieb:
> Doch das steht da.

Wo steht das da? Du beschreibst was passiert wenn die ISR angesprungen 
wurde und das WDIE-Bit automatisch gelöscht wurde. Wo bitte steht im 
Datenblatt, dass das manuelle Löschen des WDIE-Bits den Timer zurück 
setzt, wie es batman oben schrieb? Das lese ich nirgends im Datenblatt, 
Sorry. Das ist eine nicht beschriebene Funktionalität auf die man sich 
IMO nicht verlassen sollte, sonst ist man irgendwann mal verlassen.

von Peter (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

so hab noch einige sachen Probiert...
Hier das Programm sendet genau ein mal, geht in Sleep (ca 4.3uA) wird 
nach 8 Sekunden geweckt (sieht man am Strom ca 680uA und bleibt da dann 
hängen.

Ab dann werden keine neuen Werte mehr gesendet. Wie verhält der uC sich? 
Arbeitet dieser nur die WD Routine ab oder auch die RFM_init (Also 
ganzes Programm)?

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
sleep_now in der ISR - ob das eine gute Idee ist? Auf jeden Fall fehlt 
da ein sei; normalerweise erfolgt das am Ende der ISR per reti.

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
sleep_now in der ISR - vermutlich eine schlechte Idee; wenn ich mich 
nicht täusche (kann kaum c), läuft da der Stack voll.

von M. K. (sylaina)


Bewertung
0 lesenswert
nicht lesenswert
Ja, das sleep_now würde ich auch in die Main-Loop verfrachten und nicht 
in der ISR belassen.

von Dieter F. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
M. K. schrieb:
> Wo bitte steht im
> Datenblatt, dass das manuelle Löschen des WDIE-Bits den Timer zurück
> setzt, wie es batman oben schrieb?

Nirgendwo. Es steht da nur, dass das Interrupt-Enable-Register 
zurückgesetzt wird (wenn die WDT-ISR ausgeführt wird)

von Thomas E. (Firma: Thomas Eckmann Informationst.) (thomase)


Bewertung
0 lesenswert
nicht lesenswert
M. K. schrieb:
> Wo steht das da? Du beschreibst was passiert wenn die ISR angesprungen
> wurde und das WDIE-Bit automatisch gelöscht wurde. Wo bitte steht im
> Datenblatt, dass das manuelle Löschen des WDIE-Bits den Timer zurück
> setzt, wie es batman oben schrieb? Das lese ich nirgends im Datenblatt,
> Sorry. Das ist eine nicht beschriebene Funktionalität auf die man sich
> IMO nicht verlassen sollte, sonst ist man irgendwann mal verlassen.

Nun reg dich mal wieder ab. Ich hab doch klar beschrieben, was da 
passiert. Und auch, was nicht passiert. Nämlich, daß der Timer-Counter 
beim Setzen des WDIE-Bits nicht zurückgesetzt wird. Vom manuellen 
Löschen war zumindest bei mir nie die Rede.

von Peter (Gast)


Angehängte Dateien:

Bewertung
2 lesenswert
nicht lesenswert
Siehe an es funktioniert. Zieht jetzt 4,3uA im Power down Modus.
Waren scheinbar mehrere Faktoren dafür Schuld.
power_all_disable();
War aber mit der Hauptgrund wieso es nicht weiter ging.

So funktioniert es jetzt bisher.

Der RFM69CW soll im Sleep Modus Typ 0.1uA Max 1uA ziehen.
Der Atmega328p Power Down Modus WDT enabled Typ 3.9uA Max 15uA ziehen.

Heißt die Werte sollten also grob passen. Vor allem bei meinem alten 
Benning CMM3 Messgerät.

Vielen dank an alle!
Für Verbesserungen bin ich gerne zu haben. Man lernt nie aus!

von M. K. (sylaina)


Bewertung
0 lesenswert
nicht lesenswert
Thomas E. schrieb:
> Nun reg dich mal wieder ab. Ich hab doch klar beschrieben, was da
> passiert. Und auch, was nicht passiert. Nämlich, daß der Timer-Counter
> beim Setzen des WDIE-Bits nicht zurückgesetzt wird. Vom manuellen
> Löschen war zumindest bei mir nie die Rede.

Ich konnte ja nicht ahnen, dass du dem Faden nicht folgen konntest:

batman schrieb, dass durch das Löschen des WDIE-Bits in seiner Funktion 
sleep der Watchdog resetet werden würde (Post #5157819). Ich fragte ihn 
daraufhin wo er das gelesen hätte (kann ja sein, dass das in einer 
AppNote drin steht), denn im Datenblatt stünde das nicht (Post #5157859) 
worauf von dir kam, dass das sehr wohl im Datenblatt stehen würde (Post 
#5157936) und du dann den "automatischen" Reset des Watchdogs durch die 
ISR beschrieben hast (das ist der Teil, den ich auch gar nicht 
angezweifelt hatte, hatte halt nur nichts mit dem Thema zu tun). Bevor 
du das nächste Mal in eine Diskussion einsteigst lies doch erst mal 
worüber genau diskutiert wird. Hält den Blutdruck bei allen unten und 
verringert die Missverständnisse.

Peter schrieb:
> Siehe an es funktioniert.

Sehr schön.

Peter schrieb:
> Vielen dank an alle!
> Für Verbesserungen bin ich gerne zu haben. Man lernt nie aus!

Ich würde noch das set_sleep_mode() in den Init-Bereich werfen, damit 
wird die sleep_now() praktisch überflüssig. Außerdem muss man den 
Sleep-Modus nicht ständig neu einstellen wenn man eh nur einen nutzt ;)
Das sei() im watchdog-init() würde ich an Ende des Init-Bereichs stellen 
und ich würde das watchdog-init() aus dem todo() raus werfen. Macht IMO 
da keinen Sinn drin. Also in etwa so würde ich es machen:
//  Atmega328p intern 1 Mhz
#define    F_CPU        1000000UL
#include  <avr/io.h>
#include   <util/delay.h>
#include   <avr/interrupt.h>
// #include   <avr/power.h>
#include   <avr/sleep.h>
#include   "rfm69.c"

uint8_t array[MAX_ARRAYSIZE + 1];
uint8_t tx_length;

volatile uint8_t sekunden=0;

void watchdog_init()
{
  // watchdog konfigurieren
  WDTCSR = (1 << WDCE)|(1 << WDE);  // zunaechst Schutz des Registers aufheben gemaess Datasheet
  WDTCSR = (1 << WDIE)|(1 << WDP3)|(1 << WDP0);  // Interruptmode an, Zeit auf 8s einstellen
}

void todo()
{
  //Daten auswerten und senden
  sekunden=sekunden+8;
  array[0]=0;
  array[1]++;
  array[2]=0;
  array[3]=array[3]+10;
  array[4]=sekunden;
  tx_length=5;
  rfm_transmit(array, tx_length);  
}

ISR(WDT_vect)
{
  todo();
}

int main( void )
{
  watchdog_init();
  rfm_init();  
  todo();
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  //  SLEEP_MODE_PWR_SAVE SLEEP_MODE_PWR_DOWN
  sei();
  while(1)
  {
    sleep_mode();
  }
}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.