Execution time with a rotary encoder

Hi all! Having a problem with using rotary encoder. I'm updating a counter with a rotary encoder and displaying the value on a display. I'm having trouble figuring out how to read the encoder's value without being influenced by the execution time of the display (at least I believe this is what's happening).

When I turn the encoder slowly, it works great but when I go too fast, it skips some steps, like if the contact time was during the display update execution and the Arduino doesn't get it. I'm still a bit new to this so I might be in the wrong direction here :stuck_out_tongue:

Here's the sketch :

#include <U8g2lib.h>;

U8G2_SH1107_PIMORONI_128X128_F_HW_I2C u8g2(U8G2_R0, 21, 20);

bool a_value;
bool b_value;
bool a_last_value;
volatile long counter_value = 0;

void update_rotary_encoder() {
  a_value = digitalRead(2);
  b_value = digitalRead(3);

  // if the A value has changed and == 1
  if (a_value != a_last_value && a_value) {
    // check if going forward or backwards
    if (a_value != b_value) {
      counter_value++;
    } else {
      counter_value--;
    }
  }
  a_last_value = a_value;
}

void setup() {
  Serial.begin(9600);

  pinMode(2, INPUT);
  pinMode(3, INPUT);

  // setup the display
  u8g2.begin();
  u8g2.setFont(u8g2_font_6x10_mf);

  // display the initial counter value
  u8g2.clearBuffer();
  u8g2.setCursor(4, 124);
  u8g2.print(counter_value);
  u8g2.sendBuffer();

  // set the initial A value
  a_last_value = digitalRead(2);

  // set interrupts for the 2 encoder values
  attachInterrupt(digitalPinToInterrupt(2), update_rotary_encoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(3), update_rotary_encoder, CHANGE);
}

void loop() {

  // display the counter value
  u8g2.clearBuffer();
  u8g2.setCursor(4, 124);
  u8g2.print(counter_value);
  u8g2.updateDisplayArea(0, 14, 4, 2);
}

I've tried not using the interrupts and manually checking every loop for a value change but it doesn't get better.

EDIT :
I removed the second condition in the IF statement to have only

if (a_value != a_last_value) { ... }

and now it works perfectly except that it counts in doubles. I figure this is because it's now counting the start of stepping AND the end of stepping, so basically anytime the A value changes.

Any clue why the storing and comparing of the last A value would change something in the execution time enough to skip some values..?

Plot the four quadrant pulsetrain. Decide the points for upcount resp downcount.
I did that 35 years ago but the details lay too deep down in the memory.
Especially handling the logic when the direction is changed is sometimes important, sometimes not.

Well you are doing twice the amount of work for a start.

Plus this is a very poor way of reading a rotary encoder. Basically mechanical rotary bounce, but the protocol allows for an auto debounce protocol using a state machine You need a good library and I have found this one very good at doing things.

http://www.pjrc.com/teensy/td_libs_Encoder.html

Rotary encoder mechanical or optical??

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