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?
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?
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.
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:
1
// Atmega328p intern 1 Mhz
2
#define F_CPU 1000000UL
3
#include<avr/io.h>
4
#include<util/delay.h>
5
#include<avr/interrupt.h>
6
#include<avr/power.h>
7
#include<avr/sleep.h>
8
#include"rfm69.c"
9
10
uint8_tarray[MAX_ARRAYSIZE+1];
11
uint8_ttx_length;
12
13
volatileuint8_tsekunden=0;
14
15
voidsleep_now()
16
{
17
power_all_disable();
18
sleep_mode();
19
}
20
21
voidtodo()
22
{
23
//Daten auswerten und senden
24
sekunden++;
25
array[0]=sekunden;
26
array[1]++;
27
tx_length=2;
28
rfm_transmit(array,tx_length);
29
}
30
31
intmain(void)
32
{
33
// watchdog konfigurieren
34
// zunaechst Schutz des Registers aufheben gemaess Datasheet
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.
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.
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.
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" ;)
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?
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:
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.
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.
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:
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.
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.
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
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.
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.
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. :)
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.
Thomas E. schrieb:> Peter D. schrieb:>> Du vergißt, daß er noch seine ATmega8 Schätzchen aufbrauchen will.>> ???:
Sorry, war gedanklich im falschen Thread.
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:
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.
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.
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 ;)
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.
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.
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.
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)?
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)
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.
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!
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:
1
// Atmega328p intern 1 Mhz
2
#define F_CPU 1000000UL
3
#include<avr/io.h>
4
#include<util/delay.h>
5
#include<avr/interrupt.h>
6
// #include <avr/power.h>
7
#include<avr/sleep.h>
8
#include"rfm69.c"
9
10
uint8_tarray[MAX_ARRAYSIZE+1];
11
uint8_ttx_length;
12
13
volatileuint8_tsekunden=0;
14
15
voidwatchdog_init()
16
{
17
// watchdog konfigurieren
18
WDTCSR=(1<<WDCE)|(1<<WDE);// zunaechst Schutz des Registers aufheben gemaess Datasheet
19
WDTCSR=(1<<WDIE)|(1<<WDP3)|(1<<WDP0);// Interruptmode an, Zeit auf 8s einstellen