Hi there, I have a push-button for my Arduino Uno that's normally pulled high (internal pull-up) and when I push the button I need the it go to sleep, and wake up when I push it again. Pretty simple, and I have already done that with this sample code:
#include <avr/sleep.h>
#include <avr/power.h>
#include <PinChangeInterrupt.h>
#define LED 13
#define BUTTON A1 // Main power button (toggle device on/off)
volatile bool buttonPressed = false;
volatile bool MCU_turnedOn = false;
unsigned long previous = 0;
void setup() {
Serial.begin(115200);
pinMode(LED, OUTPUT);
pinMode(BUTTON, INPUT_PULLUP);
attachPCINT(digitalPinToPCINT(BUTTON), toggle, FALLING);
}
void loop() {
if (MCU_turnedOn) { // Blinks LED 3 times when MCU wakes up
for (int i=0; i<3; i++) {
digitalWrite(LED, HIGH);
delay(50);
digitalWrite(LED, LOW);
delay(50);
}
MCU_turnedOn = false;
}
digitalWrite(LED, HIGH); // Normally LED is on
if (buttonPressed) {
MCU_powerDown();
}
delay(50);
}
void MCU_powerDown() {
digitalWrite(LED, LOW); // Turn off LED before sleeping
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
ADCSRA = 0; // Turn off ADC
power_all_disable (); // Power off ADC, Timer 0 and 1, serial interface
noInterrupts();
sleep_enable();
attachPCINT(digitalPinToPCINT(BUTTON), wakeUp, FALLING);
interrupts();
sleep_cpu();
// Code resumes here after wakeup
sleep_disable();
power_all_enable(); // Power everything back on
}
void wakeUp() {
buttonPressed = false;
MCU_turnedOn = true;
// PCIFR = (1<<PCIF1); // Clear pending flag for PCINT1_vect
attachPCINT(digitalPinToPCINT(BUTTON), toggle, FALLING); // Re-attach toggle ISR instead of in loop()
}
void toggle() {
delay(10); // Debouncing
if (!digitalRead(BUTTON)) { // If state is still low, then button was pressed for sure
buttonPressed = true;
}
}
This test code runs just fine, and I intentionally made it mimic my actual code structure where I check for the flag "buttonPressed" and go directly to sleep when it's true.
Now for the weird part: In my actual code (with a lot more intensive while loops, basically sending AT commands and getting a reply), when I press the button it does indeed go to the sleep function, but instead of actually sleeping it somehow wakes up directly after, thus making it seem like it did nothing.
This seems to indicate that the wakeUp() ISR is being triggered by something like the release of the button, but why would it do this in my actual code vs the test code?
I've been pulling my hair out trying to figure out this issue for the past couple days and can't seem to get this resolved. Again, it's indeed reaching the MCU_powerDown() function, but it's waking up directly after. My actual code involves a while loop to receive a response from an AT command that is sent via Software Serial, but within that while loop it checks for "buttonPressed" and if true, it calls MCU_powerDown(). So the real issue here (at least I think) is preventing the wakeUp() function from falsely triggering.
Any ideas? Thanks!
EDIT: if you're really interested in seeing my code, I'm using this library and in the Adafruit_FONA.cpp at line 1762 I am inserting this code:
if (buttonPressed) {
buttonPressed = false; // Reset flag so it won't trigger multiple times
MCU_powerDown();
}
then in my loop I have this:
if (!fona.begin(*fonaSerial)) { // This runs the function at line 41 of Adafruit_FONA.cpp
Serial.println(F("Couldn't find FONA"));
}
delay(100);
This basically runs setup over and over. Of course I wouldn't do this in my actual code but I am using this to test the concept. The function fona.begin() in line 41 of the .cpp will be interrupted whenever I press the button, and it jumps directly to my MCU_powerDown() function. However, it seems to wake up immediately after trying to sleep...