Sunday, December 11, 2011

Arduino + Rotary Encoders, rev2

This version of the rotary encoder code handles the random misreading and also has a 2 stage debouncer to help minimize the annoyance of the big debounce time. Here's the code:

/* 
   read a rotary encoder with interrupts
   Encoder hooked up with common to GROUND,
   encoderPinA to pin 2, encoderPinB to pin 3
   it doesn't matter which encoder pin you use for A or B  

   uses Arduino pullups on A & B channel outputs
   turning on the pullups saves having to hook up resistors 
   to the A & B channel outputs
   
   initially based on http://www.arduino.cc/playground/Main/RotaryEncoders
*/ 

#define encoderPinA 2
#define encoderPinB 3
#define interruptPin 0

const long encoderDebounce = 175;
const long encoderDebounceFast = 10;
const long encoderFastTimeout = 200;
const int encoderStepsTilFast = 2;
long nextEncoderTime = 0;
boolean encoderActive = false;
int encoderLastDirection = 0;

void setup() { 
  pinMode(encoderPinA, INPUT); 
  digitalWrite(encoderPinA, HIGH);
  pinMode(encoderPinB, INPUT); 
  digitalWrite(encoderPinB, HIGH);
  attachInterrupt(interruptPin, startEncoder, CHANGE);  // encoder pin on interrupt 0 - pin 2
  Serial.begin (9600);
  Serial.println("start");
} 

void loop() {
  if (encoderActive) {
    encoderActive = false;
    long now = millis();
    if (now > nextEncoderTime) {
      //reset fast debounce since there was a pause
      if (now > nextEncoderTime + encoderFastTimeout) {
        encoderLastDirection = 0;
      }
      int a = digitalRead(encoderPinA);
      int b = digitalRead(encoderPinB);
      int encoderDirection = 0;
      if (a == b && a == HIGH) {
        encoderDirection = 1;
      } else if (a != b && b == HIGH) {
        encoderDirection = -1;
      } else {
        encoderDirection = 0;
      }
      boolean fastMode = abs(encoderLastDirection) > encoderStepsTilFast;
      //if we get a random direction change while fast, ignore it
      if (fastMode
            && (encoderLastDirection > 0 && encoderDirection < 0
            || encoderLastDirection < 0 && encoderLastDirection > 0)) {
        encoderDirection = 0;
      }
      encoderLastDirection += encoderDirection;

      if (encoderDirection != 0) {
        nextEncoderTime = now + (fastMode ? encoderDebounceFast : encoderDebounce);
        Serial.println(encoderDirection);
      }
    }
  }

}

void startEncoder() {
  encoderActive = true;
}
Post a Comment