Built an incubator controller, but Arduino mega stops running after a couple hours

Hi.

I've built a humidity and temperature controller for an incubator that runs the code shown below.
I'ts my first project in arduino ever, but it works perfectly, except for that the codes stops running and the LCD screen goes blank and eventually turns off after a few hours.

It's based on a Arduino Mega, its connected to two bme280 humid/temperature sensors , four ds18b20 temperature sensors, one LCD display, a 8x relay (no external power) and a 16x relay (with external power). Both the arduino mega and the 16x relay are powered with separate 12v 1a power supplies.

My local electronic dealer suggested it was overheating so i installed a fan, which didn't solve the issue.

Everything is wired up as it should, and since it runs perfectly for 7-14 hours, it seems more like it's a programming issue, rather than a hardware issue.
I read online it could be related to memory, I'm not sure why that could be and how to fix it. other suggestions are welcome as well.

Also when I verifies the code in platformio, it looks like there is plenty of memory left.

image

additional info that might not be relevant:
the reason there is 2 separate relays, is because when it turned on a 230v 5a heating element on the 8x relay, the arduino would slowly lose power and reboot. Therefor it was necessary to use a externally powered relay. But I didnt wanna redo all the wiring for all the low current electronics that ran without a problem on the 8x relay. That's why I use two relay modules. Also it seems that the arduino can run on the power supplied from the 16x relays external power supply, without its own power supply connected as well. so the problem should not be rooted in insufficient power.

#include <Arduino.h>

//------Temperature------
//Temperature goal Koji
float TG_koji  = 35;            //temperature goal for koji

//Temperature range koji
float TH_koji  = 0.5;           //high temperature range for koji
float TL_koji   = 0.25;          //low temperature range for koji

//Temperature goal air
float TG_air  = 35;             //temperature goal for air

//Temperature range air
float TH_air = 2;               //high temperature range for air 
float TL_air  = 0;              //low temperature range for air

//------Humidity------
//humidity goal 
float HG_air = 75;               //humidity goal

//humidity range
float HH_air = 5;                //low humidiy range
float HL_air  = 0;               //high humidity range

//--advandced controls---
float Air_T_avg_1 = 5;           //Koji_T_avg=TG_koji & Air_T_avg>TG_air
float T_koji_2 = 2;              //Koji_T_avg>TG_koji & Air_T_avg=TG_air
float T_koji_3 = 2;              //Koji_T_avg>TG_koji & Air_T_avg<TG_air
float T_koji_4 = 2;              //Koji_T_avg>TG_koji & Air_T_avg>TG_air 

//------libraries------
//import libraries for DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>

//import libraries for BME280
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

//import libraries for LCD
#include <LiquidCrystal_I2C.h>

//------defines-------
//BME280
#define SEALEVELPRESSURE_HPA (1013.25)
//DS18B20
#define ONE_WIRE_BUS 2   

//------objects-------
Adafruit_BME280 bme1;                                          //Creates a bme280 object called "bme" with
Adafruit_BME280 bme2;                                          //Creates a bme280 object called "bme" with
OneWire oneWire(ONE_WIRE_BUS);                                 //Creates a one-wire object called "oneWire", usinge "one_wire_bus" as reference.
DallasTemperature sensors(&oneWire);                           //Creates a DS18B20 object called sensors, using the "oneWire" as reference.
LiquidCrystal_I2C lcd(0x27,20,4);                              //Sets the LCD address to x for a 20 chars and 4 line display
uint8_t T1[8] = { 0x28, 0xFF, 0x64, 0x02, 0xE9, 0x25, 0x27, 0x96 };  //1
uint8_t T2[8] = { 0x28, 0xFF, 0x64, 0x02, 0xE9, 0x29, 0x02, 0xC7 };  //2
uint8_t T3[8] = { 0x28, 0xFF, 0x64, 0x02, 0xE9, 0x2E, 0x91, 0x5A };  //3
uint8_t T4[8] = { 0x28, 0xFF, 0x64, 0x02, 0xEB, 0xD5, 0x9C, 0x52 };  //4 

