"Extend" Watchdog Timer Beyond 8 Seconds?

I'm trying to create a system that will be in SLEEP_MODE_PWR_DOWN state for 4 minutes at a time, and then wake up and take measurements. I understand that the watchdog timer works well to wake up a system. Is there a way to have the timer not wake up the system for 240 seconds (4 minutes) at a time? I've tried WHILE statements but that didn't work (i.e. WHILE x < 30 stay asleep [as 30 * 8s = 240 seconds]). Is there a better option that I should be considering?

Here's my (adapted) code so far:

/*
 * Sketch for testing sleep mode with wake up on WDT.
 * Donal Morrissey - 2011.
 *
 */
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

#define Set_prescaler(x)   (CLKPR = (1 << CLKPCE), CLKPR = x)
#define LED_PIN (13)

volatile int f_wdt=1;
int test_mode_clock = 4;
int test_mode_pin = 3;


/***************************************************
 *  Name:        ISR(WDT_vect)
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Watchdog Interrupt Service. This
 *               is executed when watchdog timed out.
 *
 ***************************************************/
ISR(WDT_vect)
{
  if(f_wdt == 0)
  {
    f_wdt=1;
  }
}


/***************************************************
 *  Name:        enterSleep
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Enters the Arduino into sleep mode.
 *
 ***************************************************/
void enterSleep(void)
{
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   /* EDIT: could also use SLEEP_MODE_PWR_DOWN for lowest power consumption. */
  sleep_enable();

  /* Now enter sleep mode. */
  sleep_mode();

  /* The program will continue from here after the WDT timeout*/
  sleep_disable(); /* First thing to do is disable sleep. */

  /* Re-enable the peripherals. */
  power_all_enable();
}


/***************************************************
 *  Name:        setup
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Setup for the serial comms and the
 *                Watch dog timeout. 
 *
 ***************************************************/
void setup()
{
  Set_prescaler(test_mode_clock);

  int i;
  for(i = 0; i <= 19; i++)
  {
    switch(test_mode_pin)
    {
    case 0:
      pinMode(i, INPUT);
      break;
    case 1:
      pinMode(i, INPUT);
      digitalWrite(i, HIGH);
      break;
    case 2:
      pinMode(i, OUTPUT);
      digitalWrite(i, LOW);
      break;
    case 3:
      pinMode(i, OUTPUT);
      digitalWrite(i, HIGH);
      break;
    }
  }

  pinMode(LED_PIN, OUTPUT);

  /*** Setup the WDT ***/

  /* Clear the reset flag. */
  MCUSR &= ~(1 << WDRF);

  /* In order to change WDE or the prescaler, we need to
   * set WDCE (This will allow updates for 4 clock cycles).
   */
  WDTCSR |= (1 << WDCE) | (1 << WDE);

  /* set new watchdog timeout prescaler value */
  WDTCSR = 1 << WDP0 | 1 << WDP3; /* 8.0 seconds */

  /* Enable the WD interrupt (note no reset). */
  WDTCSR |= _BV(WDIE);
}


/***************************************************
 *  Name:        enterSleep
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Main application loop.
 *
 ***************************************************/
void loop()
{
  if(f_wdt == 1)
  {
    /* Toggle the LED */
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));

    /* Don't forget to clear the flag. */
    f_wdt = 0;

    /* Re-enter sleep mode. */
    enterSleep();
  }
  else
  {
    /* Do nothing. */
  }
}

You could use a FOR loop to sleep the required number of times to achieve your desired overall sleep duration.

PeterH:
You could use a FOR loop to sleep the required number of times to achieve your desired overall sleep duration.

I'll be honest, I'm not sure how to do that (code wise). I'm still trying to figure out all of the intricacies of the watchdog code, specifically this section:

/* Clear the reset flag. */
  MCUSR &= ~(1 << WDRF);

  /* In order to change WDE or the prescaler, we need to
   * set WDCE (This will allow updates for 4 clock cycles).
   */
  WDTCSR |= (1 << WDCE) | (1 << WDE);

  /* set new watchdog timeout prescaler value */
  WDTCSR = 1 << WDP0 | 1 << WDP3; /* 8.0 seconds */

  /* Enable the WD interrupt (note no reset). */
  WDTCSR |= _BV(WDIE);

