Arduino Program Stops Working After a Day Help

Hello, I am looking for a bit of help (not sure if its hardware or software problem), but basically my code has the ability to turn on/off different relays at different time intervals.

When executing and running all seems to be working very well. But after a day or so of running it simply just stops working; I am taking a guess and assuming that the memory is being oversaturated? Not sure. Could also be power supply?

My initial solution is to disconnect the arduino USB power supply and reconnect, but hopefully there can be a more elegant solution.

Here is my code:

//////////////////////////////////////////////////////////
//Variables for Serial parse
//////////////////////////////////////////////////////////
const byte numChars = 128;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

char messageFromPC[numChars] = {0};
int integerFromPC = 0;

boolean newData = false;

//////////////////////////////////////////////////////////
//Variables for selecting valves to turn ON/OFF
//////////////////////////////////////////////////////////
int valvePower[9] = {1,1,1,1,0,0,0,0};

//////////////////////////////////////////////////////////
//Variables for declaring the time ON/OFF for the valves
//////////////////////////////////////////////////////////
int timeOn[9] = {1000,500,200,1000,1000,2000,500,500}; //The amount of time the valve stays open
int timeOff[9] = {1500,1000,500,2000,2000,3000,1000,1000}; //This is the TOTAL time between an ON/OFF lopp
                                                           //if we want to have a valve0 ON 1 sec and OFF 1 sec
                                                           //then we need timeOn[0] = 1000;
                                                           //and we need timeOff[0] = 2000;

//////////////////////////////////////////////////////////
//Variable for pin declaration
//////////////////////////////////////////////////////////
const int valvePins[9] = {2,3,4,5,6,7,8,9}; 

//////////////////////////////////////////////////////////
//Variables for running the millis() function
//////////////////////////////////////////////////////////
byte valveStatus[9] = {LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW};

unsigned long currentMillis = 0;
unsigned long previousValvesMillis[9] = {0,0,0,0,0,0,0,0};

//////////////////////////////////////////////////////////
//Main Set-up
//////////////////////////////////////////////////////////
void setup() {
  Serial.begin(9600);
  //Serial.println("Starting SeveralThingsAtTheSameTimeRev1.ino");  // so we know what sketch is running
  
  for (int i = 0; i <9; i++){
    pinMode(valvePins[i], OUTPUT);
  }
  delay(2000);
  
}

//////////////////////////////////////////////////////////
//Main loop function
//////////////////////////////////////////////////////////
void loop() {
  recvWithStartEndMarkers();
    if (newData == true) {
      strcpy(tempChars, receivedChars);
      // this temporary copy is necessary to protect the original data
      //   because strtok() used in parseData() replaces the commas with \0
      parseData();
      showParsedData();
      newData = false;
    }
  
  currentMillis = millis();   // capture the latest value of millis()
                              //   this is equivalent to noting the time from a clock
                              //   use the same time for all LED flashes to keep them synchronized

  updateValve0();
  updateValve1();
  updateValve2();
  updateValve3();
  updateValve4();
  updateValve5();
  updateValve6();
  updateValve7();

  valveControl();
    
}

//////////////////////////////////////////////////////////
//Function for initializing the marker for receiving data
//////////////////////////////////////////////////////////
void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//////////////////////////////////////////////////////////
//Function to parse data
//////////////////////////////////////////////////////////
void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars,",");      // get the first part - the string
    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    valvePower[0] = atoi(strtokIndx);     // convert this part to an 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOn[0] = atoi(strtokIndx);     // convert this part to an integer
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOff[0] = atoi(strtokIndx);     // convert this part to an integer
    
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    valvePower[1] = atoi(strtokIndx);     // convert this part to an 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOn[1] = atoi(strtokIndx);     // convert this part to an integer
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOff[1] = atoi(strtokIndx);     // convert this part to an integer
    
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    valvePower[2] = atoi(strtokIndx);     // convert this part to an 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOn[2] = atoi(strtokIndx);     // convert this part to an integer
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOff[2] = atoi(strtokIndx);     // convert this part to an integer
        
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    valvePower[3] = atoi(strtokIndx);     // convert this part to an 
    strtokIndx = strtok(NULL, ",");
    timeOn[3] = atoi(strtokIndx);     // convert this part to an integer
    strtokIndx = strtok(NULL, ",");
    timeOff[3] = atoi(strtokIndx);     // convert this part to an integer
        
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    valvePower[4] = atoi(strtokIndx);     // convert this part to an 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOn[4] = atoi(strtokIndx);     // convert this part to an integer
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOff[4] = atoi(strtokIndx);     // convert this part to an integer
        
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    valvePower[5] = atoi(strtokIndx);     // convert this part to an 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOn[5] = atoi(strtokIndx);     // convert this part to an integer
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOff[5] = atoi(strtokIndx);     // convert this part to an integer
        
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    valvePower[6] = atoi(strtokIndx);     // convert this part to an 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOn[6] = atoi(strtokIndx);     // convert this part to an integer
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOff[6] = atoi(strtokIndx);     // convert this part to an integer
    
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    valvePower[7] = atoi(strtokIndx);     // convert this part to an 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOn[7] = atoi(strtokIndx);     // convert this part to an integer
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    timeOff[7] = atoi(strtokIndx);     // convert this part to an integer
    
}

