LCD 20x4 and RTC problem using ESP32

i found a problem when display real time clock DS3231 in LCD 20x4 i2c using ESP32 microcontroller, the code works properly, but every 8 second, it skipped one data, so both the serial monitor and LCD display became like this:

Time: hh:mm:13
Time: hh:mm:14
Time: hh:mm:15
Time: hh:mm:16
Time: hh:mm:17
Time: hh:mm:18
Time: hh:mm:19
Time: hh:mm:20
Time: hh:mm:22
....

and so on (every 8 second), the time hh:mm:21 did not display, it display 22 instead, make the time become offset from the real time.

i used oled SSD1306 to compare it, when it's sharing I2C bus with LCD, the oled SSD1306 also skip one data even in LCD i don't display any RTC data (i display dummy text instead because i just want to check the effect of sharing connection i2c between them), but when oled SSD1306 stands alone, it works normally without skip any data.

is there any solutions for this? i'm still a beginner and in my project i need this 2 module display (oled and lcd), should i use different i2c bus for them to work properly ? (as far as i know esp32 has two i2c bus)

here i drop the program code

#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

RTC_DS3231 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 20 chars and 4 line display
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire, -1);

void setup(){
  Serial.begin(115200);
  rtc.begin();
  //rtc.adjust(DateTime(__DATE__, __TIME__));

  lcd.init();
  lcd.backlight();

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.setCursor(0, 0);
  display.print("Processing...");
  display.display();
  delay(3000);
}

void loop(){
  DateTime now = rtc.now();
  
  Serial.print("Time: ");Serial.print(now.hour(), DEC);Serial.print(":");Serial.print(now.minute(), DEC);Serial.print(":");Serial.println(now.second(), DEC);

  lcd.setCursor(0,0);
  lcd.print("Acc-m/s^2");
  lcd.setCursor(0,1);lcd.print("X:-AA.AA");
  lcd.setCursor(0,2);lcd.print("Y:-AA.AA");
  lcd.setCursor(0,3);lcd.print("Y:-AA.AA");
  lcd.setCursor(9,0);lcd.print("|");
  lcd.setCursor(9,1);lcd.print("|");
  lcd.setCursor(9,2);lcd.print("|");
  lcd.setCursor(9,3);lcd.print("|");
  lcd.setCursor(11,0);lcd.print("hh");
  lcd.setCursor(13,0);lcd.print(":");
  lcd.setCursor(14,0);lcd.print("mm");
  lcd.setCursor(16,0);lcd.print(":");
  lcd.setCursor(17,0);lcd.print("ss");
  lcd.setCursor(10,1);lcd.print("CO:AAA ppm");
  lcd.setCursor(10,2);lcd.print("T :AA.AA C");
  lcd.setCursor(10,3);lcd.print("RH:AA.AA %");
  
  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(0, 0);
  display.print("Time: ");display.print(now.hour(), DEC);display.print(":");display.print(now.minute(), DEC);display.print(":");display.println(now.second(), DEC);
  display.display();

  delay(1000);
}

That is the result of using a 1000mS delay instead of looking for the seconds to change in the clock. The LCD functions take a few milliseconds to write to the display, eventually adding up to enough to affect your timing.

All that display code takes time. You do a one second delay at the end that does not account for that time. Apparently it is about 1/8 of a second since it skips every 8 seconds.

EDIT: Looks like @david_2018 beat me to it.

thanks for ur replies, so the LCD module take a little bit more time to display than OLED SSD1306. then how to determine exactly the delay? should i use exactly 1/8 s delay?

A snippet to ponder.

unsigned long lastDisplay = 0;

void loop(){
   unsigned long currentMillis = millis();
   if( currentMillis - lastDisplay >= 1000 ) {
      lastDisplay = currentMillis;
      // display stuff here
   }
}

Don't use a delay. Do like @david_2018 has proposed. Check if the second has changed!

something like

void loop() {
 static int previousSecond = 0;
 DateTime now = rtc.now();
 if (now.second() != previousSecond) {
  previousSecond = now.second();
  Serial.print("Time: ");Serial.print(now.hour(), DEC);Serial.print(":");Serial.print(now.minute(), DEC);Serial.print(":");Serial.println(now.second(), DEC);
  // and lot more

  }
}

thank you so much to all of ur replies guys, i use the program and it works without skip data, but there was a new problem, the lcd save the previous display, since the second is display in one digit for 0-9 s, so when it changes from hh:24:59 to hh:25:0, the lcd display became 00:25:09 , there's additional 9 because the display overlap with the previous second, (it'll display normally when reach tens number, start at hh:mm:10 to be exactly]

i was looking for the solution and i hope this can help if someone out there find the same problem as me.

#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

RTC_DS3231 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 20 chars and 4 line display
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire, -1);

unsigned long lastdisplay = 0;

void setup(){
  Serial.begin(115200);
  rtc.begin();
  //rtc.adjust(DateTime(__DATE__, __TIME__));

  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("Processing...");

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.setCursor(0, 0);
  display.print("Processing...");
  display.display();
  delay(3000);
}

void loop(){
  unsigned long currentMillis = millis();
  DateTime now = rtc.now();
  if (currentMillis - lastdisplay >= 1000) {
    lastdisplay = currentMillis;
    Serial.printf("Time: %02d:%02d:%02d\n", now.hour(), now.minute(), now.second()); //to display 2 digits for second
    Serial.println();

    lcd.setCursor(0,0);
    lcd.print("Acc-m/s^2");
    lcd.setCursor(0,1);lcd.print("X:-AA.AA");
    lcd.setCursor(0,2);lcd.print("Y:-AA.AA");
    lcd.setCursor(0,3);lcd.print("Y:-AA.AA");
    lcd.setCursor(9,0);lcd.print("|");
    lcd.setCursor(9,1);lcd.print("|");
    lcd.setCursor(9,2);lcd.print("|");
    lcd.setCursor(9,3);lcd.print("|");
    lcd.setCursor(11, 0);
    lcd.printf("%02d:%02d:%02d", now.hour(), now.minute(), now.second()); //to display 2 digits for second
    lcd.setCursor(10,1);lcd.print("CO:AAA ppm");
    lcd.setCursor(10,2);lcd.print("T :AA.AA C");
    lcd.setCursor(10,3);lcd.print("RH:AA.AA %");
  
    display.clearDisplay();
    display.setTextSize(2);
    display.setCursor(0, 0);
    display.print("Time: ");display.print(now.hour(), DEC);display.print(":");display.print(now.minute(), DEC);display.print(":");display.println(now.second(), DEC);
    display.display();
  }
  //delay(1000); //don't use delay
}

note: i also connect LCD on the same I2C bus with OLED SSD1306, they work together and display the same data, since i'm gonna add some new peripherals, i think i should modify the program include adding the delay, hope it can work properly without skip any data later, thank u so much for everybody's help

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