Is there an easier way to include this in my sketch? Something similar to using "wdt_enable(WDTO_8S);", or do I need all of the above as well?

It's not that complicated. Here is an example of using a watchdog to reset you:

#include <avr/wdt.h>

void setup ()
  {
  Serial.begin (115200);
  wdt_enable(WDTO_1S);  // reset after one second, if no "pat the dog" received
   }  // end of setup

void loop ()
  {
  Serial.println ("Entered loop ...");
  Serial.println ("Point A");
  delay (900);
  
  wdt_reset();  // give me another second to do stuff (pat the dog)
  Serial.println ("Point B");
  delay (900);
  
  while (true) ;   // oops, went into a loop
  }  // end of loop

And here is an example of using a watchdog to wake after sleep. Yes, you have to do it multiple times to get more than 8 seconds, but it isn't that bad:

// Example of sleeping and saving power
// 
// Author: Nick Gammon
// Date:   25 May 2011

#include <avr/sleep.h>
#include <avr/wdt.h>

#define LED 13

// watchdog interrupt
ISR(WDT_vect) 
  {
  wdt_disable();  // disable watchdog
  }

void myWatchdogEnable(const byte interval) 
  {  
  MCUSR = 0;                          // reset various flags
  WDTCSR |= 0b00011000;               // see docs, set WDCE, WDE
  WDTCSR =  0b01000000 | interval;    // set WDIE, and appropriate delay

  wdt_reset();
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_mode();            // now goes to Sleep and waits for the interrupt
  } 

void setup()
{
 pinMode (LED, OUTPUT);
}  // end of setup

void loop()
{
  digitalWrite (LED, HIGH);  // awake
  delay (2000);    // ie. do stuff here
  digitalWrite (LED, LOW);  // asleep

  // sleep for a total of 20 seconds
  myWatchdogEnable (0b100001);  // 8 seconds
  myWatchdogEnable (0b100001);  // 8 seconds
  myWatchdogEnable (0b100000);  // 4 seconds

}  // end ofloop

// sleep bit patterns:
//  1 second:  0b000110
//  2 seconds: 0b000111
//  4 seconds: 0b100000
//  8 seconds: 0b100001
1 Like

And here is an example of using a watchdog to wake after sleep. Yes, you have to do it multiple times to get more than 8 seconds, but it isn't that bad

That's fantastic! Thanks. Then I can use something like this for 4 minutes (240 seconds, or 30x 8 second intervals), correct?

  // sleep for a total of 240 seconds
  int i;
  for (i = 0; i <=30; i++)
  {  
    myWatchdogEnable (0b100001);  // 8 seconds
  }
  for (i = 0; i <=30; i++)

Yes, but < 30, not <= 30, or that would be 31 times around the loop.

Right! Thank you.

Now when I want to take measurements, I put that code here?

digitalWrite (LED, HIGH);  // awake
  delay (2000);    // ie. do stuff here
  digitalWrite (LED, LOW);  // asleep

If that's where you want to sleep, I suppose so.

I'm not sure I understand. Shouldn't I have my measurements taken during the awake phase (ie before the sleep phase starts)? Is that not between the digitalWrite HIGH and LOW in the code you gave (where it says "do stuff here")? Should those measurements be somewhere else in the code?

Here's what I'm using so far:

// Example of sleeping and saving power
// 
// Author: Nick Gammon
// Date:   25 May 2011

#include <avr/sleep.h>
#include <avr/wdt.h>

/*********************
 * PRESCALER - modifies the clock times. For delay(1000) with Mode 4, delay would be 16x longer.
 * Mode 0 - Do nothing - normal 16Mhz clock
 * Mode 1 - Clock divide by 2 - 8MHz
 * Mode 2 - Clock divide by 4 - 4MHz
 * Mode 3 - Clock divide by 8 - 2MHz
 * Mode 4 - Clock divide by 16 - 1MHz
 * Mode 5 - Clock divide by 32 - 500kHz
 * Mode 6 - Clock divide by 64 - 250kHz
 * Mode 7 - Clock divide by 128 - 125kHz
 * Mode 8 - Clock divide by 256 - 62.5kHz
 *********************/
#define Set_prescaler(x)  (CLKPR = (1<<CLKPCE),CLKPR = x) //for any delays, they are multiplied by the prescaler time
#define LED 5
int Prescaler_mode = 4;
const int A0_pin = A0;