//------variables-------
//relay pin and name
const int RELAY1  = 22; 
const int RELAY2  = 23; 
const int RELAY3  = 26; 
const int RELAY4  = 28; 
const int RELAY5  = 30; 
const int RELAY6  = 32; 
const int RELAY7  = 34; 
const int RELAY8  = 36; 

//humid
int circlationfan = RELAY7;
int humidifier1 = RELAY5;

//heater 
int heatElement = RELAY2;
int heatFan = RELAY8;

//outlet
int outlet = RELAY6;

//serial
String serialtemperaturelogic;
String serialhumiditylogic;
String serialheatfanlogic;
String serialheatelementlogic;
String serialhumidifierlogic;
String serialoutletLogic;

//--loop-- 
unsigned long currentTime;
unsigned long previousTime;
unsigned int cycleTime = 10;

//sensor readings
float Air_T_bme1; 
float Air_T_bme2;
float Air_H_bme1;
float Air_H_bme2;
float Air_T_avg;
float Air_H_avg;
float Koji_T_T1;
float Koji_T_T2;
float Koji_T_T3;
float Koji_T_avg;
float Koji_T_T4; 


//-------code------

//lcd
void LCDstatus (){
  lcd.clear();
  lcd.print("Koji T:");
  lcd.print(Koji_T_avg);

  lcd.setCursor(0,1);
  lcd.print("Air  T:");
  lcd.print(Air_T_avg);

  lcd.setCursor(0,2);
  lcd.print("Air  H:");
  lcd.print(Air_H_avg);
}

//outlet
void outletLogic(bool condition) {
  if (condition==true) {
    if (digitalRead(outlet)==LOW) {
      digitalWrite(outlet, HIGH);
      serialoutletLogic="Outlet status: OPEN";
    }
  }
  else {
    if (digitalRead(outlet)==HIGH) {
      digitalWrite(outlet, LOW);
      serialoutletLogic="Outlet status: CLOSED";
    }
  }
}

//humidifier
void humidifierLogic(bool condition) {
  if (condition==true) {
    if (digitalRead(humidifier1)==LOW ) {
      digitalWrite(humidifier1, HIGH);
      serialhumidifierlogic="Humidifier status: ON";
    }
  }
  else {
    if (digitalRead(humidifier1)==HIGH ) {
      digitalWrite(humidifier1, LOW);
      serialhumidifierlogic="Humidifier status: OFF";
    }
  }
}

//heat element
void heatelementlogic (bool condition){
 if (condition==true) {
    if (digitalRead(heatElement)==HIGH){
        digitalWrite(heatElement, LOW);
        serialheatelementlogic="Heat Element Status: ON";
    }
  }
  else {
    if (digitalRead(heatElement)==LOW) {
        digitalWrite(heatElement, HIGH);
        serialheatelementlogic="Heat Element Status: OFF";
    }
  }
}

//heat fan
void heatfanlogic (bool status){
  if (status==true) {
    if (digitalRead(heatFan)==LOW) {
      digitalWrite(heatFan, HIGH);
      serialheatfanlogic="Heat fan Status: ON";
    }
  }
  else {
    if (digitalRead(heatFan)==HIGH) {
      digitalWrite(heatFan, LOW);
      serialheatfanlogic="Heat fan Status: OFF";
    }
  }
}