//////////////////////////////////////////////////////////
//Function for timer of first valve
//////////////////////////////////////////////////////////
void updateValve0(){
  if(valveStatus[0] == LOW){ // if the valve is off, we must wait for the interval to expire before turning it on
    if(currentMillis - previousValvesMillis[0] >= timeOff[0]){
      // time is up, so change the state to HIG
      valveStatus[0] = HIGH;
      // and save the time when we made the change
      previousValvesMillis[0]+= timeOff[0] ;
      // NOTE: The previous line could alternatively be
          //              previousOnBoardLedMillis = currentMillis
          //        which is the style used in the BlinkWithoutDelay example sketch
          //        Adding on the interval is a better way to ensure that succesive periods are identical

    }
  }
  else { // i.e. if onBoardLedState is HIGH
    // if the Led is on, we must wait for the duration to expire before turning it off
    if(currentMillis - previousValvesMillis[0] >= timeOn[0]){
      // time is up, so change the state to LOW
      valveStatus[0] = LOW;
      // and save the time when we made the change
      previousValvesMillis[0];
    }
  }
}
 
//////////////////////////////////////////////////////////
//Function for timer of second valve
//////////////////////////////////////////////////////////
void updateValve1(){
  if(valveStatus[1] == LOW){ // if the valve is off, we must wait for the interval to expire before turning it on
    if(currentMillis - previousValvesMillis[1] >= timeOff[1]){
      // time is up, so change the state to HIG
      valveStatus[1] = HIGH;
      // and save the time when we made the change
      previousValvesMillis[1]+= timeOff[1] ;
      // NOTE: The previous line could alternatively be
          //              previousOnBoardLedMillis = currentMillis
          //        which is the style used in the BlinkWithoutDelay example sketch
          //        Adding on the interval is a better way to ensure that succesive periods are identical

    }
  }
  else { // i.e. if onBoardLedState is HIGH
    // if the Led is on, we must wait for the duration to expire before turning it off
    if(currentMillis - previousValvesMillis[1] >= timeOn[1]){
      // time is up, so change the state to LOW
      valveStatus[1] = LOW;
      // and save the time when we made the change
      previousValvesMillis[1];
    }
  }
}

//////////////////////////////////////////////////////////
//Function for timer of third valve
//////////////////////////////////////////////////////////
void updateValve2(){
  if(valveStatus[2] == LOW){ // if the valve is off, we must wait for the interval to expire before turning it on
    if(currentMillis - previousValvesMillis[2] >= timeOff[2]){
      // time is up, so change the state to HIG
      valveStatus[2] = HIGH;
      // and save the time when we made the change
      previousValvesMillis[2]+= timeOff[2] ;
      // NOTE: The previous line could alternatively be
          //              previousOnBoardLedMillis = currentMillis
          //        which is the style used in the BlinkWithoutDelay example sketch
          //        Adding on the interval is a better way to ensure that succesive periods are identical

    }
  }
  else { // i.e. if onBoardLedState is HIGH
    if(currentMillis - previousValvesMillis[2] >= timeOn[2]){
      // time is up, so change the state to LOW
      valveStatus[2] = LOW;
      // and save the time when we made the change
      previousValvesMillis[2];
    }
  }
}

//////////////////////////////////////////////////////////
//Function for timer of fourth valve
//////////////////////////////////////////////////////////
void updateValve3(){
  if(valveStatus[3] == LOW){ // if the valve is off, we must wait for the interval to expire before turning it on
    if(currentMillis - previousValvesMillis[3] >= timeOff[3]){
      // time is up, so change the state to HIG
      valveStatus[3] = HIGH;
      // and save the time when we made the change
      previousValvesMillis[3]+= timeOff[3] ;
      // NOTE: The previous line could alternatively be
          //              previousOnBoardLedMillis = currentMillis
          //        which is the style used in the BlinkWithoutDelay example sketch
          //        Adding on the interval is a better way to ensure that succesive periods are identical

    }
  }
  else { // i.e. if onBoardLedState is HIGH
    // if the Led is on, we must wait for the duration to expire before turning it off
    if(currentMillis - previousValvesMillis[3] >= timeOn[3]){
      // time is up, so change the state to LOW
      valveStatus[3] = LOW;
      // and save the time when we made the change
      previousValvesMillis[3];
    }
  }
}

