I’m struggling a bit with the sleep mode (stop). After a lot of debugging I found that when calling my stateManager
function waking up doesn’t work fine.
I made this example code to demonstrate it. I use a timer to keep track of an on/off button (the type that keep’s in the state, so either stays HIGH
or it stays LOW
). I do this because in my original code lot of things happen. Using a timer guaranties that button is checked every millisecond (I don’t use an interrupt because that doesn’t work with debounce).
I’ve added a delay in the loop of 100ms. Removing this, break the program. I have no idea why.
#include "Particle.h"
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);
void senseOnOffButton();
void stateManager();
const int onOffButtonPin = A6;
Timer senseOnOffButtonTimer(1, senseOnOffButton);
bool WkpValue;
bool lastWkpValue;
bool wkpButtonState;
long _lastBounceTime;
enum States { WAKE_FROM_OFF, WAKE_FROM_SLEEP, WAKING_UP, AWAKE, GO_TO_SLEEP, ASLEEP };
enum States state;
void setup()
{
pinMode(onOffButtonPin, INPUT);
pinMode(D7, OUTPUT);
//Serial.begin(57600);
// delay(2000);
// Serial.println("Hi! Setup!");
state = WAKE_FROM_OFF;
}
void loop()
{
stateManager();
// This delay is needed otherwise we don't wake up from sleep anymore.
// Why can't we call stateManager as fast as possible?
// What kind of hidden things happen in the background?
delay(100);
}
void stateManager() {
switch(state) {
case WAKE_FROM_OFF:
// Serial.println("WAKE_FROM_OFF");
state = WAKING_UP;
break;
case WAKE_FROM_SLEEP:
// Serial.println("WAKE_FROM_SLEEP");
// delay(500);
// The device will not reset before going into stop mode so all the application
// variables are preserved after waking up from this mode.
// we might force a reset to be sure things won't happen twice.
//System.reset();
state = WAKING_UP;
break;
case WAKING_UP:
//WkpValue = digitalRead(onOffButtonPin);
//lastWkpValue = WkpValue;
//wkpButtonState = WkpValue;
// Serial.println("WAKING_UP");
senseOnOffButtonTimer.start();
state = AWAKE;
break;
case AWAKE:
digitalWrite(D7, HIGH);
if(Particle.connected()) {
// we can parse the Cloud
}
break;
case GO_TO_SLEEP:
// Serial.println("GO_TO_SLEEP");
// We can't stop this one, because then we don't detect the button on
// waking up.
// senseOnOffButtonTimer.stop();
state = ASLEEP;
break;
case ASLEEP:
digitalWrite(D7, LOW);
// Serial.println("ASLEEP");
// stop mode
System.sleep(onOffButtonPin, CHANGE);
break;
}
}
void senseOnOffButton() {
// we sense every ms. First idea was to connect it to and interrupt and let the interrupt start
// at timer. That doesn't work and seems to break the interupt as well...
// This works so no need to improve it now.
WkpValue = digitalRead(onOffButtonPin);
if(WkpValue != lastWkpValue) {
_lastBounceTime = (long) millis();
lastWkpValue = WkpValue;
}
if(WkpValue != wkpButtonState)
{
if ((long) millis() - _lastBounceTime > 20)
{
if(state != ASLEEP) {
// go to sleep
state = GO_TO_SLEEP;
}
else {
state = WAKE_FROM_SLEEP;
}
wkpButtonState = WkpValue;
stateManager();
}
}
}