I'm using this code and its working perfectly in a RBBB (an arduino clone with Duemilanove bootloader).
/*
Watchdog Sleepy Bones (the skeleton is the essential armature for any living thing)
This is the basic structure that you need to Sleep_Mode_Pwr_Down/Watchdog interrupt wake
Provided for general consumption by Rachel's Electronics http://www.rachelselectronics.com
Under the CC licence here (http://creativecommons.org/licenses/by-sa/3.0/us/)
Rachel's Electronics: Making the World Safe for Robots! -Joel Murphy joel@joelmurphy.net
Built in part from code posted by:
* KHM 2008 / Lab3/ Martin Nawrath nawrath@khm.de
* Kunsthochschule fuer Medien Koeln
* Academy of Media Arts Cologne
http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
*/
#include <avr/sleep.h>
#include <avr/wdt.h>
#define sleepTime 1 //number of 8 second sleep cycles
volatile byte wdt=0; //used to cound number of sleep cycles
void setup(){
setup_watchdog(); // set prescaller and enable interrupt
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here Power Down uses the least current
pinMode(13,OUTPUT); // system clock is turned off, so millis won't be reliable!
delay(10);
}
void loop(){
// do what you want to before you sleep here
system_sleep();
// do what you want to after you sleep here
digitalWrite(13, HIGH);
delay(100);
digitalWrite(13, LOW);
delay(100);
digitalWrite(13, HIGH);
delay(100);
digitalWrite(13, LOW);
delay(100);
}
void system_sleep() {
ADCSRA |= (0<<ADEN); // disable ADC
sleep_enable(); // enable sleeping
while (wdt < sleepTime){ // sleep for sleepTime * 8sec
sleep_mode(); // activate system sleep
// sleeping ...
}
sleep_disable(); // disable sleep
ADCSRA |= (1<<ADEN); // switch ADC on
wdt = 0; // reset wdt for next cycle
}
void setup_watchdog() {
cli(); //disable global interrupts
MCUSR = 0x00; //clear all reset flags
//set WD_ChangeEnable and WD_resetEnable to alter the register
WDTCSR |= (1<<WDCE) | (1<<WDE); // this is a timed sequence to protect WDTCSR
// set new watchdog timeout value to 1024K cycles (~8.0 sec)
WDTCSR = (1<<WDP3) | (1<<WDP0);
//enable watchdog interrupt
WDTCSR |= (1<<WDIE);
sei(); //enable global interrupts
}
// Watchdog Interrupt Service Routine.
// Very first thing after sleep wakes with WDT Interrupt
ISR(WDT_vect) {
wdt++; // increment the watchdog timer
}
I have however a question that I couldn't figure out reading the datasheet. This line:
WDTCSR |= (1<<WDCE) | (1<<WDE);
sets the Watchdog to both interrupt and reset. I wonder to which point does it reset and why it is necessary to set the watchdog to reset reset in order to obtain the expected functionality (a LED that blinks every 8 seconds).
If I just set it to Interrupt mode, it blinks all the time.