//////////////////////////////////////////////////////////
//Function for timer of fifth valve
//////////////////////////////////////////////////////////
void updateValve4(){
  if(valveStatus[4] == LOW){ // if the valve is off, we must wait for the interval to expire before turning it on
    if(currentMillis - previousValvesMillis[4] >= timeOff[4]){
      // time is up, so change the state to HIG
      valveStatus[4] = HIGH;
      // and save the time when we made the change
      previousValvesMillis[4]+= timeOff[4] ;
      // NOTE: The previous line could alternatively be
          //              previousOnBoardLedMillis = currentMillis
          //        which is the style used in the BlinkWithoutDelay example sketch
          //        Adding on the interval is a better way to ensure that succesive periods are identical

    }
  }
  else { // i.e. if onBoardLedState is HIGH
    // if the Led is on, we must wait for the duration to expire before turning it off
    if(currentMillis - previousValvesMillis[4] >= timeOn[4]){
      // time is up, so change the state to LOW
      valveStatus[4] = LOW;
      // and save the time when we made the change
      previousValvesMillis[4];
    }
  }
}

//////////////////////////////////////////////////////////
//Function for timer of sixth valve
//////////////////////////////////////////////////////////
void updateValve5(){
  if(valveStatus[5] == LOW){ // if the valve is off, we must wait for the interval to expire before turning it on
    if(currentMillis - previousValvesMillis[5] >= timeOff[5]){
      // time is up, so change the state to HIG
      valveStatus[5] = HIGH;
      // and save the time when we made the change
      previousValvesMillis[5]+= timeOff[5] ;
      // NOTE: The previous line could alternatively be
          //              previousOnBoardLedMillis = currentMillis
          //        which is the style used in the BlinkWithoutDelay example sketch
          //        Adding on the interval is a better way to ensure that succesive periods are identical

    }
  }
  else { // i.e. if onBoardLedState is HIGH
    // if the Led is on, we must wait for the duration to expire before turning it off
    if(currentMillis - previousValvesMillis[5] >= timeOn[5]){
      // time is up, so change the state to LOW
      valveStatus[5] = LOW;
      // and save the time when we made the change
      previousValvesMillis[5];
    }
  }
}

//////////////////////////////////////////////////////////
//Function for timer of seventh valve
//////////////////////////////////////////////////////////
void updateValve6(){
  if(valveStatus[6] == LOW){ // if the valve is off, we must wait for the interval to expire before turning it on
    if(currentMillis - previousValvesMillis[6] >= timeOff[6]){
      // time is up, so change the state to HIG
      valveStatus[6] = HIGH;
      // and save the time when we made the change
      previousValvesMillis[6]+= timeOff[6] ;
      // NOTE: The previous line could alternatively be
          //              previousOnBoardLedMillis = currentMillis
          //        which is the style used in the BlinkWithoutDelay example sketch
          //        Adding on the interval is a better way to ensure that succesive periods are identical

    }
  }
  else { // i.e. if onBoardLedState is HIGH
    // if the Led is on, we must wait for the duration to expire before turning it off
    if(currentMillis - previousValvesMillis[6] >= timeOn[6]){
      // time is up, so change the state to LOW
      valveStatus[6] = LOW;
      // and save the time when we made the change
      previousValvesMillis[6];
    }
  }
}

//////////////////////////////////////////////////////////
//Function for timer of eigth valve
//////////////////////////////////////////////////////////
void updateValve7(){
  if(valveStatus[7] == LOW){ // if the valve is off, we must wait for the interval to expire before turning it on
    if(currentMillis - previousValvesMillis[7] >= timeOff[7]){
      // time is up, so change the state to HIG
      valveStatus[7] = HIGH;
      // and save the time when we made the change
      previousValvesMillis[7]+= timeOff[7] ;
      // NOTE: The previous line could alternatively be
          //              previousOnBoardLedMillis = currentMillis
          //        which is the style used in the BlinkWithoutDelay example sketch
          //        Adding on the interval is a better way to ensure that succesive periods are identical

    }
  }
  else { // i.e. if onBoardLedState is HIGH
    // if the Led is on, we must wait for the duration to expire before turning it off
    if(currentMillis - previousValvesMillis[7] >= timeOn[7]){
      // time is up, so change the state to LOW
      valveStatus[7] = LOW;
      // and save the time when we made the change
      previousValvesMillis[7];
    }
  }
}

