你当然可以。根据数据表,看门狗定时器可以设置为复位 MCU 或在触发时产生中断。看来您对中断的可能性更感兴趣。
WDT 实际上比普通定时器更容易设置,原因与它不太有用的原因相同:更少的选项。它在内部校准的 128kHz 时钟上运行,这意味着它的时序不受 MCU 主时钟速度的影响。它还可以在最深睡眠模式下继续运行以提供唤醒源。
我将介绍几个数据表示例以及我使用过的一些代码(在 C 中)。
包含的文件和定义
首先,您可能需要包含以下两个头文件才能正常工作:
#include <avr/wdt.h> // Supplied Watch Dog Timer Macros
#include <avr/sleep.h> // Supplied AVR Sleep Macros
另外,我使用了在标准 AVR 标头之一中定义的宏 <_BV(BIT)>,如下所示(对您来说可能更熟悉):
#define _BV(BIT) (1<<BIT)
代码开头
当 MCU 首次启动时,您通常会初始化 I/O、设置计时器等。此时是确保 WDT 不会导致复位的好时机,因为它可以再次执行此操作,从而使您的程序保持在一个不稳定的循环。
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 设置
然后,在您设置好芯片的其余部分后,重做 WDT。设置 WDT 需要一个“定时序列”,但这很容易做到……
// 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
当然,在此代码期间应禁用您的中断。请务必在之后重新启用它们!
cli(); // Disable the Interrupts
sei(); // Enable the Interrupts
WDT 中断服务程序
接下来要担心的是处理 WDT ISR。这样做是这样的:
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 在 WDT ISR 内进入睡眠状态,我建议在 ISR 结束时简单地启用睡眠模式,然后让 MAIN 程序让 MCU 进入睡眠状态。这样,程序实际上在进入睡眠之前就离开了 ISR,它会醒来并直接回到 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
****************************/
}
}