Das können Sie mit Sicherheit. Laut Datenblatt kann der Watchdog-Timer so eingestellt werden, dass die MCU zurückgesetzt wird oder ein Interrupt ausgelöst wird. Es scheint, dass Sie mehr an der Interrupt-Möglichkeit interessiert sind.
Der WDT ist aus dem gleichen Grund, aus dem er weniger nützlich ist: weniger Optionen, einfacher einzurichten als ein normaler Timer. Es läuft mit einem intern kalibrierten 128-kHz-Takt, was bedeutet, dass das Timing nicht durch die Haupttaktrate der MCU beeinflusst wird. Es kann auch im Tiefschlafmodus weiterlaufen, um eine Weckquelle bereitzustellen.
Ich werde ein paar Datenblattbeispiele sowie einen Code durchgehen, den ich verwendet habe (in C).
Enthaltene Dateien und Definitionen
Zu Beginn möchten Sie wahrscheinlich die folgenden zwei Header-Dateien einbinden, damit die Dinge funktionieren:
#include <avr/wdt.h> // Supplied Watch Dog Timer Macros
#include <avr/sleep.h> // Supplied AVR Sleep Macros
Außerdem verwende ich das Makro <_BV (BIT)>, das in einem der Standard-AVR-Header wie folgt definiert ist (was für Sie möglicherweise vertrauter ist):
#define _BV(BIT) (1<<BIT)
Beginn des Codes
Wenn die MCU zum ersten Mal gestartet wird, initialisieren Sie in der Regel die E / A, richten Timer ein usw. Hier ist ein guter Zeitpunkt, um sicherzustellen, dass der WDT keinen Reset verursacht, da er dies erneut ausführen kann, und Ihr Programm dabei belässt eine instabile Schleife.
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
Nachdem Sie den Rest des Chips eingerichtet haben, wiederholen Sie den WDT. Das Einrichten des WDT erfordert eine "zeitgesteuerte Sequenz", aber es ist wirklich einfach zu tun ...
// 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
Natürlich sollten Ihre Interrupts während dieses Codes deaktiviert sein. Vergessen Sie nicht, sie danach wieder zu aktivieren!
cli(); // Disable the Interrupts
sei(); // Enable the Interrupts
WDT-Interrupt-Serviceroutine
Das nächste, worüber Sie sich Sorgen machen müssen, ist die Behandlung des WDT-ISR. Dies geschieht so:
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-Schlaf
Anstatt die MCU innerhalb des WDT-ISR in den Ruhezustand zu versetzen, empfehle ich, einfach den Ruhezustand am Ende des ISR zu aktivieren und die MCU dann vom MAIN-Programm in den Ruhezustand zu versetzen. Auf diese Weise verlässt das Programm den ISR tatsächlich, bevor es in den Ruhezustand wechselt, und wird aufgeweckt und kehrt direkt in den WDT-ISR zurück.
// 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
****************************/
}
}