EC11 code

Hi all,

I spent a lot of time trying to read an EC11 rotary encoder, all code I found did not satisfy my idea of a truly reactive device, so I finally wrote my own code. Of course it uses 2 pins but only one pin with attached interrupts, the second one doesn't need interrupts; I found that useful, as they are not plethoric (with Uno and Nano33IoT I used). The code is compact and reactive enough for me, without reading errors or missing increment. Probably perfectible, comments are welcome.
Hope to be useful

/*  Arduino Rotary Encoder Tester
 *  -----------------------------
 *  by O.Seston
 */
 
#define encoderPinA 3
#define encoderPinB 4

volatile int count;

void setup() { 
  pinMode (encoderPinA, INPUT);
  pinMode (encoderPinB, INPUT);
  attachInterrupt(digitalPinToInterrupt(encoderPinA), pulseFromA, CHANGE);   
  Serial.begin (9600);
} 

void loop() {
  static int lastCount, lastDelta;
  if (count != lastCount){
    if ((count - lastCount) * lastDelta < 1)
      Serial.println("**********");
    lastDelta = count - lastCount;
    lastCount = count;
    Serial.print("New count: ");
    Serial.println(lastCount);
  }
}

void pulseFromA(){
  // It seems that we get better results with a little delay before reading pins,
  // probably because of the stabilization delay of the signal.
  // Also 4.7K pull-down resistors give better results than 10K and not better than 1K.
  delayMicroseconds(50);
  
  // We combine outputA and outputB of the encoder state to get a number between 0 and 3
  // This number is used later to recognize valid sequences:
  // - 2 (A high and B low) then 1 (A low and B high) --> increment (clockwise)
  // - 3 (A high and B high) then 0 (A low and B low) --> decrement (anticlockwise)
  byte state = ((digitalRead(encoderPinA) << 1) + digitalRead(encoderPinB));

  // The starting sequence signals are saved in 2 bytes, because there can be several
  // different consecutive start (this is noise of course),
  // but at the moment we don't know which is the right one (we'll know that when
  // we get the right closing state).
  static byte start[2];

if (state >= 2) {                         // Save a starting sequence (2 or 3)
    start[state - 2] = 1;
  } else if (start[0] && state == 1) {    // 2 (A high and B low) then 1 (A low and B high)
    count++;
    start[0] = start[1] = 0;
  } else if (start[1] && !state) {        // 3 (A high and B high) then 0 (A low and B low)
    count--;
    start[0] = start[1] = 0;
  }
}

I omitted to tell that my wiring was not the more conventional, I had connected the +of power supply instead of the ground. To be more classic I connected the ground like said in literature and modified slightly the code:

/*  Arduino Rotary Encoder Tester
 *  -----------------------------
 *  by O.Seston
 */
 
#define encoderPinA 9
#define encoderPinB 10

volatile int count;

void setup() { 
  pinMode (encoderPinA, INPUT_PULLUP);
  pinMode (encoderPinB, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(encoderPinA), pulseFromA, CHANGE);   
  Serial.begin (9600);
} 

void loop() {
  static int lastCount, lastDelta;
  if (count != lastCount){
    if ((count - lastCount) * lastDelta < 1)
      Serial.println("**********");
    lastDelta = count - lastCount;
    lastCount = count;
    Serial.print("New count: ");
    Serial.println(lastCount);
  }
}

void pulseFromA(){
  // It seems that we get better results with a little delay before reading pins,
  // probably because of the stabilization delay of the signal.
  // The value must be compatible with the rest of the program and the desired reactivity...
  delayMicroseconds(50);
  
  // We combine outputA and outputB of the encoder state to get a number between 0 and 3
  // This number is used later to recognize valid sequences:
  // - 0 (A low and B low) then 3 (A high and B high) --> decrement (anticlockwise)
  // - 1 (A low and B high) then 2 (A high and B low) --> increment (clockwise)
  byte state = ((digitalRead(encoderPinA) << 1) + digitalRead(encoderPinB));

  // The starting sequence signals are saved in 2 bytes, because there can be several
  // different consecutive start (this is noise of course),
  // but at the moment we don't know which is the right one (we'll know that when
  // we get the right closing state).
  static byte start[2];

  if (state < 2) {                        // Save a starting sequence (0 or 1)
    start[state] = 1;
  } else if (start[0] && state == 3) {    // 0 (A low and B low) then 3 (A high and B high)
    count--;
    start[0] = start[1] = 0;
  } else if (start[1] && state == 2) {    // 1 (A low and B high) then 2 (A high and B low)
    count++;
    start[0] = start[1] = 0;
  }
}