Encoder library jumping 4

After fiddling around with interrupts and encoders, i came across this great little encoder library.


the only trouble is each ‘notch’ of the encoder increases the value by 4.

#include <Encoder.h>
Encoder myEnc(4, 5);

void setup() {
Serial.println(“Basic Encoder Test:”);

long oldPosition = -999;

void loop() {
long newPosition = myEnc.read();
if (newPosition != oldPosition) {

oldPosition = newPosition;

is there an easy way to fix this?

is there an easy way to fix this?

Since you know what to expect, what is the problem?

the only trouble is each 'notch' of the encoder increases the value by 4.

is there an easy way to fix this?

See if reading this might help you see what's happening:

Note how there are four states...

Since you know what to expect, what is the problem?

since your comment has no suggestions, information or value, why did you bother to reply? :smiley:

since your comment has no suggestions, information or value, why did you bother to reply?

To encourage you to tell us why incrementing by 4 is a problem. If the encoder consistently increments by 4, I do not see that you have a problem.

I want to set a value using a rotary encoder. using the library as is means I can only set the value to a multiple of four.

I understand that the library must be counting the rise/fall from each pin, of which there are four in each notch of the encoder.

I seem to be able to achieve a value that increments by one using the code below.
(I'm only triggering the interrupt on one pin when the value falls)

But it doesn't seem as neat as using the library. So can is there a way to do this with the library?

int reading;
int previous = LOW;
const int PinCLK = 4;
const int PinDT = 5;
volatile boolean encChanged;
volatile long encPosition = 62;

void setup()
Serial.println("Basic Encoder Test:");
pinMode(PinCLK, INPUT);
pinMode(PinDT, INPUT);
attachInterrupt(PinCLK, rotary, FALLING);

void loop()
if (encChanged)
encChanged = false;
static unsigned long SpamTimerSerial;

void rotary()

if (digitalRead(PinDT))
encPosition = min(100, max(0, encPosition));
encChanged = true;

I still want to know what is wrong with counting the ticks you get from the library, and dividing by 4. If you can't turn the encoder less than an amount that generates 4 clicks, how will getting the clicks more often be useful?

Okay, I just ran into this. As far as suggestions to simply divide by 4 go, for starters, how about just bad form from a UX perspective?

Consider this, as stated above, there are 4 states to a rotary encoder, this is why you're seeing increments of 4, the library is counting every change in state. Fiddling with a sketch, TFT display, a rotary encoder and an Amica, I found that I could very easily increment by something other than 4 rocking the encoder back and forth around a detent without actually moving to an adjacent detent.

A good rule of thumb to keep in mind is users are living their lives to fulfill their life's purpose, not make sure your code executes correctly. If you have any sort of knob on a panel with detents, bet real money at some point, somebody somewhere will put it in between the detents. That said, here a quick breakdown of my fix.

Add a long variable, for clarity we'll call it rPosition, up in the init section set to 0.
In the if section in the loop for oldPosition != newPosition, check if its less than or greater than with a nested if and increment your rPosition variable. This way you an increment by any value you like, and work in min/max caps, roll overs (at a min value go to max, at a max value go to min), detect direction of rotation, etc.

You can even set a minimum change value in to decide whether or not to increment and take some of the bounciness out of it. Think of real word scenarios like a volume, EQ and track position in an MP3 player. Volume would be 0 to 100, incrementing by 1 and not roll over. The EQ bands might be -15 to +15 incrementing by 3 and track position would be 0 to the length of a given track, incrementing by 1 second to the end of the track and then resetting to 0 with a call to go to the next track and setting a new max.

As for all the snarky, condescending responders, knock it off. You're not helpful, just rude.

Nobody has been condescending except for you. It has been suggested that you do what most everyone else does in this situation. I don't see how that suggestion is snarky or unhelpful just because you didn't like it. You need to get over yourself a little, remember that we don't live to serve you, remember that this is the Internet and anyone can post anything they like, and see if we can't solve your problem.

One way is to simply divide by 4. That's what most people do. The other option is to only consider one edge on one pin instead of both rising and falling edges on both pins. There you will get single ticks.

Bitching at someone for asking questions to try to understand why you don't just do things the normal way isn't going to do anything but cause people to start ignoring your threads and then you'll get zero help. Is that what you want?

I'm running into this same issue right now. I've been dividing by 4 to return the right count.

Question: Why on the Encoder.h webpage does it show the examples changing by a value of 1 - ??

That's very confusing. The guy is running Teensy boards, not Arduinos, so maybe that's the difference?

Why on the Encoder.h webpage does it show the examples changing by a value of 1

This issue relates to the specific encoder and the relationship of the mechanical detents to internal encoder switches.

Some encoders have no detents, some have a detent every 4 internal transitions, some have a detent at every internal transition.

The two main types of rotary encoders with detents are those that step half a quadrature cycle between detents and those that step a full quadrature cycle between detents. You might try this library that handles both types: GitHub - gfvalvo/NewEncoder: Rotary Encoder Library. It uses a state-table based approach and lets you select which type of encoder you're using. This technique inherently provides de-bouncing also. However, this library only works with pins that are capable of triggering external interrupts (i.e. able to support 'attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);'). This is all explained in the README which you should read thoroughly. There are a couple example programs.

@gfvalvo: Your library looks very interesting. Thanks for sharing that!