EDIT: I was able to solve the problem (see 2nd code, I've put if(enableSleepButton)
in beggining of sleepNow()), but I am still unsure if this is correct approach. Still seeking for answers!
I am using Arduino Nano and have a button connected to D2. I want to put the device to sleep when this button is pressed - and wake it back up when button is pressed again (this can be done many times).
What I don't understand is how to handle interrupts so they don't fire continuously once set up. Based on documentation, you can only wake up the device with LOW state on pin:
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), sleepNow, LOW);
}
void sleepNow() {
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sei();
sleep_cpu();
}
void wakeUp() {
sleep_disable();
DBG("IRQ");
}
Problem is that sleepNow() will keep firing while BUTTON_PIN is in LOW state, right? So I tried using multiple interrupts and juggling them around and it's working:
volatile bool enableSleepButton = false;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), sleepNow, RISING); // rising will work while device is not in sleep
}
void loop() {
if(enableSleepButton) // after adding this, it now works properly - but is the approach correct?
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), sleepNow, RISING); // this re-enables interrupt for sleep mode on button press
}
void sleepNow() {
if(enableSleepButton)
return; // device not fully awaken yet, don't allow sleep
detachInterrupt(digitalPinToInterrupt(BUTTON_PIN)); // prevent further IRQs for sleep
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), wakeUp, LOW); // wakeup only works for LOW; this will wake up the device next time we press the button
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sei(); - why do I need this? Some people have it, others not. For me the wakeup isn't working without it
sleep_cpu();
}
void wakeUp() {
detachInterrupt(digitalPinToInterrupt(BUTTON_PIN)); // detach LOW interrupt now so this function doesn't get called repeatedly while pin is in LOW mode
sleep_disable();
DBG("IRQ");
}
Questions:
- is juggling with interrupts required, or could I just somehow use 1 interrupt inside setup()?
- why is sei() required for wake-up and why is it omitted from documentation?
why is the program hanging after setting the sleep interrupt again in loop() and how to solve this?
Please note I've spent 2 hours reading Gammon's guide to Interrupts, this, this, this, this, and many more threads, so I would really appreciate if someone could guide me and/or correct my code. Thank you