Shopping Cart

Posts

Reading rotary encoder on Arduino

Rotary encoder connected to Arduino

Rotary encoder connected to Arduino


Quadrature rotary encoders, also known as rotary pulse generators, are popular input devices for embedded platforms, including Arduino. Several rotary encoder code examples are posted on Arduino site and elsewhere, however, they treat encoder as a pair of switches, adding decoding/debouncing overhead. For many years, I used an algorithm based on the fact that quadrature encoder is a Gray code generator and if treated as such, can be read reliably in 3 straight step without need for debouncing. As a result, the code I’m using is very fast and simple, works very well with cheap low-quality encoders, but is somewhat cryptic and difficult to understand. Soon after posting one of my projects where I used rotary encoder to set motor speed i started receiving e-mails asking to explain the code. This article is a summary of my replies – I’m presenting small example written for the purpose of illustrating my method. I’m also going through the code highlighting important parts.

The hardware setup can be seen on title picture. The encoder from Sparkfun is connected to a vintage Atmega168-based Arduino Pro. Common pin of the encoder is connected to ground, pins A and B are connected to pins 14 and 15, AKA Analog pins 0 and 1, configured as digital inputs. We also need a serial connection to the PC to receive power, program the Arduino, and send program output to the terminal. For this purpose, Sparkfun FTDI basic breakout is used.

Connecting encoder pins to pins 0 and 1 of 8-bit MCU port makes encoder reading code very simple. If analog pins are needed for something else, it is possible to move encoder to digital pins 8,9 or 0,1 (losing serial port) with no modification of code logic. While technically using any two consecutive port pins is possible with a bit of tweaking, using non-consecutive pins for encoder input with this method is not recommended. Lastly, it sometimes hard to determine which encoder pin is A and which is B; it is easier to connect them at random and if direction is wrong, swap the pins.

Example code is posted below. It is complete sketch – you can copy it from this page and paste into Arduino IDE window, compile, upload and run. The result of rotating the encoder can be seen in terminal window. Note that serial speed in the sketch is set to 115200, you will need to set your PC terminal to that speed as well. The explanation of the code is given after the listing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/* Rotary encoder read example */
#define ENC_A 14
#define ENC_B 15
#define ENC_PORT PINC
 
void setup()
{
  /* Setup encoder pins as inputs */
  pinMode(ENC_A, INPUT);
  digitalWrite(ENC_A, HIGH);
  pinMode(ENC_B, INPUT);
  digitalWrite(ENC_B, HIGH);
  Serial.begin (115200);
  Serial.println("Start");
}
 
void loop()
{
 static uint8_t counter = 0;      //this variable will be changed by encoder input
 int8_t tmpdata;
 /**/
  tmpdata = read_encoder();
  if( tmpdata ) {
    Serial.print("Counter value: ");
    Serial.println(counter, DEC);
    counter += tmpdata;
  }
}
 
/* returns change in encoder state (-1,0,1) */
int8_t read_encoder()
{
  static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
  static uint8_t old_AB = 0;
  /**/
  old_AB <<= 2;                   //remember previous state
  old_AB |= ( ENC_PORT & 0x03 );  //add current state
  return ( enc_states[( old_AB & 0x0f )]);
}

First three #defines set names for port pins. This way, if you want to use different pins for your encoder, you can do it here without sifting through code looking for pin names. If you’d like to move encoder pins to Arduino pins 8 and 9, ENC_PORT shall be defined as PINB, and for pins 0,1 as PIND.

In setup() function hardware is initialized. pinMode sets the pin as input so we can read it and digitalWrite turns on pull-up resistor on the pin so it won’t dangle in the air when switch is open. Finally, the serial port is initialized and message is printed as an indicator that port is working – if you can’t see “Start” on your terminal screen, check PC port settings.

Let’s go down to line 30, where read_encoder() function starts. enc_states[] array is a look-up table; it is pre-filled with encoder states, with “-1″ or “1″ being valid states and “0″ being invalid. We know that there can be only two valid combination of previous and current readings of the encoder – one for the step in a clockwise direction, another one for counterclockwise. Anything else, whether it’s encoder that didn’t move between reads or an incorrect combination due to switch bouncing, is reported as zero.

