Sunday, 25 April 2010

Sleeping Arduino - Part 2 Wake Up Via An External Interrupt

Overview
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:
  1. Set up the serial port and set pin 2 (INT0) as an input;
  2. Run the loop function which will:
    1. Stay awake for 3 seconds;
    2. Once the 3 seconds have elapsed, SLEEP_MODE_PWR_DOWN will be entered;
    3. All code execution stops;
  3. The user then pushes the switch and pin 2 (INT0) will become low;
  4. The INT0 interrupt will fire and bring the Arduino out of sleep mode;
  5. Code execution continues where it had previously stopped.

Circuit
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:


15 comments:

  1. Hi Donal,

    I'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

    ReplyDelete
    Replies
    1. Hi, first thanks for the article!
      And 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

      Delete
    2. 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

      The 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

      Delete
  2. Hello, What is the best way to set to sleep arduino using a Xbee module?
    I need minimum consumption for my project. Thank you and great blog.

    ReplyDelete
  3. Hi Giannis,
    Apologies 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

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. This comment has been removed by a blog administrator.

    ReplyDelete
  6. hello Donal,

    I 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

    ReplyDelete
  7. I reply to myself.
    I have added "digitalWrite(2,HIGH);" in setup after "pinMode" and it works perfectly now.

    ReplyDelete
    Replies
    1. or
      pinMode(pin2, INPUT_PULLUP);

      or put a pullup resistor 10K

      Very Good Example Thank you ! ! ! ! :-)

      Delete
  8. HI and thanks a lot for your help
    But where can we find these ones
    #include
    #include
    Seems not so easy to find

    ReplyDelete
  9. sorry these ones
    avr/sleep.h
    avr/power.h

    ReplyDelete
  10. 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
    So ,"we should never change the arduino name directory"
    jm

    ReplyDelete
  11. 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

    ReplyDelete
    Replies
    1. I'm using a pro mini, and I'm experiencing the same problem.

      Delete