Pages: [1]   Go Down
Author Topic: Both HIGH and RISING interrupt triggered when releasing button after sleep  (Read 1732 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, so I've never worked with interrupts before, but this project requires long battery life, so I'm trying to learn.  I have got the code working properly for putting the Arduino to sleep after holding the button for a few seconds, and it even wakes up with the interrupt, if I release the button before sleep starts.  The problem occurs if the button is still held after the Arduino goes to sleep, then it will wake upon release, even though the line is going LOW or FALLING.  As you can see in my code below, I am using a HIGH interrupt.  I have also tried it with a RISING interrupt, but I get the same behavior.  I can only think that maybe I need to debounce the interrupt in some way, but I'm not sure how to do that.  Also, in case anyone is wondering, the button is connected on one side to 5v, on the other side to Pin 2 and a 10k resistor to ground.  Code is below, any help is greatly appreciated. 

Code:
#include <avr/sleep.h>

// set pin numbers:
const int led0Pin = 8;      // the number of the 1st LED pin
const int led1Pin = 9;      // the number of the 2nd LED pin
const int buttonPin = 2;     // the number of the button pin

// Set up initial Variables
long lastDebounceTime = 0;     // the last time the output pin was toggled
long sleepButtonDelay = 3000;  // How long the button needs to be pressed to turn off
int lastButtonState = LOW;     // the previous reading from the input pin
int buttonState = LOW;         // Current reading of button state

void setup() {
  // initialize the LED pin as an output:
  pinMode(led0Pin, OUTPUT);
  pinMode(led1Pin, OUTPUT);
  pinMode(buttonPin, INPUT);
 
  buttonState = digitalRead(buttonPin);
  if (buttonState)
    lastButtonState = LOW;
  else
    lastButtonState = HIGH;
}

void loop() {
  // Long Button hold will put arduino to sleep
//  if (buttonPressed)
//  {
//     buttonLongPressSleep();
//    goToSleepNow();
//  } else {
    // Insert code for lighting loops here.
   
    digitalWrite(led0Pin, HIGH);
    digitalWrite(led1Pin, HIGH);
    delay(500);
    digitalWrite(led0Pin, LOW);
    digitalWrite(led1Pin, LOW);
    delay(500);
   
    buttonLongPressSleep();
//  }
   
}

// check for a long button press and put uc to sleep if one is detected
// short press will wake it back up through interrupt
int buttonLongPressSleep()
{
  // Read current state of the button
  int reading = digitalRead(buttonPin);
 
  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    lastButtonState = reading;
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
 
  if (((millis() - lastDebounceTime) > sleepButtonDelay) && lastButtonState == HIGH)
  {
    // The pin has been HIGH longer
    // than the delay, so we should go to sleep here:
    goToSleepNow();
  }
}

// Interupt service routine for a button press, Nothing needed but to wake up.
void isrWakeUp()
{
  // No action required, wake up only.
}

void goToSleepNow()
{
  // Flash twice quickly to notify that sleep is starting.
  notificationFlash();
  // Enable Interrupts
  interrupts();
  // Set up sleep mode
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  // Enable Sleep Mode
  sleep_enable();
  // Attach an interrupt to the button pin to bring us out of sleep
  attachInterrupt(0, isrWakeUp, HIGH);
//  attachInterrupt(0, isrWakeUp, RISING);
  // Sleep
  sleep_mode();
  //
  //  Right here we are sleeping until the button is pressed
  //
  sleep_disable(); // Disable Sleep Mode
  detachInterrupt(0);
  noInterrupts();
  // Reset the sketch to the beginning after resuming from sleep 
  softReset();
}

//  Sketch starts over, but, not a full hardware reset. 
void softReset()
{
  // Reset sketch.  Code pulled from arduino forums.
  asm volatile ("  jmp 0");
}

// Flash twice to indicate sleep
void notificationFlash()
{
    digitalWrite(led0Pin, HIGH);
    digitalWrite(led1Pin, HIGH);
    delay(250);
    digitalWrite(led0Pin, LOW);
    digitalWrite(led1Pin, LOW);
    delay(250);
    digitalWrite(led0Pin, HIGH);
    digitalWrite(led1Pin, HIGH);
    delay(250);
    digitalWrite(led0Pin, LOW);
    digitalWrite(led1Pin, LOW);
}
Logged

Offline Offline
Edison Member
*
Karma: 19
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

HIGH cannot be used with interrupts:

http://arduino.cc/en/Reference/AttachInterrupt
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

After a little more digging, I found what initially appeared to be a workaround and it works great, the first time I put the arduino to sleep, but on subsequent sleeps, I get the same behavior as before.  
This should prevent the arduino from sleeping until the button is released, but it only works the first time through the goToSleepNow function.  Also, I don't really see why it should be needed since I am using RISING or HIGH interrupts, I just can't understand why the interrupt is triggering on LOW or FALLING?  Here is the modified version of the goToSleepNow() function:
Code:
void goToSleepNow()
{
  // Flash twice quickly to notify that sleep is started.
  notificationFlash();
  // Check status of pin 2
  int pinStatus = digitalRead(2);
  // Loop until button is released then sleep.
  // Prevents problems with interrupt triggering on
  // FALLING and LOW for some reason
  while (pinStatus)
  {
    pinStatus = digitalRead(2);
  }
  // Set up sleep mode
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  // Enable Sleep Mode
  sleep_enable();
  // Enable Interrupts
  interrupts();
  // Attach an interrupt to the button pin to bring us out of sleep
//  attachInterrupt(0, isrWakeUp, HIGH);
  attachInterrupt(0, isrWakeUp, RISING);
  // Sleep
  sleep_mode();
  //
  //  Right here we are sleeping until the button is pressed
  //
  sleep_disable(); // Disable Sleep Mode
  detachInterrupt(0);
  noInterrupts();
  // Reset the sketch to the beginning after resuming from sleep  
  softReset();
}
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks, that is good to know, but as I stated previously, I get exactly the same behavior with RISING.  I just changed the line, again and tested, just to be sure. 
Logged

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19363
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Couple of things here.

First, in power-down mode only a level interrupt works. That is, a LOW interrupt. So you need to make it be low to wake (ie. default to be high) which you can achieve with a pull-up.

Second, interrupt states are remembered, so it is probably triggering from the previous interrupt. You can clear a rising/falling interrupt state before attaching the interrupt handler. See here for more details:

http://www.gammon.com.au/interrupts
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19363
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
// Reset the sketch to the beginning after resuming from sleep 
  softReset();

I don't particularly like doing a soft reset after waking. Can't you code so that isn't necessary?
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ah, now that is very helpful.  I kind of remember reading that on the arduino documentation, but I didn't fully understand what a "level interrupt" was.  Also, strangely enough, I already had your site on interrupts open in another tab and was trying to work through it and understand it all, but it's quite a lot to take in, at least for me. 

I just rewired my circuit to be LOW on button press instead of HIGH and changed my code to reflect this.  Now it works perfectly.  Thanks a lot for the assistance. 
I will also try coding a function to reset everything manually, instead of doing a soft reset.  That was mainly a crutch while working through this interrupt code. 
Logged

Pages: [1]   Go Up
Jump to: