Put an LCD menu on a project

Hi,

I'm looking to learn on how to install an LCD menu on my projects.
I have many projects working now but I want to enhance them with new feature like an LCD menu.

Example:

If in one of my project I have a condition like;

if (PSI == 3000){
do something
}

There is no probleme and my device will do what I want when it reach 3000PSI

But If I want to change that value for 2200, I need to change it in my code and instead, I would like
to change that with my push button.

I looked on a few examples and tutorials and I found one interresting. In this sketch I have 10 items and with 4 push buttons I can navigate from Item_0 to Item_9 and for each of them I can change the value.

This is working nice but I need to expand it and learn more about it in order to integrate it into my real projects.

That's the code I found, I change it a little and it's working nice

/*
 * From the tutorial of EEEnthusiast
 * Arduino LCD Menu system Implemented
 */


#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);

//Input & Button Logic
const int numOfInputs = 4;
const int inputPins[numOfInputs] = {8,9,10,11};
int inputState[numOfInputs];
int lastInputState[numOfInputs] = {LOW,LOW,LOW,LOW};
bool inputFlags[numOfInputs] = {LOW,LOW,LOW,LOW};
long lastDebounceTime[numOfInputs] = {0,0,0,0};
long debounceDelay = 5;


//LCD Menu Logic
const int numOfScreens = 10;
int currentScreen = 0;
String screens[numOfScreens][2] = {
{"Item_0","Value"},
{"Item_1","Value"}, 
{"Item_2","Value"},
{"Item_3","Value"},
{"Item_4","Value"},
{"Item_5","Value"},
{"Item_6","Value"},
{"Item_7","Value"},
{"Item_8","Value"},
{"Item_9","Value"}
};

int parameters[numOfScreens];


void setup(){

  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
   
  for(int i = 0; i < numOfInputs; i++) {
    pinMode(inputPins[i], INPUT);
    digitalWrite(inputPins[i], HIGH); 
    } 
}


void setInputFlags() {
  for(int i = 0; i < numOfInputs; i++) {
    int reading = digitalRead(inputPins[i]);
    if (reading != lastInputState[i]) {
      lastDebounceTime[i] = millis();
    }
    if ((millis() - lastDebounceTime[i]) > debounceDelay) {
      if (reading != inputState[i]) {
        inputState[i] = reading;
        if (inputState[i] == HIGH) {
        inputFlags[i] = HIGH;
        }
      }
    } 
    lastInputState[i] = reading;
  }
}


void resolveInputFlags() {
   for(int i = 0; i < numOfInputs; i++) {
    if(inputFlags[i] == HIGH) {
      inputAction(i);
      inputFlags[i] = LOW;
      printScreen();
    }
  }
}


void inputAction(int input) {  //input button
  if(input == 0) {
    if (currentScreen == 0) {
    currentScreen = numOfScreens-1;
    }else{
    currentScreen--;
    }
  }else if(input == 1) {
    if (currentScreen == numOfScreens-1) {
    currentScreen = 0;
    }else{
    currentScreen++;
    }
  }else if(input == 2) { 
    parameterChange(0);
  }else if(input == 3) {
    parameterChange(1);
  }
}


void parameterChange(int key) {
  if(key == 0) {
    parameters[currentScreen]++;
  }else if(key == 1) {
    parameters[currentScreen]--;
  }
}


void printScreen() {
  lcd.clear();
  lcd.print(screens[currentScreen][0]);
  lcd.setCursor(0,1);
  lcd.print(parameters[currentScreen]);
  lcd.print(" ");
  lcd.print(screens[currentScreen][1]);
  
  serialPrint();

}

void serialPrint(){

  Serial.print("Item ");
  Serial.print(currentScreen);
  Serial.print("   Value = ");
  Serial.println(parameters[currentScreen]);

  Serial.println("  ");
  Serial.println("  ");
}

void loop() {
  
  setInputFlags();
  resolveInputFlags(); 
}

I know it will be very wide questions but I need to start somewhere.

I created a Serial.print to see what was store where and I found that the value that are changed in the menu are stored in parameters[currentScreen]

The value stay in memory for each item so If I increase the parameters to 5 in item_4 and to 7 in Item_5, it will stay in each item until I reboot the arduino.

Questions

How can I take the value for each item and store it in variables so I can use it for my example with the If condition?

It stays in memory until I reboot the Arduino but how can I store the variables in a way that it will stay
that way until I go back in the menu to change it again. I don't want it to be erase when I reboot the arduino.

