How to read a rotary encoder with interrupts on ESP32 and global flags

When using interrupts, any kind of digitalRead should be obsolete, or so i think. Let me explain my understanding of this to show my problem:

Say, a quadrature incremental rotary encoder (RE) is pulled up on both signal pins and is therefore idle HIGH. If i configure an interrupt service routine (ISR) on the falling edge on both pins and have the ISR for pin B do nothing more than set the flag "flag_B" to false (representing the logic state at the pin) and the ISR for pin A sets or resets a flag "flag_clockwise" depending on the state of flag_B during A's ISR, then i should get the right direction for every turning step, right? My only task is to then set the state of pin B to high again after the ISRs and my code should be ready for the next interrupt. But that doesn't work, with many random cases of the wrong direction being displayed or showing counter clockwise on the first half of the turning step when you can feel a little "bump" while turning the knob and then going clockwise on the second half, when the shaft has completed a single step, basically performing two opposite actions while only turning one step. Is my logic flawed? All signals are debounced in hardware and look like expected on the oscilloscope.

ISRs:

//re-CLK signal
void IRAM_ATTR reCLK_ISR(void){ if(myFlags->pinBstate){ //this means the first interrupt of a turning step comes from the clock, not data myFlags->direction = CCW; } else{ //this means the interrupt of a turning step occured from data first myFlags->direction = CW; }
}
//re-DATA signal
void IRAM_ATTR reDATA_ISR(void){ myFlags->pinDATAstate = false;
}

further processing:

//some function
//scroll = CW / CCW if((myFlags->direction) != STOP){ if(myFlags->direction == CW){ //DEBUG digitalWrite(PIN_LED_DEBUG, LOW); } } if(myFlags->direction == CCW){ //DEBUG digitalWrite(PIN_LED_DEBUG, HIGH); } myFlags->pinDATAstate = true; myFlags->direction = STOP; //direction has 3 states: CW, CCW and STOP }

the last 2 statements should restore all affected flags to the state before the encoder was touched, meaning ready for the next turn. The LED is just a replacement for different calculations which should be performed depending on the turning direction.

1

1 Answer

Even if the pin is assigned as interrupt, you can still use digitalRead() to determine the direction. For example:

const uint8_t pinA = 25;
const uint8_t pinB = 26;
volatile int counter;
void IRAM_ATTR isr(){ if(digitalRead(pinA) == digitalRead(pinB)) { //Clockwise counter++; } else { //Counter Clockwise counter--; }
}

You don't even need another ISR to determine the direction. I used this method to determine both the speed and the direction;

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like