The system is getting stuck after a while

Hi everybody
I built a system based on Arduino Mega. The system consists of two pumps, a clock, a data logger (SD card) and sensors for methane and CO2. There is a problem that is repeated several times. After a while the system works (sometimes after half an hour, sometimes after several hours), the system stuck, pumps work non-stop and the data logger stops writing on the card. I have tried a lot of variations already.

thanks

Please post your code

The easier you make it to read and copy the code the more likely it is that you will get help

Please follow the advice given in the link below when posting code

#include <Wire.h>//for DS3231 (rtc)
#include "RTClib.h"// for DS3231 (rtc)
#include <SPI.h>//SD card
#include <SD.h>//SD card
#include <LiquidCrystal.h>
#include <string.h>
#include <SoftwareSerial.h>
#include <MHZ.h>

/*   please ReCheck !
 * CH4 sensor (MQ4) analog ourput is conect to A0
 * pressure sensor (MPXH6400A) is conect to A1
 * co2 sensor (MH-Z19B) PMW output is conected to D8
 */
#define ch4Pin A0
#define pressurPin A1
byte CO2_IN = 8;
byte pump_PIN = 30;   // pump on\off control

int Interval = 1;//setthe interval between readings (in minutes)

//  rtc  //
RTC_DS3231 rtc;
char daysOfTheWeek[7][12] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
char buffer[24];
int secq, minq, hourq, dayq, monthq, yearq;

//SD card//
char FileName[] = "120421.txt";// change the file name
char FileNameP[] = "1104P.txt";// change the file name
const int chipSelect = 53;//SD input
String LoggerHeader = "Date [hh:mm:ss dd/mm/yyyy],pressure [mBar],CH4 [ppm],CO2 [ppm]:";//insert the heaters for the SD logging
String LoggerHeaderP = "Date [hh:mm:ss dd/mm/yyyy],Pumps status:";
File dataFile;
File dataFileP;

//CO2 sesor//
// pin for uart reading
#define MH_Z19_RX 4  // D7
#define MH_Z19_TX 0  // D6

MHZ co2(MH_Z19_RX, MH_Z19_TX, CO2_IN, MHZ19B);

//pressure//
double V_out;
double V_s = 5+0.36;

void setup(void) {

  Serial.begin(9600);
  Serial.println("Hi");
  digitalWrite(pump_PIN, LOW);
  //SD card//
  Serial.print(F("Initializing SD card..."));
  // see if the card is present and can be initialized:
  pinMode(10, OUTPUT);
 digitalWrite(10, HIGH);// davekw7x: If it's low, the Wiznet chip corrupts the SPI bus
  SD.begin(chipSelect);
  if (!SD.begin(chipSelect)) {
    Serial.println(F("Card failed, or not present"));
    while(1);
  }
  Serial.println(F("card initialized."));
  Serial.print("File name: ");
  Serial.println(FileName);
  dataFile = SD.open(FileName, FILE_WRITE);// testing if this is a new file then add heaters
  if (dataFile == NULL) {
      Serial.println(F("error creating new datalog.txt"));
      File dataFile = SD.open(FileName, FILE_WRITE);// testing if this is a new file then add heaters
      delay (1000);
    }
  Serial.print("File size: ");
  Serial.println(dataFile.size());
  if (dataFile.size() == 0) {
    dataFile.println(LoggerHeader);
    // print to the serial port too:
    Serial.print("create new file:  ");
    Serial.println(LoggerHeader);
  }
  dataFile.close();

  
  // Initialize DS3231
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  // Set sketch compiling time
  ///
 // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));//use this line only if time calibration is needed
  /* IF THINK HERE IS THE RTC'S PROBLME */
  Serial.println("All good, no worries  :) ");

  // for CO2 sensor
  pinMode(CO2_IN, INPUT);
  pinMode(pump_PIN, OUTPUT);
}

void loop(void) {
  //Serial.println("HI ");
  DateTime now = rtc.now();
  secq = (now.second());
  minq = (now.minute());
  hourq = (now.hour()); 
  sprintf(buffer, "%02u:%02u:%02u %02u/%02u", hourq, minq, secq, dayq, monthq);//this is to zero in single nreadings (e.g., 5 sec to 05 sec)  

   // int Interval=1;//setthe interval between readings (in minutes)
  int Mod_A = (hourq * 60 + minq) % Interval;
  //if (Mod_A == 0 && secq == 0){  // for sampling evry [Interval] minutes
  if (secq == 0) {  // for sampling evry minute 
  // Serial.println(Mod_A);
 
    double V_out= NULL;
    double CH4= NULL;
    CH4 = analogRead(ch4Pin);
    // double CH4 = (10.938*exp(1.7742*CH4pin));
    
     V_out = analogRead(pressurPin)*(5.0 / 1023.0);
    double pressure =((V_out/V_s) + 0.00842) / 0.002421; //conversion equation to convert analog reading to kPa

    
    //SD logging//
     // make a string for assembling the data to log:
    String dataString = "";
    dataString += String(now.hour());
    dataString += ":";
    dataString += String(now.minute());
    dataString += ":";
    dataString += String(now.second());
    dataString += " ";
    dataString += String(now.day());
    dataString += "/";
    dataString += String(now.month());
    dataString += "/";
    dataString += String(now.year());  //HH:MM:SS DD/MM/YY
    dataString += ",";
    //  dataString += ", Sensor 1:  ";
    dataString += String(pressure);// pressure
    dataString += ",";
    // dataString += ", Sensor 2:  ";
    dataString += String(CH4);//Mehtane
    dataString += ",";
    // dataString += ", Sensor 3:  ";
    dataString += String(co2.readCO2PWM());//CO2 ppm

     // open the file. note that only one file can be open at a time,
    // so you have to close this one before opening another.
    dataFile = SD.open(FileName, FILE_WRITE);
    delay(1000);
    // if the file is available, write to it:
    if (dataFile) {
      dataFile.println(dataString);
      dataFile.close();
    }
    // if the file isn't open, pop up an error:
    else {
      Serial.println(F("error opening datalog.txt"));
    }
    // print to the serial port too:
    Serial.println(dataString);

    delay(2000); 
  }
  if ((minq == 1 & secq ==0) || (minq == 40 & secq ==0)) {  // for sampling evry 30 minute 
    digitalWrite(pump_PIN, HIGH);
    Serial.println("pump is ON");
    delay(1000);
    digitalWrite(pump_PIN, LOW);
    Serial.println("pump is OFF");
  }
  delay(1000);
}

You not use code tags. Was that deliberate ?

No, it was a mistake…

Your extensive use of String objects is a possible cause. Find a copy of the FreeMem or FreeMemory function (Adafruit has one) and see whether you’re fragmenting your memory.

You might do better by making dataString a global and reserve a big enough buffer for it.

For best results though, use C strings instead.

@ omer_sab
Thanks for fixing it

thanks, I’ll try it :slight_smile:

See my tutorial on Taming Arduino Strings
for detailed guidelines and code to help you get you Strings running smoothly.

Your String dataString in the loop() would be better made a global and in setup() call
dataString.reserve(50); // 50 seems to be a good size, but check dataString.length() after you add all the parts.

Once you do that it should solve any memory problems you may have.

However in general you don’t need use
dataString += String(now.hour());
just use
dataString += now.hour();
but once you reserve space for dataString those other small Strings just pop on and off the heap with out causing any problems.

I would not recommend using raw c-strings as they are very fragile, if you get the char[.] size wrong your sketch will just crash. Makes it hard to debug.

If you want the fixed unchanging memory size afforded by char[.] but want to retain the code safety and ease of use of String, I would suggest my SafeString library, available from the library manager.

It is simple to convert from Strings to SafeStrings as the += operator is still supported. SafeStrings uses fixed sized char[.] underneath but it will protect you from buffer overflow and give you nice detailed error messages if you don’t allow enough space for all the text you want to add.

My first observation, while not ‘a problem’, would be to play with the sprintf() at the top of loop…
There’s no need to update the buffer a million times per second… you could do more interesting things with that time!

Strings are convenient and fine if you understand their limitations, but if you put the work into c-strings, they’re more efficient and typically will run faster than ‘processed’ Strings.

Both have a place, but a lot of developers prefer to use the right tool for the right job.

