Rotary encoder with ESP32

Hi,

I am trying to interface a generic (3 pin) rotary encoder with an ESP32. Issue is I am only getting either 0 or 1 (sometimes -1) as the value of the counter when I run my project. I tried using external pullup resistors, and changing the input pins, with no luck.

The encoder:
image

Here is my code:

Pins.h

#ifndef PINS_H
#define PINS_H

#define ENCODER_PIN_A 32
#define ENCODER_PIN_B 33

#endif

Encoder.h

#ifndef ENCODER_H
#define ENCODER_H

#include <Arduino.h>
#include "Pins.h"

class RotaryEncoder
{
    uint8_t pinA, pinB;
    int16_t state, prevState;
    int16_t counter;

    public:
        RotaryEncoder(uint8_t, uint8_t, int16_t = 0);

        int16_t loop();
};

#endif

Encoder.cpp

#include "Encoder.h"
#include "UI.h"

RotaryEncoder::RotaryEncoder(uint8_t _pinA, uint8_t _pinB, int16_t _start_count) : pinA{_pinA}, pinB{pinB}, counter{_start_count}
{
    pinMode(pinA, INPUT);
    pinMode(pinB, INPUT);    

    prevState = digitalRead(pinA);
}

int16_t RotaryEncoder::loop()
{
    state = digitalRead(pinA);

    if(state != prevState)
    {
        if(digitalRead(pinB) != state)
        {
            counter++;
        }
        else
        {
            counter--;
        } 
    }

    prevState = state;

    return counter;
}

main.cpp (I am using PlatformIO)

#include <Arduino.h>
#include <LiquidCrystal_I2C.h>
#include "Encoder.h"

LiquidCrystal_I2C main_display(0x27, 20, 4);
RotaryEncoder screen_encoder(ENCODER_PIN_A, ENCODER_PIN_B);

void display_setup(LiquidCrystal_I2C &display)
{
  display.init();
  display.backlight();
}

void setup()
{
  display_setup(main_display);
}

void loop()
{
  main_display.setCursor(0, 0);
  main_display.print(screen_encoder.loop());
}

Does this not overwrite prevState regardless of whether any state change has occurred?

If the state has not changed it does not hurt anyway.

To @ningaman151 have you looked at code like

Or other esp32 specific libraries that leverage the hardware features / capabilities of the platform ?

Is a problem.

Read why, GPIO & RTC GPIO - ESP32 - — ESP-IDF Programming Guide latest documentation (espressif.com).

What is the fix? I had a skim through the link you sent but couldn't find anything about pins 32 and 33.

Thank you so much for this help.

I also tried using pins 18 and 19 with no luck.

I didn't like any of the libraries I found.

Does't make a difference.

OK... sure it's always fun to develop your own thing.

At the moment those libraries do a better job than your digitalRead though.

I use this one GitHub - madhephaestus/ESP32Encoder: A Quadrature and half quadrature PCNT peripheral driven encoder library supporting 8 encoders and it works well. Curious to hear about what you could not achieve with those libraries

Ok I tried that library but I have some doubts.

#1- What is the difference between attachHalfQuad and attachFullQuad?
#2- How do I disable the use of interrupts?
#3- Do I have to poll the encoder as fast as possible in the loop() function, is that done by calling getCount?
#4- Is the encoder debounced?

Cheers.

From the GitHub if you did not read it:

——-
ESP32Encoder library that uses the ESP32 pulse counter hardware peripheral:

https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/pcnt.html

There is only one interrupt for the peripheral, and that is managed by the library. The user has no interrupt interface, and no interrupts are generated on each pulse. Interrupts arrive when the 16 bit counter buffer overflows, so this library has a tiny interrupt footprint while providing support for up to 8 simultaneous quadrature encoders.

This hardware peripheral supports only 8 encoders.

Documentation by Doxygen

ESP32Encoder Doxygen

Pull Downs/Ups

To specify the weak pull resistor set the value useInternalWeakPullResistors with the enum types UP, DOWN, or NONE

A note on KY-040 and similar

The "switch style" encoder wheels used by breakout modules such as:

need electrical debouncing in the range of 0.1 - 2 uf per encoder line to ground. This device bounces much more than the PCNT hardware modules debouncing time limits. Be sure to setFilter() to 1023 as well after attaching in order to get the maximum hardware debouncing.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.