Arduino resets or hangs - RTC + LCD +DHT11

Greetings !

I am using Arduino Uno to control a terrarium for my pet.

Parts:
-RTC module
-LCD
-DHT sensor
-Relay board 4-channel

Objectives:
-Day-night cicle where the lights are turned on/off
-Diferent temperature for day and night
-Hot side and cool side with different temperatures
-Fans turning on/off according to the humidity

Display:


Everything that is fixed display is printed on the setup.
Things that are variable are done in the loop. (Day/Night symbol, time and blinking “:”, temperature, humidity and status of the fans and relays)

Problem:
The program can run for days without a problem but then it freezes or gets random restarts. it also can happen after a few minutes only. Either the LCD turns all blank or the time stops and the LCD freezes displaying the last info.

I checked the ram and it was not increasing.
Tried 3 different power supplies powering the arduino via USB.

So i assume I have a blackhole in my code somewhere, it is a bit extense but easy to understand, i believe.

Thank you for your time !

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <dht.h>

#if defined(ARDUINO) && ARDUINO >= 100
#define printByte(args)  write(args);
#else
#define printByte(args)  print(args,BYTE);
#endif

#define RELAY1  9   //hot side relay
#define RELAY2  10   //cool side relay
#define RELAY3  11   //fan relay
#define RELAY4  12   //light relay
#define DHT11_HOT 5  //hot side sensor
#define DHT11_COOL 4 //cool side sensor

RTC_DS1307 RTC;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
dht DHT;
bool hoton = false;
bool coolon = false;
bool fanon = false;
int chk = 0;
int tempHot = 0;
int humHot = 0;
int tempCool = 0;
int humCool = 0;
int checkTemp = 0;
int checkHum = 0;
int segAnt = -1;

byte termometru[8] = //icon for termometer
{
  B00100,
  B01010,
  B01010,
  B01110,
  B01110,
  B11111,
  B11111,
  B01110
};

byte picatura[8] = //icon for water droplet
{
  B00100,
  B00100,
  B01010,
  B01010,
  B10001,
  B10001,
  B10001,
  B01110,
};

byte night[8] = { //icon for moon
  0b11100,
  0b00110,
  0b00011,
  0b00011,
  0b00011,
  0b00011,
  0b00110,
  0b11100
};

byte dia[8] = { //icon for sun
  0b00000,
  0b00100,
  0b10101,
  0b01110,
  0b11111,
  0b01110,
  0b10101,
  0b00100
};

void setup()
{
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  digitalWrite(RELAY1, LOW);
  digitalWrite(RELAY2, LOW);
  digitalWrite(RELAY3, LOW);
  digitalWrite(RELAY4, LOW);
  lcd.begin (20, 4) ;                     // initialize the lcd
  lcd.print("Initialising...");
  lcd.createChar(1, termometru);
  lcd.createChar(2, picatura);
  lcd.createChar(3, night);
  lcd.createChar(4, dia);
  lcd.setBacklight(LOW);
  lcd.clear();
  Wire.begin();
  RTC.begin();

  //RTC.adjust(DateTime(__DATE__, __TIME__)); //sets the rtc time to the compilation time
  //basic layout of the LCD
  lcd.setCursor(1, 0); lcd.print("   Yoshi's Land    ");
  lcd.setCursor(0, 1); lcd.print(" "); lcd.write(1);
  lcd.setCursor(2, 1); lcd.print("     ");
  lcd.setCursor(13, 1); lcd.print("      ");
  lcd.setCursor(18, 1);  lcd.write(2); lcd.print(" ");
  lcd.setCursor(0, 2); lcd.print("Hot :"); lcd.setCursor(7, 2); lcd.print((char)223); lcd.print("C ");
  lcd.setCursor(0, 3); lcd.print("Cool:"); lcd.setCursor(7, 3); lcd.print((char)223); lcd.print("C ");

}

