ESP8266 Peripherals: KY-040 Rotary Encoder

The ESP8266 took the hearts of the IoT and Do-It-Yourself community by storm, due the very attractive price, its internet connectivity and due to the relatively rich amount of available GPIO pins. But an internet connected device is not worth much without means to interact with the real world. Thanks to standardised communication protocols like I2C, SPI and serial interface and the work of the Arduino community there are many sensors and actors available for a really good price. But do they play well with the ESP8266? In this series of blog posts I will share my experience with these modules and how you can use them.

The start makes an input device which is surprisingly low tech but offers a nice way to adjust settings on a display without using too much of your valuable GPIO pins: the KY-040 rotary encoder

KY-040
KY-040 Rotary Encoder

 

What is a Rotary Encoder?

At first glance you might mistake the KY-040 for an adjustable resistor, a potentiometer. It has a knob which you can turn. But unlike real potentiometers the KY-040 can turn round and round without ever getting to a blocking limit. When turning the KY-04 you will also feel certain positions where the encoder will slide into. A potentiometer on the other hand can usually be turned smoothly until you get to the end stop. And there is another difference: the KY-040 (like most rotary encoders) has a switch which can be closed when pressing the knob vertically to the rotation axis. I have seen rotary encoders like this being used in modern radios or in built-in car navigation systems. The advantage is that they can be used relatively easy in a digital system as opposed to an analog/digital converter (ADC) reading the values from a potentiometer. There you also might have to deal with temperature drift and similar ugly problems. So in many ways a rotary encoder is the younger (millennial/digital) brother of a potentiometer.

 

How do you use  a Rotary Encoder?

There are different types of rotary encoders. Some can determine the absolute position/angle of the knob without constantly keeping track of its movements. But the KY-040 a very simple minded fellow. By tracking the signals on two pins an MCU can determine if the knob was turned to the left or to the right. With a third pin the state of the knob button can be tracked. The wave form on the two rotation pins looks more or less like this:

RotaryEncoderWaveform
Rotary Encoder Wave Form. Picture from [http://playground.arduino.cc/Main/RotaryEncoders]
When turning the knob clockwise the signal on line B will first go high, before line A will also have a rising edge. Followed by a falling edge on line B and later by a falling edge on line A. The sequence from one click position to the next is then 00, 01, 11, 10, 00. For a counter clockwise movement the order is 00, 10, 11, 01, 00. Hence by tracking these signals carefully you can determine the direction of the rotation and also track 4 intermediate states between two clicks. If you have interrupts available you can have your code get some notification about a change of the signals on the two lines. If you don’t have interrupts available you’ll have to trust that your reading the signals often enough to not miss any important change of the signal (AKA polling the signals). And there is yet another complication: we are living in an imperfect world (in case you haven’t noticed that yet, that’s the bloody truth;-)). The mechanical contacts inside the KY-040 might “missfire” from time to time. Maybe there is some dust on the contacts or the copper has a tiny dent. However, your MCU might get a dirty signal unlike the one depicted above and draw wrong conclusions. This is where debouncing comes in. You can debounce buttons and rotary encoders like the KY-040 either in hardware or in software. The hardware solution is to use a tiny condensator to smoothen the signal from the noise a bit. But by applying a time frame where you’d expect changes to happen you can also filter out the noise pretty well. The library we will use here does that under the hood and we don’t have to worry about it. I just wanted to point out this fact so that you can understand why you might miss states occasionally and that you have to deal with that fact in your application.

 

 

Lets get our hands dirty!

Now to a practical example. Wire up your encoder like this the following picture, make sure that you follow the labels and not the ordering, I might have turned something upside down:

RotaryEncoderKY-040
Wiring of the KY-040 with the NodeMCU
  • GND to GND
  • + to 3.3V
  • SW to D3
  • DT to D2
  • CLK to D1

 

Installing the library

There are different libraries that might work. This library worked well for me: https://github.com/PaulStoffregen/Encoder Download the ZIP and unpack it into your Arduino library directory. Restart the Arduino IDE and copy the code from here:


#include <Encoder.h>

Encoder myEnc(D1, D2);


long oldPosition  = -999;
boolean isButtonPressed = false;
long lastUpdateMillis = 0;

void handleKey() {
  isButtonPressed = true;  
}

void setup() {
  Serial.begin(115200);
  Serial.println("Basic Encoder Test:");
   pinMode(D3, INPUT_PULLUP);
   attachInterrupt(D3, handleKey, RISING);
}


void loop() {
  long newPosition = myEnc.read();
  if (newPosition != oldPosition) {
    oldPosition = newPosition;
    Serial.println(newPosition);
  }
  // software debounce
  if (isButtonPressed &amp;&amp; millis() - lastUpdateMillis &gt; 50) {
    isButtonPressed = false;
    lastUpdateMillis = millis();
    // Reset the counter
    myEnc.write(0);
  }
}

After uploading the sketch you can open the serial console, turn the knob up and down and press the axis to reset the counter. Your output might look something like this:


Basic Encoder Test:
0
1
2
3
2
3
4
0 - Knob pressed
1
2
3
4
0 - Knob pressed

 

Suggested applications

  • WeatherStation Frame Controller: Some readers were asking me how they could control the currently displayed frame of the WeatherStation. Depending on the amount of the frames you are using it might take a while until the one that interests you the most comes around. The rotary encoder is a nice extension which allows you to quickly zap through the frames without having to implement a lot of code
  • Wifi Selector for unprotected APs: lets assume you have a setup with an ESP8266, a display and you want to quickly select an unprotected wifi to connect to without using the web interface: just implement some kind of menu and use the rotary encoder to move a cursor from one SSID to the next and the knob button to select the AP you actually want to connect to

 

Where to buy?

As always I recommend to order it from my favourite Chinese retailer Banggood

Posted by Daniel Eichhorn

Daniel Eichhorn is a software engineer and an enthusiastic maker. He loves working on projects related to the Internet of Things, electronics, and embedded software. He owns two 3D printers: a Creality Ender 3 V2 and an Elegoo Mars 3. In 2018, he co-founded ThingPulse along with Marcel Stör. Together, they develop IoT hardware and distribute it to various locations around the world.

5 comments

  1. Hi.
    Is it formatting error in code?
    ————————–
    if (isButtonPressed && millis() – lastUpdateMillis > 50) {
    ————————–
    wrong letters?: && and >

    • Hi Frank. Depends what exactly you see. It shoulb be two ampersands and one “greater than” sign…

  2. Don´t you have problem compiling in Arduino IDE ? I put the board esp8266 generic or Wemos D1 mini and i get errors with library. Pin definitions errors compiling

  3. I’m getting 4 counts per click, both + and _- direction.

    Using Paul Stoffregen / Encoder library.

    I have checked other libraries and cannot resolve the issue with the ESP8266.

Leave a Reply to squix78Cancel reply