In the second entry of this "Sleeping Arduino" series, we will be covering how to wake the Arduino via an external interrupt. We will be using the external interrupt circuit that has been covered in a previous blog Arduino External Interrupts. Please be sure to get the basic external interrupt example working before attempting to follow this entry, this will prove that your hardware setup is correct.
Operation
Our code will operate as follows:
- Set up the serial port and set pin 2 (INT0) as an input;
- Run the loop function which will:
- Stay awake for 3 seconds;
- Once the 3 seconds have elapsed, SLEEP_MODE_PWR_DOWN will be entered;
- All code execution stops;
- The user then pushes the switch and pin 2 (INT0) will become low;
- The INT0 interrupt will fire and bring the Arduino out of sleep mode;
- Code execution continues where it had previously stopped.
The circuit is set up as specified in the Arduino External Interrupts blog.
Source Code
#include <avr/sleep.h>
#include <avr/power.h>
int pin2 = 2;
/***************************************************
* Name: pin2Interrupt
*
* Returns: Nothing.
*
* Parameters: None.
*
* Description: Service routine for pin2 interrupt
*
***************************************************/
void pin2Interrupt(void)
{
/* This will bring us back from sleep. */
/* We detach the interrupt to stop it from
* continuously firing while the interrupt pin
* is low.
*/
detachInterrupt(0);
}
/***************************************************
* Name: enterSleep
*
* Returns: Nothing.
*
* Parameters: None.
*
* Description: Enters the arduino into sleep mode.
*
***************************************************/
void enterSleep(void)
{
/* Setup pin2 as an interrupt and attach handler. */
attachInterrupt(0, pin2Interrupt, LOW);
delay(100);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
/* The program will continue from here. */
/* First thing to do is disable sleep. */
sleep_disable();
}
/***************************************************
* Name: setup
*
* Returns: Nothing.
*
* Parameters: None.
*
* Description: Setup for the Arduino.
*
***************************************************/
void setup()
{
Serial.begin(9600);
/* Setup the pin direction. */
pinMode(pin2, INPUT);
Serial.println("Initialisation complete.");
}
/***************************************************
* Name: loop
*
* Returns: Nothing.
*
* Parameters: None.
*
* Description: Main application loop.
*
***************************************************/
int seconds=0;
void loop()
{
delay(1000);
seconds++;
Serial.print("Awake for ");
Serial.print(seconds, DEC);
Serial.println(" second");
if(seconds == 3)
{
Serial.println("Entering sleep");
delay(200);
seconds = 0;
enterSleep();
}
}
The sketch for this program can be downloaded here.
All parts of this series:
- Part 1 Overview Of Arduino Sleep Modes
- Part 2 Wake Up Via An External Interrupt
- Part 3 Wake Up Via the UART
- Part 4 Wake Up Via Internal Timer
- Part 5 Wake Up Via The Watchdog Timer
Hi Donal,
ReplyDeleteI'm finding that if I continually press the button I have setup to trigger the interrupt with code as it is the program kind of locks up after it goes into sleep.
BUT if I move the "detachInterrupt(0);" statement out of the call back function, and just put it at the bottom of the enterSleep() method than things seems to work robustly.
Any ideas why?
Cheers
Greg
Hi, first thanks for the article!
DeleteAnd thanks Greg for your comment, I have the same thing here, spent some time to understand why, but can't find anything, and your solution made it work for me, any bug with the detachInterrupt function?
Bye!
Quentin
It's been a long time since this comment was posted, but I am sure there is still someone out there seeking an answer to this behaviour, which I got here: http://www.gammon.com.au/forum/?id=11488
DeleteThe short answer is that an interrupt might occur between the call to attachInterrupt(...) and the call to sleep_mode(), in which case the arduino will never wake up.
1: attachInterrupt(...) gets called.
2: interrupt gets triggered.
3: isr callback gets called and so does detachInterrupt(...)
4: sleep_mode() get called.
5: arduino sleeps forever since interrupts are disabled.
Hope it helps
JL
Hello, What is the best way to set to sleep arduino using a Xbee module?
ReplyDeleteI need minimum consumption for my project. Thank you and great blog.
Hi Giannis,
ReplyDeleteApologies for the delay in replying to you. Probably your best bet is to follow the very helpful tutorial here:
http://www.sensor-networks.org/index.php?page=0820520514
Cheers,
Donal
This comment has been removed by the author.
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDeletehello Donal,
ReplyDeleteI have tried this code on an Arduino Duemilanove, but I never get out the sleep. I have trie it by short utting GND and digital pin 2.
Do you have an explanation ?
Regards
I reply to myself.
ReplyDeleteI have added "digitalWrite(2,HIGH);" in setup after "pinMode" and it works perfectly now.
or
DeletepinMode(pin2, INPUT_PULLUP);
or put a pullup resistor 10K
Very Good Example Thank you ! ! ! ! :-)
HI and thanks a lot for your help
ReplyDeleteBut where can we find these ones
#include
#include
Seems not so easy to find
sorry these ones
ReplyDeleteavr/sleep.h
avr/power.h
Problem is solved ,these files are in arduino directory ,but not in library so because my Arduino main directory was an another name ,the soft did not find the root
ReplyDeleteSo ,"we should never change the arduino name directory"
jm
Trying to use this with a Pro Micro. It appears that it goes to sleep but I can not get it to wake up. I did make a change from INPUT to INPUT_PULLUP
ReplyDeleteI'm using a pro mini, and I'm experiencing the same problem.
DeleteThis comment has been removed by the author.
DeleteThe problem is that if we attach the interrupt while the interrupt pin is HIGH, then we will immediately go to the interrupt-function and detach the intterupt. Hence, when we go to sleep, there is no way to wake up.
DeleteThis is solved by adding an if-statement:
if (digitalRead(pin2)){
sleep_mode();}
Also use this for the setup:
pinMode(pin2, INPUT_PULLUP);
I'm using a pro mini.
It might not be 100% fail proof in theory, but seems to work for me all the time.
Cheers :}
The code written thus works stablly.
Deletevoid enterSleep(void)
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
/* Setup pin2 as an interrupt and attach handler. */
attachInterrupt(0, pin2Interrupt, LOW);
sleep_mode();
/* The program will continue from here. */
/* First thing to do is disable sleep. */
sleep_disable();
}
sleeb_mod() is a macro....defined in sleep.h:
ReplyDelete#define sleep_mode() \
do { \
sleep_enable(); \
sleep_cpu(); \
sleep_disable(); \
} while (0)
so think 10 Sec. now!
/*
ReplyDelete* Rain Counter
* in Power Down Mode
* Wake short up for count
* Bord Crumb128 with atmega128
*/
#include avr/sleep.h
#include util/delay.h
const int INT_0 =2; //Arduino Interrupt-No. for INT0
const int INT_0_PIN=16; //Arduino Pin-No. for INT0/PD0 Pin on atmega128
int count;
void setup()
{
pinMode(INT_0_PIN, INPUT_PULLUP); //Pullup Button Input PD0/INT0
set_sleep_mode ( SLEEP_MODE_PWR_DOWN ); // sleep mode is set here
attachInterrupt ( INT_0, interrupt1, FALLING ); //INT0 PD0
Serial.begin(9600);
}
void loop()
{
Serial.print("Counter: "); Serial.println(count);
delay(500);
sleep_mode(); //Sleep now
}
void interrupt1()
{
count++;
// Some Stuff for debouncing
while(digitalRead(INT_0_PIN)==LOW);
_delay_ms(1000);
while(digitalRead(INT_0_PIN)==LOW);
EIFR |= (1<<INTF0); //Other Interrupt? Clear! Write 1 to clear Interrupt-Flag INT0!
}
I'm confused by this bit of code:
ReplyDeletesleep_mode();
/* The program will continue from here. */
/* First thing to do is disable sleep. */
sleep_disable();
Specifically, what is meant by the comment "The program will continue from here"? I'm assuming that once "sleep_mode();" executes, the Arduino is asleep, and will remain asleep until the Interrupt signal is received. When that happens, does the code start to execute right where the comment is? If that's right, it would explain the next comment, "First thing to do is disable sleep", with sleep_disable().
So, inside loop(), when the condition is met to put the Arduino to sleep, call enterSleep(). Immediately after that, put whatever code I want to execute when the Arduino is NOT asleep (or when it comes out of being asleep), right? It's just kind of confusing in this example Sketch, because the very last thing that happens in loop() is enterSleep() - what's the point in turning the Arduino on for 3 seconds, just to put it to sleep? Would the following be correct? (All I did was add the COMMENT line.)
if(seconds == 3)
{
Serial.println("Entering sleep");
delay(200);
seconds = 0;
enterSleep();
}
// COMMENT: put whatever code here that you want to execute when the
// Arduino is NOT asleep.
}
Thanks so much!
Hi Brian,
Delete> "When that happens, does the code start to execute right where the comment is? If that's right"
Execution of the main loop is 'paused' within the sleep_mode() function. When the pin2Interrupt() interrupt is triggered by the pin chance, execution resumes in the sleep_mode() function.
> So, inside loop(), when the condition is met to put the Arduino to sleep, call enterSleep(). Immediately after that, put whatever code I want to execute when the Arduino is NOT asleep (or when it comes out of being asleep), right?
Correct
> what's the point in turning the Arduino on for 3 seconds, just to put it to sleep?
Purely just an example of 'doing stuff for a few seconds', and then going back to sleep until the external interrupt is triggered again.
> Would the following be correct? (All I did was add the COMMENT line.)
Correct
Hope that helps :-)
Best Regards,
Donal
Hi guys,
ReplyDeleteDo we have any examples of using sleep for PIR motion detection - wake on interrupt & and time delay sensors. I would like to wake when motion is detected and send rf messages and when a timer hits 5 mins, get a temp reading and send it.
My sensors are battery powered so i need to sleep as much as possible.
Thanks
Wayne
Hi Wayne,
ReplyDeleteYou should be able to use a combination of External Interrupts (Part 2 of this guide) and waking up via watchdog (Part 5).
BR,
Donal
Thanku So Much Such A Wonder full Blog On Arduino Sleep TY..
ReplyDelete