void loop()
{
  DateTime now = RTC.now(); //get the time from the rtc

  //DISPLAYING THE TIME

  if (now.hour() < 10) {    //using 24h format if hour<10 adds the 0 and prints the hour
    lcd.setCursor(7, 1); lcd.print("0"); lcd.print(now.hour(), DEC);
  };
  if (now.hour() >= 10) {
    lcd.setCursor(7, 1); lcd.print(now.hour(), DEC);
  };
  if (now.second() % 2 == 0)lcd.print(":");//blinking ":" 1 sec on/off
  if (now.second() % 2 != 0)lcd.print(" ");
  if (now.minute() < 10) {  //if min<10 adds the 0 and prints the minutes
    lcd.print("0");
  };
  lcd.print(now.minute(), DEC);

  //READING SENSORS AND COMMAND RELAYS

  if (now.hour() >= 14) { //at 14h the day cycle starts
    lcd.setCursor(0, 0);
    lcd.write(4);
    lcd.setBacklight(HIGH);
    if (now.second() % 2 == 0 && now.second() != segAnt) { //every 2 seconds, read the sensor
      chk = DHT.read11(DHT11_HOT);
      checkTemp = DHT.temperature;
      if (checkTemp > 0 && checkTemp < 60) {     //only temperature and humidity readings that make sense are processed
        tempHot = checkTemp + 3;
      }
      checkHum = DHT.humidity;
      if (checkHum > 0 && checkHum < 100) {
        humHot = checkHum;
      }
      chk = DHT.read11(DHT11_COOL);
      checkTemp = DHT.temperature;
      if (checkTemp > 0 && checkTemp < 60) {
        tempCool = checkTemp;
      }
      checkHum = DHT.humidity;
      if (checkHum > 0 && checkHum < 100) {
        humCool = checkHum - 23;
      }
      segAnt = now.second();  //saves the seconds so that it only reads one time in each second
    }
    //acting on the relays
    if (tempHot < 30)
    {
      digitalWrite(RELAY1, LOW);
      hoton = true;
    }
    if (tempHot > 30)
    {
      digitalWrite(RELAY1, HIGH);
      hoton = false;
    }

    if (tempCool < 22)
    {
      digitalWrite(RELAY2, LOW);
      coolon = true;
    }
    if (tempCool > 22)
    {
      digitalWrite(RELAY2, HIGH);
      coolon = false;
    }
    if (humHot > 50 || humCool > 50)
    {
      digitalWrite(RELAY3, LOW);
      fanon = true;
    }
    if (humHot < 50 && humCool < 50)
    {
      digitalWrite(RELAY3, HIGH);
      fanon = false;
    }
    digitalWrite(RELAY4, LOW);
  }

  if (now.hour() < 14) { //at 00 the night cycle starts
    lcd.setCursor(0, 0);
    lcd.write(3);
    lcd.setBacklight(LOW);
    if (now.second() % 2 == 0 && now.second() != segAnt) {
      chk = DHT.read11(DHT11_HOT);
      checkTemp = DHT.temperature;
      if (checkTemp > 0 && checkTemp < 60) {
        tempHot = checkTemp + 3;
      }
      checkHum = DHT.humidity;
      if (checkHum > 0 && checkHum < 100) {
        humHot = checkHum;
      }
      chk = DHT.read11(DHT11_COOL);
      checkTemp = DHT.temperature;
      if (checkTemp > 0 && checkTemp < 60) {
        tempCool = checkTemp;
      }
      checkHum = DHT.humidity;
      if (checkHum > 0 && checkHum < 100) {
        humCool = checkHum - 23;
      }
      segAnt = now.second();
    }
    if (tempHot < 16)
    {
      digitalWrite(RELAY1, LOW);
      hoton = true;
    }
    if (tempHot > 16)
    {
      digitalWrite(RELAY1, HIGH);
      hoton = false;
    }

    if (tempCool < 16)
    {
      digitalWrite(RELAY2, LOW);
      coolon = true;
    }
    if (tempCool > 16)
    {
      digitalWrite(RELAY2, HIGH);
      coolon = false;
    }
    digitalWrite(RELAY3, HIGH);
    fanon = false;
    digitalWrite(RELAY4, HIGH);
  }
  //TEMP, HUM AND OTHER INFO ON THE LCD
  lcd.setCursor(5, 2); lcd.print(tempHot);
  lcd.setCursor(10, 2);
  if (hoton == true) {
    lcd.print("[ON]  ");
  } else {
    lcd.print("[OFF] ");
  }
  if (fanon == true) {
    lcd.print("*");
  } else {
    lcd.print(" ");
  }
  lcd.print(humHot); lcd.print("%");

  lcd.setCursor(5, 3); lcd.print(tempCool);
  lcd.setCursor(10, 3);
  if (coolon == true) {
    lcd.print("[ON]  ");
  } else {
    lcd.print("[OFF] ");
  }
  if (fanon == true) {
    lcd.print("*");
  } else {
    lcd.print(" ");
  }
  lcd.print(humCool); lcd.print("%");
}

