Rotary Encoder LCD Menu (Simple - yes one of these I'm sorry)

Summary: The menu system is terrible, Cant add new items with the current system, butting the selection is incredibly temperamental. Need advice for a ceap dirty way to get it working fast. Efficiency etc not important.

Hi, Apologies In advance, I know someone posts something about a rotary encoder menu just about every week on here and I hoped I wouldn't have to be one of them.

My project uses an Arduino mega 2560, a i2c 4 lined LCD display and a cheap rotary encoder. Below is a circuit diagram.

Recently I've started a project requiring a very simple menu and adjustment settings. for instance:

  • On initialization, it must have a scrolling list of items to select.
  • On selection, the other options must disappear displaying a controllable value (with the rotary encoder) for the user to adjust

The code doesn't have to be fancy, or even efficient, therefore I made it with several if statements and a button counter. Depending on the position of the encoder it displays particular information, Every time the button is pressed it counts up on a counter, depending on the value of the counter, it displays a particular page of information. (basically a terrible array of info).

However for some reason, it never seems to want to work past page 2, and if I copy the code to add more page 1 menu items, it no longer works past a particular rotary position. (the libraries are a mess I know, however, I have checked and they are not the issue. I'm assuming I have been an idiot and there's a simple explanation, bad practice, stupid structure, etc. Any suggestions or help would be appreciated.

For some reason, it wouldn't let me post the code in a preferred way and apparently new users cant just attach a zip. so here's a google drive link, it's my first time posting, sorry to be such a pain. Let me know if anyone requires more info/ different files or better explination.

https://drive.google.com/drive/folders/1EqN8xG3RutTQJN7SVhNKkS4ipEDvBDb5?usp=sharing

Your link is not working. Please post a schematic as you have it wired and links to technical information on each of the hardware devices. Read the forum instructions and post your code, at this point the best we can do is guess. Your frizzy picture has errors. No power source, cannot read the labels on the I2C (there are different pinouts on these) the switch connections do notcompute.

I have a simple menu system here which may be of use/interest?
It uses an oled but shouldn't be difficult to convert

1 Like

In case you change your mind about using your code, here is a ready made library to implement a menu system for LCD modules

Better Diagram as requested

Below is the code, im using an arduin 2560

KY-040 encoder (link: https://www.amazon.co.uk/gp/product/B09726Y8RB/ref=ppx_yo_dt_b_asin_title_o05_s00?ie=UTF8&psc=1)

And a IIC/I2C/TWI Serial 2004/20x4 LCD (Link: https://www.amazon.co.uk/gp/product/B01GPUMP9C/ref=ppx_yo_dt_b_asin_title_o07_s01?ie=UTF8&psc=1)


// Include Libraries
#include "Arduino.h"
#include "LiquidCrystal_PCF8574.h"
#include "Encoder.h"
#include "Button.h"

// Pin Definitions
#define ROTARYENCI_PIN_CLK	2
#define ROTARYENCI_PIN_D	3
#define ROTARYENCI_PIN_S1	4

#define LCD_ADDRESS 0x27
//#define LCD_ADDRESS 0x27 0x3F
#define LCD_ROWS 4
#define LCD_COLUMNS 20
#define SCROLL_DELAY 150
#define BACKLIGHT 255
long rotaryEncIOldPosition  = 0;
// object initialization
LiquidCrystal_PCF8574 lcd20x4;
Encoder rotaryEncI(ROTARYENCI_PIN_D,ROTARYENCI_PIN_CLK);
Button rotaryEncIButton(ROTARYENCI_PIN_S1);

// define vars for testing menu
const int timeout = 10000;       //define timeout of 10 sec
char menuOption = 0;
long time0;

// Setup the essentials for your circuit to work. It runs first every time your circuit is powered with electricity.
void setup() 
{
    Serial.begin(9600);
    while (!Serial) ; // wait for serial port to connect. Needed for native USB
    Serial.println("start");
    // initialize the lcd
    lcd20x4.begin(LCD_COLUMNS, LCD_ROWS, LCD_ADDRESS, BACKLIGHT); 
    rotaryEncIButton.init();
    pinMode(ROTARYENCI_PIN_S1, INPUT_PULLUP);
    menuOption = menu();  

}

// Main logic of your circuit. It defines the interaction between the components you selected. After setup, it runs over and over again, in an eternal loop.
void loop() 
{
    if(menuOption == '1') {
    // LCD Display 20x4 I2C - Test Code
    // The LCD Screen will display the text of your choice.
    lcd20x4.clear();                          // Clear LCD screen.
    lcd20x4.selectLine(2);                    // Set cursor at the begining of line 2
    lcd20x4.print("    Testing LCD IC2  ");                   // Print print String to LCD on first line
    lcd20x4.selectLine(3);                    // Set cursor at the begining of line 3
    lcd20x4.print("      V1       ");                   // Print print String to LCD on second line
    delay(10000);
    lcd20x4.clear();
    lcd20x4.selectLine(1);  
    lcd20x4.print("Menu system 2");
    lcd20x4.selectLine(2); 
    lcd20x4.print("Hello there");
    delay(10000);
    lcd20x4.clear();

    }
    else if(menuOption == '2') {
    // Rotary Encoder Module - Test Code
    //Read encoder new position
    long rotaryEncINewPosition = rotaryEncI.read();
    bool rotaryEncIButtonVal = rotaryEncIButton.onPress();
    if (rotaryEncINewPosition != rotaryEncIOldPosition || rotaryEncIButtonVal) {
    rotaryEncIOldPosition = rotaryEncINewPosition;
    Serial.print(F("Pos: "));
    Serial.print(rotaryEncINewPosition);
    Serial.print(F("\tButton: "));
    Serial.println(rotaryEncIButtonVal);
    }
    }

else if(menuOption == '3') {
int Verticle_Item;
int Horizontal_Item;
int Button_Press = 0;
int Counter;
    
long rotaryEncINewPosition = rotaryEncI.read();
bool rotaryEncIButtonVal = rotaryEncIButton.onPress();
long ButtonNew;
    if (rotaryEncINewPosition != rotaryEncIOldPosition || rotaryEncIButtonVal) {
    rotaryEncIOldPosition = rotaryEncINewPosition;
    Serial.print(F("Pos: "));
    Serial.print(rotaryEncINewPosition);
    Serial.print(F("\tButton: ----> "));
    Serial.println(rotaryEncIButtonVal);
if (ButtonNew != rotaryEncIButtonVal) {
rotaryEncIButtonVal = ButtonNew;
Serial.println("Different");
Counter = Counter + 1;
}
Counter = Counter + rotaryEncIButtonVal;
Serial.print(F("Counter ----> "));
Serial.println(Counter);

 if (rotaryEncINewPosition >= 0 and rotaryEncINewPosition <= 4){ //If its at possition one and the button is pressed. 
   if (Counter <= 257){
   lcd20x4.clear();
   lcd20x4.selectLine(1);
   lcd20x4.print("> P1_Item_1_TEST2"); 
   }   
   else if (Counter = 258){
   lcd20x4.clear();
   lcd20x4.selectLine(1);
   lcd20x4.print("> P2_Item_1_TEST2"); 
   }
   else if(Counter = 259){
   lcd20x4.clear();
   lcd20x4.selectLine(1);
   lcd20x4.print("> P3_Item_1_TEST3"); 
   }
}  
if (rotaryEncINewPosition > 4 and rotaryEncINewPosition <= 8){ //if at possition 2
   if (Counter = 256){
     lcd20x4.clear();
     lcd20x4.selectLine(2);
     lcd20x4.print("> P1_Item_2"); 
   }   
   else if (Counter = 258){
     lcd20x4.clear();
     lcd20x4.selectLine(2);
     lcd20x4.print("> P2_Item_2"); 
   }
   else if(Counter = 259){
     lcd20x4.clear();
     lcd20x4.selectLine(2);
     lcd20x4.print("> P3_Item_2"); 
   }
}  
}
if (millis() - time0 > timeout){
menuOption = menu();
    }
  }
}
// Menu function for selecting the components to be tested
// Follow serial monitor for instrcutions
char menu()
{
    Serial.println(F("\nWhich component would you like to test?"));
    Serial.println(F("(1) LCD Display 20x4 I2C"));
    Serial.println(F("(2) Rotary Encoder Module"));
    Serial.println(F("(3) Menu Test"));
    while (!Serial.available());
    // Read data from serial monitor if received
    while (Serial.available()) 
    {
        char c = Serial.read();
        if (isAlphaNumeric(c)) 
        {   
            if(c == '1') 
    			Serial.println(F("Now Testing LCD Display 20x4 I2C"));
    		else if(c == '2') 
    			Serial.println(F("Now Testing Rotary Encoder Module"));
        else if(c == '3') 
          Serial.println(F("Now Testing Menu System"));
            else
            {
                Serial.println(F("illegal input!"));
                return 0;
            }
            time0 = millis();
            return c;//c menu counter, copy that code
        }
    }
}

Again its all a little bit of a mess, hopefull you can see the cheap easy route i was going with it. Apologies if something is'nt clear let know any issues / info needed.

Hi, thanks for linking that, Il take a look :), looks interesting.
honestly If I have to abandon my code, I will.

Hi there, thanks for the reply. Annoying i decided to use a 20x4 LCD as I thought it would be simpler than an OLED. Your code looks great though v similar to what I'm trying to do myself. In the meantime, I may try adapting parts of it, if that's ok.

Hi, Link should be working, unsure on that one. Ive updated the image, and included purchasing info for all the components. Apologies I was a bit dumb on the code posting, Just didnt press a button. As I said hardware doesn't seem to be the issue, pieces of test code work fine, the Arduino can read the rotary encoder and button pressing and display any information on the LCD powered 5V by the arduino. It's just the menu interaction code that's the problem. Hope this helps, apologies if something is wrong or I've missed something.

Pretty cool. You should add a README.md file to the Sim to make a Description tab.

1 Like

Good job, that is one of the first frizzy pictures I understand. I will take a guess and suggest you check for switch bounce. If that is happening it will be rough to adjust.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.