Waking up Arduino using pin change interrupt

Hi,
sorry for any “inappropriate” language… this is my first post.
I’m working on a new project and I’m trying to put the Arrduino Uno in sleep mode and wake it using using pin interrupt through a single button on pin A0, thus push once go to sleep, push again wake up. The reason I’m not using the canonical interrupt is that they are already used for different purposes.
I tested the basic logic using messages on the console, and it worked fine, but when I enable the sleep mode it doesn’t wake up, it looks like Arduino is not going in the interrupt function, why ?? What am I doing wrong ?
The code is the following:

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

const byte ledPin = 13;
const byte sleepbtn=A0;
const byte btntest=7;
const byte testled=11;

volatile byte state = LOW;

byte sleepmode=HIGH;
 
void setup(){
   Serial.begin(115200);
   pinMode(ledPin, OUTPUT);
   pinMode(sleepbtn, INPUT_PULLUP);
   pinMode(btntest, INPUT_PULLUP);
   pinMode(testled, OUTPUT);
   digitalWrite(ledPin, HIGH);
   PCMSK1 = B00000001; //enable PCINT8
   PCIFR = B00000000; // clear all interrupt flags   
   
   
}
 
void loop(){
   sleepmode=digitalRead(sleepbtn);
   state=digitalRead(btntest);
   digitalWrite(testled,!state);
   if (sleepmode==LOW) {
    Serial.println("go to sleep");     
    
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    digitalWrite(ledPin,LOW);
    for (int i=0; i<3; i++){
      digitalWrite(ledPin,HIGH);
      delay(500);
      digitalWrite(ledPin,LOW);
      delay(500);
    }
    digitalWrite(ledPin,HIGH);
    sleep_enable();
    PCICR = B00000010; // enable PCIE1 group
    sleep_mode();

    sleep_disable();  
   }
}
 
ISR(PCINT1_vect) {
  
  PCICR  &= ~(1 << PCIE1);   // disable pin change interrupts for A0 to A5
  Serial.println("wake up"); 
}

sleep_no_interrupt.ino (1.14 KB)

Looking at your code,

when you pressed the sleep button, the Arduino goes to Sleep. The moment you release the button (thereby pulling the signal high), the Arduino wakes up because that would qualify a PIN change (from LOW to HIGH)

Also, there's this thing called "bounce" where any physical button will register multiple UPs-and-DOWNs before settling, and since the Arduino samples the state at millions of times per second, there's a good chance that it will register this multiple states in between

Here's some article online about button debouncing

hzrnbgy:
Looking at your code,

when you pressed the sleep button, the Arduino goes to Sleep. The moment you release the button (thereby pulling the signal high), the Arduino wakes up because that would qualify a PIN change (from LOW to HIGH)

Also, there's this thing called "bounce" where any physical button will register multiple UPs-and-DOWNs before settling, and since the Arduino samples the state at millions of times per second, there's a good chance that it will register this multiple states in between

Here's some article online about button debouncing

What is Switch Bouncing and How to prevent it using Switch Debounce Circuit

Well if the interrupt is fired on the low to high then the Arduino should go in sleep mode and immediately wake up, the issue is that it goes in sleep mode but it doesn't wake up anymore.
I'm aware of the bouncing issue but also this should not be the reason why the board doesn't wake up, since Arduino should go in sleep mode (and indeed it goes in sleep mode) as soon as the button is pressed and the loop execute the code in the if block for the first time.

I don't understand how it can be going into sleep mode. It appears you never actually tell it to go to sleep. Try changing line 44 from sleep_mode() to sleep_cpu().

Also, be aware that the flag bit is cleared by writing a one to it. So you would OR the existing value with 2 to clear it. Or just write a 7 to the PCIFR

You'll have to add code to make sure the switch has been released and stays high for, say, 1/4 second, then clear the flag bit, before you do anything with it after it has been pressed. I would also clear the flag bit in the ISR after you disable the interrupt.

Here's a function that would wait for the button to be released and remain high for 0.1 second, then clear the flag bit. It would be called before you enable the interrupt, and after you wake up.

void waitforrelease() {
  unsigned long oldMilli = millis();
  int countdown = 100;
  while (countdown) {
    unsigned long newMilli = millis();
    if (newMilli != oldMilli) {
      oldMilli = newMilli;
      countdown--;
      if (digitalRead(sleepbtn) == LOW) countdown = 100;
    }
  }
  PCIFR = 2;
}

YES!!!
Thank you very much ShermanP, it is working fine now, here is the full code.

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

const byte ledPin = 13;
const byte sleepbtn=A0;
const byte btntest=7;
const byte testled=6;

volatile byte state = LOW;

byte sleepmode=HIGH;
 
void setup(){
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  pinMode(sleepbtn, INPUT_PULLUP);
  pinMode(btntest, INPUT_PULLUP);
  pinMode(testled, OUTPUT);
  digitalWrite(ledPin, HIGH);
  PCMSK1 = B00000001; //enable PCINT8
  PCIFR = B00000111; // clear all interrupt flags    
}

volatile int flg_sleeping=0;

void loop(){
   sleepmode=digitalRead(sleepbtn);
   state=digitalRead(btntest);
   digitalWrite(testled,!state);
   if (sleepmode==LOW) {
    Serial.println("go to sleep"); 
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    waitforrelease();
    PCICR = B00000010; // enable PCIE1 group      
    sleep_mode();
 
    waitforrelease();   
    sleep_disable();
    Serial.println("wake up");      
   }
}

void waitforrelease() {
  unsigned long oldMilli = millis();
  int countdown = 100;
  while (countdown) {
    unsigned long newMilli = millis();
    if (newMilli != oldMilli) {
      oldMilli = newMilli;
      countdown--;
      if (digitalRead(sleepbtn) == LOW) countdown = 100;
    }
  }
  PCIFR = 2;
}

ISR(PCINT1_vect) {
   PCICR  &= ~(1 << PCIE1);   // disable pin change interrupts for A0 to A5
 }