Hello Helpful Community!
As a small part of a fully automated hydroponic system I want to switch a relay (LOW level trigger, to power on and off an LED driver) based on time from an RTC DS 1370.
All works fine... until the LCD gets connected to the I2C bus. Then, before the time comes to switch ON the relay, all serial monitor readings look good, but after the initial switch ON (which works) the RTC either gives 165:165 or random numbers or stops at all or the relay gets switched OFF and ON at short random intervals. This very simple system freezes.
I already spent days working thru this forum or other corners of the internet, but nothing seems to help in this case, so I decided to open a new topic hoping to find expert advise.
Your help is highly appreciated! Thank you very much!
#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
// Initialize the RTC
RTC_DS1307 rtc;
// Initialize the LCD with the I2C address
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Relay pin
const int relayPin = 9;
// Sunrise and sunset times (24-hour format)
const int sunriseHour = 6; // Set sunrise hour here
const int sunriseMinute = 0; // Set sunrise minute here
const int sunsetHour = 22; // Set sunset hour here
const int sunsetMinute = 0; // Set sunset minute here
bool sunriseTriggered = false;
bool sunsetTriggered = false;
void setup() {
// Start the I2C interface
Wire.begin();
// Initialize the LCD
lcd.init();
lcd.backlight();
// Initialize the Serial Monitor
Serial.begin(9600);
// Initialize the RTC
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
// Check if the RTC is running, otherwise set the date and time
if (!rtc.isrunning()) {
Serial.println("RTC is NOT running!");
// Uncomment to set the date and time
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// Initialize relay pin
pinMode(relayPin, OUTPUT);
digitalWrite(relayPin, HIGH); // Ensure relay is off initially
}
void loop() {
// Get the current date and time
DateTime now = rtc.now();
// Display the date and time on the Serial Monitor
Serial.print("Date: ");
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" Time: ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
// Display the date
lcd.setCursor(0, 0);
lcd.print("Date: ");
lcd.print(now.year(), DEC);
lcd.print('/');
lcd.print(now.month(), DEC);
lcd.print('/');
lcd.print(now.day(), DEC);
// Display the time
lcd.setCursor(0, 1);
lcd.print("Time: ");
lcd.print(now.hour(), DEC);
lcd.print(':');
lcd.print(now.minute(), DEC);
lcd.print(':');
lcd.print(now.second(), DEC);
// Check if it's time to switch the relay
checkRelaySwitch(now);
// Update every second
delay(1000);
}
void checkRelaySwitch(DateTime now) {
// Calculate current time in minutes
int currentMinutes = now.hour() * 60 + now.minute();
int sunriseMinutes = sunriseHour * 60 + sunriseMinute;
int sunsetMinutes = sunsetHour * 60 + sunsetMinute;
// Control the relay based on the current time
if (currentMinutes == sunriseMinutes && !sunriseTriggered) {
// It's the exact time of sunrise, turn relay on
digitalWrite(relayPin, LOW);
Serial.println("Relay turned ON at sunrise.");
sunriseTriggered = true;
sunsetTriggered = false; // Reset sunset trigger for the next day
} else if (currentMinutes == sunsetMinutes && !sunsetTriggered) {
// It's the exact time of sunset, turn relay off
digitalWrite(relayPin, HIGH);
Serial.println("Relay turned OFF at sunset.");
sunsetTriggered = true;
sunriseTriggered = false; // Reset sunrise trigger for the next day
}
}
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);
const byte relayPin = 9;
// Sunrise and sunset times (24-hour format)
const byte sunriseHour = 6; // Set sunrise hour here
const byte sunsetHour = 22; // Set sunset hour here
bool isDay = false;
void setup() {
digitalWrite(relayPin, HIGH); // Ensure relay is off initially
lcd.init();
lcd.backlight();
Serial.begin(9600);
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
// Check if the RTC is running, otherwise set the date and time
if (!rtc.isrunning()) {
Serial.println("RTC is NOT running!");
}
pinMode(relayPin, OUTPUT);
}
void loop() {
DateTime now = rtc.now(); // Get the current date and time
char DateText[21];
sprintf(DateText, "Date: %u/%02u/%02u ", now.year(), now.month(), now.day());
char TimeText[21];
sprintf(TimeText, "Time: %02u:%02u:%02u", now.hour(), now.minute(), now.second());
Serial.print(DateText);
Serial.println(TimeText);
lcd.setCursor(0, 0);
lcd.print(DateText);
lcd.setCursor(0, 1);
lcd.print(TimeText);
if (now.minute() == 0) {
bool isTime = (now.hour() >= sunriseHour) && (now.hour() < sunsetHour);
if (isDay != isTime) {
isDay = isTime;
digitalWrite(relayPin, !isDay);
if (isDay)Serial.println("Relay turned ON at sunrise.");
else Serial.println("Relay turned OFF at sunset.");
}
}
delay(1000); // Update every second
}
Can you show a photo of the project and a photo of the power supply.
Do you have a multimeter ? To measure all the voltages.
If your display is not nearby the Nano board, and is connected via a flat bed cable, then this will happen.
If the power supply is very noisy (for example a 5V Power Supply that is only for leds), then this can also happen.
If your project is on a breadboard, then breadboards can have bad contacts and jumper wires can be broken.
Hi @kolaha,
Thanks for this code, but it doesn´t change anything, though I really like your elegant time code.
Here is the serial reading of the switch moment:
How long are the wires you are using to the I2C peripherals ? If these are long try either shortening them, use stronger I2C pull up resistors or slow down the I2C bus clock rate.
Thank you for the photos.
You have build to it in a better way, because this is not possible.
Good:
A 12V Mean Well power supply to a voltage regulator and powering the Nano via the 5V pin is okay.
The measured voltages are okay.
The solid state relays are better than the mechanical ones. The module might not pass the rules for using the main voltage. In most cases those relays are still okay.
Bad:
A final project with a breadboard is not okay. The contacts of a breadboard are not reliable.
The I2C bus in that cable is not okay. The I2C bus can not deal with crosstalk between SDA and SCL. If you do it wrong, then the official standard gives you 10 cm for the maximum length of a I2C bus. See page 54, paragraph 7.5 in the official standard for the I2C bus: https://www.nxp.com/docs/en/user-guide/UM10204.pdf
Your I2C bus can probably be made stronger. Do you know how much pullup there is on the RTC module ? The maximum sink current for SDA and SCL is 3mA. That is the current that is needed to pull SDA (or SCL) low.
Can you do a test ?
Remove the gray cable to the display. Use 4 separate wires, and don't tie them together.
What other cables do you have. How short can the cable to the display be ?
The I2C bus is not designed to go into a cable. It is not that kind of bus. Keep SDA away from SCL.
relay better to power from different source with arduino and I2C devices, very suspicious that error appear only after relay activated. i suppose you powers left side(of breadboard) with 5v from USB and right side from LDO PCB.
can you check if breadboard power lines have conductivity on whole length?
Thanx for your comments and suggestions!
I just hooked up the LCD directly to the breadboard with jumper wires and it worked
But as I want to have the LCD quite far away from the central electronics I will start experimenting with different cable lengths until it all breaks down again haha. Separate cables, shielded cables to avoid crosstalk...
Your third point, making the I2C bus stronger... I don´t know about the pullups on the RTC module.
My "Arduino" has a second I2C bus. Maybe that´s an option.
But even after reading tons of webpages and getting Chat GPT to modify the wire library .h and .cpp files (I´m not a coder, just learning little by little), I wasn´t able to figure out how to address the second I2C bus for the LCD or the RTC. If you have a hint for me, I´d be very happy to test this, too.
I totally agree on this very suspicious timing of the error.
The relays are powered from the same 5V source as everything else.
In my setup all power (left and right of the breadboard) comes from the one external power supply and is perfectly distributed all the way from top to bottom.
To leave no stone unturned I hooked up the relay on a different power source (5V from a USB charger cable) and to my very surprise the relay didn´t switch at all.
Don't use ChatGPT. If you have a detailed specific question, then ChatGPT will send you in the wrong direction and you have to "unlearn" everything that ChatGPT told you. You are wasting your and our time with that.
Don't try 12k5 kHz. About 50kHz is the lowest possible speed with the Wire.setClock().
"quite far" is not a length. How much length do you need ? Did you read the official standard about 10 cm ?
Why would the second I2C bus be better ? I don't know if there is Arduino support for it. The RTC has little influence on the I2C bus. It is about the cable, not the RTC.