From 625b9a3b21572d553e2754ac58618b54b5578da2 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 18 Feb 2016 23:29:19 -0500 Subject: [PATCH 01/34] Fix race condition causing lost events If the ISR set the state of button after ret was set but before button was set to open, the event was lost --- ClickEncoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index 4ca135b..ba78641 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -213,7 +213,7 @@ int16_t ClickEncoder::getValue(void) ClickEncoder::Button ClickEncoder::getButton(void) { ClickEncoder::Button ret = button; - if (button != ClickEncoder::Held) { + if (button != ClickEncoder::Held && ret != ClickEncoder::Open) { button = ClickEncoder::Open; // reset } return ret; From 97dd97e25c474e44693c7d490d984221a07c1636 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 18 Feb 2016 23:34:34 -0500 Subject: [PATCH 02/34] Fix bug when double click disabled doubleClickTicks was being decremented twice, which caused things to not work right when double clicks were disabled. --- ClickEncoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index ba78641..22ff5d9 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -167,7 +167,7 @@ void ClickEncoder::service(void) if (doubleClickTicks > 0) { doubleClickTicks--; - if (--doubleClickTicks == 0) { + if (doubleClickTicks == 0) { button = Clicked; } } From 383127484c8b4e17924450dde94cb7c838405920 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 18 Feb 2016 23:45:26 -0500 Subject: [PATCH 03/34] accelerationEnabled Moved definition so compile works when WITHOUT_BUTTON is defined. this is a duplicate of AndyHunti's change --- ClickEncoder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ClickEncoder.h b/ClickEncoder.h index 73f9f41..8148579 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -103,13 +103,13 @@ class ClickEncoder volatile int16_t last; uint8_t steps; volatile uint16_t acceleration; + bool accelerationEnabled; #if ENC_DECODER != ENC_NORMAL static const int8_t table[16]; #endif #ifndef WITHOUT_BUTTON volatile Button button; bool doubleClickEnabled; - bool accelerationEnabled; #endif }; From e08e7fa5ad33bf6b02b55eb3f8e7628334e11a55 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 18 Feb 2016 23:55:43 -0500 Subject: [PATCH 04/34] Added method to enable/disable the button hold/release events defaults to enabled. controlled with setButtonHeldEnabled --- ClickEncoder.cpp | 4 ++-- ClickEncoder.h | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index 22ff5d9..63f4b6a 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -44,7 +44,7 @@ // ---------------------------------------------------------------------------- ClickEncoder::ClickEncoder(uint8_t A, uint8_t B, uint8_t BTN, uint8_t stepsPerNotch, bool active) - : doubleClickEnabled(true), accelerationEnabled(true), + : doubleClickEnabled(true),buttonHeldEnabled(true), accelerationEnabled(true), delta(0), last(0), acceleration(0), button(Open), steps(stepsPerNotch), pinA(A), pinB(B), pinBTN(BTN), pinsActive(active) @@ -137,7 +137,7 @@ void ClickEncoder::service(void) if (digitalRead(pinBTN) == pinsActive) { // key is down keyDownTicks++; - if (keyDownTicks > (ENC_HOLDTIME / ENC_BUTTONINTERVAL)) { + if ((keyDownTicks > (ENC_HOLDTIME / ENC_BUTTONINTERVAL)) && (buttonHeldEnabled)) { button = Held; } } diff --git a/ClickEncoder.h b/ClickEncoder.h index 8148579..364231a 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -78,6 +78,17 @@ class ClickEncoder { return doubleClickEnabled; } + +public: + void setButtonHeldEnabled(const bool &d) + { + buttonHeldEnabled = d; + } + + const bool getButtonHeldEnabled() + { + return buttonHeldEnabled; + } #endif public: @@ -110,6 +121,7 @@ class ClickEncoder #ifndef WITHOUT_BUTTON volatile Button button; bool doubleClickEnabled; + bool buttonHeldEnabled; #endif }; From 9937dd4cecc68f816b5e1634d7ffad95827ab6d5 Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 19 Feb 2016 00:01:06 -0500 Subject: [PATCH 05/34] Adjusted double click time after fixing the double decrement on doubleClickTicks, things felt sluggish, so reduced ENC_DOUBLECLICKTIME to 400 --- ClickEncoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index 63f4b6a..71da077 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -15,7 +15,7 @@ // Button configuration (values for 1ms timer service calls) // #define ENC_BUTTONINTERVAL 10 // check button every x milliseconds, also debouce time -#define ENC_DOUBLECLICKTIME 600 // second click within 600ms +#define ENC_DOUBLECLICKTIME 400 // second click within 600ms #define ENC_HOLDTIME 1200 // report held button after 1.2s // ---------------------------------------------------------------------------- From 9798ec899a0c68e620d5cb9892f3922991550abb Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 19 Feb 2016 00:11:34 -0500 Subject: [PATCH 06/34] Allow multiple instances of object to co-exist Moved static variables to be private variables instead so that each instance of the object has it's own copy. --- ClickEncoder.cpp | 3 --- ClickEncoder.h | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index 71da077..67554f2 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -126,9 +126,6 @@ void ClickEncoder::service(void) // handle button // #ifndef WITHOUT_BUTTON - static uint16_t keyDownTicks = 0; - static uint8_t doubleClickTicks = 0; - static unsigned long lastButtonCheck = 0; if (pinBTN > 0 // check button only, if a pin has been provided && (now - lastButtonCheck) >= ENC_BUTTONINTERVAL) // checking button is sufficient every 10-30ms diff --git a/ClickEncoder.h b/ClickEncoder.h index 364231a..d76b501 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -122,6 +122,9 @@ class ClickEncoder volatile Button button; bool doubleClickEnabled; bool buttonHeldEnabled; + uint16_t keyDownTicks = 0; + uint8_t doubleClickTicks = 0; + unsigned long lastButtonCheck = 0; #endif }; From 5b63c464fa58cdaaf4bb088eee20edfe9c6d3a69 Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 19 Feb 2016 16:54:30 -0500 Subject: [PATCH 07/34] Fixed "FLAKY" mode The table lookup method was not working because the tbl variable was not signed. Also HALFSET was always used because the #ifndef needs to be #if --- ClickEncoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index 67554f2..14e050a 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -28,7 +28,7 @@ // ---------------------------------------------------------------------------- #if ENC_DECODER != ENC_NORMAL -# ifdef ENC_HALFSTEP +# if ENC_HALFSTEP // decoding table for hardware with flaky notch (half resolution) const int8_t ClickEncoder::table[16] __attribute__((__progmem__)) = { 0, 0, -1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, 0, 0 @@ -89,7 +89,7 @@ void ClickEncoder::service(void) last |= 1; } - uint8_t tbl = pgm_read_byte(&table[last]); + int8_t tbl = pgm_read_byte(&table[last]); if (tbl) { delta += tbl; moved = true; From 3546f7a593c8a658abaa76aefd00fcbf51807664 Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 19 Feb 2016 17:13:07 -0500 Subject: [PATCH 08/34] Added ability to use button without encoder and allow pin 0 to be used Added new constructor for button only initialization. Changes all pin definitions to int8_t so a negative pin number will disable the button operation, or also the encoder operation. There was a previously an issue with the default button pin being -1, but stored unsigned was pin 255, so the button logic was running unless you explicitly specified pin 0 - this caused pin 0 to be unusable for a button. Note that if you previously specified pin 0 in your sketch to disable the button operation, then this should be changed to -1 --- ClickEncoder.cpp | 29 +++++++++++++++++++++++------ ClickEncoder.h | 12 ++++++++---- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index 14e050a..bdd78ac 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -43,16 +43,18 @@ // ---------------------------------------------------------------------------- -ClickEncoder::ClickEncoder(uint8_t A, uint8_t B, uint8_t BTN, uint8_t stepsPerNotch, bool active) +ClickEncoder::ClickEncoder(int8_t A, int8_t B, int8_t BTN, uint8_t stepsPerNotch, bool active) : doubleClickEnabled(true),buttonHeldEnabled(true), accelerationEnabled(true), delta(0), last(0), acceleration(0), button(Open), steps(stepsPerNotch), pinA(A), pinB(B), pinBTN(BTN), pinsActive(active) { uint8_t configType = (pinsActive == LOW) ? INPUT_PULLUP : INPUT; - pinMode(pinA, configType); - pinMode(pinB, configType); - pinMode(pinBTN, configType); + if (pinA >= 0) {pinMode(pinA, configType);} + if (pinB >= 0) {pinMode(pinB, configType);} +#ifndef WITHOUT_BUTTON + if (pinBTN >= 0) {pinMode(pinBTN, configType);} +#endif if (digitalRead(pinA) == pinsActive) { last = 3; @@ -63,6 +65,20 @@ ClickEncoder::ClickEncoder(uint8_t A, uint8_t B, uint8_t BTN, uint8_t stepsPerNo } } +// ---------------------------------------------------------------------------- +#ifndef WITHOUT_BUTTON + +ClickEncoder::ClickEncoder(int8_t BTN, bool active) + : doubleClickEnabled(true),buttonHeldEnabled(true), accelerationEnabled(true), + delta(0), last(0), acceleration(0), + button(Open), steps(1), + pinA(-1), pinB(-1), pinBTN(BTN), pinsActive(active) +{ + uint8_t configType = (pinsActive == LOW) ? INPUT_PULLUP : INPUT; + if (pinBTN >= 0) {pinMode(pinBTN, configType);} +} +#endif + // ---------------------------------------------------------------------------- // call this every 1 millisecond via timer ISR // @@ -71,6 +87,7 @@ void ClickEncoder::service(void) bool moved = false; unsigned long now = millis(); + if (pinA >= 0 && pinA >= 0) { if (accelerationEnabled) { // decelerate every tick acceleration -= ENC_ACCEL_DEC; if (acceleration & 0x8000) { // handle overflow of MSB is set @@ -122,12 +139,12 @@ void ClickEncoder::service(void) acceleration += ENC_ACCEL_INC; } } - +} // handle button // #ifndef WITHOUT_BUTTON - if (pinBTN > 0 // check button only, if a pin has been provided + if (pinBTN >= 0 // check button only, if a pin has been provided && (now - lastButtonCheck) >= ENC_BUTTONINTERVAL) // checking button is sufficient every 10-30ms { lastButtonCheck = now; diff --git a/ClickEncoder.h b/ClickEncoder.h index d76b501..392cb5a 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -56,8 +56,12 @@ class ClickEncoder } Button; public: - ClickEncoder(uint8_t A, uint8_t B, uint8_t BTN = -1, + ClickEncoder(int8_t A, int8_t B, int8_t BTN = -1, uint8_t stepsPerNotch = 1, bool active = LOW); + +#ifndef WITHOUT_BUTTON + explicit ClickEncoder(int8_t BTN, bool active = LOW); +#endif void service(void); int16_t getValue(void); @@ -106,9 +110,9 @@ class ClickEncoder } private: - const uint8_t pinA; - const uint8_t pinB; - const uint8_t pinBTN; + const int8_t pinA; + const int8_t pinB; + const int8_t pinBTN; const bool pinsActive; volatile int16_t delta; volatile int16_t last; From 14e66077587f3a673d1a1b81dcf3aa7b3f5082f5 Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 19 Feb 2016 17:29:54 -0500 Subject: [PATCH 09/34] Added example showing how to use 2 devices simultaneously Also shows the new button-only constructor and disabling hold/release and double click --- examples/TwoDevices/TwoDevices.ino | 77 ++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 examples/TwoDevices/TwoDevices.ino diff --git a/examples/TwoDevices/TwoDevices.ino b/examples/TwoDevices/TwoDevices.ino new file mode 100644 index 0000000..837a06b --- /dev/null +++ b/examples/TwoDevices/TwoDevices.ino @@ -0,0 +1,77 @@ +/* + +This example demonstrates the use of 2 devices controlled by the ClickEncoder library + +In thie example, the 2 devides are a rotary encoder with built in button, and a normal momentary button + + */ +#include +#include + +#define ENCODER_PINA 5 // If the encoder moved in the wrong direction, swap PINA and PINB +#define ENCODER_PINB 6 +#define ENCODER_BTN 7 + +#define ENCODER_STEPS_PER_NOTCH 4 // Change this depending on which encoder is used + +#define EXTRA_BUTTON_PIN 8 + +ClickEncoder button = ClickEncoder(EXTRA_BUTTON_PIN); +ClickEncoder encoder = ClickEncoder(ENCODER_PINA,ENCODER_PINB,ENCODER_BTN,ENCODER_STEPS_PER_NOTCH); + +void timerIsr() { //Service methods from both instances must be included + encoder.service(); + button.service(); +} + +void setup() { + Serial.begin(115200); + + Timer1.initialize(1000); + Timer1.attachInterrupt(timerIsr); + + encoder.setButtonHeldEnabled(false); + encoder.setDoubleClickEnabled(true); + + button.setButtonHeldEnabled(true); + button.setDoubleClickEnabled(false); + +} + +void loop() { +static int16_t last, value; + value += encoder.getValue(); + + if (value != last) { + last = value; + Serial.print("Encoder Value: "); + Serial.println(value); + + } + + ClickEncoder::Button b = encoder.getButton(); + if (b != ClickEncoder::Open) { + Serial.print("Button: "); + #define VERBOSECASE(label) case label: Serial.println(#label); break; + switch (b) { + VERBOSECASE(ClickEncoder::Pressed); + VERBOSECASE(ClickEncoder::Held) + VERBOSECASE(ClickEncoder::Released) + VERBOSECASE(ClickEncoder::Clicked) + VERBOSECASE(ClickEncoder::DoubleClicked) + } + } + + ClickEncoder::Button b2 = button.getButton(); + if (b2 != ClickEncoder::Open) { + Serial.print("Button2: "); + #define VERBOSECASE(label) case label: Serial.println(#label); break; + switch (b2) { + VERBOSECASE(ClickEncoder::Pressed); + VERBOSECASE(ClickEncoder::Held) + VERBOSECASE(ClickEncoder::Released) + VERBOSECASE(ClickEncoder::Clicked) + VERBOSECASE(ClickEncoder::DoubleClicked) + } + } +} From f60058c8fb479b928e2f6ef480e0f1fd3c55fcb2 Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 19 Feb 2016 20:22:32 -0500 Subject: [PATCH 10/34] Restored original behavior for button on pin 0, but can now optionally enable pin 0 To maintain backward compatibility, buttons by default wont work on pin 0, however setButtonOnPinZeroEnabled(true) can be used if a button is desired on pin zero. Recommendation is to use pin -1 to disable button logic rather than pin 0 --- ClickEncoder.cpp | 4 ++-- ClickEncoder.h | 12 ++++++++++++ examples/TwoDevices/TwoDevices.ino | 6 ++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index bdd78ac..55ffde3 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -144,8 +144,8 @@ void ClickEncoder::service(void) // #ifndef WITHOUT_BUTTON - if (pinBTN >= 0 // check button only, if a pin has been provided - && (now - lastButtonCheck) >= ENC_BUTTONINTERVAL) // checking button is sufficient every 10-30ms + if ((pinBTN > 0 || (pinBTN == 0 && buttonOnPinZeroEnabled)) // check button only, if a pin has been provided + && (now - lastButtonCheck) >= ENC_BUTTONINTERVAL) // checking button is sufficient every 10-30ms { lastButtonCheck = now; diff --git a/ClickEncoder.h b/ClickEncoder.h index 392cb5a..0904044 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -93,6 +93,17 @@ class ClickEncoder { return buttonHeldEnabled; } + +public: + void setButtonOnPinZeroEnabled(const bool &d) + { + buttonOnPinZeroEnabled = d; + } + + const bool getButtonOnPinZeroEnabled() + { + return buttonOnPinZeroEnabled; + } #endif public: @@ -126,6 +137,7 @@ class ClickEncoder volatile Button button; bool doubleClickEnabled; bool buttonHeldEnabled; + bool buttonOnPinZeroEnabled = false; uint16_t keyDownTicks = 0; uint8_t doubleClickTicks = 0; unsigned long lastButtonCheck = 0; diff --git a/examples/TwoDevices/TwoDevices.ino b/examples/TwoDevices/TwoDevices.ino index 837a06b..4488f71 100644 --- a/examples/TwoDevices/TwoDevices.ino +++ b/examples/TwoDevices/TwoDevices.ino @@ -35,6 +35,12 @@ void setup() { button.setButtonHeldEnabled(true); button.setDoubleClickEnabled(false); + + // Enable the button to be on pin 0. Normally pin 0 is not recognized as a valid pin for a button, + // this is to maintain backward compatibility with an old version of the library + // This version can have the button on pin zero, and this call enables the feature. + // in this version best to use pin -1 instead of 0 to disable button functions + encoder.setButtonOnPinZeroEnabled(false); } From d9e6f8ab3f54aae578aa1034737afd214f671ce8 Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 19 Feb 2016 20:24:11 -0500 Subject: [PATCH 11/34] Added support for ESP8266 and example Added condition to include of AVR libraries --- ClickEncoder.h | 2 + examples/ESP8266Example/ESP8266Example.ino | 66 ++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 examples/ESP8266Example/ESP8266Example.ino diff --git a/ClickEncoder.h b/ClickEncoder.h index 0904044..e637d2a 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -15,9 +15,11 @@ // ---------------------------------------------------------------------------- #include +#ifndef ARDUINO_ARCH_ESP8266 #include #include #include +#endif #include "Arduino.h" // ---------------------------------------------------------------------------- diff --git a/examples/ESP8266Example/ESP8266Example.ino b/examples/ESP8266Example/ESP8266Example.ino new file mode 100644 index 0000000..363e460 --- /dev/null +++ b/examples/ESP8266Example/ESP8266Example.ino @@ -0,0 +1,66 @@ +/* + +This example demonstrates the use of the library on an ESP8266. without using a timer interrupt + + */ + +#include +//#include + + +#define ENCODER_PINA 13 +#define ENCODER_PINB 14 +#define ENCODER_BTN 0 + +#define ENCODER_STEPS_PER_NOTCH 4 // Change this depending on which encoder is used + +ClickEncoder encoder = ClickEncoder(ENCODER_PINA,ENCODER_PINB,ENCODER_BTN,ENCODER_STEPS_PER_NOTCH); + +void setup() { + Serial.begin(115200); + + encoder.setButtonHeldEnabled(true); + encoder.setDoubleClickEnabled(true); + + // Enable the button to be on pin 0. Normally pin 0 is not recognized as a valid pin for a button, + // this is to maintain backward compatibility with an old version of the library + // This version can have the button on pin zero, and this call enables the feature. + // in this version best to use pin -1 instead of 0 to disable button functions + encoder.setButtonOnPinZeroEnabled(true); + +} + +void loop() { + + //Call Service in loop becasue using timer interrupts may affect ESP8266 WIFI + //however call no more than 1 time per millisecond to reduce encoder bounce + static uint32_t lastService = 0; + if (lastService + 1000 < micros()) { + lastService = micros(); + encoder.service(); + } + + +static int16_t last, value; + value += encoder.getValue(); + + if (value != last) { + last = value; + Serial.print("Encoder Value: "); + Serial.println(value); + + } + + ClickEncoder::Button b = encoder.getButton(); + if (b != ClickEncoder::Open) { + Serial.print("Button: "); + #define VERBOSECASE(label) case label: Serial.println(#label); break; + switch (b) { + VERBOSECASE(ClickEncoder::Pressed); + VERBOSECASE(ClickEncoder::Held) + VERBOSECASE(ClickEncoder::Released) + VERBOSECASE(ClickEncoder::Clicked) + VERBOSECASE(ClickEncoder::DoubleClicked) + } + } +} From 97fd7e51318abcddc5cccebec170944b6f1afba7 Mon Sep 17 00:00:00 2001 From: Dennis Date: Sun, 20 Mar 2016 09:47:50 -0400 Subject: [PATCH 12/34] Filter out transient events on the button Button must stay down at least 1 full tick to register. This filters out out transient spikes that registered as clicks. This problem is likely due to a dodgy button and/or case vibration, but having this software fix does not affect normal operation. --- ClickEncoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index 55ffde3..238fe63 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -157,7 +157,7 @@ void ClickEncoder::service(void) } if (digitalRead(pinBTN) == !pinsActive) { // key is now up - if (keyDownTicks /*> ENC_BUTTONINTERVAL*/) { + if (keyDownTicks > 1) { //Make sure key was down through 1 complete tick to prevent random transients from registering as click if (button == Held) { button = Released; doubleClickTicks = 0; From 4124fc6a5e5ec921d8252eac547dd693446159e2 Mon Sep 17 00:00:00 2001 From: Valerii Koval Date: Wed, 4 May 2016 10:56:19 +0300 Subject: [PATCH 13/34] @PlatformIO Library Registry manifest file --- library.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 library.json diff --git a/library.json b/library.json new file mode 100644 index 0000000..af03521 --- /dev/null +++ b/library.json @@ -0,0 +1,17 @@ +{ + "name": "ClickEncoder", + "keywords": "encoder, button, input", + "description": "Arduino library to handle rotary encoders with buttons as a user input device", + "repository": + { + "type": "git", + "url": "https://github.com/soligen2010/encoder.git" + }, + "frameworks": "arduino", + "platforms": [ + "atmelavr", + "atmelsam", + "teensy", + "espressif" + ] +} From 2ad751fd44df33bd80a65d328579c1b655851f2c Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 23 Jun 2016 07:07:51 -0400 Subject: [PATCH 14/34] Change conditional on AVR included Changed #IF to positive logic to include only if AVR --- ClickEncoder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ClickEncoder.h b/ClickEncoder.h index e637d2a..26924d2 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -15,7 +15,7 @@ // ---------------------------------------------------------------------------- #include -#ifndef ARDUINO_ARCH_ESP8266 +#if defined(__AVR__) #include #include #include From c471bc1f9c3c6ab676e84800a511925efc23348e Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 24 Jun 2016 19:15:10 -0400 Subject: [PATCH 15/34] Revert "Change conditional on AVR included" This reverts commit 2ad751fd44df33bd80a65d328579c1b655851f2c. --- ClickEncoder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ClickEncoder.h b/ClickEncoder.h index 26924d2..e637d2a 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -15,7 +15,7 @@ // ---------------------------------------------------------------------------- #include -#if defined(__AVR__) +#ifndef ARDUINO_ARCH_ESP8266 #include #include #include From 98982a57a7ffa9ffdedd588fd5f94b014b473c13 Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 24 Jun 2016 19:15:42 -0400 Subject: [PATCH 16/34] Revert "Revert "Change conditional on AVR included"" This reverts commit c471bc1f9c3c6ab676e84800a511925efc23348e. --- ClickEncoder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ClickEncoder.h b/ClickEncoder.h index e637d2a..26924d2 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -15,7 +15,7 @@ // ---------------------------------------------------------------------------- #include -#ifndef ARDUINO_ARCH_ESP8266 +#if defined(__AVR__) #include #include #include From a351ccbdf47d5ca1dee9729e6982ad80a1e7276a Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 24 Jun 2016 19:25:44 -0400 Subject: [PATCH 17/34] Change cli and sei to noInterrupts and interrupts Allows library to compile on the Arduino Due --- ClickEncoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index 238fe63..d76d2b7 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -196,14 +196,14 @@ int16_t ClickEncoder::getValue(void) { int16_t val; - cli(); + noInterrupts(); val = delta; if (steps == 2) delta = val & 1; else if (steps == 4) delta = val & 3; else delta = 0; // default to 1 step per notch - sei(); + interrupts(); if (steps == 4) val >>= 2; if (steps == 2) val >>= 1; From b1ee27635bb168f6484eb1c44e99731ee4d79e9d Mon Sep 17 00:00:00 2001 From: Dennis Date: Sat, 15 Oct 2016 07:44:10 -0400 Subject: [PATCH 18/34] Added methods to customize double click and hold/release times for buttons Added methods setDoubleClickTime, setHoldTime. Moved default times to header file. Changed doubleClickTicks to 16 bits. Added currentMillis variable into the service method to save calls to millis() and replace now variable.. --- ClickEncoder.cpp | 16 +++++++--------- ClickEncoder.h | 22 +++++++++++++++++++++- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index d76d2b7..d207501 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -15,8 +15,6 @@ // Button configuration (values for 1ms timer service calls) // #define ENC_BUTTONINTERVAL 10 // check button every x milliseconds, also debouce time -#define ENC_DOUBLECLICKTIME 400 // second click within 600ms -#define ENC_HOLDTIME 1200 // report held button after 1.2s // ---------------------------------------------------------------------------- // Acceleration configuration (for 1000Hz calls to ::service()) @@ -85,7 +83,6 @@ ClickEncoder::ClickEncoder(int8_t BTN, bool active) void ClickEncoder::service(void) { bool moved = false; - unsigned long now = millis(); if (pinA >= 0 && pinA >= 0) { if (accelerationEnabled) { // decelerate every tick @@ -143,15 +140,16 @@ void ClickEncoder::service(void) // handle button // #ifndef WITHOUT_BUTTON - + unsigned long currentMillis = millis(); + if (currentMillis < lastButtonCheck) lastButtonCheck = 0; // Handle case when millis() wraps back around to zero if ((pinBTN > 0 || (pinBTN == 0 && buttonOnPinZeroEnabled)) // check button only, if a pin has been provided - && (now - lastButtonCheck) >= ENC_BUTTONINTERVAL) // checking button is sufficient every 10-30ms + && ((currentMillis - lastButtonCheck) >= ENC_BUTTONINTERVAL)) // checking button is sufficient every 10-30ms { - lastButtonCheck = now; + lastButtonCheck = currentMillis; if (digitalRead(pinBTN) == pinsActive) { // key is down keyDownTicks++; - if ((keyDownTicks > (ENC_HOLDTIME / ENC_BUTTONINTERVAL)) && (buttonHeldEnabled)) { + if ((keyDownTicks > (buttonHoldTime / ENC_BUTTONINTERVAL)) && (buttonHeldEnabled)) { button = Held; } } @@ -165,13 +163,13 @@ void ClickEncoder::service(void) else { #define ENC_SINGLECLICKONLY 1 if (doubleClickTicks > ENC_SINGLECLICKONLY) { // prevent trigger in single click mode - if (doubleClickTicks < (ENC_DOUBLECLICKTIME / ENC_BUTTONINTERVAL)) { + if (doubleClickTicks < (buttonDoubleClickTime / ENC_BUTTONINTERVAL)) { button = DoubleClicked; doubleClickTicks = 0; } } else { - doubleClickTicks = (doubleClickEnabled) ? (ENC_DOUBLECLICKTIME / ENC_BUTTONINTERVAL) : ENC_SINGLECLICKONLY; + doubleClickTicks = (doubleClickEnabled) ? (buttonDoubleClickTime / ENC_BUTTONINTERVAL) : ENC_SINGLECLICKONLY; } } } diff --git a/ClickEncoder.h b/ClickEncoder.h index 26924d2..ea4d1cf 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -12,6 +12,12 @@ #ifndef __have__ClickEncoder_h__ #define __have__ClickEncoder_h__ +// ---Button defaults------------------------------------------------------------- + +#define BTN_DOUBLECLICKTIME 400 // second click within 400ms +#define BTN_HOLDTIME 1000 // report held button after 1s + + // ---------------------------------------------------------------------------- #include @@ -74,6 +80,18 @@ class ClickEncoder #endif #ifndef WITHOUT_BUTTON +public: + void setDoubleClickTime(uint16_t durationMilliseconds) + { + buttonDoubleClickTime = durationMilliseconds; + } + +public: + void setHoldTime(uint16_t durationMilliseconds) + { + buttonHoldTime = durationMilliseconds; + } + public: void setDoubleClickEnabled(const bool &d) { @@ -141,7 +159,9 @@ class ClickEncoder bool buttonHeldEnabled; bool buttonOnPinZeroEnabled = false; uint16_t keyDownTicks = 0; - uint8_t doubleClickTicks = 0; + uint16_t doubleClickTicks = 0; + uint16_t buttonHoldTime = BTN_HOLDTIME; + uint16_t buttonDoubleClickTime = BTN_DOUBLECLICKTIME; unsigned long lastButtonCheck = 0; #endif }; From 9efede6b90c3588dab8939aed1657d991bb4a962 Mon Sep 17 00:00:00 2001 From: Dennis Date: Mon, 31 Oct 2016 20:51:42 -0400 Subject: [PATCH 19/34] Added ability to have multiple buttons on one analog pin/Button race condition fixed Multiple buttons can be put on one analog pin by defining a range for the analog input that presents a button press. Note that this method only really works for one button pressed at a time. Multiple buttons pressed at a time may not register at all, or register as the wrong button. A new constructir was added that allowed the analog input range to be specified. Also added noInterrupts to getButton to cure race condition --- ClickEncoder.cpp | 44 +++++- ClickEncoder.h | 346 ++++++++++++++++++++++++----------------------- 2 files changed, 217 insertions(+), 173 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index d207501..07ee09b 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -46,6 +46,9 @@ ClickEncoder::ClickEncoder(int8_t A, int8_t B, int8_t BTN, uint8_t stepsPerNotch delta(0), last(0), acceleration(0), button(Open), steps(stepsPerNotch), pinA(A), pinB(B), pinBTN(BTN), pinsActive(active) +#ifndef WITHOUT_BUTTON + , analogInput(false) +#endif { uint8_t configType = (pinsActive == LOW) ? INPUT_PULLUP : INPUT; if (pinA >= 0) {pinMode(pinA, configType);} @@ -69,12 +72,30 @@ ClickEncoder::ClickEncoder(int8_t A, int8_t B, int8_t BTN, uint8_t stepsPerNotch ClickEncoder::ClickEncoder(int8_t BTN, bool active) : doubleClickEnabled(true),buttonHeldEnabled(true), accelerationEnabled(true), delta(0), last(0), acceleration(0), - button(Open), steps(1), + button(Open), steps(1), analogInput(false), pinA(-1), pinB(-1), pinBTN(BTN), pinsActive(active) { uint8_t configType = (pinsActive == LOW) ? INPUT_PULLUP : INPUT; if (pinBTN >= 0) {pinMode(pinBTN, configType);} } + +// ---------------------------------------------------------------------------- +// Constructor for using analog input range as a button + +ClickEncoder::ClickEncoder(int8_t BTN, int16_t rangeLow, int16_t rangeHigh) + : doubleClickEnabled(true),buttonHeldEnabled(true), accelerationEnabled(true), + delta(0), last(0), acceleration(0), + button(Open), steps(1), analogInput(true), + pinA(-1), pinB(-1), pinBTN(BTN), pinsActive(LOW), anlogActiveRangeLow(rangeLow), anlogActiveRangeHigh(rangeHigh) +{ + pinMode(pinBTN, INPUT); + + if (anlogActiveRangeLow > anlogActiveRangeHigh) { // swap values if provided in the wrong order + int16_t t = anlogActiveRangeLow; + anlogActiveRangeLow = anlogActiveRangeHigh; + anlogActiveRangeHigh = t; + } +} #endif // ---------------------------------------------------------------------------- @@ -146,15 +167,17 @@ void ClickEncoder::service(void) && ((currentMillis - lastButtonCheck) >= ENC_BUTTONINTERVAL)) // checking button is sufficient every 10-30ms { lastButtonCheck = currentMillis; + + bool pinRead = getPinState(); - if (digitalRead(pinBTN) == pinsActive) { // key is down + if (pinRead == pinsActive) { // key is down keyDownTicks++; if ((keyDownTicks > (buttonHoldTime / ENC_BUTTONINTERVAL)) && (buttonHeldEnabled)) { button = Held; } } - if (digitalRead(pinBTN) == !pinsActive) { // key is now up + if (pinRead == !pinsActive) { // key is now up if (keyDownTicks > 1) { //Make sure key was down through 1 complete tick to prevent random transients from registering as click if (button == Held) { button = Released; @@ -224,10 +247,25 @@ int16_t ClickEncoder::getValue(void) #ifndef WITHOUT_BUTTON ClickEncoder::Button ClickEncoder::getButton(void) { + noInterrupts(); ClickEncoder::Button ret = button; if (button != ClickEncoder::Held && ret != ClickEncoder::Open) { button = ClickEncoder::Open; // reset } + interrupts(); + return ret; } + +bool ClickEncoder::getPinState() { + bool pinState; + if (analogInput) { + int16_t pinValue = analogRead(pinBTN); + pinState = ((pinValue >= anlogActiveRangeLow) && (pinValue <= anlogActiveRangeHigh)) ? LOW : HIGH; // set result to LOW (button pressed) if analog input is in range + } else { + pinState = digitalRead(pinBTN); + } + return pinState; +} + #endif diff --git a/ClickEncoder.h b/ClickEncoder.h index ea4d1cf..726117f 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -1,171 +1,177 @@ -// ---------------------------------------------------------------------------- -// Rotary Encoder Driver with Acceleration -// Supports Click, DoubleClick, Long Click -// -// (c) 2010 karl@pitrich.com -// (c) 2014 karl@pitrich.com -// -// Timer-based rotary encoder logic by Peter Dannegger -// http://www.mikrocontroller.net/articles/Drehgeber -// ---------------------------------------------------------------------------- - -#ifndef __have__ClickEncoder_h__ -#define __have__ClickEncoder_h__ - -// ---Button defaults------------------------------------------------------------- - -#define BTN_DOUBLECLICKTIME 400 // second click within 400ms -#define BTN_HOLDTIME 1000 // report held button after 1s - - -// ---------------------------------------------------------------------------- - -#include -#if defined(__AVR__) -#include -#include -#include -#endif -#include "Arduino.h" - -// ---------------------------------------------------------------------------- - -#define ENC_NORMAL (1 << 1) // use Peter Danneger's decoder -#define ENC_FLAKY (1 << 2) // use Table-based decoder - -// ---------------------------------------------------------------------------- - -#ifndef ENC_DECODER -# define ENC_DECODER ENC_NORMAL -#endif - -#if ENC_DECODER == ENC_FLAKY -# ifndef ENC_HALFSTEP -# define ENC_HALFSTEP 1 // use table for half step per default -# endif -#endif - -// ---------------------------------------------------------------------------- - -class ClickEncoder -{ -public: - typedef enum Button_e { - Open = 0, - Closed, - - Pressed, - Held, - Released, - - Clicked, - DoubleClicked - - } Button; - -public: - ClickEncoder(int8_t A, int8_t B, int8_t BTN = -1, - uint8_t stepsPerNotch = 1, bool active = LOW); - -#ifndef WITHOUT_BUTTON - explicit ClickEncoder(int8_t BTN, bool active = LOW); -#endif - - void service(void); - int16_t getValue(void); - -#ifndef WITHOUT_BUTTON -public: - Button getButton(void); -#endif - -#ifndef WITHOUT_BUTTON -public: - void setDoubleClickTime(uint16_t durationMilliseconds) - { - buttonDoubleClickTime = durationMilliseconds; - } - -public: - void setHoldTime(uint16_t durationMilliseconds) - { - buttonHoldTime = durationMilliseconds; - } - -public: - void setDoubleClickEnabled(const bool &d) - { - doubleClickEnabled = d; - } - - const bool getDoubleClickEnabled() - { - return doubleClickEnabled; - } - -public: - void setButtonHeldEnabled(const bool &d) - { - buttonHeldEnabled = d; - } - - const bool getButtonHeldEnabled() - { - return buttonHeldEnabled; - } - -public: - void setButtonOnPinZeroEnabled(const bool &d) - { - buttonOnPinZeroEnabled = d; - } - - const bool getButtonOnPinZeroEnabled() - { - return buttonOnPinZeroEnabled; - } -#endif - -public: - void setAccelerationEnabled(const bool &a) - { - accelerationEnabled = a; - if (accelerationEnabled == false) { - acceleration = 0; - } - } - - const bool getAccelerationEnabled() - { - return accelerationEnabled; - } - -private: - const int8_t pinA; - const int8_t pinB; - const int8_t pinBTN; - const bool pinsActive; - volatile int16_t delta; - volatile int16_t last; - uint8_t steps; - volatile uint16_t acceleration; - bool accelerationEnabled; -#if ENC_DECODER != ENC_NORMAL - static const int8_t table[16]; -#endif -#ifndef WITHOUT_BUTTON - volatile Button button; - bool doubleClickEnabled; - bool buttonHeldEnabled; - bool buttonOnPinZeroEnabled = false; - uint16_t keyDownTicks = 0; - uint16_t doubleClickTicks = 0; - uint16_t buttonHoldTime = BTN_HOLDTIME; - uint16_t buttonDoubleClickTime = BTN_DOUBLECLICKTIME; - unsigned long lastButtonCheck = 0; -#endif -}; - -// ---------------------------------------------------------------------------- - +// ---------------------------------------------------------------------------- +// Rotary Encoder Driver with Acceleration +// Supports Click, DoubleClick, Long Click +// +// (c) 2010 karl@pitrich.com +// (c) 2014 karl@pitrich.com +// +// Timer-based rotary encoder logic by Peter Dannegger +// http://www.mikrocontroller.net/articles/Drehgeber +// ---------------------------------------------------------------------------- + +#ifndef __have__ClickEncoder_h__ +#define __have__ClickEncoder_h__ + +// ---Button defaults------------------------------------------------------------- + +#define BTN_DOUBLECLICKTIME 400 // second click within 400ms +#define BTN_HOLDTIME 1000 // report held button after 1s + + +// ---------------------------------------------------------------------------- + +#include +#if defined(__AVR__) +#include +#include +#include +#endif +#include "Arduino.h" + +// ---------------------------------------------------------------------------- + +#define ENC_NORMAL (1 << 1) // use Peter Danneger's decoder +#define ENC_FLAKY (1 << 2) // use Table-based decoder + +// ---------------------------------------------------------------------------- + +#ifndef ENC_DECODER +# define ENC_DECODER ENC_NORMAL +#endif + +#if ENC_DECODER == ENC_FLAKY +# ifndef ENC_HALFSTEP +# define ENC_HALFSTEP 1 // use table for half step per default +# endif +#endif + +// ---------------------------------------------------------------------------- + +class ClickEncoder +{ +public: + typedef enum Button_e { + Open = 0, + Closed, + + Pressed, + Held, + Released, + + Clicked, + DoubleClicked + + } Button; + +public: + ClickEncoder(int8_t A, int8_t B, int8_t BTN = -1, + uint8_t stepsPerNotch = 1, bool active = LOW); + +#ifndef WITHOUT_BUTTON + explicit ClickEncoder(int8_t BTN, bool active = LOW); + explicit ClickEncoder(int8_t BTN, int16_t rangeLow, int16_t rangeHigh); // Constructor for using alaog input range as a button + +#endif + + void service(void); + int16_t getValue(void); + +#ifndef WITHOUT_BUTTON +public: + Button getButton(void); +#endif + +#ifndef WITHOUT_BUTTON +public: + void setDoubleClickTime(uint16_t durationMilliseconds) + { + buttonDoubleClickTime = durationMilliseconds; + } + +public: + void setHoldTime(uint16_t durationMilliseconds) + { + buttonHoldTime = durationMilliseconds; + } + +public: + void setDoubleClickEnabled(const bool &d) + { + doubleClickEnabled = d; + } + + const bool getDoubleClickEnabled() + { + return doubleClickEnabled; + } + +public: + void setButtonHeldEnabled(const bool &d) + { + buttonHeldEnabled = d; + } + + const bool getButtonHeldEnabled() + { + return buttonHeldEnabled; + } + +public: + void setButtonOnPinZeroEnabled(const bool &d) + { + buttonOnPinZeroEnabled = d; + } + + const bool getButtonOnPinZeroEnabled() + { + return buttonOnPinZeroEnabled; + } +#endif + +public: + void setAccelerationEnabled(const bool &a) + { + accelerationEnabled = a; + if (accelerationEnabled == false) { + acceleration = 0; + } + } + + const bool getAccelerationEnabled() + { + return accelerationEnabled; + } + +private: + const int8_t pinA; + const int8_t pinB; + const int8_t pinBTN; + const bool pinsActive; + volatile int16_t delta; + volatile int16_t last; + uint8_t steps; + volatile uint16_t acceleration; + bool accelerationEnabled; +#if ENC_DECODER != ENC_NORMAL + static const int8_t table[16]; +#endif +#ifndef WITHOUT_BUTTON + volatile Button button; + bool doubleClickEnabled; + bool buttonHeldEnabled; + bool buttonOnPinZeroEnabled = false; + bool analogInput = false; + uint16_t keyDownTicks = 0; + uint16_t doubleClickTicks = 0; + uint16_t buttonHoldTime = BTN_HOLDTIME; + uint16_t buttonDoubleClickTime = BTN_DOUBLECLICKTIME; + unsigned long lastButtonCheck = 0; + int16_t anlogActiveRangeLow = 0; + int16_t anlogActiveRangeHigh = 0; + bool getPinState(); +#endif +}; + +// ---------------------------------------------------------------------------- + #endif // __have__ClickEncoder_h__ From 4dacba3f8870bc7a29fed52fb01e96cbe12f45e3 Mon Sep 17 00:00:00 2001 From: Dennis Date: Mon, 31 Oct 2016 21:37:51 -0400 Subject: [PATCH 20/34] moved interupts() in getValue to be sure no race condition happens Also made steps variable volitile like the other variables used in getValue --- ClickEncoder.cpp | 3 +-- ClickEncoder.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index 07ee09b..0679156 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -224,8 +224,6 @@ int16_t ClickEncoder::getValue(void) else if (steps == 4) delta = val & 3; else delta = 0; // default to 1 step per notch - interrupts(); - if (steps == 4) val >>= 2; if (steps == 2) val >>= 1; @@ -238,6 +236,7 @@ int16_t ClickEncoder::getValue(void) else if (val > 0) { r += 1 + accel; } + interrupts(); return r; } diff --git a/ClickEncoder.h b/ClickEncoder.h index 726117f..e8954b3 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -149,7 +149,7 @@ class ClickEncoder const bool pinsActive; volatile int16_t delta; volatile int16_t last; - uint8_t steps; + volatile uint8_t steps; volatile uint16_t acceleration; bool accelerationEnabled; #if ENC_DECODER != ENC_NORMAL From dba405b8672e6a6468a33622dfe396aab0d0ceaf Mon Sep 17 00:00:00 2001 From: Dennis Date: Sun, 12 Feb 2017 18:59:45 -0500 Subject: [PATCH 21/34] Steps Per Notch default changes to 4 This seems to be a better default as inexpensive e-bay encoders use 4 --- ClickEncoder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ClickEncoder.h b/ClickEncoder.h index e8954b3..77d6098 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -65,7 +65,7 @@ class ClickEncoder public: ClickEncoder(int8_t A, int8_t B, int8_t BTN = -1, - uint8_t stepsPerNotch = 1, bool active = LOW); + uint8_t stepsPerNotch = 4, bool active = LOW); #ifndef WITHOUT_BUTTON explicit ClickEncoder(int8_t BTN, bool active = LOW); From e2cf703073ebdfef4fa58b06b4ddb07d5f2fee9d Mon Sep 17 00:00:00 2001 From: Dennis Date: Sun, 12 Feb 2017 19:03:38 -0500 Subject: [PATCH 22/34] Fixed ambiguous constructor. Analog buttons are now a seperate object Removed the ClickEncoder constructor for multiplexed analog buttons. AnalogButton is now a child class that can be used to defined these buttons. Also added a DIgitalButton child class for using a stand alone buttons (without an encoder). The ClickEncoder constructor for a stand alone button still exists, but consider it depricated in favor of DigitalButton. --- ClickEncoder.cpp | 21 ++++++++++++++++----- ClickEncoder.h | 28 +++++++++++++++++++++------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index 0679156..6fc5645 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -69,6 +69,8 @@ ClickEncoder::ClickEncoder(int8_t A, int8_t B, int8_t BTN, uint8_t stepsPerNotch // ---------------------------------------------------------------------------- #ifndef WITHOUT_BUTTON + +// Depricated. Use DigitalButton instead ClickEncoder::ClickEncoder(int8_t BTN, bool active) : doubleClickEnabled(true),buttonHeldEnabled(true), accelerationEnabled(true), delta(0), last(0), acceleration(0), @@ -79,17 +81,26 @@ ClickEncoder::ClickEncoder(int8_t BTN, bool active) if (pinBTN >= 0) {pinMode(pinBTN, configType);} } +// ---------------------------------------------------------------------------- +// Constructor for using digital input as a button + +DigitalButton::DigitalButton(int8_t BTN, bool active) : ClickEncoder(BTN, active) + +{ + +} + // ---------------------------------------------------------------------------- // Constructor for using analog input range as a button -ClickEncoder::ClickEncoder(int8_t BTN, int16_t rangeLow, int16_t rangeHigh) - : doubleClickEnabled(true),buttonHeldEnabled(true), accelerationEnabled(true), - delta(0), last(0), acceleration(0), - button(Open), steps(1), analogInput(true), - pinA(-1), pinB(-1), pinBTN(BTN), pinsActive(LOW), anlogActiveRangeLow(rangeLow), anlogActiveRangeHigh(rangeHigh) +AnalogButton::AnalogButton(int8_t BTN, int16_t rangeLow, int16_t rangeHigh) : ClickEncoder(BTN, false) { pinMode(pinBTN, INPUT); + anlogActiveRangeLow = rangeLow; + anlogActiveRangeHigh = rangeHigh; + analogInput = true; + if (anlogActiveRangeLow > anlogActiveRangeHigh) { // swap values if provided in the wrong order int16_t t = anlogActiveRangeLow; anlogActiveRangeLow = anlogActiveRangeHigh; diff --git a/ClickEncoder.h b/ClickEncoder.h index 77d6098..e1054e8 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -68,8 +68,7 @@ class ClickEncoder uint8_t stepsPerNotch = 4, bool active = LOW); #ifndef WITHOUT_BUTTON - explicit ClickEncoder(int8_t BTN, bool active = LOW); - explicit ClickEncoder(int8_t BTN, int16_t rangeLow, int16_t rangeHigh); // Constructor for using alaog input range as a button + explicit ClickEncoder(int8_t BTN, bool active = false); // Depricated. Use Digtial Button instead #endif @@ -142,11 +141,11 @@ class ClickEncoder return accelerationEnabled; } -private: - const int8_t pinA; - const int8_t pinB; - const int8_t pinBTN; - const bool pinsActive; +protected: + int8_t pinA; + int8_t pinB; + int8_t pinBTN; + bool pinsActive; volatile int16_t delta; volatile int16_t last; volatile uint8_t steps; @@ -172,6 +171,21 @@ class ClickEncoder #endif }; +#ifndef WITHOUT_BUTTON +class AnalogButton : public ClickEncoder +{ + public: + explicit AnalogButton(int8_t BTN, int16_t rangeLow, int16_t rangeHigh); // Constructor for using analog input range as a button +}; + +class DigitalButton : public ClickEncoder +{ + public: + explicit DigitalButton(int8_t BTN, bool active = false); // Constructor for using a button only +}; + +#endif + // ---------------------------------------------------------------------------- #endif // __have__ClickEncoder_h__ From e30f7ac827262d100f75409c5913da07a5568cac Mon Sep 17 00:00:00 2001 From: Dennis Date: Sun, 12 Feb 2017 19:13:07 -0500 Subject: [PATCH 23/34] Changed TwoDevices example to use DigitalButton Using ClickEncoder to define a stand alone button has been depricated. Use DigitalButton instead. --- examples/TwoDevices/TwoDevices.ino | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/TwoDevices/TwoDevices.ino b/examples/TwoDevices/TwoDevices.ino index 4488f71..9352c7b 100644 --- a/examples/TwoDevices/TwoDevices.ino +++ b/examples/TwoDevices/TwoDevices.ino @@ -2,7 +2,7 @@ This example demonstrates the use of 2 devices controlled by the ClickEncoder library -In thie example, the 2 devides are a rotary encoder with built in button, and a normal momentary button +In thie example, the 2 devices are a rotary encoder with built in button, and a normal momentary button */ #include @@ -16,7 +16,9 @@ In thie example, the 2 devides are a rotary encoder with built in button, and a #define EXTRA_BUTTON_PIN 8 -ClickEncoder button = ClickEncoder(EXTRA_BUTTON_PIN); +// Note, using ClickEncoder to define a stand alone button has been depricated. Use DigitalButton instead + +DigitalButton button = DigitalButton(EXTRA_BUTTON_PIN); ClickEncoder encoder = ClickEncoder(ENCODER_PINA,ENCODER_PINB,ENCODER_BTN,ENCODER_STEPS_PER_NOTCH); void timerIsr() { //Service methods from both instances must be included @@ -80,4 +82,4 @@ static int16_t last, value; VERBOSECASE(ClickEncoder::DoubleClicked) } } -} +} \ No newline at end of file From 31ca2f730de8012d472cd73740728b095134e13b Mon Sep 17 00:00:00 2001 From: Dennis Date: Sat, 18 Feb 2017 07:38:09 -0500 Subject: [PATCH 24/34] Corrected IF statement to check both pinA and pinB --- ClickEncoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index 6fc5645..f4f9e96 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -116,7 +116,7 @@ void ClickEncoder::service(void) { bool moved = false; - if (pinA >= 0 && pinA >= 0) { + if (pinA >= 0 && pinB >= 0) { if (accelerationEnabled) { // decelerate every tick acceleration -= ENC_ACCEL_DEC; if (acceleration & 0x8000) { // handle overflow of MSB is set From 16505d9f665e1684ea4a0d6f0a991deb71441b00 Mon Sep 17 00:00:00 2001 From: Dennis Date: Mon, 10 Apr 2017 21:01:17 -0400 Subject: [PATCH 25/34] Support for STM23duino --- ClickEncoder.cpp | 6 +++--- ClickEncoder.h | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index f4f9e96..09bdf8b 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -50,7 +50,7 @@ ClickEncoder::ClickEncoder(int8_t A, int8_t B, int8_t BTN, uint8_t stepsPerNotch , analogInput(false) #endif { - uint8_t configType = (pinsActive == LOW) ? INPUT_PULLUP : INPUT; + pinMode_t configType = (pinsActive == LOW) ? INPUT_PULLUP : INPUT; if (pinA >= 0) {pinMode(pinA, configType);} if (pinB >= 0) {pinMode(pinB, configType);} #ifndef WITHOUT_BUTTON @@ -77,7 +77,7 @@ ClickEncoder::ClickEncoder(int8_t BTN, bool active) button(Open), steps(1), analogInput(false), pinA(-1), pinB(-1), pinBTN(BTN), pinsActive(active) { - uint8_t configType = (pinsActive == LOW) ? INPUT_PULLUP : INPUT; + pinMode_t configType = (pinsActive == LOW) ? INPUT_PULLUP : INPUT; if (pinBTN >= 0) {pinMode(pinBTN, configType);} } @@ -93,7 +93,7 @@ DigitalButton::DigitalButton(int8_t BTN, bool active) : ClickEncoder(BTN, active // ---------------------------------------------------------------------------- // Constructor for using analog input range as a button -AnalogButton::AnalogButton(int8_t BTN, int16_t rangeLow, int16_t rangeHigh) : ClickEncoder(BTN, false) +AnalogButton::AnalogButton(int8_t BTN, int16_t rangeLow, int16_t rangeHigh) : ClickEncoder(BTN, (bool)false) { pinMode(pinBTN, INPUT); diff --git a/ClickEncoder.h b/ClickEncoder.h index e1054e8..2f38510 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -47,6 +47,12 @@ // ---------------------------------------------------------------------------- +#if defined(__arm__) + typedef WiringPinMode pinMode_t; +#else + typedef uint8_t pinMode_t; +#endif + class ClickEncoder { public: From f37641814f7206e5c32b5df62fbfa81ad18d82fc Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 21 Apr 2017 11:14:02 -0400 Subject: [PATCH 26/34] Fix Typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 30dbc66..ea518ac 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ or see it in action at my modified [reflow oven controller] ### Encoder The library supports **acceleration**, so when the encoder is rotated faster, the encoders value will increment faster. -Acceleration can be enabled or disabled at runtine using `setAccelerationEnabled(bool)`. +Acceleration can be enabled or disabled at runtime using `setAccelerationEnabled(bool)`. For instance, it makes sense to disable acceleration when entering a configuration menu that will be navigated using the encoder. From 4b3b30bf1c99ec077a9f31719bee261c045a0f28 Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 28 Apr 2017 23:38:12 -0400 Subject: [PATCH 27/34] Fix for Due --- ClickEncoder.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ClickEncoder.h b/ClickEncoder.h index 2f38510..6c486ac 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -46,8 +46,7 @@ #endif // ---------------------------------------------------------------------------- - -#if defined(__arm__) +#if defined(__arm__) && (defined (__STM32F1__) || defined (__STM32F4__) ) typedef WiringPinMode pinMode_t; #else typedef uint8_t pinMode_t; From 9337a0c46c3fb5f910ede295df5a0dcb277ee7bf Mon Sep 17 00:00:00 2001 From: aster94 Date: Mon, 15 Jan 2018 17:35:27 +0100 Subject: [PATCH 28/34] Another way to access the clickEncoder class (#9) * Add files via upload * Add files via upload --- examples/ArduinoStyle/ArduinoStyle.ino | 68 ++++++++++++++++++++++++++ keywords.txt | 13 +++++ 2 files changed, 81 insertions(+) create mode 100644 examples/ArduinoStyle/ArduinoStyle.ino create mode 100644 keywords.txt diff --git a/examples/ArduinoStyle/ArduinoStyle.ino b/examples/ArduinoStyle/ArduinoStyle.ino new file mode 100644 index 0000000..fcf5983 --- /dev/null +++ b/examples/ArduinoStyle/ArduinoStyle.ino @@ -0,0 +1,68 @@ +#include +#include + +int16_t oldEncPos, encPos; +uint8_t buttonState; + +#define pinA A2 +#define pinB A1 +#define pinSw A0 //switch +#define STEPS 4 + +ClickEncoder encoder(pinA, pinB, pinSw, STEPS); + +void setup() { + Serial.begin(9600); + + Timer1.initialize(1000); + Timer1.attachInterrupt(timerIsr); + + encoder.setAccelerationEnabled(true); + + Serial.print("Acceleration is "); + Serial.println((encoder.getAccelerationEnabled()) ? "enabled" : "disabled"); + + oldEncPos = -1; +} + +void loop() { + encPos += encoder.getValue(); + + if (encPos != oldEncPos) { + oldEncPos = encPos; + Serial.print("Encoder Value: "); + Serial.println(encPos); + } + + buttonState = encoder.getButton(); + + if (buttonState != 0) { + Serial.print("Button: "); Serial.println(buttonState); + switch (buttonState) { + case ClickEncoder::Open: //0 + break; + + case ClickEncoder::Closed: //1 + break; + + case ClickEncoder::Pressed: //2 + break; + + case ClickEncoder::Held: //3 + break; + + case ClickEncoder::Released: //4 + break; + + case ClickEncoder::Clicked: //5 + break; + + case ClickEncoder::DoubleClicked: //6 + break; + } + } +} + +void timerIsr() { + encoder.service(); +} diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..605d6ec --- /dev/null +++ b/keywords.txt @@ -0,0 +1,13 @@ +ClickEncoder KEYWORD1 + +setAccelerationEnabled KEYWORD2 +getAccelerationEnabled KEYWORD2 +getButton KEYWORD2 +getValue KEYWORD2 +service KEYWORD2 +setDoubleClickTime KEYWORD2 +setHoldTime KEYWORD2 +setDoubleClickEnabled KEYWORD2 +getDoubleClickEnabled KEYWORD2 +setButtonHeldEnabled KEYWORD2 +getButtonHeldEnabled KEYWORD2 \ No newline at end of file From 9d0d2264c5b3eb32f6a5c9b76a5fd849cc340054 Mon Sep 17 00:00:00 2001 From: soligen2010 <16547088+soligen2010@users.noreply.github.com> Date: Sat, 23 Jan 2021 15:11:06 -0500 Subject: [PATCH 29/34] Update ESP8266Example.ino Fixed timing compare --- examples/ESP8266Example/ESP8266Example.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ESP8266Example/ESP8266Example.ino b/examples/ESP8266Example/ESP8266Example.ino index 363e460..c651a9e 100644 --- a/examples/ESP8266Example/ESP8266Example.ino +++ b/examples/ESP8266Example/ESP8266Example.ino @@ -35,7 +35,7 @@ void loop() { //Call Service in loop becasue using timer interrupts may affect ESP8266 WIFI //however call no more than 1 time per millisecond to reduce encoder bounce static uint32_t lastService = 0; - if (lastService + 1000 < micros()) { + if (micros() - lastService >= 1000) { lastService = micros(); encoder.service(); } From 2081c04113096fbd3586785540efffdfa90eb5ca Mon Sep 17 00:00:00 2001 From: soligen2010 <16547088+soligen2010@users.noreply.github.com> Date: Sat, 23 Jan 2021 16:04:17 -0500 Subject: [PATCH 30/34] CCW Negative Bit Fix Use math instead of bit operations to sign is never lost --- ClickEncoder.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index 09bdf8b..ca7c237 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -230,13 +230,17 @@ int16_t ClickEncoder::getValue(void) noInterrupts(); val = delta; + + delta = val % steps; + val /= steps; +// +// if (steps == 2) delta = val & 1; +// else if (steps == 4) delta = val & 3; +// else delta = 0; // default to 1 step per notch +// +// if (steps == 4) val >>= 2; +// if (steps == 2) val >>= 1; - if (steps == 2) delta = val & 1; - else if (steps == 4) delta = val & 3; - else delta = 0; // default to 1 step per notch - - if (steps == 4) val >>= 2; - if (steps == 2) val >>= 1; int16_t r = 0; int16_t accel = ((accelerationEnabled) ? (acceleration >> 8) : 0); From 7d11d4829250abcc49545f78a1cd90f76416392d Mon Sep 17 00:00:00 2001 From: Dennis <16547088+soligen2010@users.noreply.github.com> Date: Sat, 12 Feb 2022 23:59:40 -0500 Subject: [PATCH 31/34] Reset Encoder Method; Improved Timing Add reset Encoder method. Improved timing. All timing is now done with Millis instead of counting "clicks", making operation more consistent if calls to service happen on an odd schedule. --- ClickEncoder.cpp | 92 +++++++++++++++++++++++++++++++----------------- ClickEncoder.h | 7 ++-- 2 files changed, 64 insertions(+), 35 deletions(-) diff --git a/ClickEncoder.cpp b/ClickEncoder.cpp index ca7c237..efee883 100644 --- a/ClickEncoder.cpp +++ b/ClickEncoder.cpp @@ -102,9 +102,9 @@ AnalogButton::AnalogButton(int8_t BTN, int16_t rangeLow, int16_t rangeHigh) : Cl analogInput = true; if (anlogActiveRangeLow > anlogActiveRangeHigh) { // swap values if provided in the wrong order - int16_t t = anlogActiveRangeLow; - anlogActiveRangeLow = anlogActiveRangeHigh; - anlogActiveRangeHigh = t; + int16_t t = anlogActiveRangeLow; + anlogActiveRangeLow = anlogActiveRangeHigh; + anlogActiveRangeHigh = t; } } #endif @@ -117,12 +117,13 @@ void ClickEncoder::service(void) bool moved = false; if (pinA >= 0 && pinB >= 0) { - if (accelerationEnabled) { // decelerate every tick - acceleration -= ENC_ACCEL_DEC; - if (acceleration & 0x8000) { // handle overflow of MSB is set - acceleration = 0; + if (accelerationEnabled) { // decelerate every tick + acceleration -= ENC_ACCEL_DEC; + if (acceleration & 0x8000) { // handle overflow of MSB is set + acceleration = 0; + } } - } + #if ENC_DECODER == ENC_FLAKY last = (last << 2) & 0x0F; @@ -173,20 +174,20 @@ void ClickEncoder::service(void) // #ifndef WITHOUT_BUTTON unsigned long currentMillis = millis(); - if (currentMillis < lastButtonCheck) lastButtonCheck = 0; // Handle case when millis() wraps back around to zero + unsigned long millisSinceLastCheck = currentMillis - lastButtonCheck; if ((pinBTN > 0 || (pinBTN == 0 && buttonOnPinZeroEnabled)) // check button only, if a pin has been provided - && ((currentMillis - lastButtonCheck) >= ENC_BUTTONINTERVAL)) // checking button is sufficient every 10-30ms + && (millisSinceLastCheck >= ENC_BUTTONINTERVAL)) // checking button is sufficient every 10-30ms { lastButtonCheck = currentMillis; bool pinRead = getPinState(); - - if (pinRead == pinsActive) { // key is down - keyDownTicks++; - if ((keyDownTicks > (buttonHoldTime / ENC_BUTTONINTERVAL)) && (buttonHeldEnabled)) { - button = Held; - } - } + + + + + + + if (pinRead == !pinsActive) { // key is now up if (keyDownTicks > 1) { //Make sure key was down through 1 complete tick to prevent random transients from registering as click @@ -197,22 +198,29 @@ void ClickEncoder::service(void) else { #define ENC_SINGLECLICKONLY 1 if (doubleClickTicks > ENC_SINGLECLICKONLY) { // prevent trigger in single click mode - if (doubleClickTicks < (buttonDoubleClickTime / ENC_BUTTONINTERVAL)) { + if (doubleClickTicks < (buttonDoubleClickTime)) { button = DoubleClicked; doubleClickTicks = 0; } } else { - doubleClickTicks = (doubleClickEnabled) ? (buttonDoubleClickTime / ENC_BUTTONINTERVAL) : ENC_SINGLECLICKONLY; + doubleClickTicks = (doubleClickEnabled) ? (buttonDoubleClickTime) : ENC_SINGLECLICKONLY; } } } keyDownTicks = 0; } + + if (pinRead == pinsActive) { // key is down + if ((keyDownTicks > (buttonHoldTime)) && (buttonHeldEnabled)) { + button = Held; + } + keyDownTicks += millisSinceLastCheck; + } if (doubleClickTicks > 0) { - doubleClickTicks--; + doubleClickTicks -= min(millisSinceLastCheck, doubleClickTicks); if (doubleClickTicks == 0) { button = Clicked; } @@ -227,23 +235,27 @@ void ClickEncoder::service(void) int16_t ClickEncoder::getValue(void) { int16_t val; - + int16_t r = 0; + noInterrupts(); - val = delta; + val = delta; delta = val % steps; - val /= steps; -// -// if (steps == 2) delta = val & 1; -// else if (steps == 4) delta = val & 3; -// else delta = 0; // default to 1 step per notch -// -// if (steps == 4) val >>= 2; -// if (steps == 2) val >>= 1; + + + + + + + + - int16_t r = 0; + int16_t accel = ((accelerationEnabled) ? (acceleration >> 8) : 0); + interrupts(); + + val /= steps; if (val < 0) { r -= 1 + accel; @@ -251,11 +263,27 @@ int16_t ClickEncoder::getValue(void) else if (val > 0) { r += 1 + accel; } - interrupts(); + return r; } +// ---------------------------------------------------------------------------- +// This is used to reset the encoder. If the encoder gets 'between' dedents +// (for example only needs 3 more dedents for next click instead of 4) +// it could cause changing direction of encoder to do nothing on first turn +// this could happen if teh encoder misses a reansition, or if the encoder +// is being turned during initialization +// This routine resets the encoder to re-sync it with the dedents + +void ClickEncoder::resetEncoder(void) +{ + noInterrupts(); + delta = 0; + acceleration = 0; + interrupts(); +} + // ---------------------------------------------------------------------------- #ifndef WITHOUT_BUTTON diff --git a/ClickEncoder.h b/ClickEncoder.h index 6c486ac..9bbe856 100644 --- a/ClickEncoder.h +++ b/ClickEncoder.h @@ -71,13 +71,14 @@ class ClickEncoder public: ClickEncoder(int8_t A, int8_t B, int8_t BTN = -1, uint8_t stepsPerNotch = 4, bool active = LOW); - + #ifndef WITHOUT_BUTTON explicit ClickEncoder(int8_t BTN, bool active = false); // Depricated. Use Digtial Button instead #endif void service(void); + void resetEncoder(void); int16_t getValue(void); #ifndef WITHOUT_BUTTON @@ -153,7 +154,7 @@ class ClickEncoder bool pinsActive; volatile int16_t delta; volatile int16_t last; - volatile uint8_t steps; + uint8_t steps; volatile uint16_t acceleration; bool accelerationEnabled; #if ENC_DECODER != ENC_NORMAL @@ -193,4 +194,4 @@ class DigitalButton : public ClickEncoder // ---------------------------------------------------------------------------- -#endif // __have__ClickEncoder_h__ +#endif // __have__ClickEncoder_h__ From 0de753bf97bdd9d1f48eaf256fa22631c6aae324 Mon Sep 17 00:00:00 2001 From: robaol Date: Fri, 8 Sep 2023 18:32:24 +0100 Subject: [PATCH 32/34] Add library.properties and update folder structure for Arduino library standard (#24) --- keywords.txt | 22 +++++++++++++++++++++- library.properties | 9 +++++++++ ClickEncoder.cpp => src/ClickEncoder.cpp | 0 ClickEncoder.h => src/ClickEncoder.h | 0 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 library.properties rename ClickEncoder.cpp => src/ClickEncoder.cpp (100%) rename ClickEncoder.h => src/ClickEncoder.h (100%) diff --git a/keywords.txt b/keywords.txt index 605d6ec..7802efc 100644 --- a/keywords.txt +++ b/keywords.txt @@ -1,5 +1,17 @@ +####################################### +# Syntax Coloring Map for ClickEncoder +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + ClickEncoder KEYWORD1 +####################################### +# Methods and Functions (KEYWORD2) +####################################### + setAccelerationEnabled KEYWORD2 getAccelerationEnabled KEYWORD2 getButton KEYWORD2 @@ -10,4 +22,12 @@ setHoldTime KEYWORD2 setDoubleClickEnabled KEYWORD2 getDoubleClickEnabled KEYWORD2 setButtonHeldEnabled KEYWORD2 -getButtonHeldEnabled KEYWORD2 \ No newline at end of file +getButtonHeldEnabled KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..6bb5570 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=ClickEncoder +version=1.0.1 +author=soligen2010 +maintainer=Dennis +sentence=Arduino library to handle rotary encoders with buttons as a user input device. +paragraph= +category=Display +url=https://github.com/soligen2010/encoder +architectures=* \ No newline at end of file diff --git a/ClickEncoder.cpp b/src/ClickEncoder.cpp similarity index 100% rename from ClickEncoder.cpp rename to src/ClickEncoder.cpp diff --git a/ClickEncoder.h b/src/ClickEncoder.h similarity index 100% rename from ClickEncoder.h rename to src/ClickEncoder.h From 58a6c82ef815e524e8dd1b8262168ea3d2d40601 Mon Sep 17 00:00:00 2001 From: Dennis <16547088+soligen2010@users.noreply.github.com> Date: Fri, 8 Sep 2023 14:08:18 -0400 Subject: [PATCH 33/34] ESP32 Fix Explicit cast to correct type issue on ESP32 --- src/ClickEncoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ClickEncoder.cpp b/src/ClickEncoder.cpp index efee883..623b997 100644 --- a/src/ClickEncoder.cpp +++ b/src/ClickEncoder.cpp @@ -220,7 +220,7 @@ void ClickEncoder::service(void) } if (doubleClickTicks > 0) { - doubleClickTicks -= min(millisSinceLastCheck, doubleClickTicks); + doubleClickTicks -= min(millisSinceLastCheck, (unsigned long)doubleClickTicks); if (doubleClickTicks == 0) { button = Clicked; } From 6c41ff6ab8c3b407cee2439b675621dd64b5a8b1 Mon Sep 17 00:00:00 2001 From: Dennis <16547088+soligen2010@users.noreply.github.com> Date: Fri, 8 Sep 2023 14:30:47 -0400 Subject: [PATCH 34/34] improved ESP32 fix fully safe casting --- src/ClickEncoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ClickEncoder.cpp b/src/ClickEncoder.cpp index 623b997..3684db3 100644 --- a/src/ClickEncoder.cpp +++ b/src/ClickEncoder.cpp @@ -220,7 +220,7 @@ void ClickEncoder::service(void) } if (doubleClickTicks > 0) { - doubleClickTicks -= min(millisSinceLastCheck, (unsigned long)doubleClickTicks); + doubleClickTicks -= (uint16_t)constrain(min(millisSinceLastCheck, (unsigned long)doubleClickTicks), 0, 65536); if (doubleClickTicks == 0) { button = Clicked; }