I’ve been playing with the Arduino sleep modes and i wanted to be able to wake up from the sleep when receiving data on the serial port. Mainly, because in my project I’m using the XBee in the API mode and the tricks exposed in http://www.arduino.cc/playground/Learning/ArduinoSleepCode and http://www.libelium.com/squidbee/index.php?title=Save_power_in_SquidBee_-_sleep_mode involve putting Arduino in SLEEP_MODE_PWR_DOWN and using an extra pin on the arduino to monitor the RX pin and detecting LOW.
I didn’t like that much that solution so I started to look into other ways of doing it without using an extra pin and without risk of losing data in the serial interface. Because as I understood it using SLEEP_MODE_PWR_DOWN requires to send first a burst of data to the serial interface in order to wake up the arduino. And it takes a while for the Arduino to become fully functional so that means that you will lose/miss data in the serial interface. That was something that didn’t fit my project.
In order to be able to sleep but without missing serial data I used POWER_MODE_IDLE, a power saving mode that leaves the USART on and then using the functions defined in power.h (you have to use arduino-12 to get power.h) I disabled all other modules that I don’t need to cut down the power consumption. When any data is received in the USART the Arduino will be brought back to normal power mode (USART uses interrupts and any interrupt makes the ATmega168 to exit the power saving mode).
See the actual code in this
/* Sleep Demo Serial * ----------------- * Example code to demonstrate the sleep functions in a Arduino. Arduino will wake up * when new data is received in the serial port USART * Based on Sleep Demo Serial from http://www.arduino.cc/playground/Learning/ArduinoSleepCode * * Copyright (C) 2006 MacSimski 2006-12-30 * Copyright (C) 2007 D. Cuartielles 2007-07-08 - Mexico DF * * With modifications from Ruben Laguna 2008-10-15 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ #include <avr/power.h> #include <avr/sleep.h> int sleepStatus = 0; // variable to store a request for sleep int count = 0; // counter void setup() { Serial.begin(9600); } void sleepNow() { /* Now is the time to set the sleep mode. In the Atmega8 datasheet * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35 * there is a list of sleep modes which explains which clocks and * wake up sources are available in which sleep modus. * * In the avr/sleep.h file, the call names of these sleep modus are to be found: * * The 5 different modes are: * SLEEP_MODE_IDLE -the least power savings * SLEEP_MODE_ADC * SLEEP_MODE_PWR_SAVE * SLEEP_MODE_STANDBY * SLEEP_MODE_PWR_DOWN -the most power savings * * the power reduction management <avr/power.h> is described in * http://www.nongnu.org/avr-libc/user-manual/group__avr__power.html */ set_sleep_mode(SLEEP_MODE_IDLE); // sleep mode is set here sleep_enable(); // enables the sleep bit in the mcucr register // so sleep is possible. just a safety pin power_adc_disable(); power_spi_disable(); power_timer0_disable(); power_timer1_disable(); power_timer2_disable(); power_twi_disable(); sleep_mode(); // here the device is actually put to sleep!! // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP sleep_disable(); // first thing after waking from sleep: // disable sleep... power_all_enable(); } void loop() { // display information about the counter Serial.print("Awake for "); Serial.print(count); Serial.println("sec"); count++; delay(1000); // waits for a second // compute the serial input if (Serial.available()) { int val = Serial.read(); if (val == 'S') { Serial.println("Serial: Entering Sleep mode"); delay(100); // this delay is needed, the sleep //function will provoke a Serial error otherwise!! count = 0; sleepNow(); // sleep function called here } if (val == 'A') { Serial.println("Hola Caracola"); // classic dummy message } } // check if it should go asleep because of time if (count >= 10) { Serial.println("Timer: Entering Sleep mode"); delay(100); // this delay is needed, the sleep //function will provoke a Serial error otherwise!! count = 0; sleepNow(); // sleep function called here } }






































5 Comments
In function ‘void sleepNow()’:
error: ‘power_adc_disable’ was not declared in this scope
Which version of Arduino did you use, grendel? I only tested it in Arduino-12
I just tried the example on both Arduino-12 and Arduino-14 and it compiles with no errors. Are you sure that you copied the example verbatim, grendel?
Hi, Ruben your blog has been very helpful to me, thanks a lot, when i finish my project i’ll write a review and show it you and see if you liked it =D.
Hey Ruben. I am a newbie here working on Arduino 0017 (Duemilanove) for our project. I want to awake my arduino whenever I get a 5V from a device. Since this is going to be an interrupt, I set the pin number 2 as input and set it to 0V, then wait for a CHANGE to wake the Arduino?
Does this seem reasonable ? Can I actually set an input pin as 0V?
One Trackback
[...] Arduino sleep mode – Waking up when receiving data on the USART « Ruben’s blog [...]