From 39fc93059df52736aeed7c00e8494b89b72aa064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemens=20Sch=C3=B6lhorn?= Date: Fri, 17 Nov 2017 17:55:32 +0100 Subject: [PATCH] Add state machines for recognizing different button presses For now single, double and long presses are supported. --- code/button.h | 81 +++++++++++++++++++++++++++++++++++++++++++++++++ code/code.ino | 1 + code/debounce.h | 57 ++++++++++++++++++++++++++++++---- 3 files changed, 133 insertions(+), 6 deletions(-) create mode 100644 code/button.h diff --git a/code/button.h b/code/button.h new file mode 100644 index 0000000..f942b8d --- /dev/null +++ b/code/button.h @@ -0,0 +1,81 @@ +#include "debounce.h" + +template +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; +}; diff --git a/code/code.ino b/code/code.ino index 2eaef84..28f58cd 100644 --- a/code/code.ino +++ b/code/code.ino @@ -2,6 +2,7 @@ #undef min #undef max +#include "button.h" #include "debounce.h" #include "lcg_rng.h" #include "segment.h" diff --git a/code/debounce.h b/code/debounce.h index 857860f..9209327 100644 --- a/code/debounce.h +++ b/code/debounce.h @@ -1,12 +1,57 @@ -enum class State : uint8_t { - Unpressed, - UnpressedDebounced, - Pressed, - PressedDebounced, -}; +#ifndef _DEBOUNCE_H_ +#define _DEBOUNCE_H_ template 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