3 board project runs for 55 minutes and stops

My project has a MEGA which acts as the master and two UNOs which are connected through Serial coms. The UNOs monitor a button counter and two encoders. The MEGA polls the UNOs, receives those readings, puts them in an array, and then prints them at a set time. To simplify a little, I set all the parameters during Setup() by typing "p". Then I type "Y" and hit enter and the program begins running. It is set to begin polling the UNOs in 5 minutes and to begin printing the results in 10 minutes. When 10 minutes is reached it prints the results of it's most recent 5 polls. Then it's supposed to reset the array location back to zero and overwrite the previous data with the next 5 polls, and then print them at 15 minutes and so on. So in summery, starting at 10 minutes and repeating every 5 minutes (as long as power is applied) encoder values should be printed out. The problem is it works fine until it reaches 55 minutes and then locks up. I assume it's because some memory is full but if I'm always overwriting, that doesn't make sense to me. Can anyone please tell me why it only works for 55 minutes and how to fix it? :~

My main code

void loop() 
{
  getDateDs1307(); //Gets time info from the Real Time Clock (Ds1307)
    
    if ((hour == (hoursLog + (LogIntervalHours * e))) && (minute == (minutesLog + (LogIntervalMinutes * e))) && (second > 0))
    {  //Populating the array named Data[][] with the readings received from the UNOs 
      Data[INDEX2][0] = COUNT;  //populate a number we can use as a referance if needed in location 0
      Data[INDEX2][1] = hour;  //populating the time in locations 1 and 2
      Data[INDEX2][2] = minute;
      Serial2.write ("e");  //"e" requests the encoder value. "Serial2" means it's encoder 1 (on the first UNO).
      delay (5);
      if (Serial2.available() > 0)
      {
        temp = FetchEdata2();
        delay (5);
        Channel[1][2] = (((temp * Channel[1][1]) + Channel[1][2])); //formats the raw data
        Data[INDEX2][3] = Channel[1][2];  //places the formatted data in the array named Data[][]
        delay (5);
      }
      Serial3.write ("t");  //"t" requests the tipping bucket reading
      delay (5);
      if (Serial3.available() > 0)
      {
        temp = FetchTdata3();
        delay (5);
        Channel[3][2] = (((temp * Channel[3][1]) + Channel[3][2])); //formats the raw data
        Data[INDEX2][4] = Channel[3][2];  //places the formatted data in the array named Data[][]
        delay (5);
      }
      Serial3.write ("e");  //"e" requests the encoder value. "Serial3" means it's encoder 2 (on the second UNO).
      delay (5);
      if (Serial3.available() > 0)
      {
        temp = FetchEdata3();
        delay (5);
        Channel[2][2] = (((temp * Channel[2][1]) + Channel[2][2])); //formats the raw data
        Data[INDEX2][5] = Channel[2][2];  //places the formatted data in the array named Data[][]     
        delay (5);
      }
      COUNT = COUNT++;
      INDEX2 = INDEX2++;
      X = (INDEX2 - scans);
      e = e++;
    }
    
    if ((hour == (hoursNext + (intHours * f))) && (minute == (minutesNext + (intMinutes * f))) && (second > 0))    
  { //If time to print is reached do this  
     for(p = scans; p > 0; p--)
   {
      if ((Data[X][1]) < 10)
       {
         Serial.print ("0");
       }
      Serial.print ((Data[X][1]), 0);
      Serial.print (":");
      if ((Data[X][2]) < 10)
       {
         Serial.print ("0");
       }
      Serial.print ((Data[X][2]), 0);
      Serial.print ("     ");
      Serial.print (Data[X][3]);
      Serial.print ("     ");
      Serial.print (Data[X][5]);
      Serial.print ("     ");
      Serial.println (Data[X][4]);
      X = (X + 1);
      
   }
     f = f++; 
     INDEX2 = 0;
  }
}


void setDateDs1307(byte hours, byte minutes, byte seconds)                
{
  hours  = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  minutes = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  seconds = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48)); // Use of (byte) type casting and ascii math to achieve result.  

  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write((byte)0x00);
  Wire.write(decToBcd(second));    // 0 to bit 7 starts the clock
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));      // If you want 12 hour am/pm you need to set
  // bit 6 (also need to change readDateDs1307)
  Wire.endTransmission();
}

// Gets the date and time from the ds1307 and prints result
void getDateDs1307()
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write((byte)0x00);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
  // A few of these need masks because certain bits are control bits
  second     = bcdToDec(Wire.read() & 0x7f);
  minute     = bcdToDec(Wire.read());
  hour       = bcdToDec(Wire.read() & 0x3f);  // Need to change this if 12 hour am/pm
}

byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}
int FetchTdata2()
{
  int var;
  if (Serial2.available() > 0)
      { //if there's any data waiting
        //Serial.available recognizes digits pending in serial buffer
          while(Serial2.available()>0)
          {
            char c = Serial2.read(); //reads data in serial buffer one byte at a time.
            readString += c; //contents of char c are placed in readString
            delay(5);
          }
      }      
     if (readString.length()>0) //when readString gets content, do something
       {
         int f = readString.toInt();
         var = f;         
         readString=""; // make readString empty for next time around
         readString[8]; //allocate 8 bytes of memory for readString
       }
       return var;       
}
int FetchEdata2()
{
  int var;
  if (Serial2.available() > 0)
      { //if there's any data waiting
        //Serial.available recognizes digits pending in serial buffer
          while(Serial2.available()>0)
          {
            char c = Serial2.read(); //reads data in serial buffer one byte at a time.
            readString += c; //contents of char c are placed in readString
            delay(5);
          }
      }      
     if (readString.length()>0) //when readString gets content, do something
       {
         int f = readString.toInt(); // turns contents of readString into an int in "f"
         
         var = f;         
         readString=""; // make readString empty for next time around
         readString[8]; //allocate 8 bytes of memory for readString
       }
       return var;
}
int FetchEdata3()
{
  int var;
  if (Serial3.available() > 0)
      { //if there's any data waiting
        //Serial.available recognizes digits pending in serial buffer
          while(Serial3.available()>0)
          {
            char c = Serial3.read(); //reads data in serial buffer one byte at a time.
            readString += c; //contents of char c are placed in readString
            delay(5);
          }
      }      
     if (readString.length()>0) //when readString gets content, do something
       {
         int f = readString.toInt(); // turns contents of readString into an int in "f"
         var = f;         
         readString=""; // make readString empty for next time around
         readString[8]; //allocate 8 bytes of memory for readString
       }
       return var;
}
int FetchTdata3()
{
  int var;
  if (Serial3.available() > 0)
      { //if there's any data waiting
        //Serial.available recognizes digits pending in serial buffer
          while(Serial3.available()>0)
          {
            char c = Serial3.read(); //reads data in serial buffer one byte at a time.
            readString += c; //contents of char c are placed in readString
            delay(5);
          }
      }      
     if (readString.length()>0) //when readString gets content, do something
       {
         int f = readString.toInt();
         var = f;         
         readString=""; // make readString empty for next time around
         readString[8]; //allocate 8 bytes of memory for readString
       }
       return var;       
}

The rest of my code

// Requires a MEGA and two UNOs
/*Wire setup on MEGA: 
  TX2 (pin 14) goes to the second UNO pin 0
  RX2 (pin 15) goes to the second UNO pin 1
  TX2 (pin 16) goes to the first UNO pin 0
  RX2 (pin 17) goes to the first UNO pin 1
  SDA (pin 20) goes to the first UNO Analog 4
  SCL (pin 21) goes to the first UNO Analog 5
  */
//download program then press "p" then press "Y" then press enter
  
#include <Wire.h> //we need Wire.h to help us tell time
#define DS1307_I2C_ADDRESS 0x68  // This is the I2C address

const int  buttonPin = 5;    // the pin that the button is attached to
const int ledPin = 8; // was there for R & D... no longer used
const int tippingBucket = 7; // the pin that the TB sensor is attached to
String readString;
double bucketTips = 0;
double actualRotaryTicks = 5.5;
double increment3 = 0;
double increment2 = 0;
double increment1 = 0;
double temp = 0;
long ID = 10000000;
long TimeClock = 0;
long AreaCode = 800;
long m = 0;  //to be used for millis()
long I = 0;  //to be used for the call Interval
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
int incomingByte;            // to read input into
int CallMode = 0;
int Baud = 110;
int Acode[3]={0,0,0}; //an array of 3 to hold the area code
int PhNum[7]={0,0,0,0,0,0,0}; //an array of 7 to hold the phone number
int TM[6]={0,0,0,0,0,0}; //an array of 6 to hold the digits of a time display
int minutesNext = 0; // variable
int hoursNext = 0; // variable
int minutesLog = 0;
int hoursLog = 0;
int intHours = 0;
int intMinutes = 0;
int LogIntervalHours = 0;
int LogIntervalMinutes = 0;
int channel = 0;
int scans = 0;
int index = 0;
int INDEX2 = 0;
int COUNT = 0;
int Run = 0;
int a = 0;
int b = 0;
int d = 0;
int e = 0;
int f = 0;
int p = 0;
int X = 0;
int printPass = 0;
int printPass2 = 0;
int Tdata2 = 0;//tipping bucket data on uno board #2
int Edata2 = 0;//encoder data on uno board #2
int Tdata3 = 0;//tipping bucket data on uno board #3
int Edata3 = 0;//encoder data on uno board #3
char c;
byte minute, hour, second;
float Channel[4][4];
double Data[10][6];

