How to Use Rotary Encoders and Interrupts With Your Arduino Projects

by taste_the_code in Circuits > Arduino

13297 Views, 8 Favorites, 0 Comments

How to Use Rotary Encoders and Interrupts With Your Arduino Projects

take 2.00_07_52_22.Still011.jpg
take 2.00_00_22_25.Still001.jpg
take 2.00_00_28_19.Still002.jpg
How to use rotary encoders and interrupts with your Arduino projects

Many Arduino projects require a form of input from the end-user. This is usually done with buttons that you connect to different input pins and based on what button is pressed, you can respond to that press in the code. In the usual arrangement, we have buttons that trigger a menu, and then other buttons that increase or decrease a value or change some of the project parameters.

However, if we want to have a more interesting interface that is also flexible and simple to use, we can use a rotary encoder and do all of the actions that way.

This post is sponsored by PCBWay. Get your custom PCBs, SMD stencils, or assembly services professionally done for cheap in less than 24 hours.

PCBWay also offers sponsorships for students and hobbyists where you can get your projects built for free.

Supplies

What Is a Rotary Encoder?

take 2.00_01_37_13.Still002.jpg

A rotary encoder is generally a position sensor that can tell us the angular position of a rotating shaft.

There are two types of rotary encoders: absolute and incremental.

With absolute rotary encoders, you know the angle at which the encoder is at any given point in time as each position generates a different code that is sent to the output.

Incremental encoders, on the other hand, return the number of increments that the shaft has turned without knowing where it started and these are the ones that we will focus on today.

How Is It Different From a Potentiometer?

take 2.00_02_01_16.Still004.jpg
take 2.00_01_43_24.Still003.jpg

A rotary encoder is very similar to a potentiometer with the main difference being that there is no start and stop positions. They can rotate indefinitely and can offer a great output resolution, telling us the change in position that happened since the turning started.

Contrary to this, potentiometers usually turn only 3/4 of a circle and are usually best suited for situations where we need to know the exact angle at which the potentiometer is.

How Does an Encoder Work?

take 2.00_06_44_06.Still009.jpg

Inside the encoder, there is a plate with contacts and two output terminals marked as CLK and DT. The plate is connected to the ground and both of the pins are pulled high through resistors. When the plate turns, it connects the output pins to the ground in a particular order, generating signals that are shifted 90 degrees from each other.

Depending on the direction that the encoder is turned to, the order at which the pins are switched low is also reversed so we can identify the direction from that.

One of the pins on the encoder is called primary and is marked as CLK. This pin will go through the cycle of going high and back to low with each rotational click on the encoder. Depending on the direction of the rotation, DT will be turned low before or after CLK.

Rotary Encoder Pinout

take 2.00_01_07_28.Still001.jpg

A rotary encoder module usually has 5 pins. We have the usual VCC and GND, where we connect the input voltage, and then we have the CLK and DT pins which are the output signals from the encoder.

Very often, a rotary encoder has a 5th pin (SW) that is connected to the ground through the built-in normally open switch.

This switch can be used as any other momentary switch and I have an entire video on switches if you want to take a look.

Connecting the Encoder to Arduino

take 2.00_04_12_25.Still005.jpg
take 2.00_04_38_11.Still006.jpg
take 2.00_05_08_26.Still008.jpg
take 2.00_04_59_17.Still007.jpg

The encoder can basically be connected to any input pins on the Arduino but there are a few caveats that we need to be aware of for the method of reading it.

The encoder state can be read with the Arduino in one of two ways, either with polling or with interrupts.

If we choose to read the encoder with polling, we need to read the values on the CLK and DT pins on each cycle of the code, and depending on the complexity of the project, the Arduino might be busy doing some other work while the encoder is turned.

If that happens, then we might miss the change of the encoder and not react to it at all since we were busy doing something else when the encoder was turned.

To mitigate this, it is recommended that we connect the encoder using the interrupt pins on the Arduino. I've explained interrupts in another video in great detail but basically, when we use interrupts, the Arduino will stop its current execution and handle the reading of the rotary encoder instead.

On the Arduino Uno or Nano, we have two interrupts available for use on pins 2 and 3 and it is best if the encoder is connected to both of them. However, if the interrupt pins are required for some other inputs as well, as the switch on the encoder, we can only use one of them and connect DT to the interrupt pin.

This won't be ideal but it will be a lot better than just polling the encoder state.

Arduino Code

To program the Arduino we will use a dedicated library called Encoder that I'll link in the description. You can also install it directly from the library manager on the Arduino IDE.

This library can work with multiple encoders at a time, and depending on the capabilities of the used pins on the microcontroller, it will either use interrupts or it will default to just polling the input values.

At the beginning of the sketch, we first include the library and we define the encoder object with the pins that we have the encoder connected to. In my case, I choose to use pins 3 and 4, where only pin 3 has interrupt capabilities.

I chose to use just one interrupt because I wanted to have pin 2 available with the second interrupt so I could also connect the switch of the encoder to it.

To do this, in the setup function, we first define pin 2 as an input using the internal pull-up resistor to keep the pin high and we then use the attachInterupt function to set it so it executes the handleSwitch function on the rising edge of the signal. This way, the handleSwitch function will be called every time when we release the switch on the rotary encoder.

Inside the loop function, we first read the position of the rotary encoder, and we compare this value with the value that we have for the previous position. If the two are different, we write the newly read value as the old position and display it to the serial monitor.

When the encoder is turned, there are hard stops or clicks that the shaft stops at. In my case, there are 30 such stops in a full circle but since the encoder will change the values of both the pins in one such click, the value is incremented by two when read from the encoder.

To mitigate this and count every click once, we can simply choose to update the new position value only at the even positions and display the position value divided by 2.

Next Steps

take 2.00_07_14_11.Still010.jpg

Since we now know how to interface the encoder, I went ahead and integrated this encoder with the other project that I'm working on where we so far have the DS1302 real-time clock and the 20x4 LCD screen attached.

When the encoder is turned, the updated position value is written to the LCD screen and I plan to use this later on so I can adjust different values in the final project.

If you are interested in seeing this then be sure to subscribe to the channel, share this Instructable with your friends and I'll see you all in the next one.