Implemented sleep modes

This commit is contained in:
Mark van Renswoude 2017-08-02 17:53:12 +02:00
parent 12d45b8760
commit 8332eb6b0f
5 changed files with 115 additions and 10 deletions

13
Source/TODO Normal file
View File

@ -0,0 +1,13 @@
- After turning off, turning on doesn't really respond well to the option button
- Store value in EEPROM (after a timeout)
- Long press shows menu with reset option (menu prevents accidental resets)
Pin-out reminder:
SW2 = - = pin 2, PB3
SW3 = menu = pin 3, PB4
SW1 = + = pin 6, PB1

View File

@ -37,7 +37,6 @@ void buttons_init()
// Enable timer interrupt
TIMSK = _BV(OCIE0A);
sei();
}

View File

@ -17,6 +17,7 @@ int main()
// Delay is required on power-on for the SSD1306 to initialize,
_delay_ms(40);
ssd1306_init();
ssd1306_clear();
buttons_init();
@ -28,6 +29,7 @@ int main()
if (powerState == On)
{
handleCurrentScreen();
sleepUntilButton(_BV(BUTTON_UP) | _BV(BUTTON_DOWN) | _BV(BUTTON_OPTION));
}
}
}

View File

@ -1,10 +1,19 @@
#include "power.h"
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include <ssd1306xled.h>
// I'm not really keen on referencing the buttons directly from here,
// feels like a coding red flag. It'll do for now until I come up with
// a better design. Or forget about it most likely.
#include "buttons.h"
#define VccOffTreshold 3000
#define VccOnTreshold 3100
@ -12,6 +21,7 @@
#define SSD1306CommandOff 0xAE
#define SSD1306CommandOn 0xAF
#define SleepInterval8s (_BV(WDP3) | _BV(WDP0))
PowerState powerState = BatteryLow;
@ -41,9 +51,7 @@ void checkPower()
if (vcc < VccOffTreshold)
{
setPowerState(BatteryLow);
// TODO go into a sleep cycle until the battery is recharged
_delay_ms(10);
sleepUntilTimer(SleepInterval8s);
}
break;
@ -52,16 +60,12 @@ void checkPower()
if (vcc > VccOnTreshold)
setPowerState(On);
else
{
// TODO continue sleep cycle
_delay_ms(10);
}
sleepUntilTimer(SleepInterval8s);
break;
case ManualOff:
// TODO go into sleep mode
_delay_ms(10);
sleepUntilButton(_BV(BUTTON_OPTION));
break;
}
}
@ -75,6 +79,7 @@ void setPowerState(PowerState newState)
{
case On:
ssd1306_send_command(SSD1306CommandOn);
//buttons_init(); TODO this doesn't help, fix it!
break;
case BatteryLow:
@ -144,4 +149,75 @@ uint16_t readVCC() {
ADCSRA &= ~(_BV(ADEN));
return result == 0 ? 0 : 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
}
inline void sleepStart()
{
// Turn ADC off
ADCSRA &= ~_BV(ADEN);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
// Set sleep bit and halt the CPU
sleep_enable();
sei();
sleep_cpu();
// ...goooood morning!
cli();
}
inline void sleepEnd()
{
sleep_disable();
ADCSRA |= _BV(ADEN);
sei();
}
void sleepUntilButton(uint8_t pinMask)
{
// Enable pin change interrupts
GIMSK |= _BV(PCIE);
// Set up pin change mask
PCMSK = pinMask;
sleepStart();
PCMSK = 0;
sleepEnd();
}
void sleepUntilTimer(uint8_t prescaler)
{
// Disable watchdog reset flag
MCUSR &= ~_BV(WDRF);
// Enable watchdog
WDTCR |= _BV(WDCE) | _BV(WDE);
// Set timeout value and enable interrupt mode
WDTCR = prescaler | _BV(WDIE);
sleepStart();
// Disable watchdog (need to write a logic one first, see datasheet)
WDTCR |= _BV(WDCE) | _BV(WDE);
WDTCR = 0;
sleepEnd();
}
// Interrupt for pin changes
ISR(PCINT0_vect)
{
}
// Interrupt for watchdog timer
ISR(WDT_vect)
{
}

View File

@ -13,6 +13,21 @@ extern uint16_t vcc;
extern void checkPower();
extern void setPowerState(PowerState newState);
extern void sleepUntilButton(uint8_t pinMask);
// 0 = 16 ms
// 1 = 32 ms
// 2 = 64 ms
// 3 = 128 ms
// 4 = 250 ms
// 5 = 500 ms
// 6 = 1 sec
// 7 = 2 sec
// 8 = 4 sec
// 9 = 8 sec
extern void sleepUntilTimer(uint8_t interval);
extern uint8_t getScreenInvalidated();
extern void setScreenInvalidated();