How to Prevent LCD Flicker

I have been playing around programming my arduino for a few years now on and off, i wrote a countdown timer that you set and start using 3 pushbuttons and the time remaining is printed to an lcd, i had the same problem with the lcd "flickering" but it wasn't all that bad, recently i purchased one of those cheap "ebay" I2C lcds and started playing around with it, i wrote this simple program, and when running, all the lcd does is flicker on the "Hold next button for 3 seconds to enter settings" holding the button stops the flickering but it will not change to the settings menu, what could the problem be? as i seem to have this problem alot and with a few other programs i tried recently.

#include <LiquidCrystal_I2C.h>
#include <Wire.h>

int nextMenu = 12;
int previousMenu = 11;
int nextButtonState = 0;
int previousButtonState = 0;

LiquidCrystal_I2C lcd(0x27,20,4);

void setup()
{
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0,0);
  pinMode(nextMenu,INPUT);
  pinMode(previousMenu,INPUT);
  digitalWrite(nextMenu,HIGH);
  digitalWrite(previousMenu,HIGH);
}

void main_menu()
{
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Hold Next Button for");
  lcd.setCursor(0,1);
  lcd.print("3 Sec to Enter      ");
  lcd.setCursor(0,2);
  lcd.print("Settings            ");
  if(digitalRead(nextMenu) == LOW)
  {
    delay(3000);
    if(digitalRead(nextMenu) == LOW)
    {
      settings_menu();
    }
  }
}

void settings_menu()
{
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Settings Menu       ");
  lcd.setCursor(0,1);
}


void loop()
{
  main_menu();
}

My problem seems to be that i need to prevent this from looping, but how would i do it?

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Hold Next Button for");
  lcd.setCursor(0,1);
  lcd.print("3 Sec to Enter      ");
  lcd.setCursor(0,2);
  lcd.print("Settings            ");

On every pass through loop(), you call main_manu(), which clears the screen, writes to it, sees that the switch isn't pressed, and exits. Of course the screen is going to flicker.

You should only clear the screen when what you are about to write to it is different from what is there.

Of course, keeping track of what is there is not trivial. But, since the main menu does not change, knowing that it is the main menu being displayed is not difficult.

1 Like

Replace this bit of code:

 if(digitalRead(nextMenu) == LOW)
  {
    delay(3000);
    if(digitalRead(nextMenu) == LOW)
    {
      settings_menu();
    }
  }

With this...

 while(digitalRead(nextMenu); //wait until the button is pushed (active-low, so TRUE=not pushed)
  unsigned long ButtonDown = millis(); //record the time the button went down
  while(!digitalRead(nextMenu) {
     //wait until the button is released
    if(millis()-ButtonDown>3000) {
      //button was held for 3 seconds
      settings_menu();
      break;  //leave the loop
    }
  }

If you push the button but release it in less than 3 seconds, the display will flicker once.

i removed that clear screen in the loop, solved the flickering and the code for reading the button works alot better than what i originally had, thanks! seems like it in not good practice to use lcd.Clear(); but would be better to just format my write commands so that it always writes over the entire row with blank spaces for unused characters. Or use lcd.clear(); and have a while loop after to look for the key presses as MorganS said?

Some displays have a problem with flicker whenever data is written to them. You just have to live with it. The rule of thumb with such displays is, never write to it unless it is absolutely necessary. So updating the entire display in the loop() function is a bad idea, because in that case you repeatedly update it when nothing is changing.

However, some displays don't have this problem. But a clear() command may force it to make mode changes that make it flicker. Details vary considerably between different displays.

Another case, is where a display can handle small updates without flicker, but it shows up if too much data is fed to it at one time. In this case the best approach is also to avoid redundant updates. So if a given digit is already set to 9, you don't write another 9 to it. If you only update the pixels or segments that actually change, the flicker will be mostly eliminated.

I have noticed with the display i am using, that the pixels are very slow to respond to updates, you can see them gradually come on, haven't noticed any flicker when not looping lcd.print(); commands, so thats gotta be my problem, i had been doing some reading and learning better teqniques for coding for the lcd

twenglish1:
seems like it in not good practice to use lcd.Clear(); but would be better to just format my write commands so that it always writes over the entire row with blank spaces for unused characters.

Instead of writing all spaces and then over that, shorter text (2 prints) ... try padding the text with spaces to the whole length and print once.

You can also get flicker from updating text too quickly/often. 4x a second is fast enough.
One way to do that is to have one routine that updates the output text string and sets a flag and a completely separate routine that every 1/4 second (or more) looks at the flag an if it is set, print the text and clear the flag. The text could update 1000x, you see the last one only which is good because if the rest displayed you would only see a mess.