Z pewnością możesz. Zgodnie z arkuszem danych, zegar nadzoru może być ustawiony tak, aby resetował MCU lub powodował przerwanie po uruchomieniu. Wygląda na to, że bardziej interesuje Cię możliwość przerwania.
WDT jest w rzeczywistości łatwiejszy do skonfigurowania niż zwykły Timer z tego samego powodu, dla którego jest mniej przydatny: mniej opcji. Działa na wewnętrznie skalibrowanym zegarze 128 kHz, co oznacza, że na jego taktowanie nie ma wpływu szybkość głównego zegara MCU. Może także działać w najgłębszych trybach uśpienia, aby zapewnić źródło budzenia.
Przejdę przez kilka przykładów arkusza danych, a także kod, którego użyłem (w C).
Dołączone pliki i definicje
Aby rozpocząć, prawdopodobnie będziesz chciał dołączyć następujące dwa pliki nagłówkowe, aby wszystko działało:
#include <avr/wdt.h> // Supplied Watch Dog Timer Macros
#include <avr/sleep.h> // Supplied AVR Sleep Macros
Ponadto używam makra <_BV (BIT)>, które jest zdefiniowane w jednym ze standardowych nagłówków AVR jako następujące (które mogą być dla ciebie bardziej rodzinne):
#define _BV(BIT) (1<<BIT)
Początek kodu
Kiedy MCU jest uruchamiane po raz pierwszy, zwykle inicjujesz I / O, ustawiasz timery itp. Gdzieś tutaj jest dobry moment, aby upewnić się, że WDT nie spowodował resetu, ponieważ mógł to zrobić ponownie, utrzymując program w niestabilna pętla.
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
}
Konfiguracja WDT
Następnie, po skonfigurowaniu reszty układu, wykonaj ponownie WDT. Konfiguracja WDT wymaga „sekwencji czasowej”, ale jest to naprawdę łatwe do zrobienia ...
// 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
Oczywiście, twoje przerwania powinny być wyłączone podczas tego kodu. Pamiętaj, aby je później ponownie włączyć!
cli(); // Disable the Interrupts
sei(); // Enable the Interrupts
Procedura przerwania usługi WDT
Następną rzeczą, o którą należy się martwić, jest obsługa WDT ISR. Odbywa się to w ten sposób:
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
Zamiast uśpienia MCU w WDR ISR, zalecam po prostu włączenie trybu uśpienia na końcu ISR, a następnie program MAIN uśpienie MCU. W ten sposób program faktycznie opuszcza ISR, zanim przejdzie w tryb uśpienia, a następnie obudzi się i przejdzie bezpośrednio do WDT ISR.
// 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
****************************/
}
}