/*********************
 * WATCHDOG INTERRUPT
 *********************/
ISR(WDT_vect) 
{
  wdt_disable();  // disable watchdog
}


/*********************
 * myWatchdogEnable
 *********************/
void myWatchdogEnable(const byte interval) 
{  
  MCUSR = 0;                          // reset various flags
  WDTCSR |= 0b00011000;               // see docs, set WDCE, WDE
  WDTCSR =  0b01000000 | interval;    // set WDIE, and appropriate delay

  wdt_reset();
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_mode();            // now goes to Sleep and waits for the interrupt
} 


/*********************
 * VOID SETUP
 *********************/
void setup()
{
  Set_prescaler(Prescaler_mode);  // 1/16 clock speed
  int i;
  for(i = 0; i <= 19; i++)  // all pins set as input with pullup resistor
  {
    pinMode(i, INPUT);
    digitalWrite(i, HIGH);
  } 
  pinMode (LED, OUTPUT);
  pinMode(A0_pin, INPUT);
}


/*********************
 * VOID LOOP
 *********************/
void loop()
{
  if (analogRead(A0_pin) >= 1000)
  {
    digitalWrite (LED, LOW);
  }
  else
  {
    digitalWrite (LED, HIGH);
  }
  delay(65);

  /*********************
   * SLEEP BIT PATTERNS
   * 1 second:  0b000110
   * 2 seconds: 0b000111
   * 4 seconds: 0b100000
   * 8 seconds: 0b100001
   *********************/

  // sleep for a total of 1 seconds
  int i;
  for (i = 0; i < 1; i++)
  {  
    myWatchdogEnable (0b000110);  // 1 seconds
  }
}

I'm not sure I understand the confusion. Naturally you take the measurements during the awake phase.

I put that code here?

I think I misunderstood what you mean by "that code". I thought you meant "the sleeping code" but you appear to have meant "the measuring code".

Perfect. Thanks for all your help!

How can you do that at the end of sleep time to reboot the controller? In your code:

// Example of sleeping and saving power
// 
// Author: Nick Gammon
// Date:   25 May 2011

#include <avr/sleep.h>
#include <avr/wdt.h>

#define LED 13

// watchdog interrupt
ISR(WDT_vect) 
  {
  wdt_disable();  // disable watchdog
  }

void myWatchdogEnable(const byte interval) 
  {  
  MCUSR = 0;                          // reset various flags
  WDTCSR |= 0b00011000;               // see docs, set WDCE, WDE
  WDTCSR =  0b01000000 | interval;    // set WDIE, and appropriate delay

  wdt_reset();
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_mode();            // now goes to Sleep and waits for the interrupt
  } 

void setup()
{
 pinMode (LED, OUTPUT);
}  // end of setup

void loop()
{
  digitalWrite (LED, HIGH);  // awake
  delay (2000);    // ie. do stuff here
  digitalWrite (LED, LOW);  // asleep

  // sleep for a total of 20 seconds
  myWatchdogEnable (0b100001);  // 8 seconds
  myWatchdogEnable (0b100001);  // 8 seconds
  myWatchdogEnable (0b100000);  // 4 seconds

}  // end ofloop

// sleep bit patterns:
//  1 second:  0b000110
//  2 seconds: 0b000111
//  4 seconds: 0b100000
//  8 seconds: 0b100001