//temperature logic 
void temperatureLogic() {
  if ((TG_koji-TL_koji)<Koji_T_avg && Koji_T_avg<(TG_koji+TH_koji) && (TG_air-TL_air)<Air_T_avg && Air_T_avg<(TG_air+TH_air)) {     
    heatelementlogic(true);
    heatfanlogic(true);
    serialtemperaturelogic="Koji_T_avg=TG_koji & Air_T_avg=TG_air";
  }
  else if ((TG_koji-TL_koji)<Koji_T_avg && Koji_T_avg<(TG_koji+TH_koji) && Air_T_avg<(TG_air-TL_air)) {                 
    heatelementlogic(true);
    heatfanlogic(true);
    serialtemperaturelogic="Koji_T_avg=TG_koji & Air_T_avg<TG_air";
  }
  else if ((TG_koji-TL_koji)<Koji_T_avg && Koji_T_avg<(TG_koji+TH_koji) && Air_T_avg>(TG_air+TH_air)) {                              
   heatelementlogic(false);
   heatfanlogic(false);
   serialtemperaturelogic="Koji_T_avg=TG_koji & Air_T_avg>TG_air";
   if ((Air_T_avg-(TG_air-TL_air))>=Air_T_avg_1){
      outletLogic(true);
      serialtemperaturelogic="Koji_T_avg=TG_koji & Air_T_avg>TG_air +!";
    }
   else {
      outletLogic(false);
    }
  }
  
  else if (Koji_T_avg>(TG_koji+TH_koji) && (TG_air-TL_air)<Air_T_avg && Air_T_avg<(TG_air+TH_air)) {                                
   heatelementlogic(false);
   heatfanlogic(false);
   serialtemperaturelogic="Koji_T_avg>TG_koji & Air_T_avg=TG_air";
   if ((Koji_T_avg-(TG_koji+TH_koji))>=T_koji_2){
      outletLogic(true);
      serialtemperaturelogic="Koji_T_avg>TG_koji & Air_T_avg=TG_air +!";
   }
   else {
      outletLogic(false);
   }
  }
  else if (Koji_T_avg>(TG_koji+TH_koji) && Air_T_avg<(TG_air-TL_air)) {                                              
   heatelementlogic(false);
   heatfanlogic(false);
   serialtemperaturelogic="Koji_T_avg>TG_koji & Air_T_avg<TG_air";
   Serial.println();
   if ((Koji_T_avg-(TG_koji+TH_koji))>=T_koji_3){
      outletLogic(true);
      serialtemperaturelogic="Koji_T_avg>TG_koji & Air_T_avg<TG_air +!";
   }
   else {
      outletLogic(false);
   }
  }
  else if (Koji_T_avg>(TG_koji+TH_koji) && Air_T_avg>(TG_air+TH_air)) {                                                       
    heatelementlogic(false);
    heatfanlogic(false);
    serialtemperaturelogic="Koji_T_avg>TG_koji & Air_T_avg>TG_air";
    if ((Koji_T_avg-(TG_koji+TH_koji))>=T_koji_4){
      outletLogic(true);
      serialtemperaturelogic="Koji_T_avg>TG_koji & Air_T_avg>TG_air +!";
    }
    else {
      outletLogic(false);
    } 
  }

  else if (Koji_T_avg<(TG_koji-TL_koji) && (TG_air-TL_air)<Air_T_avg && Air_T_avg<(TG_air+TH_air)) {                               
    heatelementlogic(true);
    heatfanlogic(true);
    serialtemperaturelogic="Koji_T_avg<TG_koji & Air_T_avg=TG_air";
  }
  else if (Koji_T_avg<(TG_koji-TL_koji) && Air_T_avg<(TG_air-TL_air)) {                                                       
    heatelementlogic(true);
    heatfanlogic(true);  
    serialtemperaturelogic="Koji_T_avg<TG_koji & Air_T_avg<TG_air";
  }
  else if (Koji_T_avg<(TG_koji-TL_koji) && Air_T_avg>(TG_air+TH_air)) {                                                        
    heatelementlogic(false);
    heatfanlogic(false);
    serialtemperaturelogic="Koji_T_avg<TG_koji & Air_T_avg>TG_air";
  }
}

//humidity logic
void humidityLogic(){
  if ((HG_air-HL_air)<Air_H_avg && Air_H_avg<(HG_air+HH_air)){
    serialhumiditylogic="Air_H_avg=HG_air";
    outletLogic(false);
    humidifierLogic(false);
  }
  if (Air_H_avg<(HG_air-HL_air)){
    serialhumiditylogic="Air_H_avg<HG_air";
    outletLogic(false);
    humidifierLogic(true);
  }
  if (Air_H_avg>(HG_air+HH_air)){
    serialhumiditylogic="Air_H_avg>HG_air";
    outletLogic(true);
    humidifierLogic(false);
  }
}

