1

I'm trying the following code on an Uno. I'm pulling the high side of a pull down 10K resistor to 5V, but it can only be woken once. Just once. Does anyone know why this might be the case?

It works fine if I use LOW for attachInterrupt along with a pull-up resistor though. Just not with RISING and a pull-down.

#include <avr/sleep.h>
#include <avr/power.h>

int pin2 = 2;

void setup() {
  Serial.begin(9600);

  /* Setup the pin direction. */
  pinMode(pin2, INPUT);

  Serial.println("Initialisation complete.");

}

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 high.
   */
  detachInterrupt(digitalPinToInterrupt(pin2));
}

void enterSleep(void)
{  

  sleep_enable();

  /* Setup pin2 as an interrupt and attach handler. */
  attachInterrupt(digitalPinToInterrupt(pin2), pin2Interrupt, RISING);
  delay(100);

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);

  sleep_mode();

  /* The program will continue from here. */

  /* First thing to do is disable sleep. */
  sleep_disable(); 
}

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();
  }
}
  • I think I have seen somewhere in the past a problem with detaching an interrupt from within an interrupt handler. You shouldn't need to detach and attach the interrupt handler all the time - just leave it attached. – Majenko Sep 11 '15 at 18:08
  • @Majenko But you wouldn't want interrupts to keep firing whilst it's going to sleep, right? – Kar Sep 11 '15 at 18:10
  • I don't understand that question. What do you mean by "going to sleep"? It's either asleep or awake. You need interrupts enabled while it's asleep so you can wake up. Does it really matter to you if an empty interrupt handler gets triggered if you press the button while it's awake? – Majenko Sep 11 '15 at 18:12
  • Based on the examples here, it says "In the interrupt service routine (ISR) for a level interrupt, the interrupt must be detached otherwise the interrupt will keep happening and the ISR will be repeatedly called until the pin changes state." So it sounds like it's essential to detach - no? – Kar Sep 11 '15 at 18:18
  • Read the last word in your attachInterrupt call. What does it say? – Majenko Sep 11 '15 at 18:18
1

For a RISING interrupt you never need to disconnect the interrupt to prevent repeat triggering.

A RISING interrupt specifically only triggers the once when the input pin transitions from LOW to HIGH rather than all the time it's in a state like a level interrupt.

Attach the interrupt once in setup() and leave it alone after that. Your interrupt handler routine can be completely empty. It will only ever be triggered at the exact moment you press the button. To trigger it again you will just need to press the button again.

1

Probably your switch is bouncing and giving two interrupts. The first wakens it, and the second is lying there waiting until you attach the interrupt again. Then it fires, detaches the interrupt, then you go to sleep, never to awaken.

Clear any pending interrupt before doing the attachInterrupt:

EIFR = bit (INTF0);  // clear flag for interrupt 0

See Interrupts.

It is also wise to have interrupts off while setting up for sleep.


Example code:

#include <avr/sleep.h>                  

const byte LED = 13;

// interrupt service routine in sleep mode
void wake ()
{
  sleep_disable ();         // first thing after waking from sleep
}  // end of wake

void sleepNow ()
{
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);   
  noInterrupts ();          // make sure we don't get interrupted before we sleep
  sleep_enable ();          // enables the sleep bit in the mcucr register
  EIFR = bit (INTF0);       // clear flag for interrupt 0
  attachInterrupt (0, wake, RISING);  // wake up on rising edge
  interrupts ();           // interrupts allowed now, next instruction WILL be executed
  sleep_cpu ();            // here the device is put to sleep
  detachInterrupt (0);      // stop this interrupt until next time
}  // end of sleepNow

void setup ()
  {
  pinMode (LED, OUTPUT);
  }  // end of setup

void loop ()
  {
  sleepNow ();
  digitalWrite (LED, HIGH);
  delay (1000);
  digitalWrite (LED, LOW);
  }  // end of loop

Tested and works OK.


Note: Since this is a rising interrupt you should have a pull-down resistor on the pin, and you trigger the interrupt by connecting the pin to +5 V.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.