Can someone explane how this part of the code works

  // sleep for a total of 240 seconds
  int i;
  for (i = 0; i <=30; i++)
  {  
    myWatchdogEnable (0b100001);  // 8 seconds

I don't understand how it can make the arduino sleep

I know this post is a little bit too old to be replied. However, I got some questions for Mr Nick Gammon.

Here are the questions.

  1. From your code the WDTCSR is written in 10 bit.
MCUSR = 0;                          // reset various flags
WDTCSR |= 0b00011000;               // see docs, set WDCE, WDE
WDTCSR =  0b01000000 | interval;    // set WDIE, and appropriate delay

But from the datasheet, it's only 8 bit. Which one is the correct one ?

  1. How can the bit is filled with "b" value when it's an binary bit. Could you explain what does "b" mean ?

  2. I tried the extended sleep code for my program. The sleep program is working. However the time of the sleep is almost no correct. For Example to set 600 sleep with this code

 void tidur ()
{
	// total waktu tidur 600s
	int  i;
	for (i=1; i <=60; i++)
	   myWatchdogEnable (0b100001);  // 8s
           myWatchdogEnable (0b000111);  // 2s
}

However, the result shows the time sleep that I count is less than 600s.

Hope you could answer my questions, thanks.

The 0b... notation is the standard way of C to express a numeric constant in binary.

The 0 lets the compiler know that it is a numeric constant, the b denotes binary.

10 decimal = 0b00001010 binary = 0x0A hexadecimal = 012 octal

So 0b00011000 still is a byte.

Whandall:
The 0b... notation is the standard way of C to express a numeric constant in binary.

The 0 lets the compiler know that it is a numeric constant, the b denotes binary.

10 decimal = 0b00001010 binary = 0x0A hexadecimal = 012 octal

So 0b00011000 still is a byte.

Haa, Okay, thanks for the explanation.

I have another question, how about I solve this equation

0b00011000 | 0b100001 = ?

is it

0b00011000
0b100001
____________ or

or this one ?

0b00011000
0b100001
____________ or

I mean should I do the operation from the left or the right one ?

That ist not different to computations in the decimal world we are all used to.

Leading zeros are insignificant (for bare numbers) and for operations (like addition, or, ... ) you align them on the right side.

So 0b101 | 0b1010 == 0b1111.

Whandall:
That ist not different to computations in the decimal world we are all used to.

Leading zeros are insignificant (for bare numbers) and for operations (like addition, or, ... ) you align them on the right side.

So 0b101 | 0b1010 == 0b1111.

Ok, Thanks Mr.Whandall for the quick explanation.
Have a good day. :slight_smile:

NickGammon:

Im starting to understand sleep & wdt. I understand blogoo (OP) wanted to take his code and make it sleep for longer than the 8 second limit. You came in and told gave him some code to reset Arduino with WDT & another for wdt to wake up up after sleep. Im unclear about why you suggested those as 2 separate options. I believe Im missing something here with the wdt_enable(& patting the dog) vs the sleep_mode(). sleep_mode() puts an Arduino to sleep and wdt wakes it up. What would you use wdt_enable(WDTO_1S); for?

enormousdreamer:

How much time does it reflect?

snowmix:

It waits for 8 seconds each loop and you make 30 loops = 8 x 30 + 240 seconds.

roman_d:

What are you asking? How to insert the 30 times-8 second loop code into the code presented by Nick Gammon? If so, I believe this is the way the final code should look:

// Example of sleeping and saving power
// Author: Nick Gammon
// Date:   25 May 2011

#include <avr/sleep.h>
#include <avr/wdt.h>

#define LED 13

// watchdog interrupt
ISR(WDT_vect) 
  {
  wdt_disable();  // disable watchdog
  }

void myWatchdogEnable(const byte interval) 
  {  
  MCUSR = 0;                          // reset various flags
  WDTCSR |= 0b00011000;               // see docs, set WDCE, WDE
  WDTCSR =  0b01000000 | interval;    // set WDIE, and appropriate delay

  wdt_reset();
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_mode();            // now goes to Sleep and waits for the interrupt
  } 

void setup()
{
pinMode (LED, OUTPUT);
}  // end of setup

void loop()
{
  digitalWrite (LED, HIGH);  // awake
  delay (2000);    // ie. do stuff here
  digitalWrite (LED, LOW);  // asleep

  // sleep for a total of 20 seconds
  //myWatchdogEnable (0b100001);  // 8 seconds
  //myWatchdogEnable (0b100001);  // 8 seconds
  //myWatchdogEnable (0b100000);  // 4 seconds
  // sleep for a total of 240 seconds - THIS IS THE CODE THAT REPLACES THE OLD ONE
  int i;
  for (i = 0; i <=30; i++)
  {  
    myWatchdogEnable (0b100001);  // 8 seconds
  }
}  // end ofloop

// sleep bit patterns:
//  1 second:  0b000110
//  2 seconds: 0b000111
//  4 seconds: 0b100000
//  8 seconds: 0b100001

Nick Gammon,
Grateful for the teachings on Arduino. An extraordinary job.
For "Example of sleeping and saving power" because are not used instructions:
sleep_enable () and sleep_disable ();
since it uses the mode: set_sleep_mode (SLEEP_MODE_PWR_DOWN)
Thanks
Francisco