ESP8266 Peripherals: KY-040 Rotary Encoder

Do you like this post? Writing posts, developing libraries and programming online font creators is actually hard work. I order most of my electronics from a Chinese website called Banggood. It is save and the items usually arrive in good quality. With every order you do there by following this link you are supporting the blog. Thank you!

[nextpage title=”Introduction” ]

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.

 

[/nextpage]

[nextpage title=”Hands on!” ]

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 && millis() - lastUpdateMillis > 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

 

Get one now!

  • 1

    KY-040 Rotary Decoder Encoder Module For Arduino AVR PIC

    $1.82
    Add to cart

 

 

[/nextpage]

Posted by squix78

40 comments

  1. Observation, you could pull the weather icons from the Weatherunderground server rather than host them yourself. I think they do-not apply any read quotas.

    Did embedding the icons in flash prove to be too great an overhead?

    1. Hi David. If I’m not mistaken these icons are from a 3rd party (which reminds me to put their credits up). So I’d have to host it somewhere anyway. I currently also only use uncompressed bmp format and I doubt that any reasonable person still has them around for normal use;-). And then: downloading has the advantage to be easier to change compared to embedding in the firmware… But it was a design decision. Comparing pros and cons…

    1. Hi Stephen. I plan to upgrade the plane spotter project to the color screen, so yes, it’s definitely possible. Just a question of time:-)

  2. Hi,

    I have a working esp8266 weather but the small LCD only.
    im trying this one as i have the exact LCD lying around. i saw the “settings.h” where values need to be changed. (i.e. wundeground API, country, city, etc).. the only one that i was not sure and I did not see any explanation was the ThingSpeak value.

    May i ask what is the purpose of the Thingspeak value? i tried to view it but I think its a private channel.

    Anyway, i uploaded it on NodeMCU and when i inspect the Serial monitor, i can get to the part where it downloads the pictures.
    Here is the last bottom lines on the Serial.
    There is a line that says “connection failed.”…. Im guessing it has something to do with the Thingspeak..or maybe something else..

    …….(lots of downloding lines here…………..)
    Downloading http://www.squix.org/blog/moonphase_L19.bmp and saving as /moon19.bmp
    Downloading http://www.squix.org/blog/moonphase_L20.bmp and saving as /moon20.bmp
    Downloading http://www.squix.org/blog/moonphase_L21.bmp and saving as /moon21.bmp
    Downloading http://www.squix.org/blog/moonphase_L22.bmp and saving as /moon22.bmp
    connection failed
    connection failed
    connection failed
    connection failed

    Loading image ‘unknown.bmp’
    File not found
    Loading image ‘/mini/unknown.bmp’
    File not found
    Loading image ‘/mini/unknown.bmp’
    File not found
    Loading image ‘/mini/unknown.bmp’
    File not found
    Loading image ‘/moon0.bmp’
    File not foundconnection failed
    connection failed
    connection failed
    connection failed

    1. Hi Glenn,
      The purpose of the Thingspeak channel is to display (say) your own local temperature and humidity. So I have an ESP8266 and BME280 sensor running that reports every 10-mins to thingspeak the current temperature and humidity in my garden. Therefore I provide the keys for my channel and it gets reported on the weather display. Ideally there would be a software (compile time) switch to remove that option.

  3. Please ignore the comment below.
    I was able to solve it. Apparently, the wifimanager didn’t connect successfully to my router, so i had to manually connect and put the static SSID and password.

    So its working now, yey! i can see the pictures and the icons properly.

    im still dumbfounded with the Thingspeak channel in the settings.h.
    May i know if that is really needed?

    1. Hi Glenn, I’m a program newbie and met same message from serial port, but I struggled for long time but cant overcome this issue, do you mind give me some suggestion?

      Thanks!

  4. Hi,
    Is there any chance regarding tutorial how to call bitmaps using WiFi connection?
    I want to prepare own set of icons but I don’t know how to use it in your script 🙁
    As well I have a question reagrding screen refreshing, as I see that is the issue when the time is updated and some pixels are not removed?
    Thanks in advance for help.
    Piotr

  5. Very impressive weather station, works great!
    If it could automatically update summer/winter-time, it would be absolutely perfect.
    Have fun with the beer 😉

  6. I was able to get this running, but wanted to mention a small issue I ran into. (Sounds like the same one Mike McRoberts references.) The bitmaps require more than 1M of SPIFFS, so if you were like me and had selected only 1M at compile time, you run out of space to download all of the bitmaps, and many of the moon-phase bitmaps will fail to download, or will be perhaps truncated or corrupted. I went back and changed to 4M (3M SPIFFS) in the IDE and was able to solve this. Still having a bit of overlay issues with the time updates, but as Daniel mentioned, the code may still need a little work.

    Thanks for all the effort on this…now to add some of my own tweaks!

  7. Hi Daniel,
    i tried to flash the script but i will receiving all the time the following error:
    *******************************
    In file included from esp8266-weather-station-color.ino:34:0:
    C:\Users\Jens\Documents\Arduino\libraries\esp8266-weather-station-color-master/WebResource.h:25:31: fatal error: ESP8266HTTPClient.h: No such file or directory
    #include
    ^
    compilation terminated.
    Fehler beim Kompilieren.
    *******************************
    I added the ESP8266HTTPClient-library to the Arduino 1.6.5 but there is still the same error.
    Do you have any idea what i can make that the script will runing?
    Jens

  8. Unfortunately Banggood.com are no longer stocking the 2.2 Inch Serial TFT SPI Display ILI9341 display! Can it be obtained from another supplier? Or can an alternative be used?

    I would like a bigger screen for my PlaneSpotter project so that I can enclose everything in a case with the lcd screen acting as a box top : )

  9. Dani, excellent! Built this over the weekend (preparing to teach another IoT class this week) and almost worked flawlessly (2.4″ TFT + Wemos D1 Mini). Couldn’t get the WifiManager to connect, tried a few different things then finally went manual mode. The 199: timeClient.updateTime(); would sometimes hang, changed the .h to use “us.pool.ntp.org” instead; didn’t do a lot of troubleshooting, was more in quick-fix mode. Maybe later this month I’ll try incorporating Neptune’s daylight savings code back into this (thanks btw for the link to that). PS will try to get some pictures with the kids doing projects over the session the next two weeks. Regards, Mike

    1. Mike, you stated that you changed the .h to use “us.pool.ntp.org”. What is the path/filename to that .h file?

  10. Dani,

    I’ve been adding some of my own enhancements to your original code for several weeks now, and thought I’d share some of my changes in case anyone was interested. I’ve posted these on GitHub if you’re interested…https://github.com/fowlerk/ESP8266-Color-Weather-Station-v8 .
    This version includes many enhancements to the displays (see the README on GitHub), along with Neptune’s enhancements for daylight savings time. The code could stand some clean-up, but otherwise seems to work well.

    Let me know what you think…I’ll post some photos of the displays when I get a chance.

    Keith Fowler

    1. Hi Keith

      You put some really nice things into the code! I knew that the WifiManager had this configuration UI feature but never got around to use it in my code. Now with your code I have a very nice example to use it;-). Thank you a lot for sharing! I just posted your fotos on Twitter and linked to your repository, I hope you don’t mind.

      I am working ATM on a 2.4″ display with touch. This would allow to switch screens or similar…

      Dani

      1. Dani…I don’t mind at all, in fact I’m honored. One thing to note, which I pointed out in the README on the repo, is that I have added a few fields over the past few months that may (or may not) have made it into the Weather Station library for the Weather Underground functions. Not sure how exactly to go about getting those into the master. (You may even be able to spot these on some of the displays.) I did not put those library changes up on the repo.

        I’d also had my eyes on those touch-screens and had similar thoughts on using them to control the screen displays. I’m anxious to see what you end up doing with it. Your projects always give me more ideas to try ;).

  11. Hey Dani and Keith, I just tried this out a few days ago and love it. Just wanted to confirm that when I tried to use Keiths’ version, it failed to compile due to the changes in the Weather_Station library. I would really like to try out this version if one of you could point me at the correct library.
    This was my first project with an esp8266 and I am really surprised at how powerful and easy it is to use.

    Kevin

    1. Kevin…yes, sorry, I knew that would bite someone. I really wanted to get the changes merged into Dani’s master library rather than start off on another branch. In the interim, I have uploaded the two changed library files for the Weather Underground components to a separate folder on the repo if you want to download those to (temporarily) replace the original ones in the Weather Station library. That should allow it to compile. Let me know if that doesn’t work for you. Hopefully I’ll figure out the right (permanent) solution to address the changes soon.

      Keith

      1. Thanks for the update Keith,

        I got the new code and everything works great. Now I just have to figure out how to make it work with a bigger screen, maybe 7 inch. My eyes ain’t what they used to be. 🙂

        Kevin

        1. Glad you got it working Kevin…and I know what you mean about the old eyes! I’m right there with you. I’m torn between the compact size and being able to read all the data displayed without my glasses ;). Let me know if you find a bigger option that works well for a reasonable cost.

  12. Dani…just made a pull request on your repository to add some of the changes I had made to your Weather Underground library. Let me know if you have questions or issues.

  13. Dani, I just made another pull request for some new updates to the Weather Underground client library. These include changes to support some additional enhancements I have been working on recently that display weather alerts (as per the WU API call “/alerts”), as well as the addition of probability of precipitation (PoP). I have uploaded a new version to my repository on GitHub that shows these additional enhancements (see the README for further details), along with screenshots.

    As always, let me know if you have any questions or issues, and best wishes for the upcoming holidays!

  14. Hi Daniel. I don’t like the Ardunid IDE because of the lack of debugging with breakpoints. Therefore, I’ve just started with VisualGDB and JLink debugger and ESP8266. I have quite some difficulties.

    Do you have any experiences with VisualGDB?

    By the way: I am situated near Zurich and I like your projects! Great work!

  15. I have been having a lot of fun working through the examples with your weatherstation library. I bought your kit, which was an easy way to get started with the ESP8266.
    I am working through the WeatherStationDemoExtendedDST, for some reason updateData is not firing every 10 minutes. updateDHT is working fine, fires every minute.
    I think this is where the problem is, it isn’t setting readyForWeatherUpdate to true. However, it looks exactly the same as your other examples.
    if (readyForWeatherUpdate && ui.getUiState()->frameState == FIXED) {
    updateData(&display);
    }
    Thanks for any help.

  16. Figured it out. Apparently you can’t attach two events to a single ticker? I created two tickers, and now it works.
    tickerUpdateData.attach(UPDATE_INTERVAL_SECS, setReadyForWeatherUpdate);
    tickerUpdateSensor.attach(60, setReadyForDHTUpdate);

Leave a Reply