//Serial monitor messages
void Serialmonitorstatus (){
  Serial.println("--------------------------------------------------------------------");
  Serial.println("average koji temperature: ");
  Serial.println(Koji_T_avg);
  Serial.println();
  Serial.println("Individual temperatures:");
  Serial.println();
  Serial.print("T1: ");
  Serial.println(Koji_T_T1);
  Serial.print("T2: ");
  Serial.println(Koji_T_T2);
  Serial.print("T3: ");
  Serial.println(Koji_T_T3);
  Serial.print("T4: ");
  Serial.println(Koji_T_T4);
  Serial.println();
  Serial.println("average air temperature: ");
  Serial.println(Air_T_avg);
  Serial.println();
  Serial.println("individual air temperature");
  Serial.print("BME 1: ");
  Serial.println(Air_T_bme1);
  Serial.print("BME 2: ");
  Serial.println(Air_T_bme2);
  Serial.println();
  Serial.println("average humidity:");
  Serial.println(Air_H_avg);
  Serial.println();
  Serial.println("Individual humidity");
  Serial.print("BME 1: ");
  Serial.println(Air_H_bme1);
  Serial.print("BME 2: ");
  Serial.println(Air_H_bme2);
  Serial.println();
  Serial.println("----Logic----");
  Serial.println("Time:");
  Serial.print("currentime: ");
  Serial.println(currentTime);
  Serial.println();
  Serial.println("Temperature:");
  Serial.println(serialtemperaturelogic);
  Serial.println(serialheatelementlogic);
  Serial.println(serialheatfanlogic);
  Serial.println();
  Serial.println("Humidity:");
  Serial.println(serialhumiditylogic);
  Serial.println(serialhumidifierlogic);
  Serial.println();
  Serial.println("other:");
  Serial.println(serialoutletLogic);
}

// -------------setup-------------
void setup(){
  //serial boot
  Serial.begin(9600);
  Serial.print("booting up...");
  Serial.println(); 

  //LCD boot
  lcd.init();                                                             //initalizes the LCD 
  lcd.clear();                                                            //clears display and moves cursor to top left corner
  lcd.backlight();                                                        //turns backlight on
  lcd.noCursor();                                                         //Hides the LCD cursor.
  lcd.setCursor(0,0);
  lcd.print("Koji ferminator v.1");
  lcd.setCursor(0,1);
  lcd.print("Booting up...");

  //bme280 setup
  bme1.begin(0x76);
  bme2.begin(0x77);

  //DS18B20 setup
  sensors.begin();  

  //relay setup
  pinMode(RELAY1, OUTPUT);
  pinMode(RELAY2, OUTPUT);
  pinMode(RELAY3, OUTPUT);
  pinMode(RELAY4, OUTPUT);
  pinMode(RELAY5, OUTPUT);
  pinMode(RELAY6, OUTPUT);
  pinMode(RELAY7, OUTPUT);
  pinMode(RELAY8, OUTPUT);

  //circulation fan
  digitalWrite(circlationfan, HIGH);
}


//-----------loop-----------
void loop(){
  currentTime = millis();
  if (currentTime-previousTime >= cycleTime*1000) {
    previousTime=currentTime;
    //bme
    Air_T_bme1 = bme1.readTemperature();                              
    Air_T_bme2 = bme2.readTemperature();                              
    Air_H_bme1 = bme1.readHumidity();                                
    Air_H_bme2 = bme2.readHumidity(); 
    //DS18B20
    sensors.requestTemperatures();                         
    Koji_T_T1 = sensors.getTempC(T1);                      
    Koji_T_T2 = sensors.getTempC(T2);                      
    Koji_T_T3 = sensors.getTempC(T3);                      
    Koji_T_T4 = sensors.getTempC(T4);
    //averages
    Air_T_avg = (Air_T_bme1+Air_T_bme2)/2;             
    Air_H_avg = (Air_H_bme1+Air_H_bme2)/2;
    Koji_T_avg = (Koji_T_T1+Koji_T_T2+Koji_T_T3+Koji_T_T4)/4;
    //heat
    temperatureLogic();
    //humidity
    humidityLogic();
    //LCD
    LCDstatus();
    //serial
    Serialmonitorstatus();
  }   
}

you could easily get rid of the Strings which are known to potentially cause issues over the long run

//serial
String serialtemperaturelogic;
String serialhumiditylogic;
String serialheatfanlogic;
String serialheatelementlogic;
String serialhumidifierlogic;
String serialoutletLogic;

