Hallo,
nachdem ich es dank eurer Hilfe geschafft habe, einen ATTiny85 schlafen
zu legen und mit einem externen Interrupt aufzuwecken wollte ich das nun
mit Hilfe des watchdog versuchen. Dabei passiert aber folgendes: die LED
leuchtet 10 Sekunden und geht dann für einen kurzen Moment aus um gleich
danach wieder 10 Sekunden zu leuchten. Sinn soll sein, dass der watchdog
den sleep-Modus unterbricht, den mitgeführten Zähler inkrementell erhöht
und prüft, ob er über einen Schwellenwert gekommen ist für einen
kompletten reset oder ob er nochmal schlafen gehen darf.
Es würde mich freuen, wenn ich hier wieder etwas Lern-hilfe bekommen
konnte.
Danke!
Jetzt geht er exakte 4 Sekunden schlafen. Kann es sein: entweder
resettet der watchdog den tiny85 noch während er im Schlaf ist und/oder
er springt nicht in die ISR(WDT_vect)
Weil, wenn ich die ISR(WDT_vect) mit einem wdt_reset() in der 1. Zeile
versehe und danach in einer kleinen for-Schleife die LED blinken lassen
will, blinkt die LED nämlich nicht.
Ich bin jetzt kein Profi in Sachen µC-Programmierung, habe aber als
Übung mal einen Treppenhausautomaten programmiert unter Verwendung des
WD-Timers. Auch mit ein paar Ehrenrunden, speziell beim WD :-).
> oder er springt nicht in die ISR(WDT_vect)
Ich sehe z.B. kein sei() in deinem Code, somit sind die Interrupts gar
nicht aktiv. Und, die Fuse WDTON darf nicht aktiviert sein!
Hier mal einen Extrakt aus meinem Code für u.U. sehr lange Zeiten, den
ich aber so nicht geprüft habe. Vielleicht kannst du damit was anfangen:
1
/*
2
* Langzeittimer mit Watchdog-Interrupt
3
*
4
* Monoflop, wie Treppenlichautomat mit Langzeittimer, nachtriggerbar
5
6
*/
7
// Hinweis: WDTON unprogrammiert!
8
9
#define F_CPU 1e6
10
11
#include<avr/io.h>
12
#include<avr/interrupt.h>
13
#include<avr/sleep.h>
14
#include<util/delay.h>
15
#include<avr/wdt.h>
16
17
#define WD_PRESCALE 9 // Prescaler-Einstellung (Einheit) von 0 (16ms) bis 9 (8s) [6: ca 1s]
18
#define TIME_MULTIPLY 5 // Faktor für Zeiteinheit
19
20
// Setup Funktion
21
#define HIGH_ACTIVE
22
#define NOT_RETRIGGERABLE
23
24
volatileuint32_tl_wcount=1;// einfach ungleich Null setzen, dann sleep nach Reset
25
26
27
ISR(WDT_vect)
28
{
29
l_wcount--;
30
WDTCR|=(1<<WDIE);// Watchdog Interrupt muss jedes mal neu aktiviert werden, sonst mach WDT Reset
31
}
32
33
ISR(INT0_vect)// Über ADC die Zahl der WD-Schleifen lesen l_wcount
34
{
35
l_wcount=TIME_MULTIPLY;// Zeit festlegen
36
GIMSK=0;// INT0-IRQ abschalten
37
}
38
39
intmain()
40
{
41
uint8_twd_timer_prescale;
42
uint8_twdt_flags;
43
44
// Ports definieren
45
/*
46
PB1 (Pin 6) Output, MISO, Schaltsignal
47
PB2 (Pin 7) Input, Starttaste, SCK, INT0
48
PB5 (Pin 1) Reset
49
50
Alle Ausgänge sind LOW-aktiv
51
INT0 und Taste sind LOW-aktiv
52
*/
53
54
// Ports definieren
55
PORTB=0x00;
56
DDRB=(1<<PB1);
57
PORTB|=(1<<PB2);//Pullup
58
59
// zum Test, ob Reset passiert
60
PORTB|=(1<<PB1);
61
_delay_ms(100);
62
PORTB&=~(1<<PB1);
63
64
// Power-Down Sleep Mode einstellen
65
set_sleep_mode(SLEEP_MODE_PWR_DOWN);// stromsparend, aufwecken über WD oder INT0
66
sleep_enable();// Schlafmodus vorbereiten
67
68
sei();
69
// Externen Pin Level IRQ auf Low Level aktivieren
70
MCUCR&=~((1<<ISC00)|(1<<ISC01));
71
72
// Watchdog IRQ vorbereiten
73
wd_timer_prescale=WD_PRESCALE;
74
if(wd_timer_prescale>9)wd_timer_prescale=9;
75
wdt_flags=wd_timer_prescale&7;
76
if(wd_timer_prescale>7)wdt_flags|=(1<<5);// wdt_flags enthält den Prescalerwert (0 .. 9)
77
wdt_flags|=(1<<WDCE);
78
79
// Hauptschleife
80
while(1)
81
{
82
if(l_wcount==0)
83
{
84
// WD-Timer ist 'l_wcount'-mal abgelaufen
85
// Watchdog ausschalten, dann Dauerschlaf bis INT0
}//Wenn Hund aufwacht sollte es hierhin gehen, tut es aber nicht...
40
41
voidgo_sleep(){
42
digitalWrite(LED,LOW);
43
set_sleep_mode(SLEEP_MODE_IDLE);//Im IDLE geht tiny nicht mehr an, PWR_DOWN macht nach WDTO_xS reboot
44
ADCSRA=0;
45
wdtEnable();
46
sleep_enable();
47
sleep_cpu();
48
sleep_disable();
49
wdtDisable();
50
}//schlafen gehen
51
52
voidwdtEnable()
53
{
54
cli();
55
wdt_enable(WDTO_4S);
56
sei();
57
}//watchdog aktivieren
58
59
voidwdtDisable()
60
{
61
cli();
62
wdt_disable();
63
sei();
64
}//watchdog deaktivieren
65
66
voidwdt_reboot(){
67
wdt_enable(WDTO_500MS);
68
while(true){}
69
}//watchdog löst nach 500ms reboot aus
Was interessant ist: im IDLE geht der Tiny überhaupt nicht mehr an, in
PWR_DOWN nach der Zeit, die in WDTO_xS steht.
Die fuses sind gebrannt mit:
low_fuses=0xe2
high_fuses=0xdf (für WDTON cf)
extended_fuses=0xff
Vom Prinzip her glaube ich reißt der watchdog den Tiny aus dem Schlaf
und macht einen reset statt einen interrupt auszulösen und in die
ISR(wdt_vect) zu springen. Wenn das stimmt, weiß ich aber leider nicht
wie ich den Code ändern müsste, damit ein interrupt draus wird.
bascom und assembler kann ich leider nicht…
Vielen Dank für weitere Starthilfe!
Die Fuses stimmen. Das Programm sieht sehr kompliziert aus, können Sie
nicht versuchen, meinen Vorschlag in c umzusetzen, so irgendwie (ich
kann kein c):
Tobias schrieb:> leider ohne Erfolg:
Kann ja auch nicht gehen, wenn WDIE erst im Interrupt gesetzt wird, der
seinerseits erst aufgerufen wird, wenn WDIE vorher gesetzt war.
Und WDE darf für den WDT-Interrupt nicht gesetzt sein, auf die
notwendige Sequenz dafür achten. Bzw. wdtDisable(); sollte es auch tun.
MWS schrieb:> Und WDE darf für den WDT-Interrupt nicht gesetzt sein, auf die> notwendige Sequenz dafür achten. Bzw. wdtDisable(); sollte es auch tun.
Aber sicher darf der gesetzt sein. Muss er sogar, wenn nach dem
Interrupt auch der Reset ausgeführt werden soll. Um diesen Reset dann
nicht auszulösen, muss, sinnvoller Weise in der ISR, WDIE erneut gesetzt
werden.
Ist WDE nicht gesetzt, läuft der WD als reiner Timer. Dann kann auch das
erneute Setzen von WDIE entfallen.
mfg.
Thomas E. schrieb:> MWS schrieb:>> Und WDE darf für den WDT-Interrupt nicht gesetzt sein, auf die>> notwendige Sequenz dafür achten. Bzw. wdtDisable(); sollte es auch tun.>> Aber sicher darf der gesetzt sein. Muss er sogar, wenn nach dem> Interrupt auch der Reset ausgeführt werden soll. Um diesen Reset dann> nicht auszulösen, muss, sinnvoller Weise in der ISR, WDIE erneut gesetzt> werden.
Ich weiß nicht, zu welchem Thread Du diskutierst, aber ich beziehe mich
auf den Thread hier und da geht's ausschließlich um's Aufwecken aus dem
Sleep per WD-Interrupt, der WD-Reset war nicht Thema.
Und "sinnvollerweise in der ISR"?
Das Datenblatt ist dazu nicht Deiner Meinung:
> WDIE must be set after each interrupt. This should however not be done> within the interrupt service routine itself, as this might compromise> the safety-function of the Watchdog System Reset mode.Thomas E. schrieb:> Ist WDE nicht gesetzt, läuft der WD als reiner Timer. Dann kann auch das> erneute Setzen von WDIE entfallen.
Das erneute Setzen kann entfallen, nicht das erstmalige. Ich hab' auch
nicht geschrieben, dass WDIE erneut gesetzt werden muss, lies meinen
Satz nochmal genau, da steht dass das WDIE so nicht erreicht werden
kann.
MWS schrieb:> der WD-Reset war nicht Thema.
Nein?
Tobias schrieb:> ob er über einen Schwellenwert gekommen ist für einen> kompletten reset oder ob er nochmal schlafen gehen darf.MWS schrieb:>> WDIE must be set after each interrupt. This should however not be done>> within the interrupt service routine itself, as this might compromise>> the safety-function of the Watchdog System Reset mode.
OK. Mein Fehler.
mfg
MWS schrieb:> Das erneute Setzen kann entfallen, nicht das erstmalige. Ich hab' auch> nicht geschrieben, dass WDIE erneut gesetzt werden muss, lies meinen> Satz nochmal genau, da steht dass das WDIE so nicht erreicht werden> kann.
Lies meinen Satz nochmal genau. Da wirst auch du vielleicht erkennen,
dass ich mich gar nicht auf das erste Setzen bezogen habe.
mfg.
MWS schrieb:> Und "sinnvollerweise in der ISR"?> Das Datenblatt ist dazu nicht Deiner Meinung:>>> WDIE must be set after each interrupt. This should however not be done>> within the interrupt service routine itself, as this might compromise>> the safety-function of the Watchdog System Reset mode.
Ich weiß nicht welches Datenblatt du hast, in meinem vom Tiny25/45/85
von 8/2013 steht: "To avoid the Watchdog Reset, WDIE must be set after
each interrupt." Und nicht mehr. Damit kann das auch in der WD-IRQ sein,
denn da ist der Interrupt schon erfolgt.
Thomas E. schrieb:> Ist WDE nicht gesetzt, läuft der WD als reiner Timer. Dann kann auch das> erneute Setzen von WDIE entfallen.
Danke - das hatte ich bisher übersehen.
HildeK schrieb:> Ich weiß nicht welches Datenblatt du hast, in meinem vom Tiny25/45/85> von 8/2013 steht: "To avoid the Watchdog Reset, WDIE must be set after> each interrupt." Und nicht mehr. Damit kann das auch in der WD-IRQ sein,> denn da ist der Interrupt schon erfolgt.
Ich hab das momentan neueste Rev. 8265D–AVR–01/2014, frisch
runtergeladene Datenblatt und Du offensichtlich ein altes. Du must kein
altes nehmen, sondern kannst auch ein neues von Atmel runterladen.
Abgesehen davon, was verstehst Du denn an dem Zitat im neuen DB nicht?
Es ist der Hinweis, dass es für die Sicherheit des WD-Resets schädlich
ist, wenn im kombinierten Mode der WD-Interrupt in zugehöriger ISR
wieder erlaubt wird.
Was klar wird, wenn man annimmt, das sich das Hauptprogramm so gefressen
hat, dass die Interrupts noch laufen. Wenn der WDT aufgrund des
Absturzes nicht zurückgesetzt wird, werden die WD-Interrupts dennoch
weiter ausgeführt, was einen Systemreset verhindert. Diese Tatsache ist
unabhängig vom DB, war auch zum Zeitpunkt des alten schon so, nur
stand's da eben noch anders.
Technisch funktioniert das erneute Setzen des WDIE in der ISR, nur eben
mit dem beschriebenen Nachteil. Das kannst Du für Dich dann halten, wie
Du willst.
MWS schrieb:> Du must kein> altes nehmen, sondern kannst auch ein neues von Atmel runterladen.
Das wundert mich, denn ich hatte mir das Tiny25/45/85 direkt von der
Atmel Webseite geholt ... und hier ging es um den Tiny85 und nicht um
den 87/167.
Da ist die Version Rev. 2586Q–AVR–08/2013 abgelegt:
http://www.atmel.com/Images/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf
Trotzdem ist dein Einwand korrekt, aber irgendwann vor Ablauf der
WD-Timerzeit muss der WDIE wieder gesetzt werden. Und danach ist es dann
für die Sicherheit wieder schädlich.
Aber, wie du schon richtig bemerkt hast:
> Das kannst Du für Dich dann halten, wie Du willst.
HildeK schrieb:> Trotzdem ist dein Einwand korrekt, aber irgendwann vor Ablauf der> WD-Timerzeit muss der WDIE wieder gesetzt werden. Und danach ist es dann> für die Sicherheit wieder schädlich.
Damit das System wie vorgesehen sicher ist, erfolgt an einer oder
mehreren Stellen in normal zu durchlaufendem Code entweder der Reset des
WDT oder es wird das WDIE gesetzt.
> Aber, wie du schon richtig bemerkt hast:>> Das kannst Du für Dich dann halten, wie Du willst.
Übers.: Du kannst es auch falsch machen.