Arduino  Menu Tutorial with a Rotary Encoder and a Nokia 5110 LCD display.

Arduino Menu Tutorial with a Rotary Encoder and a Nokia 5110 LCD display.

Dear friends welcome to another video! Today we are going to use an Arduino and a
rotary encoder to build a simple menu on a Nokia 5110 LCD display. Let’s get started! Hello guys, I am Nick and welcome to
a channel that is all about DIY electronics projects with Arduino, Raspberry Pi, ESP8266
and other popular boards. Subscribe to the channel now if you don’t
want to miss any future videos. In this video we are going learn how to build
our own menu for the popular Nokia 5110 LCD display, in order to make our projects more
user friendly and more capable. We have built a similar project in the past,
but a lot of the viewers of the channel suggested that I should prepare another video on this
subject. This time we are going to use a rotary encoder
instead of push buttons. Also, the menu we are going to build today
has more items to choose from. Let’s watch it in action. This is the project we are going to build. In the display a simple menu appears, and
with the help of the rotary encoder I can navigate up, or down and select a menu item
by pressing the rotary encoder button. The menu has 6 items, and we can scroll down
or up the menu and the items on the display will change accordingly. Let’s select the first option. As you can see a new a UI screen is displayed
and by rotating the rotary encoder shaft we can change the contrast of the display. If we press the rotary encoder button again,
we go back to the main UI screen. The second menu item offers a similar functionality
it modifies the volume variable. If we now select the third menu item and press
the button we can change the language value. I have not implemented this functionality,
this is just a demo project. A similar functionality is attached to the
4th menu item which is called difficulty. We can disable the backlight of the display
if we wish, by selecting the 5th menu item, or we can reset everything to its default
value with the 6th menu item. Of course you can modify it to build your
own more complex menus if you wish. Let’s now see how to build this project. The parts needed in order to build this project
are the following: • An Arduino Uno or any other compatible
board • A Nokia 5110 LCD display
• A rotary encoder • A small breadboard
• Some wires The cost of the project is very low, it is
less than $10. You can find links for all the parts I use
in the description of the video below. Let’s now connect all the parts together. Before building this project, if you haven’t
used a rotary encoder in the past, I encourage you to watch the tutorial I have prepared
about rotary encoders. It will help you understand how rotary encoders
work and you are going to gain some experience with them. Click on the card here if you want to watch
it now. I have placed the display on a small breadboard
like this. Let’s first connect the display. The first pin of the display which is Reset
goes to digital pin 3 of the Arduino Uno, the second pin goes to digital pin 4, the
third pin goes to digital pin 5, the fourth pin to digital pin 11 and the fifth pin to
digital pin 13. The next pin is Vcc. We connect Vcc to the positive rail of the
breadboard, and the breadboard positive rail to the 3.3V output of the Arduino. The next pin is Backlight for the display. Since we want to control it via the software
we connect it to digital pin 7. The last pin is GND. We connect GND to the negative rail of the
breadboard, and the negative rail of the breadboard to Arduino GND. Now all we have to do is to connect the rotary
encoder. The first pin is GND and we connect it to
negative rail of the breadboard. The next pin is Vcc and we connect it to the
positive rail of the breadboard. The next pin is SW and we connect it to Analog
Pin 2. The next pin is named DT and we connect it
to Analog Pin 1. Lastly the pin CLK is connected to Analog
Pin 0. You can find the schematic diagram of this
project in the description of the video below. Now we are ready to power up the project. As you can see, the project is working fine,
and the menu is working as expected! Great, let’s now see the software of the
project. The code of the project is complex but I will
do my best to explain it. You will get a basic understanding of how
the code works but if you want to fully understand it you have to make your own menu and see
exactly how it works. Let’s start. In this project we use 4 libraries. We use two libraries for the display, and
two for the rotary encoder. You can find links for all the libraries in
the description of the video below. At first we are going to take a look at the
drawMenu function. This function is responsible for drawing the
Menu on the display. This function is called every few milliseconds,
so if there is a change on the menu this function is responsible for updating the menu on the
screen. There are also 3 very important global variables,
the variable page, the variable menuitem and variable frame. The variable page remembers which UI screen
is displayed on the screen. So, if the page variable is 1, we are in the
main UI screen, and if the variable is 2 we are in the secondary UI screen where we set
the value on a variable. The menu item remembers the selected menu
item. So, if its value is 1, the first menu item
is selected, so the drawMenu function must draw this menu item as black with white letters. If the menu item is 2 the second menu item
is selected and so on. The frame variable, remembers which part of
the menu is displayed on the screen. Since the menu we have created contains 6
items and we can only display 3 of them at a time, we need to know which items are displayed
on the screen. The frame variable, tells us exactly this. If the frame variable has the value of 1,
we display the first three menu items, if it is 2, we display items 2,3,4 and so on. I tried to make the code as easy as possible
to modify so I have created some global variables that hold the names for the menu items. This way, you can create your own menus easily
without searching in code. At first we initialize all the global variables
that are needed in the code. Next we initialize the display. In the loop function, at first we call the
drawMenu function to draw the menu on the screen. Then we read the value from the Rotary encoder
and check if the button is pressed. For example, if we are on the main UI screen
and the first menu item is selected, if the value from the rotary encoder has increased,
the menuitem variable increases and in the next loop the drawMenu function will draw
the second menu item as selected. If we now press the button of the rotary encoder
we navigate to the second page, where we set the value of the variable. Again using the rotary encoder we can increase
or decrease the value of the variable. If we press the button we navigate back to
the main menu page, and page variable decreases. That’s the basic idea behind this menu. We follow the same procedure for all the menu
items and pages. The code is complex, it is over 400 lines
long. It seems complicated but if you try it yourself
you are going to understand it more easily and you will be able to change it, expand
it and use it in your own projects. As always you can find the code of the project
in a link in the description below. That’s it, now we know how to build complex
menus either with or rotary encoder or with buttons. I personally prefer buttons for my menus,
but in some cases a rotary encoder is easier to use. I would like to hear your opinion about this. Do you prefer buttons or a rotary encoder
to navigate through your menus? Please post your comments in the comments
section below. and don’t forget to like the video and share
it with your friends if you find it interesting! Also consider subscribing to the channel and
do click that bell or YouTube might not show you updates as new videos come out. If you are going to be shopping for parts
check out the affiliate links from the video description. That’s it for today guys, thanks you very
much watching, I will see you in the next video! [ Translating these subtitles? Add your name here! ]

