diff --git a/README.md b/README.md index 3164b27..1371a4e 100644 --- a/README.md +++ b/README.md @@ -122,8 +122,9 @@ Adding a rotary encoder instance is easy: { Serial.begin( 115200 ); - // This tells the library that the encoder has its own pull-up resistors - rotaryEncoder.setEncoderType( EncoderType::HAS_PULLUP ); + // Uncomment if your encoder does not have its own pull-up resistors + //rotaryEncoder.enableEncoderPinPullup(); + //rotaryEncoder.enableButtonPinPullup(); // Range of values to be returned by the encoder: minimum is 1, maximum is 10 // The third argument specifies whether turning past the minimum/maximum will diff --git a/examples/BasicRotaryEncoder/BasicRotaryEncoder.ino b/examples/BasicRotaryEncoder/BasicRotaryEncoder.ino index 1a8bfed..b166cbf 100644 --- a/examples/BasicRotaryEncoder/BasicRotaryEncoder.ino +++ b/examples/BasicRotaryEncoder/BasicRotaryEncoder.ino @@ -1,13 +1,13 @@ /** * ESP32RotaryEncoder: BasicRotaryEncoder.ino - * + * * This is a basic example of how to instantiate a single Rotary Encoder. - * + * * Turning the knob will increment/decrement a value between 1 and 10 and * print it to the serial console. - * + * * Pressing the button will output "boop!" to the serial console. - * + * * Created 3 October 2023 * Updated 1 November 2023 * By Matthew Clark @@ -41,8 +41,9 @@ void setup() { Serial.begin( 115200 ); - // This tells the library that the encoder has its own pull-up resistors - rotaryEncoder.setEncoderType( EncoderType::HAS_PULLUP ); + // Uncomment if your encoder does not have its own pull-up resistors + //rotaryEncoder.enableEncoderPinPullup(); + //rotaryEncoder.enableButtonPinPullup(); // Range of values to be returned by the encoder: minimum is 1, maximum is 10 // The third argument specifies whether turning past the minimum/maximum will diff --git a/examples/ButtonPressDuration/ButtonPressDuration.ino b/examples/ButtonPressDuration/ButtonPressDuration.ino index cb1ed0e..8561d34 100644 --- a/examples/ButtonPressDuration/ButtonPressDuration.ino +++ b/examples/ButtonPressDuration/ButtonPressDuration.ino @@ -1,14 +1,14 @@ /** * ESP32RotaryEncoder: ButtonPressDuration.ino - * + * * This example shows how to handle long button-presses differently * from long button-presses - * + * * Turning the knob will increment/decrement a value between 1 and 10 and * print it to the serial console. - * + * * Pressing the button will output "boop!" to the serial console. - * + * * Created 1 November 2023 * By Matthew Clark */ @@ -62,8 +62,9 @@ void setup() { Serial.begin( 115200 ); - // This tells the library that the encoder has its own pull-up resistors - rotaryEncoder.setEncoderType( EncoderType::HAS_PULLUP ); + // Uncomment if your encoder does not have its own pull-up resistors + //rotaryEncoder.enableEncoderPinPullup(); + //rotaryEncoder.enableButtonPinPullup(); // Range of values to be returned by the encoder: minimum is 1, maximum is 10 // The third argument specifies whether turning past the minimum/maximum will diff --git a/examples/LeftOrRight/LeftOrRight.ino b/examples/LeftOrRight/LeftOrRight.ino index fb7d370..b61de9e 100644 --- a/examples/LeftOrRight/LeftOrRight.ino +++ b/examples/LeftOrRight/LeftOrRight.ino @@ -1,9 +1,9 @@ /** * ESP32RotaryEncoder: LeftOrRight.ino - * + * * This is a simple example of how to track whether the knob was * turned left or right instead of tracking a numeric value - * + * * Created 1 November 2023 * By Matthew Clark */ @@ -82,8 +82,9 @@ void setup() { Serial.begin( 115200 ); - // This tells the library that the encoder has its own pull-up resistors - rotaryEncoder.setEncoderType( EncoderType::HAS_PULLUP ); + // Uncomment if your encoder does not have its own pull-up resistors + //rotaryEncoder.enableEncoderPinPullup(); + //rotaryEncoder.enableButtonPinPullup(); // The encoder will only return -1, 0, or 1, and will not wrap around. rotaryEncoder.setBoundaries( -1, 1, false ); diff --git a/examples/TwoRotaryEncoders/TwoRotaryEncoders.ino b/examples/TwoRotaryEncoders/TwoRotaryEncoders.ino index 1e87400..005fd7e 100644 --- a/examples/TwoRotaryEncoders/TwoRotaryEncoders.ino +++ b/examples/TwoRotaryEncoders/TwoRotaryEncoders.ino @@ -1,23 +1,23 @@ /** * ESP32RotaryEncoder: TwoRotaryEncoders.ino - * + * * This is a basic example of how to instantiate two distinct Rotary Encoders. - * + * * Rotary Encoder #1: * - Turning the knob will increment/decrement a value between 1 and 10, * and print it to the serial console. - * + * * - Pressing the button will enable/disable Rotary Encoder #2. - * + * * Rotary Encoder #2: * - Turning the knob will increment/decrement a value between -100 and 100, * and print it to the serial console. - * + * * - Pressing the button will enable/disable Rotary Encoder #1. - * + * * While a rotary encoder is disabled, turning the knob or pressing the button * will have no effect. - * + * * Created 3 October 2023 * Updated 1 November 2023 * By Matthew Clark @@ -81,8 +81,9 @@ void button2ToggleRE1( unsigned long duration ) void setup_RE1() { - // This tells the library that the encoder has its own pull-up resistors - rotaryEncoder1.setEncoderType( EncoderType::HAS_PULLUP ); + // Uncomment if your encoder does not have its own pull-up resistors + //rotaryEncoder.enableEncoderPinPullup(); + //rotaryEncoder.enableButtonPinPullup(); // Range of values to be returned by the encoder: minimum is 1, maximum is 10 // The third argument specifies whether turning past the minimum/maximum will @@ -104,9 +105,9 @@ void setup_RE1() void setup_RE2() { - // This tells the library that the encoder does not have its own pull-up - // resistors, so the internal pull-up resistors will be enabled - rotaryEncoder2.setEncoderType( EncoderType::FLOATING ); + // Uncomment if your encoder does not have its own pull-up resistors + //rotaryEncoder.enableEncoderPinPullup(); + //rotaryEncoder.enableButtonPinPullup(); // Range of values to be returned by the encoder: minimum is -100, maximum is 100 // The third argument specifies whether turning past the minimum/maximum will wrap diff --git a/src/ESP32RotaryEncoder.cpp b/src/ESP32RotaryEncoder.cpp index 1987864..b2102ad 100644 --- a/src/ESP32RotaryEncoder.cpp +++ b/src/ESP32RotaryEncoder.cpp @@ -39,33 +39,6 @@ RotaryEncoder::~RotaryEncoder() esp_timer_delete( loopTimer ); } -void RotaryEncoder::setEncoderType( EncoderType type ) -{ - switch( type ) - { - case FLOATING: - encoderPinMode = INPUT_PULLUP; - buttonPinMode = INPUT_PULLUP; - break; - - case HAS_PULLUP: - encoderPinMode = INPUT; - buttonPinMode = INPUT; - break; - - case SW_FLOAT: - encoderPinMode = INPUT; - buttonPinMode = INPUT_PULLUP; - break; - - default: - ESP_LOGE( LOG_TAG, "Invalid encoder type %i", type ); - return; - } - - ESP_LOGD( LOG_TAG, "Encoder type set to %i", type ); -} - void RotaryEncoder::setBoundaries( long minValue, long maxValue, bool circleValues ) { ESP_LOGD( LOG_TAG, "boundary minValue = %ld, maxValue = %ld, circular = %s", minValue, maxValue, ( circleValues ? "true" : "false" ) ); @@ -127,12 +100,6 @@ void RotaryEncoder::onPressed( ButtonCallback f ) callbackButtonPressed = f; } -static void timerCallback( void *arg ) -{ - RotaryEncoder *instance = (RotaryEncoder *)arg; - instance->loop(); -} - void RotaryEncoder::beginLoopTimer() { /** @@ -159,6 +126,12 @@ void RotaryEncoder::beginLoopTimer() esp_timer_start_periodic( loopTimer, RE_LOOP_INTERVAL ); } +void RotaryEncoder::timerCallback( void *self ) +{ + RotaryEncoder *instance = (RotaryEncoder *)self; + instance->loop(); +} + void RotaryEncoder::attachInterrupts() { #if defined( BOARD_HAS_PIN_REMAP ) && ( ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(3,0,0) ) diff --git a/src/ESP32RotaryEncoder.h b/src/ESP32RotaryEncoder.h index 4ad62dc..48d9128 100644 --- a/src/ESP32RotaryEncoder.h +++ b/src/ESP32RotaryEncoder.h @@ -15,20 +15,17 @@ #include -static constexpr int8_t RE_DEFAULT_PIN = -1; -static constexpr uint8_t RE_DEFAULT_STEPS = 4; -static constexpr uint64_t RE_LOOP_INTERVAL = 100000U; // 0.1 seconds - -typedef enum { - FLOATING, - HAS_PULLUP, - SW_FLOAT -} EncoderType; - class RotaryEncoder { + public: + static constexpr int8_t RE_DEFAULT_PIN = -1; + static constexpr uint8_t RE_DEFAULT_STEPS = 4; + static constexpr uint64_t RE_LOOP_INTERVAL = 100000U; // 0.1 seconds - protected: - mutable portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; + typedef enum { + FLOATING, + HAS_PULLUP, + SW_FLOAT + } Type; #if defined( ESP32 ) typedef std::function EncoderCallback; @@ -38,9 +35,6 @@ class RotaryEncoder { typedef void (*ButtonCallback)(unsigned long); #endif - - public: - /** * @brief Construct a new Rotary Encoder instance * @@ -60,20 +54,34 @@ class RotaryEncoder { /** * @brief Responsible for detaching interrupts and clearing the loop timer - * */ ~RotaryEncoder(); /** - * @brief Specifies whether the encoder pins need to use the internal pull-up resistors. + * @brief Enable the internal pull-up resistor for the encoder pin. * - * @note Call this in `setup()`. + * By default, the encoder pin on the ESP32 is floating - which requires that + * the encoder module has its own pull-up resistors or external pull-ups are used. * - * @param type FLOATING if you're using a raw encoder not mounted to a PCB (internal pull-ups will be used); - * HAS_PULLUP if your encoder is a module that has pull-up resistors, (internal pull-ups will not be used); - * SW_FLOAT your encoder is a module that has pull-up resistors, but the resistor for the switch is missing (internal pull-up will be used for switch input only) + * If the encoder module does not have its own pull-ups, calling this method + * will enable the internal pull-up in the ESP32. + * + * @note Call this before `begin()`. It has no effect after. */ - void setEncoderType( EncoderType type ); + void enableEncoderPinPullup() { encoderPinMode = INPUT_PULLUP; } + + /** + * @brief Enable the internal pull-up resistor for the button pin. + * + * By default, the button pin on the ESP32 is floating - which requires that + * the button has its own pull-up resistors or external pull-ups are used. + * + * If the button does not have its own pull-ups, calling this method + * will enable the internal pull-up in the ESP32. + * + * @note Call this before `begin()`. It has no effect after. + */ + void enableButtonPinPullup() { buttonPinMode = INPUT_PULLUP; } /** * @brief Set the minimum and maximum values that the encoder will return. @@ -147,13 +155,11 @@ class RotaryEncoder { * @brief Sets up the GPIO pins specified in the constructor and attaches the ISR callback for the encoder. * * @note Call this in `setup()` after other "set" methods. - * */ void begin( bool useTimer = true ); /** * @brief Enables the encoder knob and pushbutton if `disable()` was previously used. - * */ void enable(); @@ -161,7 +167,6 @@ class RotaryEncoder { * @brief Disables the encoder knob and pushbutton. * * Knob rotation and button presses will have no effect until after `enable()` is called - * */ void disable(); @@ -214,27 +219,12 @@ class RotaryEncoder { * @note This will try to set the value to 0, but if the minimum and maximum configured * by `setBoundaries()` does not include 0, then the minimum or maximum will be * used instead - * */ void resetEncoderValue() { setEncoderValue( 0 ); } - /** - * @brief Synchronizes the encoder value and button state from ISRs. - * - * Runs on a timer and calls `encoderChanged()` and `buttonPressed()` to determine - * if user-specified callbacks should be run. - * - * This would normally be called in userspace `loop()`, but we're using the `loopTimer` instead. - * - */ - void loop(); - private: const char *LOG_TAG = "ESP32RotaryEncoder"; - EncoderCallback callbackEncoderChanged = NULL; - ButtonCallback callbackButtonPressed = NULL; - typedef enum { LEFT = -1, STILL = 0, @@ -248,6 +238,11 @@ class RotaryEncoder { STILL, RIGHT, LEFT, STILL }; + mutable portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; + + EncoderCallback callbackEncoderChanged = NULL; + ButtonCallback callbackButtonPressed = NULL; + int encoderPinMode = INPUT; int buttonPinMode = INPUT; @@ -279,6 +274,8 @@ class RotaryEncoder { esp_timer_handle_t loopTimer; void beginLoopTimer(); + static void timerCallback( void *self ); + void loop(); void attachInterrupts(); void detachInterrupts();