Ive been working with power save mode for the Arduino lately, and Ive found that while there are multitudes of examples out there, nobody specifically gives you a working example to run with. In this post, I'll walk you through my code, and at the end, I'll provide you with a great working example of using an interrupt button to bring the Arduino back out of a low power state for a few seconds and then back to sleep. This is great for applications that require the use of a battery for long periods of time and charging is scarce.
You can follow the interrupted sleep tutorial by NoMi Design to learn just how to set things up.
My code, however, is just like this example, provided on Engblaze.com, except that Ive added some serial communications to see that its working visually and to re-enable the interrupt attach so that I can constantly bring the device out of sleep every time it goes to sleep.
//remove the space between '<' and 'avr'.
#include < avr/interrupt.h>
#include < avr/power.h>
#include < avr/sleep.h>
#include < avr/io.h>
void setup()
{
Serial.begin(9600);
DDRD &= B00000011; // set Arduino pins 2 to 7 as inputs, leaves 0 & 1 (RX & TX) as is
DDRB = B00000000; // set pins 8 to 13 as inputs
PORTD |= B11111100; // enable pullups on pins 2 to 7
PORTB |= B11111111; // enable pullups on pins 8 to 13
pinMode(13,OUTPUT); // set pin 13 as an output so we can use LED to monitor
digitalWrite(13,HIGH); // turn pin 13 LED on
}
void loop()
{
// Stay awake for 1 second, then sleep.
// LED turns off when sleeping, then back on upon wake.
delay(2000);
Serial.println("Entering Sleep Mode");
sleepNow();
Serial.println(" ");
Serial.println("I am now Awake");
}
//
void sleepNow()
{
// Choose our preferred sleep mode:
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
//
interrupts();
// Set pin 2 as interrupt and attach handler:
attachInterrupt(0, pinInterrupt, HIGH);
//delay(100);
//
// Set sleep enable (SE) bit:
sleep_enable();
//
// Put the device to sleep:
digitalWrite(13,LOW); // turn LED off to indicate sleep
sleep_mode();
//
// Upon waking up, sketch continues from this point.
sleep_disable();
digitalWrite(13,HIGH); // turn LED on to indicate awake
}
void pinInterrupt()
{
detachInterrupt(0);
attachInterrupt(0, pinInterrupt, HIGH);
}
Dont mind any avr's at the end. Its a glitch the website keeps doing when I post #includes at the top of the code on the blog.
Sleep Modes
Finally, its important to discuss the types of Sleep Modes that you can choose from. There are 6 sleep modes available on the Arduino Uno (ATMEGA328):
- SLEEP_MODE_IDLE – least power savings
- SLEEP_MODE_ADC
- SLEEP_MODE_EXTENDED_STANDBY
- SLEEP_MODE_PWR_SAVE
- SLEEP_MODE_STANDBY
- SLEEP_MODE_PWR_DOWN – most power savings
SLEEP_MODE_IDLE provides the least power savings but also retains the most functionality. SLEEP_MODE_PWR_DOWN uses the least power but turns almost everything off, so your options for wake interrupts and the like are limited. Power reduction management methods are described in more detail on the avr-libc documentation page. For details on what features are available with each power saving mode for the Arduino Uno, please refer to the ATMEGA168/328p Datasheet (look out, its a 12mb file). For all other Arduino's refer to either the Arduino website, or the Atmel website.
Ive decided to go with SLEEP_MODE_PWR_SAVE for this example, just because it gives me some flexibility with waking it, and because the power savings are a bit better than idle. Power down is overkill for my applications, and its comparative to actually turning off the device, which I don't need my hardware to do.
You're welcome to ask questions, about this code if you arent sure whats going on. The bit of setting up the pins in the Arduino hardware is explained more on the Engblaze post.