it is a bit extense but easy to understand, i believe.

It's relatively easy to understand that you have too much code. You read the temperature and humidity day and night. The code is, as near as I can tell, exactly the same for reading the temperature and humidity at night as during the day.

Move that code out of the if and else bodies, and delete one of the duplicates. It would be best to put that code in a function, and call that function from loop().

The usual thing to do is to toggle an LED, in loop(), every n milliseconds. If the LCD stops updating, but the LED keeps blinking, you have one problem. If the LED also quits blinking, you have another.

Which problem do you have?

Thanks for the reply.

So i declared the DateTime as a global and created a function readTime() that i call in that if day and night.

I also wired an LED that blinks with the “:”.
I already got a reset a few minutes after plugging, but everything is running.
The modifications are below:

...

DateTime now;

void readTemp()
{
  chk = DHT.read11(DHT11_HOT);
  checkTemp = DHT.temperature;
  if (checkTemp > 0 && checkTemp < 60) {
    tempHot = checkTemp + 3;
  }
  checkHum = DHT.humidity;
  if (checkHum > 0 && checkHum < 100) {
    humHot = checkHum;
  }
  chk = DHT.read11(DHT11_COOL);
  checkTemp = DHT.temperature;
  if (checkTemp > 0 && checkTemp < 60) {
    tempCool = checkTemp;
  }
  checkHum = DHT.humidity;
  if (checkHum > 0 && checkHum < 100) {
    humCool = checkHum - 23;
  }
  segAnt = now.second();

...

if (now.second() % 2 == 0 && now.second() != segAnt) {
      readTemp();
    }
...

if (now.second() % 2 == 0)lcd.print(":");digitalWrite(LED, HIGH);
  if (now.second() % 2 != 0)lcd.print(" ");digitalWrite(LED, LOW);
}

EDIT:

Update, the LCD froze. The LED is off.

Well, it's perfectly obvious that the code you posted is not the code running on the Arduino.

What do you mean? I made those fixes as you suggested.

DanielCabaceira:
What do you mean? I made those fixes as you suggested.

I tried to compile that code...

Arduino: 1.8.2 (Windows 7), TD: 1.36, Board: "Arduino/Genuino Uno"

sketch_feb15a:2: error: expected unqualified-id before '...' token

 ...

 ^

C:\Users\pjs9486\Documents\Arduino\Crap\Crap.ino\sketch_feb15a\sketch_feb15a.ino: In function 'void readTemp()':

sketch_feb15a:8: error: 'chk' was not declared in this scope

   chk = DHT.read11(DHT11_HOT);

   ^

sketch_feb15a:8: error: 'DHT' was not declared in this scope

   chk = DHT.read11(DHT11_HOT);

         ^

sketch_feb15a:8: error: 'DHT11_HOT' was not declared in this scope

   chk = DHT.read11(DHT11_HOT);

                    ^

sketch_feb15a:9: error: 'checkTemp' was not declared in this scope

   checkTemp = DHT.temperature;

   ^

sketch_feb15a:11: error: 'tempHot' was not declared in this scope

     tempHot = checkTemp + 3;

     ^

sketch_feb15a:13: error: 'checkHum' was not declared in this scope

   checkHum = DHT.humidity;

   ^

sketch_feb15a:15: error: 'humHot' was not declared in this scope

     humHot = checkHum;

     ^

sketch_feb15a:17: error: 'DHT11_COOL' was not declared in this scope

   chk = DHT.read11(DHT11_COOL);

                    ^

sketch_feb15a:20: error: 'tempCool' was not declared in this scope

     tempCool = checkTemp;

     ^

sketch_feb15a:24: error: 'humCool' was not declared in this scope

     humCool = checkHum - 23;

     ^

sketch_feb15a:26: error: 'segAnt' was not declared in this scope

   segAnt = now.second();

   ^

sketch_feb15a:26: error: 'now' was not declared in this scope

   segAnt = now.second();

            ^

sketch_feb15a:28: error: expected primary-expression before '...' token

 ...

 ^

sketch_feb15a:33: error: expected primary-expression before '...' token

 ...

 ^

sketch_feb15a:35: error: 'LED' was not declared in this scope

 if (now.second() % 2 == 0)lcd.print(":");digitalWrite(LED, HIGH);

                                                       ^

sketch_feb15a:36: error: 'lcd' was not declared in this scope

   if (now.second() % 2 != 0)lcd.print(" ");digitalWrite(LED, LOW);

                             ^

exit status 1
expected unqualified-id before '...' token

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

My bad, here it is.

#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <dht.h>

#if defined(ARDUINO) && ARDUINO >= 100
#define printByte(args)  write(args);
#else
#define printByte(args)  print(args,BYTE);
#endif
#define LED 8
#define RELAY1  9   //hot side relay
#define RELAY2  10   //cool side relay
#define RELAY3  11   //fan relay
#define RELAY4  12   //light relay
#define DHT11_HOT 5  //hot side sensor
#define DHT11_COOL 4 //cool side sensor

RTC_DS1307 RTC;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // set the LCD address to 0x27 for a 16 chars and 2 line display
dht DHT;
bool hoton = false;
bool coolon = false;
bool fanon = false;
int chk = 0;
int tempHot = 0;
int humHot = 0;
int tempCool = 0;
int humCool = 0;
int checkTemp = 0;
int checkHum = 0;
int segAnt = -1;
DateTime now;

byte termometru[8] = //icon for termometer
{
  B00100,
  B01010,
  B01010,
  B01110,
  B01110,
  B11111,
  B11111,
  B01110
};

byte picatura[8] = //icon for water droplet
{
  B00100,
  B00100,
  B01010,
  B01010,
  B10001,
  B10001,
  B10001,
  B01110,
};

byte night[8] = {
  0b11100,
  0b00110,
  0b00011,
  0b00011,
  0b00011,
  0b00011,
  0b00110,
  0b11100
};

byte dia[8] = {
  0b00000,
  0b00100,
  0b10101,
  0b01110,
  0b11111,
  0b01110,
  0b10101,
  0b00100
};

void readTemp()
{
  chk = DHT.read11(DHT11_HOT);
  checkTemp = DHT.temperature;
  if (checkTemp > 0 && checkTemp < 60) {
    tempHot = checkTemp + 3;
  }
  checkHum = DHT.humidity;
  if (checkHum > 0 && checkHum < 100) {
    humHot = checkHum;
  }
  chk = DHT.read11(DHT11_COOL);
  checkTemp = DHT.temperature;
  if (checkTemp > 0 && checkTemp < 60) {
    tempCool = checkTemp;
  }
  checkHum = DHT.humidity;
  if (checkHum > 0 && checkHum < 100) {
    humCool = checkHum - 23;
  }
  segAnt = now.second();
}

void setup()
{
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  digitalWrite(RELAY1, LOW);
  digitalWrite(RELAY2, LOW);
  digitalWrite(RELAY3, LOW);
  digitalWrite(RELAY4, LOW);
  lcd.begin (20, 4) ;                     // initialize the lcd
  lcd.print("Initialising...");
  lcd.createChar(1, termometru);
  lcd.createChar(2, picatura);
  lcd.createChar(3, night);
  lcd.createChar(4, dia);
  lcd.setBacklight(LOW);
  lcd.clear();
  Wire.begin();
  RTC.begin();

  //RTC.adjust(DateTime(__DATE__, __TIME__));
  lcd.setCursor(1, 0); lcd.print("   Yoshi's Land    ");
  lcd.setCursor(0, 1); lcd.print(" "); lcd.write(1);
  lcd.setCursor(2, 1); lcd.print("     ");
  lcd.setCursor(13, 1); lcd.print("      ");
  lcd.setCursor(18, 1);  lcd.write(2); lcd.print(" ");
  lcd.setCursor(0, 2); lcd.print("Hot :"); lcd.setCursor(7, 2); lcd.print((char)223); lcd.print("C ");
  lcd.setCursor(0, 3); lcd.print("Cool:"); lcd.setCursor(7, 3); lcd.print((char)223); lcd.print("C ");
}

void loop()
{
  now = RTC.now();
  if (now.hour() < 10) {
    lcd.setCursor(7, 1); lcd.print("0"); lcd.print(now.hour(), DEC);
  };
  if (now.hour() >= 10) {
    lcd.setCursor(7, 1); lcd.print(now.hour(), DEC);
  };
  if (now.second() % 2 == 0) {
    lcd.print(":");
    digitalWrite(LED, HIGH);
  }
  if (now.second() % 2 != 0) {
    lcd.print(" ");
    digitalWrite(LED, LOW);
  }
  if (now.minute() < 10) {
    lcd.print("0");
  };
  lcd.print(now.minute(), DEC);
  if (now.hour() >= 14) {
    lcd.setCursor(0, 0);
    lcd.write(4);
    lcd.setBacklight(HIGH);
    if (now.second() % 2 == 0 && now.second() != segAnt) {
      readTemp();
    }
    if (tempHot < 30)
    {
      digitalWrite(RELAY1, LOW);
      hoton = true;
    }
    if (tempHot > 30)
    {
      digitalWrite(RELAY1, HIGH);
      hoton = false;
    }

    if (tempCool < 22)
    {
      digitalWrite(RELAY2, LOW);
      coolon = true;
    }
    if (tempCool > 22)
    {
      digitalWrite(RELAY2, HIGH);
      coolon = false;
    }
    if (humHot > 50 || humCool > 50)
    {
      digitalWrite(RELAY3, LOW);
      fanon = true;
    }
    if (humHot < 50 && humCool < 50)
    {
      digitalWrite(RELAY3, HIGH);
      fanon = false;
    }
    digitalWrite(RELAY4, LOW);
  }
  if (now.hour() < 14) {
    lcd.setCursor(0, 0);
    lcd.write(3);
    lcd.setBacklight(LOW);
    if (now.second() % 2 == 0 && now.second() != segAnt) {
      readTemp();
    }
    if (tempHot < 16)
    {
      digitalWrite(RELAY1, LOW);
      hoton = true;
    }
    if (tempHot > 16)
    {
      digitalWrite(RELAY1, HIGH);
      hoton = false;
    }

    if (tempCool < 16)
    {
      digitalWrite(RELAY2, LOW);
      coolon = true;
    }
    if (tempCool > 16)
    {
      digitalWrite(RELAY2, HIGH);
      coolon = false;
    }
    digitalWrite(RELAY3, HIGH);
    fanon = false;
    digitalWrite(RELAY4, HIGH);
  }

  lcd.setCursor(5, 2); lcd.print(tempHot);
  lcd.setCursor(10, 2);
  if (hoton == true) {
    lcd.print("[ON]  ");
  } else {
    lcd.print("[OFF] ");
  }
  if (fanon == true) {
    lcd.print("*");
  } else {
    lcd.print(" ");
  }
  lcd.print(humHot); lcd.print("%");

  lcd.setCursor(5, 3); lcd.print(tempCool);
  lcd.setCursor(10, 3);
  if (coolon == true) {
    lcd.print("[ON]  ");
  } else {
    lcd.print("[OFF] ");
  }
  if (fanon == true) {
    lcd.print("*");
  } else {
    lcd.print(" ");
  }
  lcd.print(humCool); lcd.print("%");
}

BUMP/UPDATE:

Still haven't found a solution. Did some serial prints and the system is hanging or reseting in the middle of prints sometimes, other times middle loop. The LED always freezes.

  if (now.second() % 2 == 0) {
    lcd.print(":");
    digitalWrite(LED, HIGH);
  }
  if (now.second() % 2 != 0) {
    lcd.print(" ");
    digitalWrite(LED, LOW);
  }

How many of these conditions can be true at the same time? if/else looks more appropriate.

I'm wondering how much memory you have at run time. You have a lot of string literals that get copied to SRAM at run time that don't need to be there. Use the F() macro to keep them out.

lcd.print(F("This string is NOT copied to SRAM"));

PaulS:

  if (now.second() % 2 == 0) {

lcd.print(":");
    digitalWrite(LED, HIGH);
  }
  if (now.second() % 2 != 0) {
    lcd.print(" ");
    digitalWrite(LED, LOW);
  }



How many of these conditions can be true at the same time? if/else looks more appropriate.

I'm wondering how much memory you have at run time. You have a lot of string literals that get copied to SRAM at run time that don't need to be there. Use the F() macro to keep them out.

lcd.print(F("This string is NOT copied to SRAM"));

That segment is now an if/else as you suggested.

I tested some free memory functions and the free memery was arround 800, I used the macro on the possible strings and the free memory has doubled to 1600+.

I think the system hangs have stopped but the resets still occur. I found the system running (LED blinking) but the LCD was blank. This happened twice in a week.

Another week passed and it ran fine till Wednesday, when it crashed a few times in a row (blank LCD, led blinking).

Yesterday it crashed again (blank LCD, led off).

Today it crashed just now, LCD full of random chars, led ON.

Bump. Still haven't found the solution, I'll set up a watchdog for now..

Do you see the problem with the relays disconnected? There may be electrical noise or power issues when the relays switch.

Do you have flyback diodes on the relays? Do you have a capacitor across the power terminals of the lcd? How is everything powered?

Post your latest code. Can there be any relation to relays kicking in? Are you using relay boards or relays with additional circuitry?

Links to what you use and a diagram how it's wired can be useful.

cattledog:
Do you see the problem with the relays disconnected? There may be electrical noise or power issues when the relays switch.

Do you have flyback diodes on the relays? Do you have a capacitor across the power terminals of the lcd? How is everything powered?

I did not try with the relays disconnected, do you mean without the relay board or just the relays OFF?
I am using a 4-Channel relay board. The LCD has a I2C module attached and the Arduino is powering everything and being powered by USB.

sterretje:
Post your latest code. Can there be any relation to relays kicking in? Are you using relay boards or relays with additional circuitry?

Links to what you use and a diagram how it’s wired can be useful.

This is my latest code, when I added the watchdog today:

#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <dht.h>
#include <avr/wdt.h>
#include <WString.h>

#if defined(ARDUINO) && ARDUINO >= 100
#define printByte(args)  write(args);
#else
#define printByte(args)  print(args,BYTE);
#endif
#define LED 8
#define RELAY1  9   //hot side relay
#define RELAY2  10   //cool side relay
#define RELAY3  11   //fan relay
#define RELAY4  12   //light relay
#define DHT11_HOT 5  //hot side sensor
#define DHT11_COOL 4 //cool side sensor

RTC_DS1307 RTC;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // set the LCD address to 0x27 for a 16 chars and 2 line display
dht DHT;
bool hoton = false;
bool coolon = false;
bool fanon = false;
int chk = 0;
int tempHot = 0;
int humHot = 0;
int tempCool = 0;
int humCool = 0;
int checkTemp = 0;
int checkHum = 0;
int segAnt = -1;
DateTime now;

byte termometru[8] = //icon for termometer
{
  B00100,
  B01010,
  B01010,
  B01110,
  B01110,
  B11111,
  B11111,
  B01110
};

byte picatura[8] = //icon for water droplet
{
  B00100,
  B00100,
  B01010,
  B01010,
  B10001,
  B10001,
  B10001,
  B01110,
};

byte night[8] = {
  0b11100,
  0b00110,
  0b00011,
  0b00011,
  0b00011,
  0b00011,
  0b00110,
  0b11100
};

byte dia[8] = {
  0b00000,
  0b00100,
  0b10101,
  0b01110,
  0b11111,
  0b01110,
  0b10101,
  0b00100
};

/*int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
  }*/

void readTemp()
{
  chk = DHT.read11(DHT11_HOT);
  checkTemp = DHT.temperature;
  if (checkTemp > 0 && checkTemp < 60) {
    tempHot = checkTemp + 3;
  }
  checkHum = DHT.humidity;
  if (checkHum > 0 && checkHum < 100) {
    humHot = checkHum;
  }
  chk = DHT.read11(DHT11_COOL);
  checkTemp = DHT.temperature;
  if (checkTemp > 0 && checkTemp < 60) {
    tempCool = checkTemp;
  }
  checkHum = DHT.humidity;
  if (checkHum > 0 && checkHum < 100) {
    humCool = checkHum - 23;
  }
  segAnt = now.second();
}

void setup()
{
  wdt_enable(WDTO_8S);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  digitalWrite(RELAY1, LOW);
  digitalWrite(RELAY2, LOW);
  digitalWrite(RELAY3, LOW);
  digitalWrite(RELAY4, LOW);
  lcd.begin (20, 4) ;                     // initialize the lcd
  // Print a message to the LCD.
  lcd.print("Initialising...");
  lcd.createChar(1, termometru);
  lcd.createChar(2, picatura);
  lcd.createChar(3, night);
  lcd.createChar(4, dia);
  lcd.setBacklight(LOW);
  lcd.clear();
  Wire.begin();
  RTC.begin();

  // following line sets the RTC to the date & time this sketch was compiled
  //RTC.adjust(DateTime(__DATE__, __TIME__));
  lcd.setCursor(1, 0); lcd.print(F("   Yoshi's Land    "));
  lcd.setCursor(0, 1); lcd.print(F(" ")); lcd.write(1);
  lcd.setCursor(2, 1); lcd.print(F("     "));
  lcd.setCursor(13, 1); lcd.print(F("      "));
  lcd.setCursor(18, 1);  lcd.write(2); lcd.print(F(" "));
  lcd.setCursor(0, 2); lcd.print(F("Hot :")); lcd.setCursor(7, 2); lcd.print((char)223); lcd.print(F("C "));
  lcd.setCursor(0, 3); lcd.print(F("Cool:")); lcd.setCursor(7, 3); lcd.print((char)223); lcd.print(F("C "));

}

void loop()
{
  wdt_reset();
  now = RTC.now();
  if (now.hour() < 10) {
    lcd.setCursor(7, 1); lcd.print(F("0")); lcd.print(now.hour(), DEC);
  };
  if (now.hour() >= 10) {
    lcd.setCursor(7, 1); lcd.print(now.hour(), DEC);
  };
  if (now.second() % 2 == 0) {
    lcd.print(F(":"));
    digitalWrite(LED, HIGH);
  }
  else {
    lcd.print(F(" "));
    digitalWrite(LED, LOW);
  }
  if (now.minute() < 10) {
    lcd.print(F("0"));
    lcd.print(now.minute(), DEC);
  };
  if (now.minute() >= 10) {
    lcd.print(now.minute(), DEC);
  };
  if (now.hour() >= 14) {
    lcd.setCursor(0, 0);
    lcd.write(4);
    lcd.setBacklight(HIGH);
    if (now.second() % 2 == 0 && now.second() != segAnt) {
      readTemp();
    }
    if (tempHot < 29)
    {
      digitalWrite(RELAY1, LOW);
      hoton = true;
    }
    if (tempHot >= 30)
    {
      digitalWrite(RELAY1, HIGH);
      hoton = false;
    }

    if (tempCool < 21)
    {
      digitalWrite(RELAY2, LOW);
      coolon = true;
    }
    if (tempCool >= 22)
    {
      digitalWrite(RELAY2, HIGH);
      coolon = false;
    }
    if (humHot > 50 || humCool > 50)
    {
      digitalWrite(RELAY3, LOW);
      fanon = true;
    }
    if (humHot < 50 && humCool < 50)
    {
      digitalWrite(RELAY3, HIGH);
      fanon = false;
    }
    digitalWrite(RELAY4, LOW);
  }
  if (now.hour() < 14) {
    lcd.setCursor(0, 0);
    lcd.write(3);
    lcd.setBacklight(LOW);
    if (now.second() % 2 == 0 && now.second() != segAnt) {
      readTemp();
    }
    if (tempHot < 16)
    {
      digitalWrite(RELAY1, LOW);
      hoton = true;
    }
    if (tempHot > 16)
    {
      digitalWrite(RELAY1, HIGH);
      hoton = false;
    }

    if (tempCool < 16)
    {
      digitalWrite(RELAY2, LOW);
      coolon = true;
    }
    if (tempCool > 16)
    {
      digitalWrite(RELAY2, HIGH);
      coolon = false;
    }
    digitalWrite(RELAY3, HIGH);
    fanon = false;
    digitalWrite(RELAY4, HIGH);
  }

  lcd.setCursor(5, 2); lcd.print(tempHot);
  lcd.setCursor(10, 2);
  if (hoton == true) {
    lcd.print(F("[ON]  "));
  } else {
    lcd.print(F("[OFF] "));
  }
  if (fanon == true) {
    lcd.print(F("*"));
  } else {
    lcd.print(F(" "));
  }
  lcd.print(humHot); lcd.print(F("%"));

  lcd.setCursor(5, 3); lcd.print(tempCool);
  lcd.setCursor(10, 3);
  if (coolon == true) {
    lcd.print(F("[ON]  "));
  } else {
    lcd.print(F("[OFF] "));
  }
  if (fanon == true) {
    lcd.print(F("*"));
  } else {
    lcd.print(F(" "));
  }
  lcd.print(humCool); lcd.print(F("%"));
}

I will attach a diagram I made, it probably is not good but it was the best I could do with my knowledge.

Thank you both!

Schematic_Terrario.pdf (42.7 KB)

I did not try with the relays disconnected, do you mean without the relay board or just the relays OFF?

The first trouble shooting to do is what has been suggested and determine if the relays are causing the issue. I would Disconnect the wires from D9-D12 going to the relay inputs and see if the program fails. Alternatively you could disconnect Vcc and gnd from the relays.

You will need to figure out how to supply the inputs which exercises the digital writes to the relays with the heaters and fans not actually operating.

A capacitor across Vcc and Gnd of the lcd is a good idea. The lcd failing with the underlying program operating is a classic symptom of electrically noisy environments

Ok so, finally I had the time to run some tests. I have been turning the relays on and off manually to see what happens and many times when a relays is turned on the LCD hangs or freezes. So I guess we can assume that the relays are the cause of the problem.

I have little knowledge about capacitors but from I understood I need a decoupling capacitor as close as possible to the LCD, across VCC and GND. Am I correct?

Is a 1 uF cap good?

Thank you!

I had the same issue with a project I am working on. The cause was noise on the SDA/SCL lines which causes the Wire library to hang (and your program to freeze). My solution was to use a software only version on Wire on different pins and not rely on the Uno hardware and interrupts. Works perfectly. This may not be possible in your case since the LCD library uses the Wire library and you would have to hack that.

You can not reliably power a relay board from the Arduino ! Start by giving the relay board it's own power supply. Keep the grounds between Arduino and relay board connected.

Can you post a link to the relay board that you use? The relay boards that don't cause problems have a JD-Vcc jumper that you need to remove.

Not my area of experience, but I don't think 1uF is enough. 100uF is probably better.

1 Like