should be

 if ( ((minq == 1) && (secq ==0)) || ((minq == 40) && (secq ==0)) ) {  

and

   double V_out= NULL;
    double CH4= NULL;

should be

   double V_out= 0;
    double CH4= 0;

The problem is clearly NOT due to the use of String in the loop() code
Strings are the ‘right’ tool for this job as you can easily add more text to the log msg without having to worry about buffer overflows and crashes.

The reduced sketch below (keeping the String stuff)
does not change freeMemory from loop() to loop()

6:1:0 3/5/2021,167.70,456.00,5.55
pump is ON
pump is OFF
 FreeMemory:634

6:1:0 3/5/2021,146.60,393.00,5.55
pump is ON
pump is OFF
 FreeMemory:634

6:1:0 3/5/2021,138.69,371.00,5.55
pump is ON
pump is OFF
 FreeMemory:634


You might want to open the file just once and keep it open. Check what the freeMemory is doing with your complete sketch.

//https://forum.arduino.cc/t/the-system-is-getting-stuck-after-a-while/856565/2

#ifdef __arm__
// should use uinstd.h to define sbrk but Due causes a conflict
extern "C" char* sbrk(int incr);
#else  // __ARM__
extern char *__brkval;
#endif  // __arm__

int freeMemory() {
  char top;
#ifdef __arm__
  return &top - reinterpret_cast<char*>(sbrk(0));
#elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151)
  return &top - __brkval;
#else  // __arm__
  return __brkval ? &top - __brkval : &top - __malloc_heap_start;
#endif  // __arm__
}

//#include <Wire.h>//for DS3231 (rtc)
#include "RTClib.h"// for DS3231 (rtc)
//#include <SPI.h>//SD card
#include <SD.h>//SD card
//#include <LiquidCrystal.h>
//#include <string.h>
#include <SoftwareSerial.h>
//#include <MHZ.h>

/*   please ReCheck !
   CH4 sensor (MQ4) analog ourput is conect to A0
   pressure sensor (MPXH6400A) is conect to A1
   co2 sensor (MH-Z19B) PMW output is conected to D8
*/
#define ch4Pin A0
#define pressurPin A1
byte CO2_IN = 8;
byte pump_PIN = 30;   // pump on\off control

int Interval = 1;//setthe interval between readings (in minutes)

//  rtc  //
//RTC_DS3231 rtc;
char daysOfTheWeek[7][12] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
char buffer[24];
int secq, minq, hourq, dayq, monthq, yearq;

//SD card//
char FileName[] = "120421.txt";// change the file name
char FileNameP[] = "1104P.txt";// change the file name
const int chipSelect = 53;//SD input
String LoggerHeader = "Date [hh:mm:ss dd/mm/yyyy],pressure [mBar],CH4 [ppm],CO2 [ppm]:";//insert the heaters for the SD logging
String LoggerHeaderP = "Date [hh:mm:ss dd/mm/yyyy],Pumps status:";
File dataFile;
File dataFileP;

//CO2 sesor//
// pin for uart reading
#define MH_Z19_RX 4  // D7
#define MH_Z19_TX 0  // D6

//MHZ co2(MH_Z19_RX, MH_Z19_TX, CO2_IN, MHZ19B);

//pressure//
double V_out;
double V_s = 5 + 0.36;


void setup(void) {

  Serial.begin(9600);
  Serial.println("Hi");
  digitalWrite(pump_PIN, LOW);
  //SD card//
  Serial.print(F("Initializing SD card..."));
  // see if the card is present and can be initialized:
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);// davekw7x: If it's low, the Wiznet chip corrupts the SPI bus
  //  SD.begin(chipSelect);
  //  if (!SD.begin(chipSelect)) {
  //    Serial.println(F("Card failed, or not present"));
  //    while(1);
  //  }
  Serial.println(F("card initialized."));
  Serial.print("File name: ");
  Serial.println(FileName);
  //  dataFile = SD.open(FileName, FILE_WRITE);// testing if this is a new file then add heaters
  //  if (dataFile == NULL) {
  //      Serial.println(F("error creating new datalog.txt"));
  //      File dataFile = SD.open(FileName, FILE_WRITE);// testing if this is a new file then add heaters
  //      delay (1000);
  //    }
  //  Serial.print("File size: ");
  //  Serial.println(dataFile.size());
  //  if (dataFile.size() == 0) {
  //    dataFile.println(LoggerHeader);
  //    // print to the serial port too:
  //    Serial.print("create new file:  ");
  //    Serial.println(LoggerHeader);
  //  }
  //  dataFile.close();


  // Initialize DS3231
  //  if (!rtc.begin()) {
  //    Serial.println("Couldn't find RTC");
  //    while (1);
  //  }

  // Set sketch compiling time
  ///
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));//use this line only if time calibration is needed
  /* IF THINK HERE IS THE RTC'S PROBLME */
  Serial.println("All good, no worries  :) ");

  // for CO2 sensor
  pinMode(CO2_IN, INPUT);
  pinMode(pump_PIN, OUTPUT);

  // dataString.reserve(50);
  // dataStringCheck.init(dataString, Serial); // init( ) will print a msg if memory is low and checkReserve( ) will print a msg
}