//////////////////////////////////////////////////////////
//Function to show Data
//////////////////////////////////////////////////////////
void showParsedData() {
    Serial.print("Message ");
    Serial.println(messageFromPC);
    
    Serial.print("valve0 power ");
    Serial.println(valvePower[0]);
    Serial.print("valve0 ON ");
    Serial.println(timeOn[0]);
    Serial.print("valve1 OFF ");
    Serial.println(timeOff[0]);
    
    Serial.print("valve1 power ");
    Serial.println(valvePower[1]);
    Serial.print("valve1 ON ");
    Serial.println(timeOn[1]);
    Serial.print("valve1 OFF ");
    Serial.println(timeOff[1]);

    Serial.print("valve2 power ");
    Serial.println(valvePower[2]);
    Serial.print("valve2 ON ");
    Serial.println(timeOn[2]);
    Serial.print("valve2 OFF ");
    Serial.println(timeOff[2]);
    
    Serial.print("valve3 power ");
    Serial.println(valvePower[3]);
    Serial.print("valve3 ON ");
    Serial.println(timeOn[3]);
    Serial.print("valve3 OFF ");
    Serial.println(timeOff[3]);

    Serial.print("valve4 power ");
    Serial.println(valvePower[4]);
    Serial.print("valve4 ON ");
    Serial.println(timeOn[4]);
    Serial.print("valve4 OFF ");
    Serial.println(timeOff[4]);
    
    Serial.print("valve5 power ");
    Serial.println(valvePower[5]);
    Serial.print("valve5 ON ");
    Serial.println(timeOn[5]);
    Serial.print("valve5 OFF ");
    Serial.println(timeOff[5]);

    Serial.print("valve6 power ");
    Serial.println(valvePower[6]);
    Serial.print("valve6 ON ");
    Serial.println(timeOn[6]);
    Serial.print("valve6 OFF ");
    Serial.println(timeOff[6]);
    
    Serial.print("valve7 power ");
    Serial.println(valvePower[7]);
    Serial.print("valve7 ON ");
    Serial.println(timeOn[7]);
    Serial.print("valve7 OFF ");
    Serial.println(timeOff[7]);
    
}

//////////////////////////////////////////////////////////
//Function to turn ON/OFF valves
//////////////////////////////////////////////////////////
void valveControl(){
  if(valvePower[0] == 1){
    digitalWrite(valvePins[0], valveStatus[0]);
  }
  if(valvePower[1] == 1){
    digitalWrite(valvePins[1], valveStatus[1]);
  }
  if (valvePower[2] == 1){
    digitalWrite(valvePins[2], valveStatus[2]);
  }
  if(valvePower[3] == 1){
    digitalWrite(valvePins[3], valveStatus[3]);
  }
  if (valvePower[4] == 1){
    digitalWrite(valvePins[4], valveStatus[4]);
  }
  if( valvePower[5] == 1){
    digitalWrite(valvePins[5], valveStatus[5]);
  }
  if( valvePower[6] == 1){
    digitalWrite(valvePins[6], valveStatus[6]);
  }
  if (valvePower[7] ==1){
    digitalWrite(valvePins[7], valveStatus[7]);
  }
}

Thanks!

The "updateValve" functions all look very similar.

Can be done with for loop.

for int i = 0; i< max counts; i++)
{
Serial.print(" valve" );
Serial.print( i );
Serial.print( " power ");
Serial.println( "valvePower{i} );
}

Code looks good. Put some serial prints for debugging and post a diagram and image of your project. Reads like a power issue.

@anon73444976, I agree.. just not sure if each one (potentially) has its own millis time interval, then wouldn't they need their own millis loop? At least this was my thought process.. what do you recommend?

@Idahowalker you are right, I may just delete the showparseddata function, since it was mostly for testing code... still, would this be a huge factor when it comes to it shutting off?
Will post a schematic of the connections soon.

I see all your arrays set for 9 entries only have 8 initial values. Could that be causing a problem?

I think it's a power issue.

Did you address post#5?

What MCU is being used?

Just for grins, if an AVR board of ARM_M0, you can use
https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory
to prove no memory leaks.

#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__
}

Addressed post #5 made by @Paul_KD7HB.
Got rid of the void showParsedData() {...} function.
And also am now powering up the arduino via the Barrel connecter with a 12V battery; this is replacing a 5V usb power supply.

There are two times involved - the time something significant last happened for each item, and the time now.
The first seems to be covered by an array, and the time now is the same for all.
It seems to me they could all be replaced by just one function, supplied with an index.
(I haven't looked too closely because I'm on my phone)

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