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:
parent
39fc93059d
commit
5c74902502
@ -1,78 +1,61 @@
|
||||
#include "debounce.h"
|
||||
|
||||
template<uint16_t SLEEP_TIMEOUT, uint16_t LONGPRESS_TIMEOUT, uint16_t DOUBLEPRESS_TIMEOUT>
|
||||
|
||||
enum class ButtonEvent : uint8_t {
|
||||
NoEvent,
|
||||
Press,
|
||||
LongPress,
|
||||
DoublePress,
|
||||
};
|
||||
|
||||
// template wird komplett wegoptimiert (wie #define)
|
||||
template<uint16_t LONGPRESS_TIMEOUT, uint16_t DOUBLEPRESS_TIMEOUT>
|
||||
class Button {
|
||||
|
||||
using DResult = Debounce<0>::Result;
|
||||
|
||||
public:
|
||||
enum class State : uint8_t {
|
||||
Sleep,
|
||||
Idle,
|
||||
Pressed,
|
||||
LongPressed,
|
||||
Released,
|
||||
DoublePressed,
|
||||
};
|
||||
|
||||
enum class Result : uint8_t {
|
||||
NoEvent,
|
||||
Press,
|
||||
LongPress,
|
||||
DoublePress,
|
||||
};
|
||||
|
||||
Result event(DResult result) {
|
||||
ButtonEvent event(RawButtonEvent result) {
|
||||
switch(state) {
|
||||
case State::Sleep :
|
||||
state = State::Idle;
|
||||
counter = millis();
|
||||
break;
|
||||
case State::Idle :
|
||||
if(result == DResult::Pressed) {
|
||||
if(result == RawButtonEvent::Pressed) {
|
||||
state = State::Pressed;
|
||||
counter = millis();
|
||||
} else if(millis() - counter >= SLEEP_TIMEOUT) {
|
||||
state = State::Sleep;
|
||||
// Activate Hardware sleep
|
||||
}
|
||||
break;
|
||||
case State::Pressed :
|
||||
if(result == DResult::Released) {
|
||||
if(result == RawButtonEvent::Released) {
|
||||
state = State::Released;
|
||||
counter = millis();
|
||||
} else if(millis() - counter >= LONGPRESS_TIMEOUT) {
|
||||
} else if((uint16_t) millis() - counter >= LONGPRESS_TIMEOUT) {
|
||||
state = State::LongPressed;
|
||||
return Result::LongPress;
|
||||
return ButtonEvent::LongPress;
|
||||
}
|
||||
break;
|
||||
case State::Released :
|
||||
if(result == DResult::Pressed) {
|
||||
state = State::DoublePressed;
|
||||
} else if(millis() - counter >= DOUBLEPRESS_TIMEOUT) {
|
||||
if(result == RawButtonEvent::Pressed) {
|
||||
state= State::Idle;
|
||||
return ButtonEvent::DoublePress;
|
||||
} else if((uint16_t) millis() - counter >= DOUBLEPRESS_TIMEOUT) {
|
||||
state = State::Idle;
|
||||
counter = millis();
|
||||
return Result::Press;
|
||||
return ButtonEvent::Press;
|
||||
}
|
||||
break;
|
||||
case State::LongPressed :
|
||||
if(result == DResult::Released) {
|
||||
if(result == RawButtonEvent::Released) {
|
||||
state = State::Idle;
|
||||
counter = millis();
|
||||
} else {
|
||||
return Result::LongPress;
|
||||
}
|
||||
break;
|
||||
case State::DoublePressed :
|
||||
if(result == DResult::Released) {
|
||||
state = State::Idle;
|
||||
counter = millis();
|
||||
return Result::DoublePress;
|
||||
return ButtonEvent::LongPress;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return Result::NoEvent;
|
||||
return ButtonEvent::NoEvent;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -17,6 +17,11 @@ std::uniform_int_distribution<uint8_t> distribution(1,16);
|
||||
|
||||
SegmentDisplay<4, 2, 0> display;
|
||||
|
||||
using MainButton = Button<150, 150>;
|
||||
|
||||
Debounce<20> debounce;
|
||||
MainButton button;
|
||||
|
||||
#define NUM_SLOWDOWN 12
|
||||
const uint16_t PROGMEM SLOWDOWN[NUM_SLOWDOWN] = {
|
||||
35, 32,
|
||||
@ -37,19 +42,66 @@ void setup() {
|
||||
display.write();
|
||||
}
|
||||
|
||||
enum class State : uint8_t {
|
||||
Idle,
|
||||
Menu,
|
||||
Counting,
|
||||
Slowing
|
||||
};
|
||||
|
||||
auto state = State::Idle;
|
||||
uint16_t timeout;
|
||||
|
||||
void loop() {
|
||||
if(digitalRead(PIN1)) {
|
||||
rng();
|
||||
return;
|
||||
rng();
|
||||
|
||||
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 j = 0; j < pgm_read_word_near(SLOWDOWN + i); ++j) {
|
||||
num = distribution(rng);
|
||||
display.set(num);
|
||||
display.write();
|
||||
displayNextNumber();
|
||||
delay(pgm_read_word_near(SLOWDOWN + i + 1));
|
||||
}
|
||||
}
|
||||
@ -58,7 +110,7 @@ void loop() {
|
||||
display.setOff();
|
||||
display.write();
|
||||
delay(250);
|
||||
display.set(num);
|
||||
display.set(currentNumber);
|
||||
display.write();
|
||||
delay(250);
|
||||
}
|
||||
|
@ -1,9 +1,15 @@
|
||||
#ifndef _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:
|
||||
enum class State : uint8_t {
|
||||
Unpressed,
|
||||
@ -12,23 +18,18 @@ class Debounce {
|
||||
PressedDebounced,
|
||||
};
|
||||
|
||||
enum class Result : uint8_t {
|
||||
NoEvent,
|
||||
Pressed,
|
||||
Released,
|
||||
};
|
||||
|
||||
Result event(bool pressed) {
|
||||
RawButtonEvent event(bool pressed) {
|
||||
switch(state) {
|
||||
case State::Unpressed :
|
||||
if(pressed) {
|
||||
state = State::PressedDebounced;
|
||||
counter = millis();
|
||||
return Result::Pressed;
|
||||
return RawButtonEvent::Pressed;
|
||||
}
|
||||
break;
|
||||
case State::PressedDebounced :
|
||||
if(millis() - counter > DEBOUNCE_PRESSED) {
|
||||
if((uint16_t) millis() - counter > DEBOUNCE_PRESSED) {
|
||||
state = State::Pressed;
|
||||
}
|
||||
break;
|
||||
@ -36,22 +37,22 @@ class Debounce {
|
||||
if(!pressed) {
|
||||
state = State::UnpressedDebounced;
|
||||
counter = millis();
|
||||
return Result::Released;
|
||||
return RawButtonEvent::Released;
|
||||
}
|
||||
break;
|
||||
case State::UnpressedDebounced :
|
||||
if(millis() - counter > DEBOUNCE_UNPRESSED) {
|
||||
if((uint16_t) millis() - counter > DEBOUNCE_UNPRESSED) {
|
||||
state = State::Unpressed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return Result::NoEvent;
|
||||
return RawButtonEvent::NoEvent;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
State state = State::Unpressed;
|
||||
uint8_t counter = 0;
|
||||
uint16_t counter = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user