Any suggestions

Thanks,

Hi,
I am using this menu system on a 4 line 20 character LCD with good results..:

Hi Terryking228,

Thanks but that code as no push button input. I will look at it to see if I can plau with it
but I maintain my primary question about the example I found and still want to learn
on how to expand it.

How can I take the value for each item and store it in variables so I can use it for my example with the If condition?

You should be able to use parameters[currentScreen] for the conditional tests.

It stays in memory until I reboot the Arduino but how can I store the variables in a way that it will stay
that way until I go back in the menu to change it again. I don't want it to be erase when I reboot the arduino.

To keep settings through a reboot, you will need to save the latest values in the eeprom, and read them back at startup().

hddforensic:
If in one of my project I have a condition like;

if (PSI == 3000){
do something
}

There is no probleme and my device will do what I want when it reach 3000PSI

It sounds like you are relying on your system to notice every time the pressure goes up or down by a single PSI: in other words, you are relying on the measured pressure not "jumping" from 2999 to 3001.

I have a feeling that something like

if (PSI >= 3000){
    do something
}

would be more robust.

Thanks but that code as no push button input

?? Do you mean no pushbuttons to control the menu??

Here's mine with pushbuttons:

The CODE IS HERE

Hi terryKing,

Yep, you have push buttons. I saw your code and I can see them in it.

I will keep it for future reference. For now I'm moving in the one I posted
and I'm starting to understand a few things. I'm a beginner in programmation
so one thing at the time.

Hi CattleDog,

I found a way to store the value of parameters[currentScreen] and it work
to change the variable of an if condition I made.

I made a sketch with an alarm on temperature and humidity sens by a simple
DHT11 and changing the alarm values work with my menu but I don't store my values
in the EEPROM yet.

I'm at the first step. I have a lot to read and learn so I will have more questions
in a few days.

EEPROM

I checked at Arduino/reference on how to write and read EEPROM but I'm missing something.

The stored value can only be between 0 to 255. it means that If I want to store 3000,
I need to put a divider ?

The EEPROM memory as a specific life of 100,000 write/erase cycle so one day it will stop
working. Is there another way to store a value ? Well 100,000 it's a lot of write/erase so maybe
my question is useless :slight_smile:

If I store a value in one address, I will need to read it in the setup portion of my code on reboot ?

I'm not sure on how the address works, If I store values in different addresses, how do I know
in which one to read what ?

The example in Arduino reference is simple but do you know a better example where I will see
multiple value stored in different addresses and how to read them after ?

Thanks,

Have a read here: Arduino Playground - EEPROMWriteAnything

The stored value can only be between 0 to 255. it means that If I want to store 3000,
I need to put a divider ?

No the basic arduino internal eeprom library EEPROM.h has functions "put" and "get" which can handle any data type or struct of mixed data types. There is no need to use anything else.

The EEPROM memory as a specific life of 100,000 write/erase cycle so one day it will stop
working. Is there another way to store a value ? Well 100,000 it's a lot of write/erase so maybe
my question is useless :slight_smile:

100K writes is a very conservative value. If concerned, the way to handle the limited write issue is to move the data around in the 1024 memory locations available. The main thing to watch out for is that when developing the program you don't wind up in a loop which writes like crazy because you have made a mistake. I rrecommend that you test your eeprom writes in setup() at first to avoid any errors.

f I store a value in one address, I will need to read it in the setup portion of my code on reboot ?

I'm not sure on how the address works, If I store values in different addresses, how do I know
in which one to read what ?

The program can keep track of where things are written. If your storing ints in two bytes, perhaps the memory location can be the index number *2.

There is a way which used the underlying avr eeprom library which can keep track of the memory location for you, but it is more complicated and not really needed.

example where I will see
multiple value stored in different addresses and how to read them after ?

This can be made more generic and without the magic number 2, but it will give you some ideas.

#include <EEPROM.h>
void setup() {
  Serial.begin(115200);
  int dataIn[3] = {123, 456, 789};//will take 2 bytes each
  int dataOut[3] = {0};
  byte eeaddress = 10;//start storing data in address 10

  for (byte i = 0; i < 3; i++)
  {
    EEPROM.put(eeaddress +(2 * i), dataIn[i]);
  }
  for (byte i = 0; i < 3; i++)
  {
    EEPROM.get(eeaddress +(2 * i), dataOut[i]);
    Serial.println(dataOut[i]);
  }
}
void loop() {}