Add state machines for recognizing different button presses

For now single, double and long presses are supported.
This commit is contained in:
Klemens Schölhorn 2017-11-17 17:55:32 +01:00
parent 04d45ec03e
commit 39fc93059d
3 changed files with 133 additions and 6 deletions

81
code/button.h Normal file
View File

@ -0,0 +1,81 @@
#include "debounce.h"
template<uint16_t SLEEP_TIMEOUT, 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) {
switch(state) {
case State::Sleep :
state = State::Idle;
counter = millis();
break;
case State::Idle :
if(result == DResult::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) {
state = State::Released;
counter = millis();
} else if(millis() - counter >= LONGPRESS_TIMEOUT) {
state = State::LongPressed;
return Result::LongPress;
}
break;
case State::Released :
if(result == DResult::Pressed) {
state = State::DoublePressed;
} else if(millis() - counter >= DOUBLEPRESS_TIMEOUT) {
state = State::Idle;
counter = millis();
return Result::Press;
}
break;
case State::LongPressed :
if(result == DResult::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;
}
break;
}
return Result::NoEvent;
}
private:
State state = State::Idle;
uint16_t counter = 0;
};

View File

@ -2,6 +2,7 @@
#undef min
#undef max
#include "button.h"
#include "debounce.h"
#include "lcg_rng.h"
#include "segment.h"

View File

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