Hello. I am currently making my own smart watch, which obviously needs to use as little energy as possible. This is my first time implementing a hardware sleep mode, and I am having a bit of trouble.
After hours of wrong pins and and other small issues, I have gotten it to ALMOST work.
Upon starting, the code is supposed to wait for ten seconds (shortened in code below for debugging), then go into sleep mode, until it wakes up when I interrupt it with a button at pin 3.
This works good so far, but then after the next 10 seconds, it shuts down only for an instant, then is on for ten more seconds, and then it turns off, and remains off until next interrupt.
If I had been caught in a loop, I would know how to debug it, but i am perplexed as to how the bug happens ONCE.
To reinstate:
in sleep mode
Interrupt at pin 3
On for 10 seconds
Sleep for maybe 100-200ms
On for another 10 seconds
sleep mode (until next button-press)
/**************************************************************************
Fish watch OS - created by Iver Iscariot Søbakk, 27-9-23
**************************************************************************/
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DS3232RTC.h> // https://github.com/JChristensen/DS3232RTC
#include "Arduino.h"
#include <avr/sleep.h>
DS3232RTC RTC;
#include "menuSwitchCase.h"
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET A2
#define SCREEN_ADDRESS 0x3D
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define LOGO_HEIGHT 64
#define LOGO_WIDTH 64
static const unsigned char PROGMEM logo_bmp[] =
{ 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0f, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x01, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0x80, 0x03, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xfe, 0x03, 0xc0, 0x7f, 0xff, 0xfc, 0x3f, 0xfe, 0x00, 0x03, 0xc0, 0x00, 0x7f, 0xfc, 0x3f, 0xe0, 0x00, 0x03, 0xc0, 0x00, 0x07, 0xfc, 0x3f, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0xfc, 0x1c, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xfc, 0x00, 0x03, 0xc0, 0x00, 0x3f, 0xfe, 0x70, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xfc, 0x00, 0x03, 0xc0, 0x00, 0x3f, 0xfe, 0x70, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x0e
};
#define BATTERY A0
#define BUZZER 5
#define MOTOR 9
#define TOP_BUTTON 4
#define MID_BUTTON 3
#define BOT_BUTTON 2
const int SHORT_PRESS_TIME = 20;
const int LONG_PRESS_TIME = 250;
int topLastState = LOW;
int topCurrentState;
int midLastState = LOW;
int midCurrentState;
int botLastState = LOW;
int botCurrentState;
unsigned long pressedTime = 0;
unsigned long releasedTime = 0;
int menuIndex = 1;
unsigned long sleepTime = 4000;
unsigned long wokeTime = 0;
void beep(){
analogWrite(BUZZER, 220);
digitalWrite(MOTOR, HIGH);
delay(70);
analogWrite(BUZZER,LOW);
delay(70);
digitalWrite(MOTOR, LOW);
}
void eep() {
// turn display off
display.ssd1306_command(SSD1306_DISPLAYOFF);
// Disable the ADC
static byte prevADCSRA = ADCSRA;
ADCSRA = 0;
/* Set the type of sleep mode we want. Can be one of (in order of power saving): */
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_enable();
// Turn of Brown Out Detection (low voltage)
MCUCR = bit (BODS) | bit (BODSE);
// The BODS bit is automatically cleared after three clock cycles so we better get on with it
MCUCR = bit (BODS);
// Ensure we can wake up again by first disabling interupts (temporarily) so
// the wakeISR does not run before we are asleep and then prevent interrupts,
// and then defining the ISR (Interrupt Service Routine)
noInterrupts();
attachInterrupt(digitalPinToInterrupt(MID_BUTTON), sleepISR, HIGH);
// Send a message just to show we are about to sleep
Serial.println("Good night!");
Serial.flush();
// Allow interrupts now
interrupts();
// And enter sleep mode as set above
sleep_cpu();
// --------------------------------------------------------
// µController is now asleep until woken up by an interrupt
// --------------------------------------------------------
// Wakes up at this point when wakePin is brought LOW - interrupt routine is run first
Serial.println("I'm awake!");
// turn display on
display.ssd1306_command(SSD1306_DISPLAYON);
// Re-enable ADC if it was previously running
ADCSRA = prevADCSRA;
setSyncProvider(RTC.get);
}
void sleepISR() {
// Prevent sleep mode, so we don't enter it again, except deliberately, by code
sleep_disable();
// Detach the interrupt that brought us out of sleep
detachInterrupt(digitalPinToInterrupt(MID_BUTTON));
}
void setup() {
Serial.begin(9600);
analogReference(INTERNAL);
////////////////////// Initialize Clock ////////////////////////////
RTC.begin();
setSyncProvider(RTC.get); // the function to get the time from the RTC
////////////// initialize screen //////////////////
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
//////////////// Draw splash screen //////////////
display.clearDisplay();
display.drawBitmap( 0, (display.height() - LOGO_HEIGHT) / 2, logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(64, 5);
display.println("Fishwatch");
display.setCursor(64, 15);
display.setTextSize(2);
display.println("OS");
display.display();
delay(1200);
//////////////// assign pins ///////////////
pinMode(BATTERY,INPUT);
pinMode(BUZZER,OUTPUT);
pinMode(MOTOR,OUTPUT);
pinMode(TOP_BUTTON,INPUT);
pinMode(MID_BUTTON,INPUT);
pinMode(BOT_BUTTON,INPUT);
//////////////// Start sleep timer /////////////
wokeTime = millis();
}
void loop() {
///////////////////// draw the menu, based on the menu-index //////////////////////////
drawMenu();
///////////////////// See if screen has been on for more than the sleeptime variable, and sleep ////////////////////////////////
if (millis() > wokeTime + sleepTime){ // if its awake, and its been sleeptime milliseconds since it woke
wokeTime = millis();
eep();
}
/////////////////////////////////// read buttons //////////////////////////////////////////////
topCurrentState = digitalRead(TOP_BUTTON);
midCurrentState = digitalRead(MID_BUTTON);
botCurrentState = digitalRead(BOT_BUTTON);
if(topLastState == LOW && topCurrentState == HIGH) {
pressedTime = millis();
}
else if(topLastState == HIGH && topCurrentState == LOW) { // button is released
releasedTime = millis();
Serial.println("Let go of button");
long pressDuration = releasedTime - pressedTime;
if(pressDuration > LONG_PRESS_TIME ){}
else if( pressDuration > SHORT_PRESS_TIME ){}
}
topLastState = topCurrentState;
midLastState = midCurrentState;
botLastState = botCurrentState;
delay(5);
}