LCD menu flicker

I have been trying a few different methods of LCD connection in regard to John Boxall’s LCD with DS1307 timer circuit at http://tronixstuff.com/2010/06/14/getting-started-with-arduino-chapter-ten/
Aside from the normal 4 bit connection to the LCD, I have successfully tried the shift register and i2C connection methods just to turn on and off an LED. Both methods work equally well but in both cases there is excessive “flickering” of the second line of LCD text when the clock data is showing which is somewhat annoying. I have tried increasing the delay at line 403 (I know, it’s the devil’s function) but this only reduces the frequency of the flicker. When there are two lines of text displayed in other sections of the code, like at lines 414 and 416 there is no flicker at all, so I suspect it has something to do with the DS1307 timer hardware or code?
I have included a short video clip
of this flickering (albeit incorrect orientation) and the i2C code and am hoping someone might be able to suggest a solution.
Thanks Pedro.

Tronixstuff_Timer_i2c_LCD.ino (12.6 KB)

Looks to me like the time is written every time through the loop. The first thing the code does is clear the display, which will make it flicker as you are doing this hundreds of times a second.

Couple of ways to address this:

  1. Only update the screen when the time has changed. Practically you just need to remember the seconds value and when that is different from the previous time you update the LCD.
  2. Turn off screen updates while you are putting things on the LCD and then turn them on after you have update. This should make it smoother.

My preference for the first as you can avoid anything to do with the screen formatting, etc, if the time is unchanged - that means you have more clock cycles for something useful.

Marco,
would you mind showing me exactly how to modify this code to do as you suggest in your first method. As I'm sure you may realise, I think my coding skills are slowly improving XD but are still not up to this task. If not, thanks anyway for your suggestions
Pedro.

Ok.

I think this is the change you need in loop(), but I have not tested it :wink:

  static byte	lastSecond = 0;  // <-- remembers the last seconds value (static persists)
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;

  getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
		
  if (second != lastSecond)  // <-- only does the time stuff if the time has changed
  {
    lastSecond = second;  // <-- save this for next time
    lcd.clear(); // clear LCD screen
    lcd.setCursor(0,0);
//... etc, code is unchanged
    lcd.print("Off");
    }
  }

Thanks Marco,
I am just trying to incorporate that into the existing code, no luck so far but I'm trying :smiley:

Do you mean something like this to incorporate your new code snippets?

void loop()
  {
  static byte	lastSecond = 0;  // <-- remembers the last seconds value (static persists)
    
      byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
    getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
    if (second != lastSecond)  // <-- only does the time stuff if the time has changed
  {
    lastSecond = second;  // <-- save this for next time
    lcd.clear(); // clear LCD screen
    
    lcd.setCursor(0,0);
    lcd.print("On");
    if (alarmh<10)
// Continues with the rest of time code

Yes but you will need a matching close bracket to close off the 'if' statement near the end, as in my example, after the last LCD.print for the time message, so the rest of the code for time printing is unchanged but bracketed by the if.

I did put an additional closing bracket right at the end of loop, but it is still flickering. Have I maybe misinterpreted your instructions :grin:

 void loop()
  {
   static byte	lastSecond = 0;  // <-- remembers the last seconds value (static persists)
    
    byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
    getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
     if (second != lastSecond)  // <-- only does the time stuff if the time has changed
  {
    lastSecond = second;  // <-- save this for next time
    lcd.clear(); // clear LCD screen
    
    lcd.setCursor(0,0);
    lcd.print("On");
    if (alarmh<10)
    {
      lcd.print("0");
    }
    lcd.print(alarmh);
    if (alarmm<10)
    {
      lcd.print("0");
    }
    lcd.print(alarmm);
    lcd.print("h");
    lcd.print(" Now:");
    if (hour<10)
    {
      lcd.print("0");
    }
    lcd.print(hour, DEC);
    if (minute<10)
    {
      lcd.print("0");
    }
    lcd.print(minute,DEC);
    lcd.print("h");
    lcd.setCursor(0,1);
    lcd.print("Off");
    if (alarmhoff<10)
    {
      lcd.print("0");
    }
    lcd.print(alarmhoff);
    if (alarmmoff<10)
    {
      lcd.print("0");
    }
    lcd.print(alarmmoff);
    lcd.print("h Tmr:");
    if (timeron==1)
    {
      lcd.print("On");
    } 
    else
      if (timeron==0)
      {
        lcd.print("Off");
      }
    if (digitalRead(10)==HIGH)
      // has the user pressed the button? If so, display the menu
    {
      delay(200); // for debounce
      displaymenu();
    }
    if (timeron==1)
    {
      switchon(); // should I turn on?
      switchoff(); // or should I turn off?
  
    }
    delay(200); // to stop screen flicker
    }
  }

I make the closing bracket needed just before the check for the menu button. Looks like you put it later. The last brace in my original post is where I think it should be.

Sorry to be a pain Marco but you do mean here don't you, and if so there is no difference to the flicker

Flicker.png

Yes that is the spot I think it goes in.

You should try putting some serial print statements to tell you when the LCD is updated. This should have changed it to once a second, so there should be no flicker at all. One spot to print from is at the start of the if statement we just put in. It should only print once per second. Any faster and something is not right.

I will have to refresh my memory on serial monitor print usage. Thanks for your help Marco.

Serial.begin in setup() with the baud rate.
Serial.print or Serial.println when you want to print.

I don't mean to drag this on and on but is the correct place/s "to tell you when the LCD is updated"

pedro,
this is totally unrelated to your flicker issue.
This is a bit of initialization code that I'm
trying to get everyone to stomp out.
(so far I seem to be losing the battle....)

   // Switch on the backlight
    lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
    lcd.setBacklight(HIGH);

This code is incorrectly using the API.
The setBacklight() function is not for turning a backlight on/off, it is for dimming.
The argument is a dim value from 0-255. HIGH is currently defined as 1
and would be a very dim backlight. As luck would have it, the i2c interface
only supports on/off so it remaps the very dim backlight you requested
to be full on because that is the closest it can do without turning off the backlight.

But in the bigger picture, you don't have do that stuff all.
The backlight information can be filled into the constructor.
That way the begin() will turn on the backlight for you.
Then if you want/need to turn it on/off later you use the the functions:

lcd.backlight();
lcd.noBacklight();

The full constructor for your configuration would be:
LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin, BACKLIGHT_PIN, POSITIVE);

The reason I stress this is that if you fully fill in the constructor, you can switch interfaces
by simply changing the constructor. i.e. it is a simple switch from i2c to SR to 4bit parallel.
No other sketch code has to change and it will still work the same.
But if using something like setBacklight(HIGH) then if you switched to 4bit mode,
and were using a shield that used a PWM pin for backlight control, you would end up with
a very DIM LCD.

--- bill

I would put it after the start of the if statement so that you catch when the event happens, not just when you read the time. Also make it a println and you need to put a message between parentheses- Serial.println( "Time change"), or similar.

Thanks Bill.
I have adjusted the few codes that I have where this "transgression" has occurred so consider this to be one minor victory on the battlefront XD
Pedro

I will give that a try Marco, thanks again.

I think I finally got it right this time. The serial monitor is printing out time change about every second but the flicker is the same as before.

void setup()
  { 
     Serial.begin (9600);
   lcd.begin (16,2); //  <<----- My LCD was 16x2

*****************************************************************************************************

void loop()
{
  static byte	lastSecond = 0;  // <-- remembers the last seconds value (static persists)

   byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
    getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);

     if (second != lastSecond)  // <-- only does the time stuff if the time has changed
      Serial.println("Time change");

Can you repost all the code with the current changes. Something is not right.