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"
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:

View File

@ -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);
}

View File

@ -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