Arduino Mega freezes randomly

Hi,

I think my problem has something to do with using I2C bus connections and multiplexer. I appreciate it if you can guide where to find a solution for the problem I have.

I'm having my Arduino Mega 2560 set up to send signals for switching between different components for an environmental chamber. I need this chamber to control temperature and humidity for fixed durations in dry- and wet-cycles (dry-cycle: 4 hours at 60 deg C with no control over RH; wet-cycle: 4 hours at 50 deg C & 65% RH). So as you can see, one complete cycle is 8 hours and I need at least 21 cycles (168 h) for a complete test. Since the target humidity is quite high for the target temperature in wet-cycles, it needs a lot of toggling between the chamber components. I'm using four sensors in the main chamber, all connected to a multiplexer which uses I2C bus ports of the Arduino.

The code seems to be working nice for controlling the relays and sensors used in the design. But the main issue is that I don't seem to be able to rely on arduino for executing one complete test without freezing or interruption. Reading related posts that discuss freezing issues, I tried to implement a watchdog timer to break the test into 8-hour windows (one dry- and wet- cycle). I did this modification in my code, but the freezing issue is still there, since sometimes it happens before 8 hours.
I have no String variable in the code and upon uploading the code, I get a message like this:
"Sketch uses 14278 bytes (5%) of program storage space. Maximum is 253952 bytes.
Global variables use 1060 bytes (12%) of dynamic memory, leaving 7132 bytes for local variables. Maximum is 8192 bytes."
I'm trying hard to figure out a solution for the glitch that randomly happens. Basically, the concept of Interrupt function seems to match with such a problem, but as I did a bit of research in related pages, it relies mostly on an external signal such as a press button, which is not my case. For a former project I used a software interrupt to ensure the continuity of condition remains steady, but in this test time does matter and I cannot do it that way. I need some sort of reactivation when this freezing problem occurs.
I know you might immediately ask me to post the code and wiring diagram for this project, which would be fine. But it takes some time to update the diagram and I need to find a direction to solve this final problem. I appreciate it if anyone can give me some suggestions that might be helpful. I'll try to prep the documents for this setup as soon as possible.

Thanks

The memory usage messages are routine.

