In this detailed tutorial learn how to interface a Rotary encoder with Arduino and display the encoded directional values on 16X2 LCD display when rotated in clockwise and anti clockwise directions. And also learn about Rotary encoder and how it works with Example Arduino program codes.
Table of Contents
What is Rotary Encoder?
A rotary encoder is an input device which looks like a potentiometer, but it outputs a series of pulses, which are different from others and unique. When rotary encoder knob is turned clockwise or anti clockwise, it rotates in small steps which produces analog or digital signals. These signals are ideal to control stepper motors, servo motors, Dimming and brightening of lights, incrementing/decrementing digital values, measuring the lengths and many more.
How Rotary Encoder works?
A rotary encoder is an electromechanical transducer, which means it converts mechanical movement into electrical pulses. It consists of a knob, when rotated in steps produce a sequence of pulses, each conductive steps are placed on the disc with predefined lengths and gaps. There are many types of encoders each with their own working mechanism, which we already learnt in our previous article, Now as we are using KY040 incremental rotary encoder Arduino in this tutorial lets learn about it.
The internal mechanical structure of the encoder is shown in the above image. It basically of a disc (black) non conductive material and a conductive pads(white gaps) placed on surface of that disc. These conductive pads are placed at regular equal intervals. The output pins are fixed on this disc so that when the knob is rotated, the conductive pads touch output pins and generate waveforms. There are two output pins here, Output A and Output B, as shown in the above image.
The output waveforms produced by output pin A and output B are represented in dark blue and sky blue respectively as shown in the above image. When the conductive pad makes contact with the pin, it goes high, and when the conductive pad is moved away from the pin, the pin goes low for the waveform shown above. So by counting the number of pulses we can determine how many steps it moved.
We need 2 pins and 2 waveforms to determine the direction in which the knob is rotated, If we use only one we may end up with just the movement but we cannot find the direction. If you look at these two pulses, you will notice that they are both 90° out of phase. So when the knob is turned clockwise, output A will go high first, and when the knob is turned anticlockwise, output B will go high first.
To know more about Rotary Encoder principle and its working in detail refer this Article: What is Rotary Encoder? Types, Principle, working in detail
Required components:
- Rotary encoder
- Arduino microcontroller
- 16X2 LCD display with I2C adapter
- Few connecting wires.
KY-040 Rotary Encoder Pinout Diagram
There are total of 5 pins from which GND and + pins are used to power the encoder which we need to connect to 5V supply. The encoder also has a switch (active low) which we can use it by pressing the knob from top whose signal can be obtained from the pin SW. Finally it has two output pins CLK and DT which produce the waveform as described above. Now let’s learn how to interface encoder with Arduino.
Arduino Rotary Encoder Circuit Diagram:
Here we are using Arduino UNO board, you can use Other Arduino versions also, for pin diagrams refer article: What is Arduino?. Now connect Rotary Encoder with Arduino UNO and LCD display as shown in the below circuit diagram.
From the above circuit diagram you can see that the rotary encoder is connected to Arduino as the power pins VCC and GND of encoder are connected to 5V and GND of Arduino respectively, The output pins CLK and DT are connected to digital pin6 and digital pin 7 respectively.
As we are using an LCD display with I2C adapter, it has only 4 pins. The power pins of LCD display which are VCC and GND are connected to 5V and GND of Arduino respectively and the I2C communication pins SDA and SCL are connected to A4 and A5 respectively.
If you wish to use LCD display without I2C adapter refer this article: Interfacing LCD Display with Arduino in detail
To use the feature of switch you need to use the pin SW and connect a 10K ohm resistor is connected from a 5v supply to pull up the signal.
Arduino Rotary encoder Example code to read position and direction of Rotation:
Now its time to upload the code. connect Arduino to a PC where Arduino IDE is installed. Choose the board as Arduino UNO or which ever you use and select the correct port from the Tools menu. Install required libraries from the built in Library manager or you can download the latest version from the below links
Required Libraries:
- Download LiquidCrystal_I2C – Link
Next copy the below code and paste it in IDE workspace and press upload button. That’s it the code will be uploaded.
// Tested and compiled with no errors // Rotary encoder with Arduino to print position and direction of rotation // source - www.circuitschools.com #include <LiquidCrystal_I2C.h> #define outputA 6 #define outputB 7 // Initialize the LCD library with I2C address and LCD size LiquidCrystal_I2C lcd (0x27, 16,2); int counter = 0; int currentStateA; int lastStateA; String currentDir =""; void setup() { // Set encoder pins as inputs pinMode(outputA,INPUT); pinMode(outputB,INPUT); // Setup Serial Monitor Serial.begin(9600); lcd. init (); // Turn on the backlight on LCD. lcd. backlight (); lcd.print ("CIRCUITSCHOOLS.."); lcd. setCursor (0, 1); lcd.print ("ROTARY ENCODER"); delay(2000); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Rotate the knob"); // Read the initial state of outputA lastStateA = digitalRead(outputA); } void loop() { // Read the current state of outputA currentStateA = digitalRead(outputA); // If last and current state of outputA are different, then pulse occurred // React to only 1 state change to avoid double count if (currentStateA != lastStateA && currentStateA == 1){ // If the outputB state is different than the outputA state then // the encoder is rotating CCW so decrement if (digitalRead(outputB) != currentStateA) { counter ++; currentDir ="CW"; } else { // Encoder is rotating CW so increment counter --; currentDir ="ACW"; } Serial.print("Direction: "); Serial.print(currentDir); Serial.print(" | Counter: "); Serial.println(counter); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Position: "); lcd.setCursor(10, 0); lcd.print(counter); lcd.setCursor(0, 1); lcd.print("Dir: "); lcd.setCursor(5, 1); lcd.print(currentDir); } // Remember last outputA state lastStateA = currentStateA; // Put in a slight delay to help debounce the reading delay(1); }
Output:
After uploading the code open serial monitor at baud rate 9600 and check the position of the knob and direction of the rotation. So when you rotate the knob in Anti clock wise direction the counter position increases, and decreases when you rotate in anti clockwise direction.
Also the same information is displayed on the LCD display which we connected as shown in the below image.
Example 2: Measure distance with Rotary Encoder
Please refer this DIY article for this example: DIY Measuring Wheel using Arduino and Rotary Encoder
If you like this Arduino Rotary encoder project please subscribe to our YouTube Channel “Circuit Schools“ to encourage us to publish more interesting projects. If you have any doubts write to us from below comment section.
Excellent tutorial.. Thank you! I’ve tried about 10 others before this, but this is the first one that worked correctly. It doesn’t skip values and is completely consistent. I skinnied down the loop as much as possible (print value only to lcd, no serial.print, left in the 1ms delay) and get between 20 and 25 increments/decrements per turn. Nice job! Keep up the good work!!
This example is polling the inputs. Have you tested those examples that use hardware interrupts (with RotaryEncoder.h and those dedicated hardware interrupt pins)? I plan to use a rotary decoder alongside with an SPI LCD (again, on dedicated HW pins) and a PID. The main loop will be quite big and I’m using a Pro Mini at 3.3V (8MHz) so a polling rotary encoder may not be the best solution. I may be back with some results if you’re interested.
Thank you for this tutorial and for sharing the code for this. I didn’t have a KY040 but was able to use a basic encoder (A / GND / B) by pulling the input pins high:
pinMode(outputA,INPUT_PULLUP);
pinMode(outputB,INPUT_PULLUP);
and it works perfectly.
While this is ok for learning purposes but will not work in practical application because buttons and switches must use hardware interrupts otherwise the mcu will not respond to user inputs.