but I doubt this is the issue

I would explore power related issues or electromagnetic interferences. Can you post good quality, in focus, pictures of your gig and a picture of the circuit / power?


How do you know it stops? what's the symptom?

There is a function/library that can report the free memory. If you print that number every hour and it is continuously decreasing, you know it is a memory problem.

Relay coils don't pull much current, but on cheap modules it may be more than the specification leads you to believe. The Mega can't provide much current and you may find that things go wrong when all the relays are on. Better to suck it up and rewire the eight relay module to use external power too.

Incubators seem to end up in out of the way places. Often times, so does other equipment. A particularly egregious example can be an old refrigerator that puts a strain on power when the compressor kicks in. I've seen several threads here where seemingly random crashes were simply down to what the Arduino was sharing a supply with.

is it this one you are talking about?

i cant figure out how how to add it to the arduino, since it dosenst show up in the arduino IDE or platformio when i seach for the library.

it runs around 7-14 hours before the screen goes blank.
ill try and see how it goes without the strings.

as for the symptoms. i know it stops because all the relays are either turned off, or some are stuck with being turned on/off, as if the program stopped running the relays got stuck on their last setting. also the screen goes blank. usually it displays the lastest average measurements of temperature and humidity. instead, all the text is erased. it like the loop stopped running? although that doesn't explain why the text is erased. one time screen was totally turned off as well.
it helps to shut off the power and turning it on again. i haven't tried to use the reset button as i prefer not to get my hands ind box while its on.

display when its running:

display after a couple of hours:

i will try and get a picture as soon as possible. of the wiring, although its a mess as you can see, since its a prototype, prefer to wait with more permanent installations.

After you have solved the current problem, might be a good idea to implement a watchdog timer. Even with perfectly running code, there are external events that could cause problems, such as electrical storms, disruptions on the power line, etc.

you might be right. but it seems like there is no issue with the relay, only when i plugged in the heating element that draws a lot of current. then the arduino would start to lose power(could see it from the LCD screen that would start to dim and eventually go dark) and then reset within minutes of the heating element being turned on.

the arduino power supply is in the same plug that all the relays are connected to, including the heat element. so maybe that could be an issue.

Did your local electronic dealer sell you that fan, by any chance?

That should not be any issue... time for a schematic, as this might be dangerous.
Bread boards are no good for permanent wiring.
I am happy everything is in a lunch container. But 220V wires should be fastened inside your box really well. A tie wrap is not sufficient.
Where is your 5V power supply hidden?

Here is a schematic, I couldn't find any good software to draw the schematic so it's a bit simple.
btw its only 5v that run through the breadboard +/- rail from the arduino to the 6 sensors, relays and a lcd screen.

and there is no 5v power supply, the sensors are powered through the arduino.
the arduino is powered with 12v dc 1a, same goes for the 16x relay.

*i accidentally made 4 vcc an 4 gnd wires to the 16x relay instead of 2 vcc and 2 gnd wires.
and give power to the last ds18b20 sensor from the +/- rail.

equpment:
LCD: https://www.amazon.de/gp/product/B07V5K3ZVB/ref=ppx_yo_dt_b_asin_title_o01_s01?ie=UTF8&th=1

DS18B20

BME280:

16x relay

(duo to EU legislation the seller says the unit is rated to 50v/ac 5a, but in reality its rated for 230v/ac 10a)

8x relay

12v powersupply:

1 Like

What does your serial output look like when it locks up?

1A might not be sufficient for 12 relays. Unless they go on one by one...
12V is not recommended to feed via vin. 7 to 9 V is better. You feed a lot of stuff from your arduino. The regulator might overheat and shut down. If this is the problem, you should be able to feel the heat. You should be able to touch and hold the regulator without pain...
You did a lot of work, but did not make a schematic....
A schematic can be drawn with pen on paper.
12 v and 5v at top, ground at bottom. Sensors left, arduino in the middle and outputs right.
Try to make not too many crossings. Labels can be used to prevent crossings. Make a picture of your artwork and post...
And remove the solution checkmark as nothing is solved yet.

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