Working on a sketch where I will want to timestamp logs of an event. The project also displays information on a 4 x 20 LCD (on the I2C bus at the default address of 0x27) hopefully including the current date and time. First I tried the RTC simulation running via RTCZero library. I got the epoch from the NTP server ok, and have a little routine to display the time on a 4x20 LCD display. That all worked.
However, it’s wildly inaccurate, losing minutes per hour. Or gaining minutes per hour, depending on the specific Nano 33 IOT it was running on. So I decided to try a DS1307 RTC module. It is also on the I2C bus with an address of 0x86.
Running a simple test script from the RTClib.h examples library it seems to work fine. Serial.print shows the updated time reliably every second.
The problems crop up when I try to display the date/time on the LCD. There are glitches – intermittent spurious values displayed. And those values seem to be coming from the RTC, as they are duplicated in the serial monitor. The timing is random – it may take several minutes or just a few seconds to start glitching. Once it starts, it seems to become more frequent and eventually the display freezes at some random values, although the serial monitor shows it’s still running and producing garbage.
To clarify then: the LCD alone works fine. The RTC alone works fine. The problem seems to be related to having both on the same I2C bus. I have tried all combinations of two separate RTC modules, two separate LCD displays and two separate Nano 33 IOTs. This does not appear to be a hardware issue.
Here is the sketch (as modified):
/*
* Created by ArduinoGetStarted.com
*
* This example code is in the public domain
*
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-lcd-clock
*/
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
// modified the following to suit 4x20 display:
LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27 (from DIYables LCD), 16 column and 2 rows
RTC_DS1307 rtc;
void setup() {
Serial.begin(9600);
lcd.init(); // initialize the lcd
lcd.backlight(); // open the backlight
// SETUP RTC MODULE
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (true)
;
}
// automatically sets the RTC to the date & time on PC this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
void loop() {
DateTime now = rtc.now();
int year = now.year();
int month = now.month();
int day = now.day();
int hour = now.hour();
int minute = now.minute();
int second = now.second();
lcd.clear();
lcd.setCursor(0, 0); // start to print at the first row
lcd.print("Date: ");
lcd.print(year);
lcd.print("/");
lcd.print(month);
lcd.print("/");
lcd.print(day);
lcd.setCursor(0, 1); // start to print at the second row
lcd.print("Time: ");
// added if statement to print leading zero as required. Same with minutes/seconds
if(hour < 10){
lcd.print("0");
}
lcd.print(hour);
lcd.print(":");
if(minute < 10){
lcd.print("0");
}
lcd.print(minute);
lcd.print(":");
if(second < 10){
lcd.print("0");
}
lcd.print(second);
// I added these Serial.print lines to see what's going on:
Serial.print("Date: ");
Serial.print(year);
Serial.print("/");
Serial.print(month);
Serial.print("/");
Serial.print(day);
Serial.print(" Time: ");
if(hour < 10){
Serial.print("0");
}
Serial.print(hour);
Serial.print(":");
if(minute < 10){
Serial.print("0");
}
Serial.print(minute);
Serial.print(":");
if(second < 10){
Serial.print("0");
}
Serial.println(second);
delay(1000); // Update every second
}
Sample serial monitor output:
08:45:03.815 -> Date: 2025/12/14 Time: 08:44:17
08:45:04.862 -> Date: 2025/12/14 Time: 08:44:18
08:45:05.943 -> Date: 2000/61/109 Time: 104:158:00
08:45:06.989 -> Date: 2025/12/14 Time: 08:44:20
08:45:08.059 -> Date: 2025/12/14 Time: 08:44:21
08:45:09.057 -> Date: 2000/61/109 Time: 134:151:00
08:45:10.191 -> Date: 2025/12/14 Time: 08:44:23
08:45:11.188 -> Date: 2025/12/14 Time: 08:44:24
08:45:12.218 -> Date: 2025/12/14 Time: 08:44:25
Sample of serial monitor output after LCD freezes:
08:46:33.883 -> Date: 2025/12/14 Time: 08:45:47
08:46:34.920 -> Date: 2025/12/14 Time: 08:45:48
08:46:35.962 -> Date: 2000/61/109 Time: 162:153:00
08:46:36.965 -> Date: 2000/61/109 Time: 12:51:00
08:46:38.011 -> Date: 2000/61/109 Time: 21:112:00
08:46:38.962 -> Date: 2000/61/109 Time: 31:14:00
08:46:39.966 -> Date: 2000/61/109 Time: 40:76:00
08:46:40.956 -> Date: 2000/61/109 Time: 49:137:00
08:46:41.996 -> Date: 2000/61/109 Time: 59:40:00
08:46:42.992 -> Date: 2000/61/109 Time: 68:101:00
08:46:44.005 -> Date: 2000/61/109 Time: 77:163:00
08:46:44.989 -> Date: 2000/61/109 Time: 87:65:00
08:46:45.997 -> Date: 2000/61/109 Time: 96:121:00
08:46:47.034 -> Date: 2000/61/109 Time: 106:22:00
08:46:48.025 -> Date: 2000/61/109 Time: 115:85:00
I thought maybe it is a voltage issue, since both I2C devices are 5VCC and the Nano 33 IOT is 3.3VCC, so I inserted level shifters (Adafruit 4 Channels IIC I2C Bi-directional Logic Level Converter) with the device side of the bus at 5v (IE: SCL of RTC and LCD connected together at 5v side of one level shifter with 33 IOT SCL pin to the corresponding 3.3v side; SDA of RTC and LCD connected to 5v side of a second level shifter with 33 IOT SDA pin connected to corresponding 3.3v side of the second level shifter).
That did not make any difference.
Power to the Nano 33 IOT is supplied from a regulated 12v supply. Power to the 5v devices is via an LM7805* regulator. Power to the 3.3v side of the level shifters is via an AMS1117-3.3 step-down buck module. Power at all points seems stable when examined on an oscilloscope.
The fallback will be to revert to the RTCzero simulated RTC routine and just update the time via NTP every hour. But that relies on an internet connection and I really rather get a real RTC working. Any suggestions?
*Edited LM3305 typo to LM7805
