Add state machines for recognizing different button presses
For now single, double and long presses are supported.
This commit is contained in:
parent
04d45ec03e
commit
39fc93059d
81
code/button.h
Normal file
81
code/button.h
Normal 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;
|
||||||
|
};
|
@ -2,6 +2,7 @@
|
|||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
|
|
||||||
|
#include "button.h"
|
||||||
#include "debounce.h"
|
#include "debounce.h"
|
||||||
#include "lcg_rng.h"
|
#include "lcg_rng.h"
|
||||||
#include "segment.h"
|
#include "segment.h"
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
#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 {
|
enum class State : uint8_t {
|
||||||
Unpressed,
|
Unpressed,
|
||||||
UnpressedDebounced,
|
UnpressedDebounced,
|
||||||
@ -5,8 +12,46 @@ enum class State : uint8_t {
|
|||||||
PressedDebounced,
|
PressedDebounced,
|
||||||
};
|
};
|
||||||
|
|
||||||
template<uint8_t DEBOUNCE_PRESSED, uint8_t DEBOUNCE_UNPRESSED = DEBOUNCE_PRESSED>
|
enum class Result : uint8_t {
|
||||||
class Debounce {
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user