Basic Rotary Encoder Processing

This topic is huge across multiple forums and discussion groups, not to mention the many individual blogs that demonstrate encoder operation. Without a doubt, the has a very high number of forum topics covering encoders. Everyone has their opinion of how best to handle these guys. Filtering with RC networks, simple polling, interrupt driven “polling”, and state machine designs, singly and in combination, have been suggested as the most effective way to process a rotary encoder.

I‘m going to assume that you have some familiarity with rotary encoders: what they do on the inside and what their outputs do. I want to jump in and just try-out a few of the solutions that I have seen suggested. You can find good articles in many places on the internet. Be sure you are looking at machanical rotary encoders. The other major type is optical. Optical encoders have zero switch bounce (no switches), require external power, and are more expensive. Good engineering practice always seeks to reduce cost as much as possible.

Interrupt “Polling”

Polling an external (or internal) signal on a microprocessor is an easy way to obtain the state of some device that generates discrete voltage levels. But polling becomes less useful as device’s signal-change speed increases and/or the system you are running on grows in complexity or “business”. If you are reading a rotary encoder and changing a few LED’s based on that reading, you can probably use polling with no problems. But, even in this case, it may be possible to turn the knob too fast before you finish processing your LEDs.

Interrupts provide a method to “poll” your encoder without having to use-up CPU cycles needlessly. The program I use for this article/video uses what I call interrupt polling. (The program can be found in this arduino forum page. A timer is set-up to provide periodic interrupts at some fixed interval. Each interrupt will look at the encoder to determine if it has changed its outputs. If so, the interrupt code (ISR) sets a software flag (a value in some predefined variable) to “true”. The main code “polls” this flag at its leisure, does its processing and clears the flag for next time. It depends upon the ISR to find the encoder change. This is more efficient than regular polling in that the ISR can run for a very short period of time, at a rate that should ensure that every encoder change is detected and therefore, has low impact on other functions of the system. But you can probably foresee that the weakness is that the flag has to be polled. And at some encoder rate-of-change, the ISR can re-set an unserviced flag! You have to determine if this method is suitable for your design.

Interrupt Scope Photo

This scope shot shows timer generated interrupts at 1mS on the bottom trace. The top two traces are the A and B pins. You can see that all “states” of the encoder have at least one interrupt within the period of time that a state is stable. However, it’s not hard to see that with a little faster series of pulses the interrupt could occur outside of one of the states. Look at the position where A and B are both low. If the B high-to-low transition had come after that following interrupt pulse, the software would have missed that transition and messed-up the counting. But the speed of A and B in this picture is probably faster that a person would normally turn the encoder. It all depends on your requirements.

RC Network Filtering

Scope Noise Photo

Many people support the filtering of the A and B pins of the rotary encoder with an RC network. This is just a simple addition of a capacitor to ground connected at each encoder output pin. This will reduce switch bounce. But how much switch bounce? I have never seen reference to any actual signal noise. No one specifies what the period of the noise is. No one specifies what the amplitude of the noise is. They just throw out “add a couple of 0.1uF capacitors” or some such. Checkout the scope picture. That’s a wide range of pulse noise to handle. The wider “noise” is about 3uS long. What size capacitor will it take to filter that out? OK, so then, what does your noise look like now? No one says! This is a bizarre way of specifying a component value for any function. Just pulled it out of your …um, the AIR.

Scope Risetime Photo

And what about the final, steady-state signal? What does its rising edge look like? Has it been slowed down so much that the polling routine has a much greater chance of missing it? No one seems to care about that. Look at the rise-time of the pulse in the scope picture. It’s about 5uS long. That will increase the time it takes for this signal to reach a “one” state. Is that going to be acceptable? Remember that when you are filtering the noise, you are also filtering your desired signal.

And capacitors in an RC network work with the resistor. That is never specified either. The video should get you familiar with the basic issues involved in filtering.


Considering all the rotary encoder traffic on the Arduino Forums, I figured this would be a good opportunity to do some Arduino development. So I got a RedBoard from Sparkfun. This board, they say, is like a Uno (selecting “Uno” on the IDE works fine) in that it has an FTDI USB chip. That’s supposed to be more reliable than using the firmware USB/Serial conversion on other boards. RedBoard also has the mini-B USB connector. Another cable to buy? Not me! My PICkit3 cable has the mini-B connector so I can just transfer between the two (and the cable is red, too!). The board is all surface mount and there is absolutely nothing on the back of the board. That makes it non-scary for running it on your bench with cut leads and components spread around.

The only thing I don’t like is that the USB connection takes up the only USART port on the CPU. I could have made the monitor shots using a serial LCD display on the breadboard along with me turning the knob on the encoder. It would have been clearer for the viewer and easier to set up and video. We should all know by now, electronics is all about trade-offs.

I am on Slackware and getting the monitor/USB connection going took a little effort. First, plug in the board to USB and do: ls -l /dev/tty*. You’ll get a load of tty devices but you should see a ttyUSB0 or a ttyACM0. Note the group name. Mine was “dialout”. Now make yourself a member of that group: usermod -G dialout -a {yourusername}. You could restart “udevd” but it’s safer to reboot. Then in /opt/arduino/lib/preferences.txt, change “serial.port=COM1” to “serial.port=/dev/ttyUSB0″ (or ttyACM0” as necessary). Re-open/restart the IDE (maybe more than once) and open the Serial Monitor and you should be talking. (This is also required for programming (burning).)

As far as the IDE and Arduino ecosystem goes, I’m not that excited. It’s an admirable idea to provide all this software and supporting infrastructure to help new-comers to the electronics/development field. It certainly has proven its worth. But I do have issues with it. I guess I’ll write a separate blog rather than taking it up here.

©copyright 2015 pretzelogic LLC. All rights reserved.
No part of this page may be reproduced without permission.
Software, schematics, and text are presented as reference works only.
No claim as to useability, suitability, or correctness for any application is made.