Fixed button handling in combination with sleep mode

Ready for prototype!
This commit is contained in:
Mark van Renswoude 2017-08-02 22:21:59 +02:00
parent 8332eb6b0f
commit ca9c4db52e
8 changed files with 108 additions and 62 deletions

View File

@ -1,6 +1,7 @@
#include "buttons.h" #include "buttons.h"
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include <util/atomic.h> #include <util/atomic.h>
#include <util/delay.h>
ButtonState buttonUp; ButtonState buttonUp;
@ -8,24 +9,26 @@ ButtonState buttonDown;
ButtonState buttonOption; ButtonState buttonOption;
void button_init(ButtonState* state) // Since it's a pull-up, the value is low when the button is pressed.
{ // This macro just helps make the code more readable.
(*state).flags = BSFLastReported; #define isPressed(state) (!state)
(*state).debounceTicks = 0;
(*state).repeatTicks = 0; #define hasFlag(flags, value) ((flags & value) != 0)
} #define setFlag(flags, value) flags |= (value)
#define clearFlag(flags, value) flags &= ~(value)
uint8_t inactivityTicks = 0;
void buttons_init() void buttons_init()
{ {
button_init(&buttonUp);
button_init(&buttonDown);
button_init(&buttonOption);
// Input with internal pull-up resistor // Input with internal pull-up resistor
DDRB &= ~BUTTON_ALL; DDRB &= ~BUTTON_ALL;
PORTB |= BUTTON_ALL; PORTB |= BUTTON_ALL;
buttons_reset();
// Mode 2: CTC // Mode 2: CTC
TCCR0A = _BV(WGM01); TCCR0A = _BV(WGM01);
@ -41,24 +44,40 @@ void buttons_init()
} }
void button_init(ButtonState* state, uint8_t readState)
{
(*state).flags = readState ? BSFLastReported : 0;
(*state).debounceTicks = 0;
(*state).repeatTicks = 0;
}
// Since it's a pull-up, the value is low when the button is pressed.
// This macro just helps make the code more readable.
#define isPressed(state) (!state)
#define flagSet(flags, value) ((flags & value) != 0) void buttons_reset()
#define setFlag(flags, value) flags |= (value) {
#define clearFlag(flags, value) flags &= ~(value) uint8_t pinState = PINB;
button_init(&buttonUp, hasFlag(pinState, _BV(BUTTON_UP)));
button_init(&buttonDown, hasFlag(pinState, _BV(BUTTON_DOWN)));
button_init(&buttonOption, hasFlag(pinState, _BV(BUTTON_OPTION)));
}
void button_check(ButtonState* state, uint8_t readState) uint8_t buttons_active()
{
return inactivityTicks <= DEBOUNCE_TIME;
}
uint8_t button_check(ButtonState* state, uint8_t readState)
{ {
#define stateRef (*state) #define stateRef (*state)
uint8_t lastState = flagSet(stateRef.flags, BSFLastReported); uint8_t lastState = hasFlag(stateRef.flags, BSFLastReported);
uint8_t newState = lastState; uint8_t newState = lastState;
// Debounce // Debounce
if (readState != lastState) if (readState != lastState)
{ {
@ -76,7 +95,7 @@ void button_check(ButtonState* state, uint8_t readState)
} }
else else
{ {
// State changed, reset debounce timer // State reverted, reset debounce timer
stateRef.debounceTicks = 0; stateRef.debounceTicks = 0;
} }
@ -91,7 +110,7 @@ void button_check(ButtonState* state, uint8_t readState)
setFlag(stateRef.flags, BSFPressed | BSFRepeatEnabled); setFlag(stateRef.flags, BSFPressed | BSFRepeatEnabled);
stateRef.repeatTicks = REPEAT_START; stateRef.repeatTicks = REPEAT_START;
} }
else if (flagSet(stateRef.flags, BSFRepeatEnabled)) else if (hasFlag(stateRef.flags, BSFRepeatEnabled))
{ {
// Held pressed // Held pressed
stateRef.repeatTicks--; stateRef.repeatTicks--;
@ -105,10 +124,12 @@ void button_check(ButtonState* state, uint8_t readState)
} }
else if (isPressed(lastState)) else if (isPressed(lastState))
{ {
// Released // Only trigger Released if Pressed is not yet removed by polling
setFlag(stateRef.flags, BSFReleased); if (hasFlag(stateRef.flags, BSFPressed))
setFlag(stateRef.flags, BSFReleased);
} }
return isPressed(newState) || (stateRef.debounceTicks > 0);
#undef stateRef #undef stateRef
} }
@ -118,10 +139,16 @@ void button_check(ButtonState* state, uint8_t readState)
ISR(TIMER0_COMPA_vect) ISR(TIMER0_COMPA_vect)
{ {
uint8_t pinState = PINB; uint8_t pinState = PINB;
uint8_t buttonActive;
button_check(&buttonUp, flagSet(pinState, _BV(BUTTON_UP))); buttonActive = button_check(&buttonUp, hasFlag(pinState, _BV(BUTTON_UP)));
button_check(&buttonDown, flagSet(pinState, _BV(BUTTON_DOWN))); buttonActive = button_check(&buttonDown, hasFlag(pinState, _BV(BUTTON_DOWN))) || buttonActive;
button_check(&buttonOption, flagSet(pinState, _BV(BUTTON_OPTION))); buttonActive = button_check(&buttonOption, hasFlag(pinState, _BV(BUTTON_OPTION))) || buttonActive;
if (buttonActive)
inactivityTicks = 0;
else if (inactivityTicks <= DEBOUNCE_TIME)
inactivityTicks++;
} }
@ -132,7 +159,7 @@ inline uint8_t readAndClearFlag(ButtonState* state, uint8_t flag)
ATOMIC_BLOCK(ATOMIC_FORCEON) ATOMIC_BLOCK(ATOMIC_FORCEON)
{ {
result = flagSet((*state).flags, flag); result = hasFlag((*state).flags, flag);
(*state).flags &= ~(flag); (*state).flags &= ~(flag);
} }
@ -162,17 +189,18 @@ uint8_t button_is_pressed_or_repeated(ButtonState* state)
} }
uint8_t button_is_released_short(ButtonState* state) uint8_t button_is_pressed_short(ButtonState* state)
{ {
uint8_t result; uint8_t result;
ATOMIC_BLOCK(ATOMIC_FORCEON) ATOMIC_BLOCK(ATOMIC_FORCEON)
{ {
result = flagSet((*state).flags, BSFReleased) && result = hasFlag((*state).flags, BSFPressed) &&
(!flagSet((*state).flags, BSFRepeated)); hasFlag((*state).flags, BSFReleased) &&
(!hasFlag((*state).flags, BSFRepeated));
if (result) if (result)
(*state).flags &= ~BSFReleased; (*state).flags &= ~(BSFPressed | BSFReleased);
} }
return result; return result;
@ -184,8 +212,8 @@ uint8_t button_is_pressed_long(ButtonState* state)
ATOMIC_BLOCK(ATOMIC_FORCEON) ATOMIC_BLOCK(ATOMIC_FORCEON)
{ {
result = flagSet((*state).flags, BSFPressed) && result = hasFlag((*state).flags, BSFPressed) &&
flagSet((*state).flags, BSFRepeated); hasFlag((*state).flags, BSFRepeated);
// Remove RepeatEnabled as well to prevent further repeat events // Remove RepeatEnabled as well to prevent further repeat events
if (result) if (result)

View File

@ -70,8 +70,11 @@ extern ButtonState buttonOption;
// every 200ms // every 200ms
#define REPEAT_NEXT 20 #define REPEAT_NEXT 20
extern void buttons_init(); extern void buttons_init();
extern void buttons_reset();
// Returns true if sleep should be prevented
extern uint8_t buttons_active();
// Note: these functions act on events, not on the current state. // Note: these functions act on events, not on the current state.
@ -84,7 +87,7 @@ extern uint8_t button_is_repeated(ButtonState* state);
extern uint8_t button_is_pressed_or_repeated(ButtonState* state); extern uint8_t button_is_pressed_or_repeated(ButtonState* state);
extern uint8_t button_is_released_short(ButtonState* state); extern uint8_t button_is_pressed_short(ButtonState* state);
extern uint8_t button_is_pressed_long(ButtonState* state); extern uint8_t button_is_pressed_long(ButtonState* state);
#endif #endif

View File

@ -1,4 +1,5 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <util/delay.h> #include <util/delay.h>
#include <ssd1306xled.h> #include <ssd1306xled.h>
#include "power.h" #include "power.h"
@ -29,7 +30,9 @@ int main()
if (powerState == On) if (powerState == On)
{ {
handleCurrentScreen(); handleCurrentScreen();
sleepUntilButton(_BV(BUTTON_UP) | _BV(BUTTON_DOWN) | _BV(BUTTON_OPTION));
if (!buttons_active())
sleepUntilButton(_BV(BUTTON_UP) | _BV(BUTTON_DOWN) | _BV(BUTTON_OPTION));
} }
} }
} }
@ -40,13 +43,11 @@ int main()
uint8_t handleGlobalInput() uint8_t handleGlobalInput()
{ {
if (button_is_released_short(&buttonOption)) if (button_is_pressed_short(&buttonOption))
{ {
// Toggle power // Turn off power to the screen
if (powerState == On) if (powerState == On)
setPowerState(ManualOff); setPowerState(ManualOff);
else if (powerState == ManualOff)
setPowerState(On);
return 1; return 1;
} }

View File

@ -3,6 +3,7 @@
#include <avr/io.h> #include <avr/io.h>
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include <avr/sleep.h> #include <avr/sleep.h>
#include <util/atomic.h>
#include <util/delay.h> #include <util/delay.h>
#include <ssd1306xled.h> #include <ssd1306xled.h>
@ -26,7 +27,6 @@
PowerState powerState = BatteryLow; PowerState powerState = BatteryLow;
uint16_t vcc = 0; uint16_t vcc = 0;
uint8_t screenInvalidated = 0;
// Forward declarations // Forward declarations
@ -66,6 +66,7 @@ void checkPower()
case ManualOff: case ManualOff:
sleepUntilButton(_BV(BUTTON_OPTION)); sleepUntilButton(_BV(BUTTON_OPTION));
setPowerState(On);
break; break;
} }
} }
@ -78,8 +79,8 @@ void setPowerState(PowerState newState)
switch (newState) switch (newState)
{ {
case On: case On:
buttons_reset();
ssd1306_send_command(SSD1306CommandOn); ssd1306_send_command(SSD1306CommandOn);
//buttons_init(); TODO this doesn't help, fix it!
break; break;
case BatteryLow: case BatteryLow:
@ -95,22 +96,7 @@ void setPowerState(PowerState newState)
} }
uint8_t getScreenInvalidated()
{
if (screenInvalidated)
{
screenInvalidated = 0;
return 1;
}
return 0;
}
void setScreenInvalidated()
{
screenInvalidated = 1;
}
// Source: http://21stdigitalhome.blogspot.nl/2014/10/trinket-attiny85-internal-temperature.html // Source: http://21stdigitalhome.blogspot.nl/2014/10/trinket-attiny85-internal-temperature.html
@ -152,7 +138,7 @@ uint16_t readVCC() {
} }
inline void sleepStart() static inline void sleepStart()
{ {
// Turn ADC off // Turn ADC off
ADCSRA &= ~_BV(ADEN); ADCSRA &= ~_BV(ADEN);
@ -168,7 +154,7 @@ inline void sleepStart()
} }
inline void sleepEnd() static inline void sleepEnd()
{ {
sleep_disable(); sleep_disable();
ADCSRA |= _BV(ADEN); ADCSRA |= _BV(ADEN);

View File

@ -27,8 +27,4 @@ extern void sleepUntilButton(uint8_t pinMask);
// 9 = 8 sec // 9 = 8 sec
extern void sleepUntilTimer(uint8_t interval); extern void sleepUntilTimer(uint8_t interval);
extern uint8_t getScreenInvalidated();
extern void setScreenInvalidated();
#endif #endif

View File

@ -1,6 +1,7 @@
#include "counter.h" #include "counter.h"
#include <stdint.h> #include <stdint.h>
#include <ssd1306xled.h> #include <ssd1306xled.h>
#include "state.h"
#include "../buttons.h" #include "../buttons.h"

22
Source/src/screen/state.c Normal file
View File

@ -0,0 +1,22 @@
#include "state.h"
uint8_t screenInvalidated = 0;
uint8_t getScreenInvalidated()
{
if (screenInvalidated)
{
screenInvalidated = 0;
return 1;
}
return 0;
}
void setScreenInvalidated()
{
screenInvalidated = 1;
}

View File

@ -0,0 +1,9 @@
#ifndef __ScreenState
#define __ScreenState
#include <stdint.h>
extern uint8_t getScreenInvalidated();
extern void setScreenInvalidated();
#endif