/* a trial of watchdog behaviour
* the watchdog timer is usually intended to reset a micro in case code get's stuck
* alternatively the watchdog timer can be use to wake up a sleeping micro, hence making it a
* versatile means for low power applications which have to wake up only every now and then.
* I have been using this approach as a replacement for a real time clock (RTC) chip and in combination
* with a piece of code represeting a virtual RTC.
* this is intended to work on atmega328 run on 16 MHz (as is usually the case for an Arduino UNO)
* a calibration is recommended, when time has to reach a certain precision -
* the simulation model includes a logic analyser to monitor the toggeling signal of the LED
*
* ! NOTE: on hardware make sure, the fuse WDTON is unprogrammed, i.e. set to "1"
* (see for datasheet, chapter "Register description")
*
*/
#include <avr/wdt.h> // library for default watchdog functions
#include <avr/sleep.h>
#include <avr/interrupt.h> // library for interrupts handling
#include <avr/power.h>
// variables ...
uint8_t ledState;
// defines for WDT timeout
#define WDT_TO_16ms 0
#define WDT_TO_32ms (1 << WDP0)
#define WDT_TO_64ms (1 << WDP1)
#define WDT_TO_125ms (1 << WDP1) | (1 << WDP0)
#define WDT_TO_250ms (1 << WDP2)
#define WDT_TO_500ms (1 << WDP2) | (1 << WDP0)
#define WDT_TO_1s (1 << WDP2) | (1 << WDP1)
#define WDT_TO_2s (1 << WDP2) | (1 << WDP1) | (1 << WDP0)
#define WDT_TO_4s (1 << WDP3)
#define WDT_TO_8s (1 << WDP3) | (1 << WDP0)
// other HW defines
#define LED_PIN 13
// fwd declaration of (watchdog) functions
void wdtReset();
void wdtConfig();
void toggleLed();
// aux functions and IRS
ISR(WDT_vect) {
// the watch dog interrupt detection
// if the MCU was in a sleep mode, wake up, particularly the peripherals, where applicable
// reset the watchdog (timer/ counter)
wdtReset();
toggleLed();
// for low power, put the MCU to sleep now
}
void wdtConfig() {
// disable interrupts for changing the registers
cli();
// reset status register flags
MCUSR = 0;
WDTCSR |= (1 << WDCE) | (1 << WDE); // Set WDCE (5th from left) and WDE (4th from left) to enter config mode,
// Put timer in interrupt-only mode:
WDTCSR = (1 << WDIE) | WDT_TO_1s; // set WDIE: interrupt enabled (reset disabled), and set delay interval
// re-enable interrupts
sei();
}
void wdtReset() {
wdt_reset();
}
void toggleLed() {
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
}
// --- end aux functions
void setup() {
// put your setup code here, to run once:
Serial.begin(19200);
wdtConfig();
Serial.println("watchdog started");
pinMode(LED_PIN, OUTPUT);
ledState = 0;
digitalWrite(LED_PIN, ledState);
}
void loop() {
// put your main code here, to run repeatedly, note, that it will be interrupted by the watchdog timer
}