Hallo!
Ich bin recht neu in der Welt der µc's, und hänge gerade an einem
kleinen Problemchen. Gerade beschäftige ich mich mit dem Watchdog-Timer
des Attinys. Klappt so weit auch ganz gut.
Jedoch habe ich laut Datasheet nur ein maximales Timeout von 8 Sekunden.
Dieses versuche ich wie folgt zu verlängern:
1
#define F_CPU 1000000UL
2
3
#include<avr/io.h>
4
#include<util/delay.h>
5
#include<avr/sleep.h>
6
#include<avr/wdt.h>
7
#include<avr/interrupt.h>
8
9
volatilechari=0;
10
11
voidWDT_Init()
12
{
13
cli();
14
wdt_reset();
15
WDTCR=(1<<WDCE)|(1<<WDE);
16
WDTCR=(1<<WDIE)|(1<<WDE)|(1<<WDP3)|(1<<WDP0);
17
sei();
18
}
19
20
ISR(WDT_vect)
21
{
22
i++;
23
if(i>=2)
24
{
25
i=0;
26
PORTB^=(1<<PB0);
27
}
28
}
29
30
intmain()
31
{
32
DDRB=(1<<PB0);
33
WDT_Init();
34
_delay_ms(500);
35
while(1){}
36
}
Geplant ist die LED (die an PB0 angeschlossen ist) nach ~16 Sekunden zu
togglen. Leider resetet der Attiny an diesem Zeitpunkt nur. Selbst wenn
ich "i" größer 2 setze, resetet der Attiny nach ca ~16 Sekunden. Mit "i
<= 1" funktioniert alles wie gehabt, als hätte ich keine Abfrage herum
gebaut.
Könnte mir da eventuell jemand einen Denkanstoß geben? Vielen dank
schonmal!
Senz
Der ATtiny hat besser geeignete Timer für Dein Problem. Der
Watchdog-Timer ist dafür da, Deinen µC zu resetten. Um eine LED blinken
zu lassen, ist er eigentlich nicht für gedacht.
Wie wo was ?
A. K. schrieb:> Der WDT Interrupt wird durch das Ereignis abgeschaltet und muss folglich> in der ISR wieder eingeschaltet werden.
das habe ich noch nie erlebt !
Ich mache das so
Uwe S. schrieb:>> Der WDT Interrupt wird durch das Ereignis abgeschaltet und muss folglich>> in der ISR wieder eingeschaltet werden.>> das habe ich noch nie erlebt !
Das ist nicht nur so in der Doku zum WDIE Flag dokumentiert, es ergibt
sogar Sinn. Denn andernfalls wäre ein Controller verloren, dessen WDT
Interrupt versagt. Mit diesem Trick geht der zweite statt dessen auf
Reset und sorgt für klare Verhältnisse.
Ein Watchdog ist ein Wachhund. Kein Schosshündchen.
Hallo A. K.,
das von Dir beschriebe Verhalten kann ich nicht bestätigen, weder auf
eine Atmegaxy8 oder noch auf einem Attiny841, von dem der WDT-Init Code
stammt.
der WDT im Attiny841 kann als normaler Timer benützt werden.
Im meinem Attiny841 Beispielprogramm werden alle Timer0-3 und der WDT
als Timer (64ms) betrieben um 4 Task anzustoßen, diese lassen nach
weiteren Verzögerungen, 4 LED mit unterschiedlichen Frequenzen blinken.
Wenn deine Annahme richtig wäre, müsste der WDT-Task nur 1x durchlaufen.
Aber dem ist nicht so.
Aus dem Datasheet des ATtiny85 Rev 04/11:
Bit 6 – WDIE: Watchdog Timeout Interrupt Enable
[...]
If WDE is set, WDIE is automatically cleared by hardware when a time-out
occurs. This is useful for keeping the Watchdog Reset security while
using the interrupt. After the WDIE bit is cleared, the next time-out
will generate a reset. To avoid the Watchdog Reset, WDIE must be set
after each interrupt.
Und dass es auch real so ist hat Sanz eindrucksvoll bewiesen.
Danke A. K.,
für die Klarstellung im Modus WDE = 1.
In meinem Assembler Beispiel ist aber WDE = 0 ! und somit gilt die
Bedingung nicht.
/If WDE is set, WDIE is automatically cleared by hardware when a
time-out occurs. This is useful for keeping the Watchdog Reset security
while using the interrupt. After the WDIE bit is cleared, the next
time-out will generate a reset./
/To avoid the Watchdog Reset, WDIE must be set after each interrupt./
Deshalb läuft der WDT bei mir als normaler Timer mit groben Zeitraster.
Uwe S. schrieb:> Deshalb läuft der WDT bei mir als normaler Timer mit groben Zeitraster.
So ergibt das einen Sinn. Im Code von Senz ist freilich WDE=1.
Ich hatte diese Eigenschaft selbst schon auf einem ATtiny841 verwendet,
um sicherzustellen, dass es einen Reset gibt, wenn dessen I2C Slave aus
irgend einem Grund längere Zeit mitten in einer Message hängen bleibt.
Und das auch getestet:
1
ISR(WDT_vect)
2
{
3
if(i2c_state==I2C_Idle){
4
WDTCSR|=1<<WDIE;// re-enable the watch dog interrupt
WDTCR|=(1<<WDIE);// Watchdog Interrupt muss jedes mal neu aktiviert werden, sonst macht WDT Reset
5
}
In der Main wird die WD-Initialisierung einmal aufgerufen und so die
Parameter eingestellt; so werden mit WD_PRESCALE von 0...9 die
Timerzeiten von 16ms bis 8s gewählt - je nach Anwendung.
1
voidInit_WD()
2
{
3
uint8_twd_timer_prescale;
4
uint8_twdt_flags;
5
6
// Watchdog IRQ initialisieren
7
wd_timer_prescale=WD_PRESCALE;
8
if(wd_timer_prescale>9)wd_timer_prescale=9;
9
wdt_flags=wd_timer_prescale&7;
10
if(wd_timer_prescale>7)wdt_flags|=(1<<5);// wdt_flags enthält den Prescalerwert (0 .. 9)
11
wdt_flags|=(1<<WDCE);
12
13
// Watchdoginterrupt aktivieren
14
sei();
15
WDTCR|=(1<<WDCE)|(1<<WDE);
16
WDTCR=wdt_flags|(1<<WDIE);
17
}
Man muss nur nur das WDIE-Bit nach jedem Interrupt wieder neu zu setzen.
In der Main kann dann an geeigneter Stelle der Prozessor in den
Power-Down-Schlaf gelegt werden und wird nach Ablauf der WD-Zeit wieder
geweckt.
Mit 'wcount' wird die Anzahl der WD-Interrupts gezählt und bei Null die
gewünschte Aktion gestartet.
Die Fuse WDTON darf nicht aktiviert sein.
So kann man die relativ lange Zeit des WD-Timers für große Zeiten
verwenden und durch den Power-Down-Mode recht stromsparend unterwegs
sein. Mein ATtiny85 braucht dabei ca. 5µA@4V - wenn ich es richtig weiß,
ist das weniger als bei einer Lösung mit einem Timer, weil damit nicht
aus dem Power-Down-Mode geweckt werden kann.