Certamente puoi. Secondo la scheda tecnica, il timer del watchdog può essere impostato per ripristinare l'MCU o causare un interrupt quando si attiva. Sembra che tu sia più interessato alla possibilità di interrompere.
Il WDT è in realtà più facile da installare rispetto a un normale Timer per lo stesso motivo per cui è meno utile: meno opzioni. Funziona su un clock 128kHz calibrato internamente, il che significa che il suo timing non è influenzato dalla velocità di clock principale dell'MCU. Può anche continuare a funzionare durante le modalità di sospensione più profonde per fornire una fonte di sveglia.
Esaminerò un paio di esempi di schede tecniche e alcuni codici che ho usato (in C).
File e definizioni inclusi
Per iniziare, probabilmente vorrai includere i seguenti due file di intestazione affinché le cose funzionino:
#include <avr/wdt.h> // Supplied Watch Dog Timer Macros
#include <avr/sleep.h> // Supplied AVR Sleep Macros
Inoltre, uso la macro <_BV (BIT)> che è definita in una delle intestazioni AVR standard come la seguente (che potrebbe essere più familiare per te):
#define _BV(BIT) (1<<BIT)
Inizio del codice
Quando la MCU viene avviata per la prima volta, in genere si inizializzano l'I / O, si impostano i timer, ecc. Da qualche parte qui è un buon momento per assicurarsi che il WDT non abbia causato un reset perché potrebbe farlo di nuovo, mantenendo il programma in un ciclo instabile.
if(MCUSR & _BV(WDRF)){ // If a reset was caused by the Watchdog Timer...
MCUSR &= ~_BV(WDRF); // Clear the WDT reset flag
WDTCSR |= (_BV(WDCE) | _BV(WDE)); // Enable the WD Change Bit
WDTCSR = 0x00; // Disable the WDT
}
WDT Setup
Quindi, dopo aver impostato il resto del chip, ripetere il WDT. L'impostazione del WDT richiede una "sequenza temporizzata", ma è davvero facile da fare ...
// Set up Watch Dog Timer for Inactivity
WDTCSR |= (_BV(WDCE) | _BV(WDE)); // Enable the WD Change Bit
WDTCSR = _BV(WDIE) | // Enable WDT Interrupt
_BV(WDP2) | _BV(WDP1); // Set Timeout to ~1 seconds
Naturalmente, i tuoi interrupt dovrebbero essere disabilitati durante questo codice. Assicurati di riattivarli in seguito!
cli(); // Disable the Interrupts
sei(); // Enable the Interrupts
Routine di servizio di interruzione WDT
La prossima cosa di cui preoccuparsi è la gestione dell'ISR WDT. Questo viene fatto come tale:
ISR(WDT_vect)
{
sleep_disable(); // Disable Sleep on Wakeup
// Your code goes here...
// Whatever needs to happen every 1 second
sleep_enable(); // Enable Sleep Mode
}
MCU Sleep
Invece di mettere l'MCU in modalità di sospensione all'interno dell'ISR WDT, consiglio semplicemente di abilitare la modalità di sospensione alla fine dell'ISR, quindi fare in modo che il programma MAIN metta l'MCU in modalità sospensione. In questo modo, il programma sta effettivamente lasciando l'ISR prima di andare a dormire e si risveglierà e tornerà direttamente all'ISR WDT.
// Enable Sleep Mode for Power Down
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set Sleep Mode: Power Down
sleep_enable(); // Enable Sleep Mode
sei(); // Enable Interrupts
/****************************
* Enter Main Program Loop *
****************************/
for(;;)
{
if (MCUCR & _BV(SE)){ // If Sleep is Enabled...
cli(); // Disable Interrupts
sleep_bod_disable(); // Disable BOD
sei(); // Enable Interrupts
sleep_cpu(); // Go to Sleep
/****************************
* Sleep Until WDT Times Out
* -> Go to WDT ISR
****************************/
}
}