I can turn put my Arduino to sleep but can't wake it up?

Hi guys, I’m an Arduino noob and am working on a project that requires the use of one button to put the Arduino to sleep when clicked once and then wake it up the next time it is clicked. After doing some research and looking at code that other people wrote, I was able to get my Arduino to go to sleep but can’t get it to wake up.

It seems like the culprit has to do with sleep_mode() in the goToSleep() function, because when I remove it, I can clearly see that both the goToSleep and wakeUp functions work, and I can’t exactly take it out because it seems like that method call is essentially to what I want to end up doing.

It seems really simple, and I’m sure there is a simple solution that I’m missing, but if anyone could help, that would be greatly appreciated!

#include <avr/sleep.h>

int buttonPin = 2;
boolean isSleeping = false;

void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
delay(100);
Serial.println(“I’m up…”);
Serial.println(digitalRead(2));
attachInterrupt(digitalPinToInterrupt(buttonPin), toggleSleepState, LOW); //attaching wakeup to interrupt 0 on pin 2
delay(1000);
}

void loop() {
// int buttonState = digitalRead(buttonPin);
// Serial.println(buttonState);
// delay(1000); // wait 1 sec
}

void toggleSleepState() {

static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
// If interrupts come faster than 20ms, assume it’s a bounce and ignore
if (interrupt_time - last_interrupt_time > 200)
{
// toggle state of sleep
isSleeping = !isSleeping;

if (isSleeping == true) {
Serial.println(“goToSleep”);
goToSleep();
}
else {
Serial.println(“wakeUp”);
wakeUp();
}
}
last_interrupt_time = interrupt_time;
}

void goToSleep() {
Serial.println(“Power Button pressed…”);
Serial.flush();
sleep_enable(); // only enabling sleep mode, nothing more
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // setting sleep mode to max pwr saving

sleep_mode();
Serial.println(“Checkpoint!”); // gets executed after interrupt
Serial.flush();
}

void wakeUp () {
sleep_disable();
Serial.println(“Wakeup Interrupt Fired”);
}

For reference, I am using an Arduino Uno and the button I’m using is a large arcade button bought from Adafruit.

button.ino (1.55 KB)

You should not be doing everything inside the context of a ISR. Especially any Serial.print() statements since interrupts are disabled during an ISR. Just set a flag and handle all that stuff inside loop()

Thank you for your help! I removed all of the print statements and replaced them by turning the lights on the Arduino on and off, but it still doesn’t work. What exactly did you mean when you said to “set a flag and handle all that stuff inside loop()”?

Here is a working program, it uses a switch on pin 2 to wake up the Arduino

/*******************************************************************************************************
  lora Programs for Arduino - Copyright of the author Stuart Robinson - 26/12/19

  Part of SX12xx Library; https://github.com/LoRaTracker/SX12XX-LoRa

  This program is supplied as is, it is up to the user of the program to decide if the program is
  suitable for the intended purpose and free from errors.
*******************************************************************************************************/

/*******************************************************************************************************
  Program Operation - This program tests the deep sleep mode and wakeup with a switch of an Atmel 328P or
  1284P processor. The program starts, flashes the LED and then puts the processor into permanent sleep.
  It can be woken up with a switch press. Used as a base test routine for checking the sleep current of
  a board.

  Tested on a 'bare bones' ATmega328P board, the current in sleep mode was 1.7uA with a 3.3V MCP1700
  regulator being used.

  Serial monitor baud rate is set at 9600.
*******************************************************************************************************/

#define Program_Version "V1.0"

#include <avr/sleep.h>

#define LED1 8                                  //on board LED, high for on
#define SWITCH1 2                               //switch used to wake processor up, switch pin connected to 
                                                //ground to activate. Define as -1 if switch not used.

void loop()
{
  digitalWrite(LED1, HIGH);
  delay(2000);
  Serial.println(F("Sleeping zzzzz...."));
  Serial.println();
  Serial.flush();                               //make sure serial out buffer is empty
  digitalWrite(LED1, LOW);

  sleep_permanent();                            //goto sleep till woken up by switch press

  Serial.println(F("Awake !"));
  Serial.flush();
  digitalWrite(LED1, HIGH);
}


void sleep_permanent()
{
  attachInterrupt(digitalPinToInterrupt(SWITCH1), wakeUp, FALLING);   //This is a hardware interrupt

  ADCSRA = 0;                         //disable ADC
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  noInterrupts ();                   //timed sequence follows
  sleep_enable();

  //turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);  //turn on brown-out enable select
  MCUCR = bit (BODS);                //this must be done within 4 clock cycles of above
  interrupts ();                     //guarantees next instruction executed

  sleep_cpu ();                      //sleep within 3 clock cycles of above

  /* wake up here */

  sleep_disable();

  detachInterrupt(digitalPinToInterrupt(SWITCH1));
}


void wakeUp()
{
  //handler for the interrupt
}


void led_Flash(uint16_t flashes, uint16_t delaymS)
{
  uint16_t index;
  for (index = 1; index <= flashes; index++)
  {
    digitalWrite(LED1, HIGH);
    delay(delaymS);
    digitalWrite(LED1, LOW);
    delay(delaymS);
  }
}


void setup()
{
  pinMode(SWITCH1, INPUT_PULLUP);              //setup switch pin, ground to activate
  pinMode(LED1, OUTPUT);                       //setup pin as output for indicator LED
  led_Flash(2, 125);                           //two quick LED flashes to indicate program start

  pinMode(SWITCH1, INPUT_PULLUP);              //setup switch pin, connect to ground to activate

  Serial.begin(9600);
  Serial.println();
  Serial.print(__TIME__);
  Serial.print(F(" "));
  Serial.println(__DATE__);
  Serial.println(F(Program_Version));
  Serial.println();

  Serial.println(F("12_ATmel_Sleep_with_Switch_Wakeup Starting"));


}

In the context of using a flag to detect the interrupt, you would in the IRQ handler put set a gloabal flag;

void wakeUp()
{
  //handler for the interrupt
flag = true;
}

Your program can then detect, by reading the flag varaible whether an interrupt has occured.

srnet:
In the context of using a flag to detect the interrupt, you would in the IRQ handler put set a gloabal flag;

void wakeUp()

{
  //handler for the interrupt
flag = true;
}





Your program can then detect, by reading the flag varaible whether an interrupt has occured.

And make sure you declare your flag variable to be 'volatile'

volatile bool flag;