Skip to content

Instantly share code, notes, and snippets.

@stojg
Last active April 4, 2023 14:23
Show Gist options
  • Save stojg/aec2c8c54c29c0fab407 to your computer and use it in GitHub Desktop.
Save stojg/aec2c8c54c29c0fab407 to your computer and use it in GitHub Desktop.
Arduino sleep example
// This is an example how to put an arduino board into deep sleep to save on battery power and
// periodically wake up to run some logic. Ideal for sensor stations like plant moisture sensors.
#include "Arduino.h"
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
// Blink Before sleeping
#define LED_PIN (13)
// This variable is made volatile because it is changed inside
// an interrupt function
volatile int f_wdt=1;
// Watchdog Interrupt Service. This is executed when watchdog timed out.
ISR(WDT_vect) {
if(f_wdt == 0) {
// here we can implement a counter the can set the f_wdt to true if
// the watchdog cycle needs to run longer than the maximum of eight
// seconds.
f_wdt=1;
}
}
// Enters the arduino into sleep mode.
void enterSleep(void)
{
// There are five different sleep modes in order of power saving:
// SLEEP_MODE_IDLE - the lowest power saving mode
// SLEEP_MODE_ADC
// SLEEP_MODE_PWR_SAVE
// SLEEP_MODE_STANDBY
// SLEEP_MODE_PWR_DOWN - the highest power saving mode
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
// Now enter sleep mode.
sleep_mode();
// The program will continue from here after the WDT timeout
// First thing to do is disable sleep.
sleep_disable();
// Re-enable the peripherals.
power_all_enable();
}
// Setup the Watch Dog Timer (WDT)
void setupWatchDogTimer() {
// The MCU Status Register (MCUSR) is used to tell the cause of the last
// reset, such as brown-out reset, watchdog reset, etc.
// NOTE: for security reasons, there is a timed sequence for clearing the
// WDE and changing the time-out configuration. If you don't use this
// sequence properly, you'll get unexpected results.
// Clear the reset flag on the MCUSR, the WDRF bit (bit 3).
MCUSR &= ~(1<<WDRF);
// Configure the Watchdog timer Control Register (WDTCSR)
// The WDTCSR is used for configuring the time-out, mode of operation, etc
// In order to change WDE or the pre-scaler, we need to set WDCE (This will
// allow updates for 4 clock cycles).
// Set the WDCE bit (bit 4) and the WDE bit (bit 3) of the WDTCSR. The WDCE
// bit must be set in order to change WDE or the watchdog pre-scalers.
// Setting the WDCE bit will allow updates to the pre-scalers and WDE for 4
// clock cycles then it will be reset by hardware.
WDTCSR |= (1<<WDCE) | (1<<WDE);
/**
* Setting the watchdog pre-scaler value with VCC = 5.0V and 16mHZ
* WDP3 WDP2 WDP1 WDP0 | Number of WDT | Typical Time-out at Oscillator Cycles
* 0 0 0 0 | 2K cycles | 16 ms
* 0 0 0 1 | 4K cycles | 32 ms
* 0 0 1 0 | 8K cycles | 64 ms
* 0 0 1 1 | 16K cycles | 0.125 s
* 0 1 0 0 | 32K cycles | 0.25 s
* 0 1 0 1 | 64K cycles | 0.5 s
* 0 1 1 0 | 128K cycles | 1.0 s
* 0 1 1 1 | 256K cycles | 2.0 s
* 1 0 0 0 | 512K cycles | 4.0 s
* 1 0 0 1 | 1024K cycles | 8.0 s
*/
WDTCSR = (0<<WDP3) | (1<<WDP2) | (1<<WDP1) | (1<<WDP0);
// Enable the WD interrupt (note: no reset).
WDTCSR |= _BV(WDIE);
}
// Setup for the serial comms and the other things
void setup() {
Serial.begin(9600);
Serial.println("Initialising..."); delay(100);
pinMode(LED_PIN, OUTPUT);
setupWatchDogTimer();
Serial.println("Initialisation complete."); delay(100);
}
// main loop
void loop() {
// Wait until the watchdog have triggered a wake up.
if(f_wdt != 1) {
return;
}
// Toggle the LED on
digitalWrite(LED_PIN, 1);
// wait
delay(20);
// Toggle the LED off
digitalWrite(LED_PIN, 0);
// clear the flag so we can run above code again after the MCU wake up
f_wdt = 0;
// Re-enter sleep mode.
enterSleep();
}
@Elpablito
Copy link

Hi
I made your program on Arduino nano. The IDE is Atmel Studio 7. I have_ a problem whit the following instruction
WDTCSR |= _BV(WDIE)
because _BV is claimed an unrecognized symbol.
Could you suggest something

@stojg
Copy link
Author

stojg commented Feb 21, 2021

Hi
I made your program on Arduino nano. The IDE is Atmel Studio 7. I have_ a problem whit the following instruction
WDTCSR |= _BV(WDIE)
because _BV is claimed an unrecognized symbol.
Could you suggest something

It's been years since i've done any serious arduino development, but I suspect that something from the includes or their includes doesnt have _BV defined anymore.. but the first result I googled gave me.

#define _BV(bit) (1 << (bit))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment