rotary encoder software for arduino

Now that our rotary encoder or quadrature encoder hardware is up and running it’s time to tell our arduino what to do with the signals. We want it to count the pulses of the simple encoder. The quadrature encoder counting up and down depending on the turning direction is what we also want.

 polling or interrupt?

These are the two basic ways to read a microcontroller’s digital input. With polling you read the input all the time inside a loop. When your input changes to the desired value (e. g. from LOW to HIGH) then you do what you want, e. g. increase the variable that counts the pulses. Main problem of polling is that it is difficult to do other things while polling because you don’t want to miss any of the pulses. The controller does the only job reading the input and increasing the variable.

When using interrupts the controller does any other job (e. g. outputting data, calculating anything or whatever). When a pulse arrives from the encoder the controller stops it’s job, jumps to the interrupt routine and then returns to the job before. This way the controller is concerned with the encoder signal only when a new pulse comes. All the other time it can do other things. And your code will be much easier. So, working with interrupts is what we want.

Interrupt details

As the interrupt signal comes from outside the arduino it is called an external interrupt. In this example we take the arduino Uno R3. It has two external interrupts: int.0 on pin 2 and int.1 on pin 3. With the instruction attachInterrupt() we activate the interrupt and also declare what has to be done (call a function) and on which condition at the interrupt input this shall happen. Take a look at the arduino reference for all the details. In our example we take int.0 on pin 2, we call the function count() when the signal at the interrupt input has a rising edge.

Code for simple encoder

This sketch counts the pulses of the simple encoder. Every time the encoder sends a pulse the interrupt is activated at the rising edge of the pulse. The function count() is called and increments the counter. The counter variable must be declared as volatile, see the arduino reference. Otherwise you could miss some of the pulses. The datatype unsigned int gives you a maximum of 65535 pulses. If this is not enough you can take e. g. unsigned long (4,294,967,295 pulses max.). When you have more pulses your counter will overflow.

// The pin the encoder is connected
int encoder_in = 2;

// Initialize the counter
volatile unsigned int pulses = 0;

void count() {
  // This function is called by the interrupt
  pulses++;
}

void setup() {
  pinMode(encoder_in, INPUT);
  attachInterrupt(0, count, RISING);
}

void loop() {
  // Here you can output your counter value e. g. once a second
  //
  //
  delay(1000);
}

This is the basic code and it is really THAT easy! Now the total amount of pulses is not very handy. But when you divide it by the number of the stripes you have on your index disc you will get the number of revolutions:

// The pin the encoder is connected
int encoder_in = 2;

// The number of pulses per revolution
// depends on your index disc!!
unsigned int pulsesperturn = 36;

// The total number of revolutions
unsigned int revolutions = 0;

// Initialize the counter
volatile unsigned int pulses = 0;

void count() {
  // This function is called by the interrupt
  pulses++;
}

void setup() {
  pinMode(encoder_in, INPUT);
  attachInterrupt(0, count, RISING);
}

void loop() {
  revolutions = pulses / pulsesperturn;
  // Here you can output the revolutions, e. g. once a second
  //
  //
  delay(1000);
}

There are many other things you can do in your code. Example: When you set pulses to 0 once a second (everytime you go through the main loop) the revolutions tells you the number of revolutions per second.

Code for quadrature encoder

This is very much the same as with the simple encoder. Your quadrature encoder gives you two signals: A and B. One of them gives the pulses you count and the other tells you the turning direction. So here we go:

// The pins the quadrature encoder is connected.
// We connect the second signal of the encoder to pin 4.
// int.1 is free for other use.
int in_a = 2;
int in_b = 4;

// The number of pulses per revolution
// depends on your index disc!!
unsigned int pulsesperturn = 36;

// The total number of revolutions
int revolutions = 0;

// Initialize the counter
volatile int pulses = 0;

void count() {
  // This function is called by the interrupt
  // If in_b is HIGH increment the counter
  // otherwise decrement it
  if (digitalRead(in_b)) {
    pulses++;
  }
  else {
    pulses--;
  }
}

void setup() {
  pinMode(in_a, INPUT);
  pinMode(in_b, INPUT);
  attachInterrupt(0, count, RISING);
}

void loop() {
  revolutions = pulses / pulsesperturn
  // Here you can output the revolutions, e. g. once a second
  //
  //
  delay(1000);
}

The variables pulses and revolutions are now int (or long) because we count forth and back. So they can be positive or negative.

This is the very basic code you need. We have the hardware and the basic software up and running. Now you can upgrade it to whatever you want it to do.

Enjoy

heliosoph

5 thoughts on “rotary encoder software for arduino

  1. Uwe Kirchhoff

    Hello and Kind Regards from Germany,
    your examples have been improved my small project very much.
    Thank you very much for your efforts writing this article.
    Uwe

    Reply
  2. Eddy

    Hai,

    Can i have some instruction on how is the arduino can read the inkjet printer encoder disk without skipping pulse.

    Regards,

    Eddy

    Reply
    1. heliosoph Post author

      Hello,

      skipping pulses normally are a problem of mechanical play in your system. When the encoder is at the “edge” between black and white and you turn the wheel only a little bit forwards and backwards you will get these additional pulses. To get around this try it with a quadrature encoder and Schmitt triggers between the optocouplers and your logic.

      Regards

      heliosoph

      Reply
  3. Stanley

    Hi,
    nice tutorial.
    But nothing from these examples really work properly. I have Arduino UNO R3, encoder plate KEYES.
    This rotary encoder have output clk, dt and sw – this is a switch for momentary button, and 5+V, GND.

    I have connected clk to dig.pin 2, dt to dig.pin 3 and sw to dig.pin 4. I used I2C with 16×2 Display.
    Nothing work.

    #include
    #include
    LiquidCrystal_I2C lcd(0x27,16,2);

    int in_a = 2;
    int in_b = 3;

    // The number of pulses per revolution
    // depends on your index disc!!
    unsigned int pulsesperturn = 36;

    // The total number of revolutions
    int revolutions = 0;

    // Initialize the counter
    volatile int pulses = 0;

    void count() {
    // This function is called by the interrupt
    // If in_b is HIGH increment the counter
    // otherwise decrement it
    if (digitalRead(in_b)) {
    pulses++;
    }
    else {
    pulses–;
    }
    }

    void setup() {
    // display
    lcd.init();
    lcd.backlight();

    pinMode(in_a, INPUT);
    pinMode(in_b, INPUT);
    attachInterrupt(0, count, RISING);
    }

    void loop() {
    revolutions = pulses / pulsesperturn;
    // Here you can output the revolutions, e. g. once a second
    //
    //
    lcd.setCursor(0, 1);
    lcd.print(“state: “);
    lcd.print(revolutions);

    delay(1000);
    }

    Reply
    1. heliosoph Post author

      Hi,

      what type of encoder do you have? Regarding the names of the outputs it doesn’t look like a quadature encoder. Looks like you simply copied my sketch but I think you have to adapt it to your encoder. E. g. you connect your pin sw to digital input 4 but this input isn’t used by the sketch at all.

      Regards

      heliosoph

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

3 + 6 =