Note that old_AB is declared static. This means that it’s value will be retained between function calls therefore previous encoder reading will be preserved. When function is called, old_AB gets shifted left two times (line 36) saving previous reading and setting two lower bits to “0″ so the current reading can be correctly ORed here. Then ENC_PORT & 0×03 reads the port to which encoder is connected and sets all but two lower bits to zero so when you OR it with old_AB bits 2-7 would stay intact. Then it gets ORed with old_AB (line 37, old_AB |= ( ENC_PORT & 0×03 )). At this point, we have previous reading of encoder pins in bits 2,3 of old_AB, current readings in bits 0,1, and together they form index of (AKA pointer to) enc_states[] array element containing current state – either increment, decrement, or no change. All that is left to do is return this state to the calling function, and line 38 does just that. Upper half of old_AB gets zeroed by old_AB & 0x0f – if we don’t do this, we will be reading memory past enc_states[] array.

The above paragraph was pretty long explanation for mere 5 lines of code (counting two declarations); if you are reading this, 98% of work is done. The rest of the code is very easy. We are now moving up to line 17, where loop() function is residing. counter variable is the one which is modified by encoder and tmpdata is used to hold the reading. On line 22, encoder is read. If encoder state has changed, i.e., read_encoder() returned non-zero, current value of counter variable is printed and then counter is updated with tmpdata. This is done within conditional statement on lines 22-27. The loop then ends and starts again.

Now let’s briefly talk about real-life applications of this method. If you’re using Sparkfun encoder, you’ll notice that it gives 4 increments per click and it’s impossible to make it hold position between clicks. Therefore, to count clicks you will need to divide counter variable by 4. Also, if counter larger than 255 is necessary, the declaration for it would have to be changed to uint16_t or longer. Another nice modification, left out to keep code simple, would be to move enc_states[] array to program memory using PROGMEM type saving several bytes of precious RAM.

Rotary encoder singing out of tune

Rotary encoder singing out of tune


In order for this method to work well, read_encoder() function needs to be called fairly often . To see what happens when loop is slow, lower serial port speed – go to line 13, change “115200″ to “9600″, recompile the sketch and run (don’t forget to reconfigure the terminal on PC side). Picture on the left shows the result. Note that encoder goes down from 237 to 229, then jumps up to 230, then continues going down. Sometimes it counts correctly but gives 2 or 3 states per click instead of 4. Instabilities like this are good indication of slow loop. If encoder is used to things like setting motor speed or sound volume, this behavior won’t do much harm because encoder will never skip back more than one state and overall counting would still be in the right direction. However, if encoder is used for interfacing with display, glitches like that are very annoying. Therefore, for user interface applications, loop time should be kept short and in some cases it may be even necessary to convert encoder reading function into interrupt service routine. Given the size and speed of encoder read function, such conversion can be done without much difficulty.

To summarize: I presented a method to convert quadrature rotary encoder output into direction information using look-up table. The method makes debouncing unnecessary, and as a result, conversion function implemented with this method is very short, fast, and works very well on small 8-bit MCU platforms, such as Arduino.

Oleg.
[EDIT] I posted a new article describing reading an encoder from an ISR.

No related posts.

