/*
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......
Debouncing.
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()
{
Serial.begin(9600);
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) = ");
Serial.println(ButtonHoldTime);
}
static int LastEncoderPosition;
int CurrentEncoderPosition;
CurrentEncoderPosition = DoRoteryEncoder();
if (LastEncoderPosition != CurrentEncoderPosition)
{
Serial.print("EncoderPosition = ");
Serial.println(CurrentEncoderPosition);
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;
}