void setup() 
{
  digitalWrite(18, HIGH);//This would be 2 on the uno 18 on mega
  digitalWrite(19, HIGH);//This would be 3 on the uno 19 on mega
  pinMode(ledPin, OUTPUT);     
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
  Serial2.begin(9600);
  Serial3.begin(9600);
  Wire.begin();  
  
  while (Run == 0)
  {
  if (Serial.available() > 0) { //if any key is pressed 
   int incomingByte = Serial.read(); //read input into incomingByte   
   switch(incomingByte){ //depending on the value of incomingByte...
           
    case 'p': //lower case "p" will automatically program unit

      Serial.println ("Programing unit.");
      ID = 12345678;
      hour = 1; //hour, minute, and second are populated 
      minute = 0;
      second = 0;
      setDateDs1307(hour, minute, second); //The values are sent to "setDate..." to adjust the clock
      hoursNext = 1;
      minutesNext = 10;
      intHours = 0;
      intMinutes = 5;
      scans = 5;
      hoursLog = 1;
      minutesLog = 5;
      LogIntervalHours = 0;
      LogIntervalMinutes = 1;
      // Now we turn the interval time into a numeric value of milliseconds stored in "I" for later use
      I = ((LogIntervalHours * 3600000) + (LogIntervalMinutes * 60000));
      index = 1;
      Channel[index][0] = 01;
      Channel[index][1] = .01;
      Channel[index][2] = 12;
      Channel[index][3] = 67;
      index = 2;
      Channel[index][0] = 02;
      Channel[index][1] = -.01;
      Channel[index][2] = 12;
      Channel[index][3] = 68;
      index = 3;
      Channel[index][0] = 03;
      Channel[index][1] = .01;
      Channel[index][2] = 99.99;
      Channel[index][3] = 50;
      Serial.println ("Done.");      
      break;
      
    case 'Y': //upper case "Y" will prompt you to start the program

      Serial.println ("Press enter to run program.     ");
      while (Run == 0)
      {
      if (Serial.available() > 0)
      { //if any key is pressed 
       int Y = Serial.read(); //read input into incomingByte
       delay (50);
       if (Y == 13)
       {      
         Serial2.write ("p");//lower case "p" resets and zeros the UNOs.  
         Serial3.write ("p");
         delay (5);
         Serial.println ("");
         Serial.println ("Run mode. Capacity: Unknown at this time.");
         Serial2.write ("2");
         Serial3.write ("2");
         Run = 1;
       }
      }
      }
      break;
      default:      
      Serial.println ("Invalid entry. Enter p to program.");
   }
  }
 }
}

Try this:
on any Serial.print(“any text”); use Serial.print(F(“some text”);
It will only work when sending text, not variables. Try adding it line by line and watch your memory usage dive bomb.

the F() macro tells the Arduino NOT to set aside RAM for text strings. It keeps it in PROGMEM and transfers it to ram one byte at a time as it transmits it over serial.

readString=""; // make readString empty for next time around
         readString[8];

Unusual construct.

Also, if you know the values of a variable will only be 0-255, change the variable type to uint8_t. It will save you a byte of RAM each time.
If they're going to be -127 - 127, use a int8_t.

I wonder if 55 minutes means a variable type may be wrong.

Ok, sorry it took me so long to reply but I did find a solution. I tried a couple different things but to make a long story short, I’ll jump right to my findings. I put print lines in all over the place to see exactly what it was doing and found that the problem was in the “if” statement right at the beginning. It did not account for the hours to increment and the minutes to reset to 0 after the 59 minute mark. So to fix that I had to re-write the “if” statements and turn the data collection process and array printing process into functions. The whole main loop looks quite different but it’s actually sleeker and works better. Thanks so much for your help.