Grove rotary encoder incorrect readings

I tried FastInterruptEncoder first, I needed to hack it a bit to compile on a ESP32C6.

It’s not very well documented (or at all). When I set the switch type to SINGLE, it increments or decrements by 1-2 per detent. HALFQUAD or FULLQUAD, the number is incremented or decremented by exactly 4 per detent, even with glitch filter set to 250 (ns?). Sometimes those are a bit slow and cross the 300ms printout, so I might see it go from 60 to 63 and then 64, with one detent, but it always ends up being 4. I wonder if this encoder simply has 4 encodings per detent?

As my end-goal is not to maintain an internal numeric state that is incremented or decremented by the encoder, but to send up/down messages to a remote Zigbee device, I wonder how useful it is to use the hardware counter. Of course I could then hack this by checking if the number has incremented or decremented in a loop, but that seems backwards and I’d have to deal with integer overruns, rather than just have up/down events in the first place. Maybe I should go back to the interrupt method and figure out why that’s giving 4-6 readings per detent.

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

#define PIN_ROTARY_A 18
#define PIN_ROTARY_B 20

#define ENCODER_READ_DELAY 300

volatile uint8_t encoderLastState = 0;

Encoder enc(PIN_ROTARY_A, PIN_ROTARY_B, SINGLE /* or HALFQUAD or FULLQUAD */, 250 /* Noise and Debounce Filter (default 0) */);
unsigned long encodertimer = 0;

/* create a hardware timer */
hw_timer_t* timer = NULL;

void IRAM_ATTR Update_IT_callback()
{
  enc.loop();
}

void setup(void)
{
  Serial.begin();
  Serial.print("started\n");

  if (!enc.init()) {
    Serial.println("Encoder Initialization Failed");
    while (1)
      ;
  }

  if ((timer = timerBegin(1000000)) == NULL) {
    Serial.println("Timer setup failed");
    while (1)
      ;
  }
  /* Attach onTimer function to our timer */
  timerAttachInterrupt(timer, &Update_IT_callback);
  /* Set alarm to call onTimer function every 100 ms -> 100 Hz */
  timerAlarm(timer, 100000, true, 0);
}

void loop()
{
  if ((unsigned long)ENCODER_READ_DELAY < (unsigned long)(millis() - encodertimer)) {
    Serial.println(enc.getTicks());
    encodertimer = millis();
  }
}

Had to amend their timer example to work on the esp32c6 but it seems to fire okay. Also had to change the library code for esp32c6.

1 Like