220 comments to Reading rotary encoder on Arduino

  • Ok thanks a lot – that is really helpful. But as soon as I integrated this code with some more complex code I have using pulseIn() function to understand the input of a standard RC receiver, and a motor driver controlling two motors, the encoder seems totally incorrect: When I had the the same functions working on the encoder, I was getting super clean values. But when I had more code and the encoder stuff running side by side, my counter values are totally off (see below, when spinning the encoder round and round) . So it seems like the timing is totally not working –
    I’m wondering what I might be doing wrong because nothing too “high level” is happening in my code, and I took out all my “println”s.

    I can attach my code if that’d be helpful, but was wondering your thoughts / experience (re using 2 encoders with some other processes going on in Arduino UNO)
    Thank you so so much again for all the help and explanation.

    ¾ÖŸReady
    Counter value2: 0
    Counter value2: 255
    Counter value2: 0
    Counter value2: 255
    Counter value2: 0
    Counter value2: 255
    Counter value2: 0
    Counter value2: 255
    Counter value2: 0
    Counter value2: 255
    Counter value2: 254
    Counter value2: 253
    Counter value2: 254
    Counter value2: 253
    Counter value2: 252
    Counter value2: 251
    Counter value2: 252
    Counter value2: 251
    Counter value2: 252
    Counter value2: 251
    Counter value2: 252
    Counter value2: 251
    Counter value2: 252
    Counter value2: 251
    Counter value2: 252
    Counter value2: 253
    Counter value2: 252
    Counter value2: 251
    Counter value2: 252
    Counter value2: 251
    Counter value2: 250

  • Hm. Yea I commented everything out and the encoders work great. When I add back in stuff to read the receiver , that’s the point at which the encoders seem to stop working:

    Channel2Value = pulseIn (RX1, HIGH, 20000); //read RC channel 2

    Channel1Value = pulseIn (RX3, HIGH, 20000); //read RC channel 2
    // Serial.print(” motor_body : “);

    I’m wondering what you mean by the code is blocking somewhere… or what a “fix” would be ? ?

    Thanks a lot again

    • Blocking is when a piece of code is waiting for some event to happen, interrupting the flow of execution of the main loop. For example, delay() is blocking; the program won’t continue until time specified as delay has expired. If you have a delay of one second in your main loop, you can rotate your encoder full circle and miss every pulse.

      Fixing means finding blocking code and writing it differently. What does ’20000′ mean in pulseIn?

  • Ok I guess I have to use an interrupt? I wanted to be able to use Arduino UNO with the two encoders. Would there be a way to use two encoders with Arduino UNO , even if the two default interupt pins are 2 and 3?
    the third parameter (20000) is the time out in microseconds.

    just fyi, PulseIN() : Reads a pulse (either HIGH or LOW) on a pin. For example, if value is HIGH, pulseIn() waits for the pin to go HIGH, starts timing, then waits for the pin to go LOW and stops timing. Returns the length of the pulse in microseconds. Gives up and returns 0 if no pulse starts within a specified time out. so it seems the problem is it “delays” and waits (ie blocking)

  • Hi Oleg

    I really appreciate your tutorials, they are great and am wondering if you could put me in the right direction as I am building a bi-directional people sensor and counter in a room using two infrared sensors (S1 and S2).What I want is the first sequence on breaking S1 and S2 the change should signal entry and increment a counter whilst breaking the beam in the second sequence S2 first and S1 will signal exit and decrement a counter and display the count value on a 3 digit 7 segment display.
    I have thought of using the idea of reading two rotary encoder using external interrupts on an arduino. Is this the right way to go??

    Much Thanks.

    Steffano.

  • Hi Oleg,

    Please could you kindly elaborate on what you mean by coding the sensor states directly?since it’s a sequence.
    am using IR sensors with make and break beam.I will appreciate any more information.

    Thank you.
    Staffano.

  • Hi Oleg,

    This is the far have come so far and am serial printing the counts. Any idea how I could hold old value and update this old value with the current val count to a 3 digit seven segment display? depending on how the sensors are tripped? Any correction or suggestions am very willing to learn

    int counter, S1_SIG=0, S2_SIG=1;

    void setup(){
    attachInterrupt(0, S1_RISE, RISING);//hooked to pin2 on mega 2560
    attachInterrupt(1, S2_RISE, RISING);//hooked to pin3
    Serial.begin(115200);
    }//setup

    void loop(){

    }

    void S1_RISE(){
    detachInterrupt(0);
    S1_SIG=1;

    if(S2_SIG==0)
    counter++;//entry
    if(S2_SIG==1)
    counter–;//exit
    Serial.println(counter);
    attachInterrupt(0, S1_FALL, FALLING);
    }

    void S1_FALL(){
    detachInterrupt(0);
    S1_SIG=0;

    if(S2_SIG==1)
    counter++;//entry
    if(S2_SIG==0)
    counter–;//exit
    Serial.println(counter);
    attachInterrupt(0, S1_RISE, RISING);
    }

    void S2_RISE(){
    detachInterrupt(1);
    S2_SIG=1;

    if(S1_SIG==1)
    counter++;//entry
    if(S1_SIG==0)
    counter–;//exit
    Serial.println(counter);
    attachInterrupt(1, S2_FALL, FALLING);
    }

    void S2_FALL(){
    detachInterrupt(1);
    S2_SIG=0;

    if(S1_SIG==0)
    counter++;//entry
    if(S1_SIG==1)
    counter–;//exit
    Serial.println(counter);
    attachInterrupt(1, S2_RISE, RISING);
    }

    Steffano

  • steffano

    I managed to do my 2 ISR for the two sensors and the 3 digit seven segment display, however the only problem have got is when my sensors are broken at first the count goes negative for 2 or 3 cycles then comes to positive(normal) does anyone have an idea how to correct this??please. I have declared static int i in loop.

  • Windsor

    Hi, thanks for the great tutorial. I adapted your code (with minor changes) to run on an STM32F100B (ARM) micro. Works flawlessly with my encoder without the need for any hardware debouncing circuitry!

  • Josh

    Hi Mr. Oleg,
    Good day to you and thanks for the great effort helping a rookie like me to start with the arduino, I have tried your code using Uno and it works flawlessly but when i tried it using the Leonardo, it didn’t work, wandering what could be the problem.

  • Josh

    Hi Mr. Oleg,
    Below is the code I used with Uno and Leonardo, it works with Uno but not with Leonardo.

    /* Rotary encoder read example */
    #define ENC_A 14
    #define ENC_B 15
    #define ENC_PORT PINC
    // constants won’t change. They’re used here to
    // set pin numbers:
    const int buttonPin = 2; // the number of the pushbutton pin
    const int ledPin = 13; // the number of the LED pin

    // variables will change:
    int buttonState = 0; // variable for reading the pushbutton status
    int switch0=0;
    void setup() {
    /* Setup encoder pins as inputs */
    pinMode(ENC_A, INPUT);
    digitalWrite(ENC_A, HIGH);
    pinMode(ENC_B, INPUT);
    digitalWrite(ENC_B, HIGH);

    // initialize serial communication at 9600 bits per second:
    Serial.begin(115200);
    Serial.println(“Start”);
    delay(1);
    // initialize the LED pin as an output:
    pinMode(ledPin, OUTPUT);
    // initialize the pushbutton pin as an input:
    pinMode(buttonPin, INPUT);
    }

    void loop(){
    static uint8_t counter = 0; //this variable will be changed by encoder input
    int8_t tmpdata;
    /**/
    tmpdata = read_encoder();
    if( tmpdata ) {
    Serial.print(“Counter value: “);
    Serial.println(counter, DEC);
    counter += tmpdata;
    }
    // read the state of the pushbutton value:
    buttonState = digitalRead(buttonPin);

    // check if the pushbutton is pressed.
    // if it is, the buttonState is HIGH:
    if (buttonState == LOW) {
    // turn LED on:
    digitalWrite(ledPin, HIGH);
    // print out the state of the button:
    if (switch0 == 0){
    Serial.print(“Pinindot”);
    delay(1);
    Serial.println(buttonState);
    delay(1); // delay in between reads for stability
    switch0=1;
    }
    }
    else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
    if (switch0==1){
    Serial.print(“Pinindot”);
    delay(1);
    Serial.println(buttonState);
    delay(1); // delay in between reads for stability
    switch0=0;
    }
    }
    }

    /* returns change in encoder state (-1,0,1) */
    int8_t read_encoder()
    {
    static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
    static uint8_t old_AB = 0;
    /**/
    old_AB <<= 2; //remember previous state
    old_AB |= ( ENC_PORT & 0×03 ); //add current state
    return ( enc_states[( old_AB & 0x0f )]);
    }

  • Josh

    The debounce did not work for me but instead I used the switch which is perfect. The only output shown in the Serial Monitor is when the switch is being pressed but not the encoder, I am using an encoder with a switch.

  • Mike

    Ok, I get it and I like it a lot. The only thing that I cannot figure out is how to keep it from going from 255 to 0 or from 0 to 255. Is there a way that I can stop it from overflowing the register and just park it at max or min until the user decreases the value?

  • alwerner

    Using two or more encoder with the Arduino ?

    It all depends on the total of tasks being performed by the Arduino, and the number of
    pulses received by the processor.

    Say for example you have a small slow moving xy table, with 2 rotary US Digital encoders generating say 4000 pulses per second and driving two stepper motors with an “Easydriver” board you would soon be running out of head room on your project.

    My suggestions would be to use, two Tiny13 chips from Atmel to encode the rotary encoders, and than feed the resultant signal into your Arduino, where it will give an excellent performance. In my humble opnion it may even support three channels, XY and Z.

    You would need some machine code experience to do this, but this would be worth learning.

    Good luck.

  • Seif

    Hi,

    Thank you for this great useful article… I’m wondering if I can use you idea with Arduino Uno?? I mean to use the rotary encoder with Arduino Uno in order to select the power of my RC car which I’m building…

    thanx again

  • Salvatore Aiello

    Hi,
    Sweet bit of code! I am using it in a project at work, using the encoder to display a motor speed selection on a seven segment display and it works very nicely indeed. Once you remove the serial.print commands it is difficult to spin the bare encoder shaft quickly enough to generate a misread. With a suitably sized knob on the shaft it is going to slow rotation speed and make it virtually impossible for the casual operator to get an erroneous reading… ;)

    Thanks!

  • Marco

    Hi, very nice job
    my R2D2 Dome’s encoder sensor has 3 output, one of them reads just one special dent on the motor gear, like a ZERO POSITION.
    How can I implement it in the code?
    Also How can I make encoders count to 36 or +18 to -18?
    Thanks just learning here

  • Alex

    Here is the code with zero position and 3 outputs.

    int counter, S1_SIG=0, S2_SIG=1, S3_SIG=1;
    bool firstinit = false;

    void setup()
    {
    attachInterrupt(0, S1_RISE, RISING);//hooked to pin2 on mega 2560
    attachInterrupt(1, S2_RISE, RISING);//hooked to pin3
    attachInterrupt(2, S3_RISE, RISING);//hooked to pin21
    Serial.begin(115200);
    }//setup

    void loop()
    {

    }

    void S1_RISE()
    {
    detachInterrupt(0);
    S1_SIG=1;

    if(S2_SIG==0)
    counter++; //entry
    if(S2_SIG==1)
    counter–; //exit
    Serial.println(counter);
    attachInterrupt(0, S1_FALL, FALLING);
    }

    void S1_FALL()
    {
    detachInterrupt(0);
    S1_SIG=0;

    if(S2_SIG==1)
    counter++; //entry
    if(S2_SIG==0)
    counter–; //exit
    Serial.println(counter);
    attachInterrupt(0, S1_RISE, RISING);
    }

    void S2_RISE()
    {
    detachInterrupt(1);
    S2_SIG=1;

    if(S1_SIG==1)
    counter++;//entry
    if(S1_SIG==0)
    counter–;//exit
    // Serial.println(counter);
    attachInterrupt(1, S2_FALL, FALLING);
    }

    void S2_FALL()
    {
    detachInterrupt(1);
    S2_SIG=0;

    if(S1_SIG==0)
    counter++; //entry
    if(S1_SIG==1)
    counter–; //exit
    Serial.println(counter);
    attachInterrupt(1, S2_RISE, RISING);
    }

    void S3_RISE()
    {
    S3_SIG = 1;
    detachInterrupt(2);

    if (!firstinit && (( S2_SIG==1 && S1_SIG==1) || (S1_SIG==0 && S2_SIG==1)))
    {
    counter=0;
    firstinit = true;
    }

    attachInterrupt(2, S3_FALL, FALLING);
    }

    void S3_FALL()
    {
    S3_SIG = 0;
    detachInterrupt(2);

    if ( !firstinit && (( S2_SIG==1 && S1_SIG==1) || (S1_SIG==1 && S2_SIG==0)))
    {
    counter=0;
    firstinit = true;
    }

    attachInterrupt(2, S3_RISE, RISING);
    }

  • Marty

    I am new to Arduinos and am starting to play with them. I have seen many examples of rotary encoder code. But non that use the Leonardo to output key press commands when rotated. My application is a small CNC vertical machining center. The control itself can not accept a rotary encoder (manual pulse generator) The control is PC based. It CAN accept key presses, for example, to move the table in these directions:
    X+ Ctrl + Right Arrow Key
    X- Ctrl + Left Arrow Key
    Y+ Ctrl + Up Arrow Key
    Y- Ctrl + Down Arrow Key
    Z+ Ctrl + Page Up Key
    Z- Ctrl + Page Down Key
    A+ Ctrl + Plus (+) Key
    A- Ctrl + Minus (-) Key

    I can make it work with out a Ctrl key press, but better to have the combination if possible. I was thinking of using a 4 position rotary switch. Each position would be for each axis, X,Y,Z and A. When the switch is in the proper position, then depending on which direction the MPG handwheel was turned, Leonardo would send the appropriate keyboard character via the PC’s USB port. One keypress for each pulse of the MPG hand wheel. It is a 100PPR hand wheel.

    Is this doable and might someone be able to help cut my learning curve down with an example of the code? Thanks!

  • faultymonk

    Just as a note to people trying to use a Leonardo (or Micro), the code example will work if you use:

    #define ENC_A A4
    #define ENC_B A5
    #define ENC_PORT PINF

  • Ron

    You mention this:
    “… Sparkfun encoder, you’ll notice that it gives 4 increments per click and it’s impossible to make it hold position between clicks. Therefore, to count clicks you will need to divide counter variable by 4″

    My Quadrature encoders are giving 2 counts per click. Would you mind a quick lesson on just how to do this, since the variable isn’t a decimal number?

    Many thanks! Your code is forcing me to “dig in” and learn more than just the “simple” programming, as given on the Arduino site examples… which is what “teaching” is all about!

  • Ron

    I got it… one of those “doh!” moments… sorry!

  • Ron

    (with regard to the solution for 24-pos encoder which gives 2 pulses per “click”)

    What happens when I bitwise shift(1bit) right a negative number, as when I’m turning CCW?
    Does the ‘sign’ bit stay where it’s supposed to?

    I’m getting very different results CW from CCW.

    • You don’t shift numbers, you shift bytes. When you right shift the leftmost bit becomes zero. If this bit represented a sign, it will be gone.

    • If your encoder clicks every second pulse you can determine a click position without dividing. Even increments will have zero in bit 0 and odd increments will have one. This is true for both signed and unsigned representations. Also, checking single bit, like if( count & 0x01 ) { ..., could be faster than shifting.

  • fbonan

    Thanks Oleg, this sample is great and save me years : )
    Many requested a complete working example with 2 encoders, here it is:

    #define ENC_1_A A0
    #define ENC_1_B A1

    #define ENC_2_A A2
    #define ENC_2_B A3

    int encoder_1_value = 0;
    int encoder_2_value = 0;

    static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};

    void setup() {
    /* Setup encoder pins as inputs */
    pinMode(ENC_1_A, INPUT);
    digitalWrite(ENC_1_A, HIGH);
    pinMode(ENC_1_B, INPUT);
    digitalWrite(ENC_1_B, HIGH);

    /* Setup encoder pins as inputs */
    pinMode(ENC_2_A, INPUT);
    digitalWrite(ENC_2_A, HIGH);
    pinMode(ENC_2_B, INPUT);
    digitalWrite(ENC_2_B, HIGH);

    Serial.begin (115200);
    Serial.println(“************ Start *************”);
    }

    /* returns change in encoder state (-1,0,1) */
    int8_t read_encoder1() {
    static uint8_t old_AB = 0;

    old_AB <<= 2;
    old_AB |= ((digitalRead(ENC_1_B))?(1<<1):0) | ((digitalRead(ENC_1_A))?(1<<0):0);
    return ( enc_states[( old_AB & 0x0f )]);
    }

    /* returns change in encoder state (-1,0,1) */
    int8_t read_encoder2() {
    static uint8_t old_AB = 0;

    old_AB <<= 2;
    old_AB |= ((digitalRead(ENC_2_B))?(1<<1):0) | ((digitalRead(ENC_2_A))?(1<<0):0);
    return ( enc_states[( old_AB & 0x0f )]);
    }

    void loop() {
    int8_t encoderdata1;
    int8_t encoderdata2;

    encoderdata1 = read_encoder1();
    if ( encoderdata1 ) {
    encoder_1_value += encoderdata1;
    Serial.print("Encoder 1: ");
    Serial.println(encoder_1_value);
    }

    encoderdata2 = read_encoder2();
    if ( encoderdata2 ) {
    encoder_2_value += encoderdata2;
    Serial.print("Encoder 2: ");
    Serial.println(encoder_2_value);
    }

    }

    —————-
    Fabrice

  • prins

    great tutorial.

    I found HID board using PIC18F4550 chip capable of reading 16 rotary encoders (all types of rotary) in real-time, and no additional chip. anyone knows how to do that in arduino. what method is it implementing, timer or interrupt?

  • mark

    how can I use this code on mega 2560. I get serial to print “start” but that’s it. What pine do I use?

    • For 2560, you don’t need to do anything, the pins are switched in the code during compile.

      • mark

        Thanks,

        So I’m using analog pins 14 and 15 but get no response from the encoder. Tried 14 and 15 Digital, no response.

        “If you’d like to move encoder pins to Arduino pins 8 and 9, ENC_PORT shall be defined as PINB, and for pins 0,1 as PIND.”

        why does ENC_PORT change when changing pins, is this unique to the board your using?

        whats ENC_PORT do?

        • ENC_PORT is a #define for a port name. Does it work if you’re using the same pins as I?

          • Jay

            Hi Oleg, I also have the same problem with a MEGA256, I don’t get response from the encoder.
            Tried changing ENC_PORT to PINB PINC and PIND, none of them work.
            Any idea?

          • Make sure your encoder is connected to the port your sketch is reading, port bits 0 and 1.

          • Jay

            Yes, it’s properly wired and connected to the right pins

          • It should work then, but it doesn’t. Maybe your testing needs to be changed? Include the Arduino itself. For example, make sure you can read a singe pin. Connect a pushbutton to a data pin and write a sketch which reads the state of this pin and prints it out. There are many examples on the net doing similar things. Then move the button to one of the pins intended for the encoder and make it work there, then move to the other pin. Then connect the encoder, it’s really a pair of pushbuttons with some clever sequencer. Then modify my sketch with what you have learned – it will work.

            Post a good picture of your setup to the accompanying G+ community so that other people can see it and help you too -> https://plus.google.com/u/0/communities/113627505540902841340

  • Allan

    is it possoble to measure wheel speed using a rotary encoder incremental with output A, B an Z

  • aditya

    I have 12V , 500 RPM, 15 Kgcm DC geared motor and encoder. How could I control the DC motor to rotate in forward, Reverse direction and No of rotations of DC motor shaft.

  • Hi Oleg,

    I adapted this code to a PIC chip project I was/am working on many months ago. It made my rotary knob functionality perfectly clean for the first time. The code was more compact as well. I never did mention it, but this was really helpful to me. It works very very well on a rotary encoder with absolutely no hardware debouncing. The signal is really ugly.

    Just wanted to say thanks. I’ve tried lots of debounce code. This is not only the best I’ve found, but the best by far.

  • Liam Goudge

    Hi Oleg.
    What an elegant algorithm; read_encoder is a very nice way to implement the state machine.
    Thanks for publishing and sharing your ideas.
    Very simple port to the Freescale platform on ARM”s MBED.
    Worked very well but I did need 100nF of anti-bounce on my Panasonic EVE-KE2F2024B encoder, perhaps because this CPU is clocked so much faster than the ATMEGA and AVRs.

  • Jeff Beougher

    I am attempting to connect 6 encoders to an Arduino Leonardo with a MCP23017 I2c Port Expander. I have been able to use one encoder on the Arduino directly. What I am attempting to do is depending if the encoder is turned up or down to send a keyboard scan key to to the computer for a project. I was hoping to have some type of multiplexing to be able to read each encoder and know if they have been turned. The MCP23017 has not helped. I know it works because I have been able to use the example codes and blink an led and see button press input.

    So my question is how can I multiplex 6 rotary encoders. Either using the MCP 23017 or a different input expander of some type.

    Links to the encoder and MCP.

    http://www.adafruit.com/products/377
    http://www.adafruit.com/products/732

  • Neelam

    Hi,

    My project is to control the speed of the dc motor(Hardware) using PID controller in LabVIEW. For interfacing Labview with dc motor, I am using Arduino Uno. For encoder, I am using Optocoupler and a schmitt trigger. The encoder has three terminals. Red brown & black. red and black are for +5v and ground respectively and brown will read the value (i.e no.of rotations) from the dc motor. This output should be connected to arduino which in turn will pass this value to labview. Please tell me on which pin of arduino I should connect that brown wire.

    From digital pin 3 of arduino, I am passing PWM signal to the dc motor. I tried to connect that brown wire of encoder to pin 5 but I am getting an unknown error.

    Please help me in this.

Leave a Reply

  

  

  



You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">