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:
		| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user