100 thoughts to “Arduino Menu Tutorial with a Rotary Encoder and a Nokia 5110 LCD display.”

  1. more than a cool Arduino tutorial, I learned how to make better videos. great job! that's how it's done!

  2. I like rotary encoders instead of buttons, takes up less space, and can do much more. Keep up the great videos.

  3. Nice project. I can see value in both buttons and the rotary encoder approach. It sounds like the source isn't up yet so I can only see what was shown in the video. I wonder why not use an array of strings for the menu item text rather than separate variables (menuItem1…)?

    I am an experienced programmer, but new to Arduino. The Arduino IDE seems primitive in some ways. Maybe I don't fully understand how best to use it. It doesn't seem to have any concept of a Project. If I switch micro-controllers I seem to have to change a bunch of global settings. I feel like there should be some way to save the settings in a project. Also there isn't anything like intellisense (context aware code completion). As someone new to the platform code completion would be very helpful. Do these features exist in the official Arduino IDE? I understand there are alternate IDEs that have have some of these features but I haven't explored them yet. Do you have any recommendations? This might be an interesting topic for a future video: Better Arduino IDE alternatives.

  4. I like rotary over just buttons. What I think is really cool is a hybrid… use a 4-way hat switch or buttons of your choice AND a rotary… BAM! best of both worlds, user choice and you can use both to navigate, select and so on. Might be a bit of an ache to code and connect but…

    Thanks for continuously teaching me new stuff and doing so in such a way an old noob like me can understand.

  5. Good stuff. Can I offer a suggestion. For fixed menus, you might want to consider using the F macro to save RAM and store in flash memory, e.g. String menuItem1 = F("Contrast"); and so on, otherwise you can start eating up precious RAM in more complex projects just for the menus themselves.

  6. I too have been wishing for a project like this. There are many variations on the Tube, but none for a non-coder like me to understand. I appreciate the effort put in this. Thanks Nick for all your videos.

  7. Thx man, please do one for 20×4 lcd with I2C interface, sd card, and uno , thx again .LOVE your videos .

  8. I have has some of these rotary encoder on the bench for a while now. i think i will have to try it out . Thanks for another great video.

  9. tip for the bread board, if you are getting loose connections the pin rail at the back may need to be push in a bit. This fixed loose connections on my board. Some of these cheap china breadboards are fake. Had some troubles with projects check wiring, parts, power, and the rest, but not breadboard.

  10. Nice job… It gives you the option to reduce the number of buttons on a complex project. Setting month, day, year, hour, minute & second on a clock project becomes very easy for an end user.

  11. could you do a video of doing a menu like this with the nokia display, rotary encoder and raspberry pi in python or such? really enjoy your videos.

  12. Very nice project, Thanks for sharing.
    Is the Nokia 5110 display compatible with 5 volts signal ?
    Or will it get destryed over some time ?


  13. Great video, I like encoders because I can purpose them for other things, like speed of motors. Buttons are ok also depending on how many you want to use. One question, wouldn't a switch case statement help better with menu items?

  14. Thanks for this, I was thinking about needing to do this for an upcoming project.
    I like your user interface concept, but not your code.
    Below is what I think it should be like. It's half the code, and better organized, more readable and more maintainable.
    // Arduino Rotary Encoder Menu //
    // v1.0 //
    // //
    // Butchered by Bertoid //

    #include <Adafruit_GFX.h>
    #include <Adafruit_PCD8544.h>
    #include <ClickEncoder.h>
    #include <TimerOne.h>

    // Menu System definitions
    int PageSize=3; // Items on a page
    int TopItem=1; // First displayed item
    int MenuItem=1; // Currently selected item
    int EncInc=0; // Encoder change: 0,+1,-1
    boolean Updated=true; // Menu screen needs to be repainted
    boolean Selecting=true; // True=Selecting Menu Item, False=Setting Item Value
    boolean BtnClick=false; // Encoder button was clicked

    ClickEncoder *encoder;
    int16_t last, value;

    Adafruit_PCD8544 display = Adafruit_PCD8544(5,4,3); //Download the latest Adafruit Library in order to use this constructor

    // Application definitions
    String MIContrast="Contrast";
    String MIVolume="Volume";
    String MILanguage="Language";
    String MIDifficulty="Difficulty";
    String MIBackLight="Light On/Off";
    String MIReset="Reset";
    String MenuItemList[]={MIContrast,MIVolume,MILanguage,MIDifficulty,MIBackLight,MIReset};

    boolean backlight = true;
    int contrast=40;
    int volume = 50;

    String language[4]={"EN","CN","NL","FR"};
    int selectedLanguage=0;

    String difficulty[3]={"Easy","Medium","Hard"};
    int selectedDifficulty=0;

    // Menu System code
    void DisplayMenuPageSel(){
    int YP;
    //display.setCursor(0,0); display.print(MenuItem); // Debugging
    //display.setCursor(76,0); display.print(TopItem); // Debugging
    //display.setCursor(0,0); display.print(encoder->getValue()); // Debugging
    while (MenuItem>TopItem+PageSize-1) TopItem++;
    while (MenuItem<TopItem) TopItem–;
    for(int II=TopItem; II<TopItem+PageSize; II++) {
    display.setCursor(0,YP); YP=YP+10;
    if (II==MenuItem) display.setTextColor(WHITE, BLACK);
    else display.setTextColor(BLACK, WHITE);

    void DisplayMenuPageInt(String menuItem, int value){
    display.setTextColor(BLACK, WHITE);
    display.setCursor(15, 0);
    display.setCursor(5, 15);
    display.setCursor(5, 25);
    encoder->setAccelerationEnabled(true); // Don't seem to work?

    void DisplayMenuPageStr(String menuItem, String value){
    display.setTextColor(BLACK, WHITE);
    display.setCursor(15, 0);
    display.setCursor(5, 15);
    display.setCursor(5, 25);
    encoder->setAccelerationEnabled(false); // Don't seem to work?

    void timerIsr() {

    void readRotaryEncoder(){
    ClickEncoder::Button b = encoder->getButton();
    if (b==ClickEncoder::Clicked) {
    } else {
    if (value/2>last) {
    last = value/2;
    if (value/2<last) {
    last = value/2;

    void setup() {
    encoder = new ClickEncoder(A1, A0, A2);
    // encoder->setAccelerationEnabled(false);
    last = encoder->getValue();

    // Application Oriented code (mostly)
    void loop() {
    if (EncInc!=0) { // Encoder position changed?
    if (Selecting) { // Adjust menu item selection index
    if (MenuItem==0) MenuItem=1;
    if (MenuItem==7) MenuItem–;
    } else { // Adjust value of non-boolean items
    if (MenuItem==1 ) {
    if (MenuItem==2 ) {
    if (MenuItem==3 ) {
    if (selectedLanguage<0) selectedLanguage=3;
    if (selectedLanguage>3) selectedLanguage=0;
    if (MenuItem==4 ) {
    if (selectedDifficulty<0) selectedDifficulty=2;
    if (selectedDifficulty>2) selectedDifficulty=0;
    if (BtnClick) { // Button Pressed?
    if (Selecting) { // Adjust value of boolean items (from selection screen)
    if (MenuItem==5) { // Backlight Control
    if (MenuItem==6){ // Reset to defaults
    if (MenuItem<5) Selecting=false; // Non-boolean items, Go to value adjustment screens for these
    } else {
    Selecting=true; // Return to item selection screen
    drawMenu(); // Show updated menu screen

    void drawMenu(){
    if (Updated) {
    if (Selecting) { // Paint item selection screen
    display.setTextColor(BLACK, WHITE);
    display.setCursor(15, 0);
    display.print("MAIN MENU");
    } else { // Paint item value adjustment screens, where appropriate
    if (MenuItem == 1) DisplayMenuPageInt(MIContrast, contrast);
    if (MenuItem == 2) DisplayMenuPageInt(MIVolume, volume);
    if (MenuItem == 3) DisplayMenuPageStr(MILanguage, language[selectedLanguage]);
    if (MenuItem == 4) DisplayMenuPageStr(MIDifficulty, difficulty[selectedDifficulty]);

    void resetDefaults(){

    void setContrast() {

    void ToggleBacklight() {
    if (backlight) digitalWrite(7,LOW);
    else digitalWrite(7,HIGH);

    If I understood this vile despicable language better (especially how to use pointers), I'd make many more improvements…

  15. yeah I like buttons too .. do a video player with push buttons using tft screen and thnk u for great video

  16. Πραγματικά καταπληκτική δουλειά στο κανάλι! Αρκετά από τα tutorial δεν εμβαθύνουν στο θέμα όπως εσύ! Πιστεύω θα ήταν αρκετά ενδιαφέρον αν έκανες ένα tutorial για ένα Midi Controller χρησιμοποιώντας Rotary Encoders, Potentiometers, Buttons και Faders! θα με βοηθούες αρκετά, εφόσον έχω στο νου μου να φτιάξω ένα! Και πάλι ευχαριστώ και καταπληκτική δουλειά!

  17. Thanks, for this useful resource. I was looking for a E paper display.. Is It possible to get good refreash rate in waveshare 4.3 epd to show such kind of display?

  18. Hi could you do a video using one of these screens to display a hall effect sensor activating a relay on a count of detections of the magnet and then turning off after a few more detections please 🙂

  19. Dear Nick
    Great, very good , i tried it and it worked from the start after including a library SPI.h I will now try to modify it to have more menu optins and sub options. Keep up the good work. You explain things very clearly and it makes some difficult topics easy
    i love your videos. I prefer Encoder instead of buttons.

  20. Dear Nick :
    its me again.
    after only some hours of work (and hard thinking( i was able to change your sketch to include another menu ( the seventh) and also some more submenus in the language and difficulty menus.
    Again thansks ofr your excellent videos , i now have , thanks to you a working menu for my projects and i can increase it without too much difficulty.
    Carlos Frondizi

  21. Hello,

    i want to see in the same skech temprature of 2 x DS18b20
    like if the menu is not used then switch over to 2x times the temprature shown in the display.

    i like to here from you
    Gr T.Tak

  22. Two Questions Please ? One How large is the Code Compiled ? Two Are the settings completed via menu stored on power down ? On next power up will setting be the same ?

  23. Hello, how to exit the interrupt cycle to display something other than the menu without the arduino 328p blocks? I do not see that in the code. can you help me ? thank you very much, because this is very informative

  24. Hello!
    I'm using the same ramps and I displeased you. But I'm not able to map the encoder pins. Would you have any tips?

  25. Hi Nick,
    This is really great option indeed, similar to my in-vehicle infotainment system (control). The complex code is very well simplified here, I must say!

    I would like to see "Incremental Optical Rotary encoder" with stepper motor (i.e. in close – loop ckt/feedback) to determine any movement of shaft (stepper motor's shaft) when motor is in ideal state and its direction like clock-wise or anti-clock-wise.

    The cost of the project / POC (Proof of Concept) could be on higher side, but would be fun and challenging.
    Thank You,

  26. пидорский акцент! Пришлось звук отключить, а то поблевать захотелось…

  27. Great project, well explained.

    Thank you for the detailed explanation and material.

    Looking forward to seeing your new projects.

  28. like joystick buttons and i'll try to make this menu in a json format , Thanks Nick your videos is always helping

  29. Thank you for the upload. Yet, your coding is rough // this comment is non existence
    code // this code does not really help me to understand
    code /* This code is borrowed without credit
    all comments from the original code have been removed
    code // this code is full of nested IF statements.
    uint8_t comments = 3; // 🙁

  30. Πολύ καλό!
    Dear friend, is it possible to use clone's TFT's for your projects? I would like to see much more universal types than Adafruit's which is best but more expensive for the rest of us. Thank you!

  31. This is a brilliant menu, and it works perfectly on an OLED module with very few modifications to the code.
    I just have a small request. I want to build a nested menu system. For example, if I select contrast, I should see one more menu similar to the first menu.
    Can you help me with a minimalistic code example?

  32. Thanks for the video, still learning or trying to learn all the pieces I will need to merge/write for a project I would like to do, so this should help me understand what I need to do. I was wondering, how would you go about having a home page as the first window, and then enter the menu with a button push?  For my project I would like to display the time, temp and a stats for those 2 listings (aquarium lights on/off, water temp and if heater is on/off) as the main page or view, then use a menu to adjust the activating/deactivating time/temp on/off points only.

  33. Would you show an example where you can read the temperature by selecting the menu with the menu? Can you help me to run different code from selected menus?

  34. I just looked at your code, can't believe you don't stick to such common sense practice such as defining the pins with names at the beginning, to make it more readable and easier to modify for other Arduinos, or slight variations in the connection scheme… Would you mind creating this update? Or since I am working on it would you like me to send you my version? Like this:
    #define BacklightPin 7 // pin controlling the backlight LED
    Then use BacklightPin wherever in your code you use 7 to indicate that pin – this is just general good practice, you should always do it like that!
    By the way would it be reasonable to use PWM to control the brightness of the backlight LED?

  35. I'm doing a thermastat. My control will be a 5-way switch, more akin to buttons I suppose. My wife has MS and the rotation of a knob requires complex wrist movements therefore I went with the 5-way.

  36. Most difficult solution seen, and it works, congrats, this code can at least be halved and still works My professor at varsity always said if you want a difficult answer ask a student. I first tried to understand the flow before changing it, and it was really difficult. A few switch statements and whala .. if then elseif have priority and is extremely difficult to read, but switch statements can easily be read if used in a state machine, even more if enums is used instead for constants (0,1,2,.. 6).

  37. Hi! I found your tutorial very interesting, let me ask more, if I want to click one to enter the submenu, duble click to exit then what function do I have to use, thank you

  38. nice job , well done, i have one question, whatever the values i am entering, it should save so next time if i switch on the arduino, i should get the saved setting not the default one, thanks

  39. the rotary encoder is always a cool one. but combine rotary encoder with switches, creates damm good interfacing panel. my personal favourite is SMD joysticks. thank you very much for this tutorial.

  40. Hi Nick! I want to add a "home screen" in the menu, but apparently there are only two pages to work with. How can i add more pages?

  41. the contrast should be set to values between 52 and 67 (varies from display to display) during setup, otherwise nothing is visible from the menu.

  42. Как сделать такое же перелистывание по нажатию на кнопки?

  43. My menu works but I can't get sensor readings into it, my values are not updating at all.

    I have heard of state machine and the use of interrupts but I don't see how to implement it with this code.

  44. This solution with rotary encoder associated with a push button is an excellent man-machine interface used in many aeronautical equipment. But the TimerOne library is not compatible with the new Arduino Nano Every board which will replace the Nano basic board and other Arduino board of this family (Uno, …).

    Is there an alternative library ?

Leave a Reply

Your email address will not be published. Required fields are marked *