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. */
}
}
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
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
}
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 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.
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 ?
How can the bit is filled with "b" value when it's an binary bit. Could you explain what does "b" mean ?
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.
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