Use the state machines to control the finger

Fixes uint16_t comparisons with millis(), removes DoublePressed state
in button.h.
This commit is contained in:
Klemens Schölhorn 2017-11-17 18:01:23 +01:00 committed by Hannes Thalheim
parent 39fc93059d
commit 5c74902502
3 changed files with 99 additions and 63 deletions

View File

@ -1,78 +1,61 @@
#include "debounce.h" #include "debounce.h"
template<uint16_t SLEEP_TIMEOUT, uint16_t LONGPRESS_TIMEOUT, uint16_t DOUBLEPRESS_TIMEOUT>
class Button {
using DResult = Debounce<0>::Result; enum class ButtonEvent : uint8_t {
public:
enum class State : uint8_t {
Sleep,
Idle,
Pressed,
LongPressed,
Released,
DoublePressed,
};
enum class Result : uint8_t {
NoEvent, NoEvent,
Press, Press,
LongPress, LongPress,
DoublePress, DoublePress,
}; };
Result event(DResult result) { // template wird komplett wegoptimiert (wie #define)
template<uint16_t LONGPRESS_TIMEOUT, uint16_t DOUBLEPRESS_TIMEOUT>
class Button {
public:
enum class State : uint8_t {
Idle,
Pressed,
LongPressed,
Released,
};
ButtonEvent event(RawButtonEvent result) {
switch(state) { switch(state) {
case State::Sleep :
state = State::Idle;
counter = millis();
break;
case State::Idle : case State::Idle :
if(result == DResult::Pressed) { if(result == RawButtonEvent::Pressed) {
state = State::Pressed; state = State::Pressed;
counter = millis(); counter = millis();
} else if(millis() - counter >= SLEEP_TIMEOUT) {
state = State::Sleep;
// Activate Hardware sleep
} }
break; break;
case State::Pressed : case State::Pressed :
if(result == DResult::Released) { if(result == RawButtonEvent::Released) {
state = State::Released; state = State::Released;
counter = millis(); counter = millis();
} else if(millis() - counter >= LONGPRESS_TIMEOUT) { } else if((uint16_t) millis() - counter >= LONGPRESS_TIMEOUT) {
state = State::LongPressed; state = State::LongPressed;
return Result::LongPress; return ButtonEvent::LongPress;
} }
break; break;
case State::Released : case State::Released :
if(result == DResult::Pressed) { if(result == RawButtonEvent::Pressed) {
state = State::DoublePressed;
} else if(millis() - counter >= DOUBLEPRESS_TIMEOUT) {
state= State::Idle; state= State::Idle;
counter = millis(); return ButtonEvent::DoublePress;
return Result::Press; } else if((uint16_t) millis() - counter >= DOUBLEPRESS_TIMEOUT) {
state = State::Idle;
return ButtonEvent::Press;
} }
break; break;
case State::LongPressed : case State::LongPressed :
if(result == DResult::Released) { if(result == RawButtonEvent::Released) {
state = State::Idle; state = State::Idle;
counter = millis();
} else { } else {
return Result::LongPress; return ButtonEvent::LongPress;
}
break;
case State::DoublePressed :
if(result == DResult::Released) {
state = State::Idle;
counter = millis();
return Result::DoublePress;
} }
break; break;
} }
return Result::NoEvent; return ButtonEvent::NoEvent;
} }
private: private:

View File

@ -17,6 +17,11 @@ std::uniform_int_distribution<uint8_t> distribution(1,16);
SegmentDisplay<4, 2, 0> display; SegmentDisplay<4, 2, 0> display;
using MainButton = Button<150, 150>;
Debounce<20> debounce;
MainButton button;
#define NUM_SLOWDOWN 12 #define NUM_SLOWDOWN 12
const uint16_t PROGMEM SLOWDOWN[NUM_SLOWDOWN] = { const uint16_t PROGMEM SLOWDOWN[NUM_SLOWDOWN] = {
35, 32, 35, 32,
@ -37,19 +42,66 @@ void setup() {
display.write(); display.write();
} }
enum class State : uint8_t {
Idle,
Menu,
Counting,
Slowing
};
auto state = State::Idle;
uint16_t timeout;
void loop() { void loop() {
if(digitalRead(PIN1)) {
rng(); rng();
return;
bool buttonPressed = !digitalRead(PIN1);
auto event = button.event(debounce.event(buttonPressed));
switch(state) {
case State::Idle:
if(event == ButtonEvent::Press) {
state = State::Slowing;
} else if(event == ButtonEvent::LongPress) {
state = State::Counting;
timeout = millis();
} else if(event == ButtonEvent::DoublePress) {
state = State::Menu;
}
break;
case State::Menu:
// TODO
state = State::Idle;
break;
case State::Counting:
if(event == ButtonEvent::LongPress) {
// stay in this state
if((uint16_t) millis() - timeout >= 32) {
displayNextNumber();
timeout = millis();
}
} else {
state = State::Slowing;
}
break;
case State::Slowing:
slowdown();
state = State::Idle;
break;
}
} }
uint8_t num; static uint8_t currentNumber;
void displayNextNumber() {
currentNumber = distribution(rng);
display.set(currentNumber);
display.write();
}
void slowdown() {
for(size_t i = 0; i < NUM_SLOWDOWN; i += 2) { for(size_t i = 0; i < NUM_SLOWDOWN; i += 2) {
for(size_t j = 0; j < pgm_read_word_near(SLOWDOWN + i); ++j) { for(size_t j = 0; j < pgm_read_word_near(SLOWDOWN + i); ++j) {
num = distribution(rng); displayNextNumber();
display.set(num);
display.write();
delay(pgm_read_word_near(SLOWDOWN + i + 1)); delay(pgm_read_word_near(SLOWDOWN + i + 1));
} }
} }
@ -58,7 +110,7 @@ void loop() {
display.setOff(); display.setOff();
display.write(); display.write();
delay(250); delay(250);
display.set(num); display.set(currentNumber);
display.write(); display.write();
delay(250); delay(250);
} }

View File

@ -1,9 +1,15 @@
#ifndef _DEBOUNCE_H_ #ifndef _DEBOUNCE_H_
#define _DEBOUNCE_H_ #define _DEBOUNCE_H_
template<uint8_t DEBOUNCE_PRESSED, uint8_t DEBOUNCE_UNPRESSED = DEBOUNCE_PRESSED>
class Debounce {
enum class RawButtonEvent : uint8_t {
NoEvent,
Pressed,
Released,
};
template<uint16_t DEBOUNCE_PRESSED, uint16_t DEBOUNCE_UNPRESSED = DEBOUNCE_PRESSED>
class Debounce {
public: public:
enum class State : uint8_t { enum class State : uint8_t {
Unpressed, Unpressed,
@ -12,23 +18,18 @@ class Debounce {
PressedDebounced, PressedDebounced,
}; };
enum class Result : uint8_t {
NoEvent,
Pressed,
Released,
};
Result event(bool pressed) { RawButtonEvent event(bool pressed) {
switch(state) { switch(state) {
case State::Unpressed : case State::Unpressed :
if(pressed) { if(pressed) {
state = State::PressedDebounced; state = State::PressedDebounced;
counter = millis(); counter = millis();
return Result::Pressed; return RawButtonEvent::Pressed;
} }
break; break;
case State::PressedDebounced : case State::PressedDebounced :
if(millis() - counter > DEBOUNCE_PRESSED) { if((uint16_t) millis() - counter > DEBOUNCE_PRESSED) {
state = State::Pressed; state = State::Pressed;
} }
break; break;
@ -36,22 +37,22 @@ class Debounce {
if(!pressed) { if(!pressed) {
state = State::UnpressedDebounced; state = State::UnpressedDebounced;
counter = millis(); counter = millis();
return Result::Released; return RawButtonEvent::Released;
} }
break; break;
case State::UnpressedDebounced : case State::UnpressedDebounced :
if(millis() - counter > DEBOUNCE_UNPRESSED) { if((uint16_t) millis() - counter > DEBOUNCE_UNPRESSED) {
state = State::Unpressed; state = State::Unpressed;
} }
break; break;
} }
return Result::NoEvent; return RawButtonEvent::NoEvent;
} }
private: private:
State state = State::Unpressed; State state = State::Unpressed;
uint8_t counter = 0; uint16_t counter = 0;
}; };
#endif #endif