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.
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:
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.
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.
I think this is the change you need in loop(), but I have not tested it
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");
}
}
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
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.
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.
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.
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 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");