Sounds like you might have a power glitch issue. Are there anti-kickback diodes on all your relays and solenoids (if you use "loose" relays you need diodes, if using relay modules, they're normally built onboard.)

What are you using for power and what are your current levels, the Arduino is not a power source other than for a LED or two.

Are you logging data on the Serial port? Does it show anything?

Use the </> button and post the code. A hand drawn schematic is fine and usually easier to understand than the pretty drawn ones. Give us SOMETHING to work with here or the only answer we can give is "Sounds like it's broke!" LOL

1 Like

Does your code use arrays? The symptom described can also be caused by reading or writing beyond the bounds of an array into memory that you do not "own". Carefully examine all operations on any arrays for bounds violations.

The memory reported at compile time does not include memory taken by local variables.

I hope I answered your question @groundFungus. Please tell me if I missed something...

Thanks @madmark2150 for your quick response.
The wiring of this chamber is done using DIN rails and all components are wired to a central board that include relays. It has two power supplies for 12VDC and 24VDC for relays and other parts. The arduino is also connected to a circuit board with two transistor arrays (https://www.digikey.com/en/products/detail/texas-instruments/ULN2004AIN/659671) to send signals to relays.

I'm posting this code which is the final version after various modifications on the chamber and it wiring. I hope it is not confusing/nonsensical for you since I recently modified the code to reset the arduino after 8 hours and some of the previous functions are not being used anymore. It was to solve the problem I have but apparently it was not helpful.

For serial port, yes. As you can see in the code below I monitor the chamber checking each sensor. I'll try to prep the wiring diagram.

//The following libaries are required for the operation of the chamber
#include <Arduino.h>
#include <Wire.h>
#include "Adafruit_SHT31.h"
#include <LiquidCrystal.h>

//Variable required for testing the Multiplexer
#define TCAADDR 0x70 //serial address of the TCA9458A Multiplexer
#include <avr/wdt.h>

//Temperature Sensor setup
bool enableHeater = false;


//Initialize the SHT31 sensor(s) *NOTE THAT IT MIGHT BE THE CASE THAT ONLY ONE INSTANCE NEED BE INITIALIZED*
Adafruit_SHT31 sht31_1 = Adafruit_SHT31();
Adafruit_SHT31 sht31_2 = Adafruit_SHT31();
Adafruit_SHT31 sht31_3 = Adafruit_SHT31();
Adafruit_SHT31 sht31_4 = Adafruit_SHT31();

//define relay pins (these values are not changeable unless the requisite change has been made on the arduino board)
const int Safety_Lights_Relay = 22;    // Relay : https://www.mcmaster.com/8262T14/ ;  Safety Lights: Some 12VDC lights
const int Heat_Mist = 26;              // Relay : https://www.omega.ca/en/control-monitoring/relays/solid-state-relays/ssrl240-660/p/SSRL240DC25 ; Components (a heating pad and a solenoid valve): https://www.omega.ca/en/industrial-heaters/surface-heaters/flexible-heaters/srfra-srfga/p/SRFGA-508-10-P    &  https://www.mcmaster.com/4738K147/ 
const int Chamber_Fan_Relay1 = 24;     // Relay : https://www.mcmaster.com/8262T14/ ; Fan: https://www.digikey.ca/en/products/detail/qualtek/FMA1-08025WBHT12/10228356
const int Humidifier_Fan_Relay = 25;   // Relay : https://www.mcmaster.com/8262T14/ ; Fan: a 24 VDC fan
const int Humidifier_Relay = 23;       // Relay : https://www.celduc-relais.com/Technical_DataSheet/FA_SOM020200.pdf ; 
const int UV_Light_Relay = 27;         // Relay : https://www.mcmaster.com/8262T14/ ; UV Lamps: two 340nm UVA lamps
const int Chamber_Fan_Relay2 = 28;    //  Relay : https://www.mcmaster.com/8262T14/ ; Fan: https://www.digikey.ca/en/products/detail/qualtek/FAA1-08025NBMT31/2599974
const int Heater_Relay = 29;          //  Relay : https://www.digikey.com/en/products/detail/sensata-crydom/CKRD6010/1771443 ; Heater: https://www.omega.com/en-us/industrial-heaters/duct-and-enclosures-heaters/duct-heaters/ahf-heater/p/AHF-10120

//define UV sensor pins (these values are not changeable unless the requisite change has been made on the arduino board) and placeholder values
const int UV_Sensor_1 = A8;
const int UV_Sensor_2 = A9;
float uvValue1 = 0;
float uvValue2 = 0;

// define Interrupt function to avoid arduino freezing
const byte ledPin = 53;
const byte interruptPin = 18;
volatile byte state = LOW;

//Time Constant Values
const long seconds = 1000; //number of milliseconds in a second
const long minutes = 60000; //number of milliseconds in a minute
const long hours = 3600000; //number of milliseconds in an hour

//Temperature & Humidity Variables
const float sensorTempVariance = 0.5; //variable to modify target temperature set points ******************
const float sensorHumVariance = 0.5; //variable to modify target temperature set points ******************
const float RH_set_Range = 10; //variable to add moisture slowly after a certain level **************
const int targetTemp1 = 60.9; //target temperature for dry cycle
const int targetTemp2 = 50.9; //target temperature for wet cycle
float targetTemp = 60.9; //system initializing temperature (This is the value that gets modified in the code with specific cycle temps)
const float maxSafetyTemp = 85; //maximum temperature allowable for the safety sensor to reach ******************
const int targetHum = 65; //target humidity for wet cycle

const float sht3TempWeight3 = 8; //Weighting for the 1st SHT3 sensor temperature value ******************
const float sht3TempWeight1 = 0; //Weighting for the 2nd SHT3 sensor temperature value ******************
const float sht3TempWeight4 = 8; //Weighting for the 3rd SHT3 sensor temperature value ******************
const float sht3TempWeight2 = 8; //Weighting for the 4th SHT3 sensor temperature value ******************

const float sht3HumWeight3 = 6; //Weighting for the right SHT3 sensor humidity value ******************
const float sht3HumWeight1 = 0; //Weighting for the central SHT3 sensor humidity value ******************
const float sht3HumWeight4 = 9; //Weighting for the floating SHT3 sensor humidity value ******************
const float sht3HumWeight2 = 9; //Weighting for the left SHT3 sensor humidity value ******************

const int heaterPulse = 5000; //Duration for heater to run before turning off ******************
int chamberFanPulseDuration = 1000; //Duration to turn on the chamber fan during humidity control (must be in milliseconds) ******************
int humFanPulseDuration = 1000; //Duration to turn on the humidifier fan during humidity control (must be in milliseconds) ******************
int mistLoading = 2000; //Duration to run the humidifier to load the mist chamber (must be in milliseconds) *****************

//Global Variables
long startTime = 0; //dummy variable that will eventually tell the arduino at which millisecond the test began
float cycleDuration = 4  ; //number of hours that each cycle will run ******************
float singleBatchTime = cycleDuration * 2 * 3600000; // [ms]
int cycleCount = 0; //initial value for cycle counter
const int totalCycleCount = 42; //number of total cycles for test
long int timeVar = 0;

//select pins used for LCD and define LCD values
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int lcd_key = 5;  //Default value equivalent to pressing no button
int adc_key_in = 2000; //Arbitrary value assigned

//Values are arbitarily assigned but should not be changed as they are prolific throughout the code
#define btnDOWN 0
#define btnUP 1
#define btnLEFT 2
#define btnRIGHT 3
#define btnSELECT 4
#define btnNONE 5

//Code to initialize system before test cycle begins (will only be ran one time immediately after powering on)
void setup() {

  wdt_disable();

  //establish digital pins for relay control and set them all to low
  pinMode(Heater_Relay, OUTPUT);
  digitalWrite(Heater_Relay, LOW);
  pinMode(UV_Light_Relay, OUTPUT);
  digitalWrite(UV_Light_Relay, LOW);
  pinMode(Chamber_Fan_Relay1, OUTPUT);
  digitalWrite(Chamber_Fan_Relay1, LOW);
  pinMode(Humidifier_Fan_Relay, OUTPUT);
  digitalWrite(Humidifier_Fan_Relay, LOW);
  pinMode(Heat_Mist, OUTPUT);
  digitalWrite(Heat_Mist, LOW);
  pinMode(Safety_Lights_Relay, OUTPUT);
  digitalWrite(Safety_Lights_Relay, LOW);
  pinMode(Humidifier_Relay, OUTPUT);
  digitalWrite(Humidifier_Relay, LOW);
  pinMode(Chamber_Fan_Relay2, OUTPUT);
  digitalWrite(Chamber_Fan_Relay2, LOW);

  //this section is to initialize the LCD display and Serial Monitor
  Serial.begin(115200); //baud rate is determined by the requirement of the UV sensors
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);

  //Initialize the temperature & Humidity sensors
  sht31_1.begin();
  sht31_2.begin();
  sht31_3.begin();
  sht31_4.begin();

  //Troubleshooting stuff
  //this section of code allows for testing of Multiplexer function and displays which of the 8 ports the sensors are connected to in the serial monitor (*please note that if physical changes were required that the corresponding values for "tcaselect" function will need to be adjusted)
  while (!Serial);
  delay(1000);
  Wire.begin();
  Serial.println("\nTCAScanner Ready!");

  //Setting up the multiplexer for SHT3x sensors
  for (uint8_t t = 0; t < 8; t++) {
    tcaselect(t);
    Serial.print("TCA Port #");
    Serial.println(t);
    for (uint8_t addr = 0; addr <= 127; addr++) {
      if (addr == TCAADDR) continue;
      Wire.beginTransmission(addr);
      if (!Wire.endTransmission()) {
        Serial.print("Found I2C 0x");
        Serial.println(addr, HEX);
      }
    }
  }
  Serial.println("\ndone");
  Serial.println("");
  digitalWrite(Safety_Lights_Relay, HIGH);

} //End of Setup


//main loop that controls cycles
void loop() {

  //This is to reset the arduino every 8 hours
  timeVar = millis() - startTime;
  if (timeVar > singleBatchTime && cycleCount != 0) {
    wdt_enable(WDTO_250MS);
  }
  
  //This section reads the input from the LCD panel and performs specific actions
  while (cycleCount == 0 && averageTemp() < targetTemp) { //Waits for user to press SELECT while maintaining target temperature
    print2Serial(averageTemp(), averageHum());
    delay(1000);
    displayData(lcd_key);
    tempMaintenance(targetTemp);
  }
  if (cycleCount == 0 && averageTemp() >= targetTemp) { //Cycle count will only be 0 upon first turning on the system, this prevents a user from restarting the test by accidentally pressing select
    startupProcedure();
  }
  else {
    displayData(lcd_key);
  }

  //This section maintains the specified temperature and humidity (depending on cycle)
  if (cycleCounter() == true) { //Only enters on even number cycles ("wet cycles")
    humMaintenance(targetTemp);
  } else {
    digitalWrite(Humidifier_Relay, LOW);
    digitalWrite(Heat_Mist, LOW);
    digitalWrite(Humidifier_Fan_Relay, LOW);
    print2Serial(averageTemp(), averageHum());
    delay(1000);
    tempMaintenance(targetTemp);
  }
  //This section checks to see if the cycle has been running for the specified time and the number of completed cycles (ends the program if cycle count is reached)
  checkTime();
  //cyclesCompleted();

} //End of Loop


//This function allows the selection of different I2C addresses on the multiplexer
void tcaselect(uint8_t i) {
  if (i > 7) return;
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}

//This function averages the temperatures of all three sensors in a weighted manner
float averageTemp() {
  tcaselect(2);
  float sht3Temp1 = sht31_1.readTemperature();
  tcaselect(3);
  float sht3Temp2 = sht31_2.readTemperature();
  tcaselect(4);
  float sht3Temp3 = sht31_3.readTemperature();
  tcaselect(5);
  float sht3Temp4 = sht31_4.readTemperature();
  float tempAverage = ((sht3TempWeight1 * sht3Temp1) + (sht3TempWeight2 * sht3Temp2) + (sht3TempWeight3 * sht3Temp3) + (sht3TempWeight4 * sht3Temp4)) / 24;
  return tempAverage;
}

//This function averages the humidity of all three sensors in a weighted manner
float averageHum() {
  tcaselect(2);
  float sht3Hum1 = sht31_1.readHumidity();
  tcaselect(3);
  float sht3Hum2 = sht31_2.readHumidity();
  tcaselect(4);
  float sht3Hum3 = sht31_3.readHumidity();
  tcaselect(5);
  float sht3Hum4 = sht31_4.readHumidity();
  float humAverage = ((sht3HumWeight1 * sht3Hum1) + (sht3HumWeight2 * sht3Hum2) + (sht3HumWeight3 * sht3Hum3) + (sht3HumWeight4 * sht3Hum4)) / 24;
  return humAverage;
}

//This function reads the value of the button on the LCD Display
int read_LCD_buttons() {
  adc_key_in = analogRead(0);
  if (adc_key_in < 50) return btnRIGHT; //3
  if (adc_key_in < 250) return btnUP; //1
  if (adc_key_in < 450) return btnDOWN; //0
  if (adc_key_in < 650) return btnLEFT; //2
  if (adc_key_in < 850) return btnSELECT; //4
  if (adc_key_in > 1000) return btnNONE; //5

  return btnNONE;
}

//This function maintains the temperature of the system (for dry-cycles)
void tempMaintenance(float temperature) {
  float maintenanceTargetTemp = temperature - sensorTempVariance;
  if (averageTemp() <= maintenanceTargetTemp) {
    digitalWrite(Chamber_Fan_Relay1, HIGH);
    digitalWrite(Chamber_Fan_Relay2, HIGH);
    digitalWrite(Heater_Relay, HIGH);
    if (averageTemp() <= maintenanceTargetTemp) {
      print2Serial(averageTemp(), averageHum());
      delay(1500);
    }
    delay(1000);
    digitalWrite(Heater_Relay, LOW);
  }
  else {
    digitalWrite(Chamber_Fan_Relay1, LOW);
    digitalWrite(Chamber_Fan_Relay2, LOW);
  }
}

//This function maintains the temperature of the system (for wet-cycles)
void tempRH_Maintenance(float temperature) {
  float maintenance_TargetTemp = temperature - sensorTempVariance;
  digitalWrite(Chamber_Fan_Relay1, LOW);
  if (averageTemp() < maintenance_TargetTemp) {
    digitalWrite(Chamber_Fan_Relay2, HIGH);
    digitalWrite(Heater_Relay, HIGH);
    if (averageTemp() <= maintenance_TargetTemp) {        
      print2Serial(averageTemp(), averageHum());
      delay(1000);
      if (averageHum() < targetHum - 2.5 ) {
        digitalWrite(Humidifier_Fan_Relay, HIGH);
      }
      else {
        digitalWrite(Humidifier_Fan_Relay, LOW);
      }
    }
  }
  else {                                                 
    digitalWrite(Heater_Relay, LOW);
    delay(1000); //Delay is required so that residual heat in the inline heater will be blown into the chamber
    digitalWrite(Chamber_Fan_Relay2, LOW);
    //digitalWrite(Humidifier_Fan_Relay, LOW);
  }
}

//This function prints the data to the serial monitor and lcd display
void displayData(int sensor2Display) { //Value of 1 = top sensor, value of 2 = left sensor, value of 3 = right sensor, and value of 0 or 5 = average
  float temp2Print = 0;
  float hum2Print = 0;
  if (sensor2Display == btnUP) {
    tcaselect(2); //value in parenthesis corresponds to the physical sensor at the highest location in the chamber
    temp2Print = sht31_1.readTemperature();
    hum2Print = sht31_1.readHumidity();
  } else if (sensor2Display == btnLEFT) {
    tcaselect(3); //value in parenthesis corresponds to the physical sensor at the left most location in the chamber
    temp2Print = sht31_2.readTemperature();
    hum2Print = sht31_2.readHumidity();
  } else if (sensor2Display == btnRIGHT) {
    tcaselect(4); //value in parenthesis corresponds to the physical sensor at the right most location in the chamber
    temp2Print = sht31_3.readTemperature();
    hum2Print = sht31_3.readHumidity();
  } else {
    temp2Print = averageTemp();
    hum2Print = averageHum();
  }
  lcd.home();
  lcd.print("T:");
  lcd.print(round(temp2Print));
  lcd.print("C");
  lcd.print(" H:");
  lcd.print(round(hum2Print));
  lcd.print("%");
  lcd.setCursor(0, 1);
  long int timeMilliseconds = timeVar;
  long int timeHours = timeMilliseconds / hours;
  long int timeMins = (timeMilliseconds - (timeHours * hours)) / minutes;
  lcd.print("t:");
  lcd.print(timeHours);
  lcd.print("h");
  lcd.print(timeMins);
  lcd.setCursor(6, 1);
  lcd.print("m");
  lcd.print(" Cycle:");
  lcd.print(cycleCount);
}

//This function is for starting the initial test
void startupProcedure() {
  lcd.clear();
  lcd.print("Starting...");
  delay(2000); //Delay is added just for user experience
  digitalWrite(UV_Light_Relay, HIGH);
  delay(500);
  int dummyVar = uvCheck(); //Added to confirm via the serial monitor that the UV is operational
  startTime = millis(); //Officially begins the start of the first cycle
  cycleCount = 1; //Initialize the cycle counting and ensures that the requirements to trigger the startup procedure can no longer be met
}

//This function checks to see if UV is on
int uvCheck() {
  uvValue1 = analogRead(UV_Sensor_1);
  uvValue2 = analogRead(UV_Sensor_2);
  float averageUV = (uvValue1 + uvValue2) / 2;
  if (averageUV != 0) {
    return 1;
  }
  else {
    return 0;
  }
}

//This function keeps count of which cycle the system is on
bool cycleCounter() {
  if (cycleCount % 2 == 0) { //Even numbered cycles (wet cycles) will return true
    return true;
  }
  else {
    return false;
  }
}

//This function removes the excess moisture if the target RH is passed. Also, by momentarily turning on the humidifier fan it tries to keep all sensors in the same RH range.
void excess_Humidity() {
  float adjustedHumTarget = targetHum - RH_set_Range * sensorHumVariance;
  if (averageHum() > adjustedHumTarget) {         // If RH is gone too much high, play with chamber fans to remove the excessive mist
    if (averageHum() > adjustedHumTarget) {       //while
      digitalWrite(Heat_Mist, LOW);
      digitalWrite(Humidifier_Fan_Relay, LOW);
      // if (swap == true) {
      digitalWrite(Chamber_Fan_Relay1, HIGH);
      delay(800);
      digitalWrite(Chamber_Fan_Relay1, LOW);
      delay(2200);
    }
  }
  else {
    tcaselect(3);
    float T_Last = sht31_2.readTemperature();
    float RH_Last = sht31_2.readHumidity();
    tcaselect(4);
    float T_First = sht31_3.readTemperature();
    float RH_First = sht31_3.readHumidity();
    if (T_First != T_Last || RH_First != RH_Last) {
      //tempRH_Maintenance(targetTemp);
      digitalWrite(Humidifier_Fan_Relay, HIGH);
      delay(250);
      digitalWrite(Humidifier_Fan_Relay, LOW);
      print2Serial(averageTemp(), averageHum());
      delay(2000);
    }
  }
}

//This function maintains the humidity of the system
void humMaintenance(float temperature) {
  float adjustedHumTarget = targetHum - RH_set_Range * sensorHumVariance;
  digitalWrite(Humidifier_Relay, HIGH);
  //Heat_Mist_counter+;
  if (digitalRead(Humidifier_Fan_Relay) == HIGH) {                // If target RH is reached turn the fogger OFF
    if (averageHum() >= adjustedHumTarget) {                  // First see if RH is in the desired range
      digitalWrite(Humidifier_Fan_Relay, LOW);
      delay(mistLoading);
      if (averageHum() < targetHum - RH_set_Range / 2 * sensorHumVariance) {                         //Going a little bit higher than the RH setpoint
        digitalWrite(Humidifier_Fan_Relay, HIGH);
        print2Serial(averageTemp(), averageHum());
        //lcd_key = read_LCD_buttons();
        delay(mistLoading / 2);
        digitalWrite(Humidifier_Fan_Relay, LOW);
      }
      tempRH_Maintenance(targetTemp);
    }
    excess_Humidity();
  }
  if (averageHum() < targetHum) {
    digitalWrite(Humidifier_Fan_Relay, HIGH);
    if (averageHum() < targetHum - RH_set_Range / 2 * sensorHumVariance) {
      digitalWrite(Heat_Mist, HIGH);
    }
    print2Serial(averageTemp(), averageHum());
    //lcd_key = read_LCD_buttons();
    delay(700);
    tempRH_Maintenance(targetTemp);
  }
  else {
    excess_Humidity();
  }
}

//This function checks to see if the current cycle has been running for more than the specified cycle time and increases the cycle count
void checkTime() {
  //int convertedTime = (int) cycleDuration * hours; //convert cycle duration to milliseconds (casting to int drops the fractions of the millisecond if any and makes it possible to convert to long)
  long cycleDurationMills = cycleDuration * hours;
  //long timeCheckVar = timeVar;
  if (timeVar >= cycleDurationMills) {
    lcd.clear();
    cycleCount = 2;
    toggleUV();
    toggleTargetTemp();
  }
  else {
    cycleCount = 1;
  }
}

//This functions turns the UV light on/off depending on the cycle
void toggleUV() {
  if (cycleCounter() == true) {
    digitalWrite(UV_Light_Relay, LOW);
    delay(500); //Delay is required so that the sensors have adequate time to determine if the UV light is off
    int dummyVar = uvCheck();
  }
  else {
    digitalWrite(UV_Light_Relay, HIGH);
    delay(500); //Delay is required so that the sensors have adequate time to determine if the UV light is on
    int dummyVar = uvCheck();
    //startTime = millis(); //Starts the timer for the current cycle as soon as the UV light is on
  }
}

//This function sets the target temperature depending on the cycle
void toggleTargetTemp() {
  if (cycleCounter() == true) {
    targetTemp = targetTemp2;
    //print2Serial(averageTemp(), averageHum());
    humMaintenance(targetTemp); //Brings system to the specified operating conditions for wet cycle
    //startTime = millis(); //Timer for the wet cycle begins when target humidity is reached
  }
  else {
    targetTemp = targetTemp1;
    //print2Serial(averageTemp(), averageHum());
  }
}

//This function prints the necessary data to the serial monitor
void print2Serial(float temperatureValue, float humidityValue) {
  float temp2Print = 0;
  float hum2Print = 0;

  Serial.println("THE ORDER OF SENSORS IS ACCORDING TO THE AIR FLOW DIRECTION");
  Serial.println("");
  Serial.print("Target Temperature: ");
  Serial.println(targetTemp);
  Serial.print("Current Avg. Temperature: ");
  Serial.print(temperatureValue);
  Serial.println(" °C");
  Serial.println("");
  Serial.print("Right Temperature (1st sensor): ");
  tcaselect(4);
  temp2Print = sht31_3.readTemperature();
  Serial.print(temp2Print);
  Serial.println(" °C");

  //Serial.print("Floating 1 Temperature (2nd sensor): ");
  //tcaselect(2);
  //temp2Print = sht31_1.readTemperature();
  //Serial.print(temp2Print);
  //Serial.println(" °C");

  Serial.print("Floating 2 Temperature (3rd sensor): ");
  tcaselect(5);
  temp2Print = sht31_4.readTemperature();
  Serial.print(temp2Print);
  Serial.println(" °C");


  Serial.print("Left Temperature (4th sensor): ");
  tcaselect(3);
  temp2Print = sht31_2.readTemperature();
  Serial.print(temp2Print);
  Serial.println(" °C");
  Serial.println("");
  Serial.print("Current Avg. RH: ");
  Serial.print(humidityValue);
  Serial.println(" %");
  Serial.println("");
  Serial.print("Right Humidity: ");
  tcaselect(4);
  hum2Print = sht31_3.readHumidity();
  Serial.print(hum2Print);
  Serial.println(" %");

  //Serial.print("Floating 1 Humidity: ");
  //tcaselect(2);
  //hum2Print = sht31_1.readHumidity();
  //Serial.print(hum2Print);
  //Serial.println(" %");

  Serial.print("Floating 2 Humidity: ");
  tcaselect(5);
  hum2Print = sht31_4.readHumidity();
  Serial.print(hum2Print);
  Serial.println(" %");

  Serial.print("Left Humidity: ");
  tcaselect(3);
  hum2Print = sht31_2.readHumidity();
  Serial.print(hum2Print);
  Serial.println(" %");
  Serial.println("");
  Serial.print("Cycle Count: ");
  Serial.println(cycleCount);
  Serial.print("Current Time Elapsed Since Start of the Batch: ");
  long int timeVarHrs = timeVar / hours;
  long int timeVar2 = (timeVar - (timeVarHrs * hours));
  long int timeVarMins = timeVar2 / minutes;
  long int timeVarSecs = (timeVar2 - (timeVarMins * minutes)) / seconds;
  Serial.print(timeVarHrs);
  Serial.print(" Hrs ");
  Serial.print(timeVarMins);
  Serial.print(" Mins ");
  Serial.print(timeVarSecs);
  Serial.println(" Secs");
  Serial.println("*****************************************************************");
  Serial.println("");

It seems you're powering the Mega with 12volt (DC socket or V-in?).
That's borderline too high. You can't draw more than about 150mA total from any pin at that voltage. If you do, then the 5volt regulator shuts down periodically. You could feel if the regulator next to the DC socket gets hot. Try powering the Mega with a 5volt cellphone charger connected to the USB socket. That bypasses the built-in 5volt regulator.
Leo..

1 Like

@Wawa: No, the arduino is wired through a USB cable to an iMac. Sorry if I did not mention this part.

Should we assume the iMac is collecting the data?

The Arduino family could be called "bare" processor boards. The I/O pins of the processor IC do directly to the "outside". There is no protection or filtering. Voltage glitches appearing on one or more pins can easily cause a reset.
This is not a criticism but just info; if you had purchased a commercial data acquisition system the processor would be protected from electrical noise and voltage spikes by filtering them with various components.

Can you provide a sketch-schematic showing all the devices, and where they get their power? Try to make the connections representative of the physical configuration.

I noticed that you have several floats without a decimal point. Per the reference:
If doing math with floats, you need to add a decimal point, otherwise it will be treated as an int.

This may be a total red herring :slight_smile:

As far as your most common relay, the one from Mcmaster-Carr: I looked at the web site, but can't find a data sheet for it. Can't tell if it has a flyback diode protection built in or not.
It probably does not matter for industrial PLCs but could this be causing glitches on the Arduino?

@cncnotes Thanks for your note on the code. I'll try to fix these rookie mistakes. The initial programming was done by a previous summer student I had for this project and some of the mistake remained in the code.

For the relay data sheet, I guess you are addressing the ultra thin ones which use a mechanical relay (finder 34.51.7.012.0010). Its data sheet should be like this: https://ca-en.alliedelec.com/m/d/af4381e6b45c3979ce8e2c484a9044d3.pdf
As far as I can tell, before the glitch there might be a lot of switching by these relays and I couldn't find a specific occasion for this problem.

One thing that I should mention is that I have an 16x2 LCD display connected to the arduino for average data monitoring, but at some point during the cycles the display goes partially/completely unreadable. I've been trying to find a reason for it, but no success yet. By unreadable I mean these random characters does not make any sense and my guesses for this issue did not work . However, as the serial monitor shows the arduino still works when this problem happens. Is this a sign for the glitching issue?

1 Like

I have seen that in my displays and it has usually been noise or glitches or drop outs on the LCD power (5V).

How are you driving those relays? They, absolutely, need flyback diodes, whatever the driver. Lack of flyback diodes can lead to noise on the power rail and damage to the driver and/or the microcontroller output pin.

Sometimes the LCD's garble (overlay multiple characters) if you update too fast. If you're updating in a tight loop try giving it a delay(100) so it can breathe.

Is your display using an I2C header? If not, change to one.

@groundFungus I use a couple of darlington transistors (https://www.ti.com/lit/ds/slrs055/slrs055.pdf) to get the input from arduino pins and send signals to relays (A1 ports of the relay).

If it's a naked relay, you MUST have kickback diodes. 1N4002 is fine. Any gp diode will work.

The data sheet shows no flyback diode. This would fit with the glitching. And it would be good practice to add the diode anyway.
Did you mention if the relays are on their own power supply? There may still be some noise spikes transmitted back.

A side note on I2C. It was never designed for long distances, and the total capacitance in your system may affect the reliability of the I2C. Please check the pull-up resistors. And that there are not multiples of those. Sometimes, a stronger pull-up (meaning lower value) is needed than the usual 10k.

The I2C protocol also does not have an automatic reset if s device for example holds the line low. One can try to send repeated starts conditions or (I forget for sure) perhaps all 1s. But to do this, you need to know that there is a hang up condition.

The ULN2004 chips have the flyback diodes built in. Those ancient chips were made to drive solenoids in teletype machines, I think.

The ULN2004AI is a high-voltage, high-current Darlington transistor array. This device consists of seven npn Darlington pairs that feature high-voltage outputs with common-cathode clamp diodes for switching inductive loads.

The clamp diodes are the flyback diodes.

How much bypass and bulk capacitance is on your power bus(es)?

@groundFungus How do I measure bypass and bulk capacitance here? You mean to relay components? I appreciate it if you can share a tutorial or something related.

An interesting thing for today was that I plugged the chamber in today and so far I have not seen any glitches yet! It's been working for 3h and 25min so far.

Here is a page on bypass (or decoupling) capacitance.

Bulk capacitance is explained pretty well in post #5 of this thread.

Yes.
BTW reaction to glitches is not repeatable. It could even be from the chamber compressors.

Only if you connect the "COM" pin. :face_with_raised_eyebrow: