Você certamente pode. De acordo com a folha de dados, o timer do watchdog pode ser configurado para redefinir o MCU ou causar uma interrupção quando acionado. Parece que você está mais interessado na possibilidade de interrupção.
O WDT é realmente mais fácil de configurar do que um temporizador normal, pelo mesmo motivo que é menos útil: menos opções. Ele roda em um relógio de 128kHz calibrado internamente, o que significa que seu tempo não é afetado pela velocidade do relógio principal do MCU. Ele também pode continuar sendo executado nos modos de sono mais profundo para fornecer uma fonte de ativação.
Analisarei alguns exemplos de dados, bem como algum código que usei (em C).
Arquivos e definições incluídos
Para começar, você provavelmente desejará incluir os dois arquivos de cabeçalho a seguir para que as coisas funcionem:
#include <avr/wdt.h> // Supplied Watch Dog Timer Macros
#include <avr/sleep.h> // Supplied AVR Sleep Macros
Além disso, eu uso a macro <_BV (BIT)> que é definida em um dos cabeçalhos padrão do AVR como a seguir (que pode ser mais familiar para você):
#define _BV(BIT) (1<<BIT)
Início do Código
Quando o MCU é iniciado pela primeira vez, você normalmente inicializa a E / S, configura os temporizadores, etc. Em algum lugar aqui é um bom momento para garantir que o WDT não tenha causado uma redefinição porque poderia fazê-lo novamente, mantendo o programa em um loop instável.
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
}
Configuração WDT
Depois de configurar o restante do chip, refaça o WDT. A configuração do WDT requer uma "sequência programada", mas é realmente fácil de fazer ...
// 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
Obviamente, suas interrupções devem ser desativadas durante esse código. Certifique-se de reativá-los depois!
cli(); // Disable the Interrupts
sei(); // Enable the Interrupts
Rotina de serviço de interrupção WDT
A próxima coisa a se preocupar é lidar com o WDT ISR. Isso é feito da seguinte maneira:
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
Em vez de colocar o MCU em repouso dentro do WDT ISR, recomendo simplesmente ativar o modo de suspensão no final do ISR e pedir ao programa PRINCIPAL que coloque o MCU em repouso. Dessa forma, o programa está realmente saindo do ISR antes que ele entre no modo de suspensão, e ele será ativado e retornará diretamente ao ISR do 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
****************************/
}
}