KY-040 rotary encoder giving double steps per detent

Hi, I’m using a KY-040 rotary encoder with an Arduino and trying to get exactly one increment per physical detent

The behavior is inconsistent:

  • Sometimes 1 detent = 1 step (correct)
  • Sometimes 1 detent = 2 steps (extra trigger in the middle)
  • Sometimes it even needs 2 detents for 1 step

Here is my code:

int readRotary() {
    static int lastState = 0;
    static int8_t enc_states[] = {0,-1,1,0, 1,0,0,-1, -1,0,0,1, 0,1,-1,0};
    static int8_t accumulator = 0;

    int currentState = (digitalRead(clkPin) << 1) | digitalRead(dtPin);
    accumulator += enc_states[(lastState << 2) | currentState];
    lastState = currentState;

    if (accumulator >= 2) { accumulator = 0; return 1; }
    if (accumulator <= -2) { accumulator = 0; return -1; }
    return 0;
}

I want so that for every detent (click) there is, the function will produce only one 1 or -1

Also btw, no hardware debouncing, and I am using digitalRead() in loop

Thanks, I hope my question can be answered.

Hi, I asked ChatGPT and it gave back a solution that actually works! (for once)

int readRotary() {
    static int lastState = 0;
    static int8_t enc_states[] = {0,-1,1,0, 1,0,0,-1, -1,0,0,1, 0,1,-1,0};
    static int8_t accumulator = 0;

    int currentState = (digitalRead(clkPin) << 1) | digitalRead(dtPin);
    accumulator += enc_states[(lastState << 2) | currentState];
    lastState = currentState;

    if (accumulator >= 4) { accumulator = 0; return 1; }
    if (accumulator <= -4) { accumulator = 0; return -1; }
    return 0;
}

No need for anyone helping anymore, as this code works good. Feel free to use this code in your own projects.

I would also add a 0.1uF ceramic capacitor from clock to ground, and another from step to ground. This will help stabilise the lines from high frequency bouncing you get with any mechanical switch.

Are you sure your rotary’ encoder does not give 2 or 4 ticks per click - always ?

Try with the encoder library and see what it says.

i believe that encoder is designed to recognize just one input as a change and the other input as the direction ... per indent