void loop(void) {
  //Serial.println("HI ");
  //DateTime now = rtc.now();
  DateTime now = DateTime (2021, 5, 3,
                           6, 1, 0);
  secq = (now.second());
  minq = (now.minute());
  hourq = (now.hour());
  sprintf(buffer, "%02u:%02u:%02u %02u/%02u", hourq, minq, secq, dayq, monthq);//this is to zero in single nreadings (e.g., 5 sec to 05 sec)

  // int Interval=1;//setthe interval between readings (in minutes)
  int Mod_A = (hourq * 60 + minq) % Interval;
  //if (Mod_A == 0 && secq == 0){  // for sampling evry [Interval] minutes
  if (secq == 0) {  // for sampling evry minute
    // Serial.println(Mod_A);

    double V_out = 0;
    double CH4 = 0;
    CH4 = analogRead(ch4Pin);
    // double CH4 = (10.938*exp(1.7742*CH4pin));

    V_out = analogRead(pressurPin) * (5.0 / 1023.0);
    double pressure = ((V_out / V_s) + 0.00842) / 0.002421; //conversion equation to convert analog reading to kPa


    //SD logging//
    // make a string for assembling the data to log:
    String dataString = "";
    dataString += String(now.hour());
    dataString += ":";
    dataString += String(now.minute());
    dataString += ":";
    dataString += String(now.second());
    dataString += " ";
    dataString += String(now.day());
    dataString += "/";
    dataString += String(now.month());
    dataString += "/";
    dataString += String(now.year());  //HH:MM:SS DD/MM/YY
    dataString += ",";
    //  dataString += ", Sensor 1:  ";
    dataString += String(pressure);// pressure
    dataString += ",";
    // dataString += ", Sensor 2:  ";
    dataString += String(CH4);//Mehtane
    dataString += ",";
    // dataString += ", Sensor 3:  ";
    dataString += String(5.552); //String(co2.readCO2PWM());//CO2 ppm

    // open the file. note that only one file can be open at a time,
    // so you have to close this one before opening another.
    //   dataFile = SD.open(FileName, FILE_WRITE);
    delay(1000);
    // if the file is available, write to it:
    //    if (dataFile) {
    //     dataFile.println(dataString);
    //      dataFile.close();
    //    }
    // if the file isn't open, pop up an error:
    //    else {
    //      Serial.println(F("error opening datalog.txt"));
    //    }
    // print to the serial port too:
    Serial.println(dataString);

    delay(2000);
  }
  if ( ((minq == 1) && (secq == 0)) || ((minq == 40) && (secq == 0)) ) { // for sampling evry 30 minute
    digitalWrite(pump_PIN, HIGH);
    Serial.println("pump is ON");
    delay(1000);
    digitalWrite(pump_PIN, LOW);
    Serial.println("pump is OFF");
  }
  delay(1000);
  Serial.print(" FreeMemory:"); Serial.println(freeMemory());
  Serial.println();
}

Is this correct?

byte pump_PIN = 30;

It suggests you are using a Mega2560 rather than an UNO, in which case use a hardware serial for the CO sensor (pass a Stream to the constructor)

Did you really mean to use the USB RX pin as the sensor TX pin?

#define MH_Z19_RX 4  // D7
#define MH_Z19_TX 0  // D6  <<<<<<<< D0  usb RX

I had a quick look a the sensor library. It as a number of references to _serial->flush(). I think the author was trying to discard further input, but that is not what flush() does (now). It just pushes the TX buffer out. So there may be problems there.

Try adding bits of the code back in one at a time, e.g. the RTC stuff, the sensor stuff, the SD stuff, and see what happens to the heap and how the sketch runs.