Rotary Encoder Arduino Library Suggestion Needed

I’m using the SparkFun rotary encoder COM-09117 and up until now this Arduino library, ClickEncoder. However, it requires the TimerOne library which has two bugs that affect the encoder’s button use (I've updated the .h file to fix that, though). Also, when I add the code to use ClickEncoder to an existing sketch that has specific LED timings it fouls them up.

Can anyone recommend an encoder library that doesn’t use TimerOne as an interrupt? I need button press functionality in addition to the standard rotation capture.

The Arduino encoder library can read the quadrature outputs, with or without using pin change interrupts.

The button status can be read by port pin polling and does not require a timer or an interrupt.

1 Like

Sorry I do not use a library. I take an interrupt on the falling edge of one of the inputs and read the other, if high it is CW, if low it is CCW. Reversing the pins will change that and you can use either one. I use a china rotary encoder that has pull up resistors and caps for debouncing, not the KY-40. The button I treat like any button. It looks like this:
image

1 Like

Thanks! Do you have any sample code you could share?

Funny, he’s also the author of TimerOne!

A single turn using the Encoder library produces this in the serial monitor:

1
0
1
2
3
4
/* Encoder Library - NoInterrupts Example
 * http://www.pjrc.com/teensy/td_libs_Encoder.html
 *
 * This example code is in the public domain.
 */

// If you define ENCODER_DO_NOT_USE_INTERRUPTS *before* including
// Encoder, the library will never use interrupts.  This is mainly
// useful to reduce the size of the library when you are using it
// with pins that do not support interrupts.  Without interrupts,
// your program must call the read() function rapidly, or risk
// missing changes in position.
#define ENCODER_DO_NOT_USE_INTERRUPTS
#include <Encoder.h>

// Beware of Serial.print() speed.  Without interrupts, if you
// transmit too much data with Serial.print() it can slow your
// reading from Encoder.  Arduino 1.0 has improved transmit code.
// Using the fastest baud rate also helps.  Teensy has USB packet
// buffering.  But all boards can experience problems if you print
// too much and fill up buffers.

// Change these two numbers to the pins connected to your encoder.
//   With ENCODER_DO_NOT_USE_INTERRUPTS, no interrupts are ever
//   used, even if the pin has interrupt capability
Encoder myEnc(A1, A0);
//   avoid using pins with LEDs attached

void setup() {
  Serial.begin(115200);
  Serial.println("Basic NoInterrupts Test:");
}

long position  = -999;

void loop() {
  long newPos = myEnc.read();
  if (newPos != position) {
    position = newPos;
    Serial.println(position);
  }
  // With any substantial delay added, Encoder can only track
  // very slow motion.  You may uncomment this line to see
  // how badly a delay affects your encoder.
  //delay(50);
}

The rotary encoder I'm using has 12 indents. I don't think this library can handle that.

The number of indents in not relevant. You simply get more clicks per rotation potentially increasing the accuracy.

The question is how many pulses per revolution, not indents.

Please post a wiring diagram. What values are you using for required pullups?

Not using interrupts you have to turn the encoder slowly not to miss steps.
Or use interrupts, so comment the line:

#define ENCODER_DO_NOT_USE_INTERRUPTS

As I'm using the rotary encoder to manually change a motor PWM I saw in the Encoder library documentation that this would work especially as I only have pins A0/A1 available in my circuit.

Why handicap yourself? Learn to use the encoder by itself, starting with external interrupt pins for A and B channels, and add pullup resistors. Suggest 4.7K.

Using internal pull-ups and pins 0 & 1 (A-Star 32u4 Micro), I've got this working now:

volatile int number = 0;                // Testnumber, print it when it changes value,
                                        // used in loop and both interrupt routines
int oldnumber = number;

volatile boolean halfleft  = false;      // Used in both interrupt routines
volatile boolean halfright = false;


void setup(){
  Serial.begin(115200);
  while (!Serial);                       // FOR A* 32U4 ONLY!!!!!!!!!

  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);

  attachInterrupt(2, isr_pin0, FALLING);   // Call isr_pin2 when digital pin 0 goes LOW
  attachInterrupt(3, isr_pin1, FALLING);   // Call isr_pin3 when digital pin 1 goes LOW
}

void loop(){
  if(number != oldnumber){     // Change in value ?
    Serial.println(number);    // Yes, print it (or whatever)
    oldnumber = number;
  }
}

void isr_pin0(){                                          // Pin2 went LOW
  delay(1);                                               // Debounce time
  if(digitalRead(0) == LOW){                              // Pin2 still LOW ?
    if(digitalRead(1) == HIGH && halfright == false){     // -->
      halfright = true;                                   // One half click clockwise
    } 
    if(digitalRead(1) == LOW && halfleft == true){        // <--
      halfleft = false;                                   // One whole click counter-
      number--;                                           // clockwise
    }
  }
}
void isr_pin1(){                                          // Pin3 went LOW
  delay(1);                                               // Debounce time
  if(digitalRead(1) == LOW){                              // Pin3 still LOW ?
    if(digitalRead(0) == HIGH && halfleft == false){      // <--
      halfleft = true;                                    // One half  click counter-
    }                                                     // clockwise
    if(digitalRead(0) == LOW && halfright == true){       // -->
      halfright = false;                                  // One whole click clockwise
      number++;
    }
  }
}