Good Rotary Encoder code

I was unhappy with the examples for rotary encoder code i was finding online, They were either too simple or too complex so i am sharing some code that includes things like......

Nonblocking. (dose !not hold up other code with delays)
Button hold time. (how long the button was pushed in seconds)
Dynamic min & max values, & start position for the encoder.(change values at any time)
HIDTriggerTime = Human interface time, (it saves the last time a human touched a control (for screen time out events, ect))

I hope some1 finds this useful!!!

Tested with Diymore rotary encoder

So here you go world, you can use this code as you see fit.
just copy & past this whole post into a arduino project.

// rotary encoder By Richard Greene
const int PinA = 2;// Pin A for the encoder
const int PinB = 3;// Pin B for the encoder
const int PinButton = 4;// Used for the push button
int EncoderPosition = 0;// The current position of the encoder
int EncoderMaxPosition = 10; // Max number of the encoder
int EncoderMinPosition = 0; // Min number of the encoder
unsigned long HIDTriggerTime = 0; // the last time a person touched the controls

void setup()
SetRoteryEncoder(-100,100,10);//set the (min, max, start) values of the rotery encoder

void loop()
long ButtonHoldTime = DoRoteryButton();//read the button

if (ButtonHoldTime < 0)//while the button is being held down it returns a negitive number in seconds
{//while the button is being held down code here

if (ButtonHoldTime > 0)//when the botton is released , time it was held in seconds
{//when the botton is released code here
Serial.print("Hold Time(S) = ");

static int LastEncoderPosition;
int CurrentEncoderPosition;

CurrentEncoderPosition = DoRoteryEncoder();

if (LastEncoderPosition != CurrentEncoderPosition)
Serial.print("EncoderPosition = ");
LastEncoderPosition = CurrentEncoderPosition;


long DoRoteryButton()
static unsigned long HumanInterfaceTime = 0;
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
static unsigned long lastDebounceTime = millis(); // the last time the output pin was toggled
static unsigned long ClickTime = millis();
unsigned long Back = 0;
static int buttonState = HIGH;; // the current reading from the input pin
static int lastButtonState = HIGH; // the previous reading from the input pin
int ButtonReading = digitalRead(PinButton);// read the state of the switch into a local variable:

if (ButtonReading != lastButtonState)
lastDebounceTime = millis();// reset the debouncing timer
if ((millis() - lastDebounceTime) > debounceDelay) //debounce delay
if (buttonState == LOW) // while the button is being held
Back = millis()-ClickTime;
Back = (Back / 1000 +1) ;
Back = -Back;
if (ButtonReading != buttonState) // has the button state changed
buttonState = ButtonReading;
if (buttonState == HIGH) //button Release
Back = millis() - ClickTime;
Back = (Back / 1000) + 1;
else if (buttonState == LOW) // button held down
ClickTime = millis();
HumanInterfaceTime = millis();// Keep track of when a person touched the button
lastButtonState = ButtonReading;//update last button state
return Back;

void SetRoteryEncoder(int MinIndex, int MaxIndex, int StartIndex)
EncoderMinPosition = MinIndex;
EncoderMaxPosition = MaxIndex;
EncoderPosition = StartIndex;
int DoRoteryEncoder()
bool RoteryEncoderAState;
bool RoteryEncoderBState;
static bool LastRoteryEncoderAState = digitalRead(PinA);
static bool LastRoteryEncoderBState = digitalRead(PinB);
static unsigned long LastInterruptTime = 0;
unsigned long InterruptTime = millis();

if (InterruptTime - LastInterruptTime > 1) //(debounce) if (X) amount of time has not passed then skip this
LastInterruptTime = InterruptTime;// Keep track of when we were here last for debounce loop
RoteryEncoderAState = digitalRead(PinA); // Reads the "current" state of PinA
RoteryEncoderBState = digitalRead(PinB); // Reads the "current" state of PinB

if ((RoteryEncoderAState + RoteryEncoderBState == 2) && (LastRoteryEncoderAState + LastRoteryEncoderBState != 2))// this is a test to see if you are turning the encoder to the last state
  int ChingeDir = LastRoteryEncoderBState - LastRoteryEncoderAState;//calculate the direction the encoder turned
  EncoderPosition = EncoderPosition + ChingeDir;//change the Encoder Position by 1 or -1
  EncoderPosition = min(EncoderMaxPosition, max(EncoderMinPosition, EncoderPosition));// limits the min and max size of output
  HIDTriggerTime = InterruptTime;// Keep track of when a person touched the Encoder
if ( RoteryEncoderAState != LastRoteryEncoderAState)
  LastRoteryEncoderAState = RoteryEncoderAState;// Update the last state
if ( RoteryEncoderBState != LastRoteryEncoderBState)
  LastRoteryEncoderBState = RoteryEncoderBState;// Update the last state

return EncoderPosition;

Hello, do yourself a favour and please read How to get the best out of this forum and modify your post accordingly (including code tags).


I would recommend this encoder library

Does this Libary runs with serval encoders?

the Encoder library available in Library Manager is good

Yes (if the question was about my link)

Encoders have 2 signals, which must be connected to 2 pins. There are three options.

  1. Best Performance: Both signals connect to interrupt pins.
  2. Good Performance: First signal connects to an interrupt pin, second to a non-interrupt pin.
  3. Low Performance: Both signals connect to non-interrupt pins, details below.

Thank you for your detailed reply.