String trouble I think

My Arduino Uno is locking up or resetting when I run my program after about 6 loops. I am brand new to this so it most likely is me but I have tried everything and can’t figure out why. Anyway the general idea of the code is to display the time in words. Like 12:15 would be “Quarter Past Twelve”. I have stripped out all of the clock stuff and isolated my hanging issue to the function that takes the hour and min as a parameter and returns the appropriate words. After about six calls the program stops responding. All that is needed to run it is the Uno since I am just outputting to the serial monitor. After it starts just type in 555555555555 (5 12 times) and hit enter. It usually fails around 6 cycles but I have had it go longer.

Update: I changed the whole approach to this as I’m sure the String objects are memory hogs and was the cause of my problem. Anyway I have abandoned the below code and approach.

/*
I can't figure out why this crashes after about 6 calls.
*/

void setup() 
{
  Serial.begin(4800);   // opens serial port, sets data rate to 4800 baud   
}



void loop() 
{
  char ch;       //variable for holding key press value
  int iHourG = 12;
  int iMinuteG = 0;
  int iHourGOld = 0;
  int iMinuteGOld = 0;

  Serial.println("Starting Arduino!");
  Serial.println("Input 5 to increase min buy 5");

  while(1)
  {

    ch = Serial.read();  //wait for a button press
     
    switch(ch)  //print out the switch number of the switch pressed, also some special things for SW 4,5 &6
    {
    case '1':
      iHourG++;
      break;

    case '2':
      iMinuteG++;
      break;

    case '3':
      break;

    case '4':
      break;

    case '5':
      iMinuteG = iMinuteG + 5;
      break;

    case '6':
      break;

    default: 
      break;
    } //end of switch-case statements   

    // roll over the Minutes and Hours 
    if (iMinuteG >= 60) {
      iMinuteG = (iMinuteG - 60); 
      iHourG = (iHourG + 1);
    }
    if (iHourG > 12) {
      iHourG = 1;
    };

    // if the hour or minute has changed/rolled then check for new word time  
    if ((iHourG != iHourGOld) || (iMinuteG != iMinuteGOld)) {    
      PrintWordClock(iHourG, iMinuteG);
      iHourGOld = iHourG;
      iMinuteGOld = iMinuteG;
    }
    delay(1000);

  } // end of main while loop

  //delay(50); 
  
} // End of loop() 


void PrintWordClock(int iHourG, int iMinuteG) {
  String sWordTime = "";
  String sLine1 = "";
  String sLine2 = "";

  // get the Words for the current time
  wordClockDisplay(iHourG, iMinuteG, sWordTime);
  // I even tested just this and it still hangs in under 10 time pressing 5
  //sWordTime = "Twenty Five Min Past Twelve";
  
  Serial.println(sWordTime);
  Serial.flush();
  delay(20);

}

void wordClockDisplay(int iHour, int iMinute, String &sWordTime) {
  // word clock stuff
  int iMinPost;
  int iOrgMinute;
 
  iMinPost = 0;
  iOrgMinute = iMinute;
  sWordTime = ""; // this handles > 57 && < 3


  // this would make the minute 45 = 15
  if (iMinute > 33) 
  {
    iMinute = (60 - iMinute);
  } 

  if ((iMinute >= 3) && (iMinute < 7))
  {
    sWordTime = "Five";
    iMinPost = 1;
  }
  else if ((iMinute >= 7) && (iMinute < 13))
  {
    sWordTime = "Ten";
    iMinPost = 1;
  }
  else if ((iMinute >= 13)  && (iMinute < 18))  
  {
    sWordTime = "Quarter";
    iMinPost = 3;
  }
  else if ((iMinute >= 18)  && (iMinute < 23))  
  {
    sWordTime = "Twenty";
    iMinPost = 1;
  }
  else if ((iMinute >= 23)  && (iMinute < 28))  
  {
    sWordTime = "Twenty Five";
    iMinPost = 2;
  }
  else if ((iMinute >= 28)  && (iMinute < 33))  
  {
    sWordTime = "Half";
    iMinPost = 3;
  }

  switch (iMinPost)
  {
  case 1:
    sWordTime += " Minutes";
    break;
  case 2:
    sWordTime += " Min";
    break;
  default:
    break;  
  }

  String sHour = "";
  switch (iHour)
  {
  case 1: 
    sHour = "One";
    break;
  case 2: 
    sHour = "Two";
    break;
  case 3: 
    sHour = "Three";
    break;
  case 4: 
    sHour = "Four";
    break;
  case 5: 
    sHour = "Five";
    break;
  case 6: 
    sHour = "Six";
    break;
  case 7: 
    sHour = "Seven";
    break;
  case 8: 
    sHour = "Eight";
    break;
  case 9: 
    sHour = "Nine";
    break;
  case 10: 
    sHour = "Ten";
    break;
  case 11: 
    sHour = "Eleven";
    break;
  case 12: 
    sHour = "Twelve";
    break;
  default:
    break;  
  }

  // Decide on To or Past
  if ((iOrgMinute > 33) && (iMinPost != 0))
  {
    sWordTime = sWordTime + " To ";
  }
  else if (iMinPost != 0)
  {
    sWordTime = sWordTime + " Past ";
  }

  if (iMinPost != 0)
  {
    sWordTime = sWordTime + sHour;
  }
  else
  {
    sWordTime = sHour + " O'Clock";
  } 
  
  return;  
}

I think the problem might be that String sWordTime; goes out-of-scope when the function exits so returning it might be a problem.

Try this instead:

void wordClockDisplay(int iHour, int iMinute, String &sWordTime) {
sWordTime = "";
.
.
.
   return;
}

Then pass a String to fill when you call wordClockDisplay().

Thanks, good thought, I made the change but it didn’t fix the problem. I don’t see any difference in behavior it still crashes after 6 or so cycles into the function. I’m thinking that all of the String manipulation is maybe causing a memory leak and some buffer or the memory is getting overflowed???

Here is the revised code that still crashes after about 6 calls.

/*
I can't figure out why this crashes after about 6 calls.
*/

void setup() 
{
  Serial.begin(4800);   // opens serial port, sets data rate to 4800 baud   
}



void loop() 
{
  char ch;       //variable for holding key press value
  int iHourG = 12;
  int iMinuteG = 0;
  int iHourGOld = 0;
  int iMinuteGOld = 0;

  Serial.println("Starting Arduino!");
  Serial.println("Input 5 to increase min buy 5");

  while(1)
  {

    ch = Serial.read();  //wait for a button press
     
    switch(ch)  //print out the switch number of the switch pressed, also some special things for SW 4,5 &6
    {
    case '1':
      iHourG++;
      break;

    case '2':
      iMinuteG++;
      break;

    case '3':
      break;

    case '4':
      break;

    case '5':
      iMinuteG = iMinuteG + 5;
      break;

    case '6':
      break;

    default: 
      break;
    } //end of switch-case statements   

    // roll over the Minutes and Hours 
    if (iMinuteG >= 60) {
      iMinuteG = (iMinuteG - 60); 
      iHourG = (iHourG + 1);
    }
    if (iHourG > 12) {
      iHourG = 1;
    };

    // if the hour or minute has changed/rolled then check for new word time  
    if ((iHourG != iHourGOld) || (iMinuteG != iMinuteGOld)) {    
      PrintWordClock(iHourG, iMinuteG);
      iHourGOld = iHourG;
      iMinuteGOld = iMinuteG;
    }
    delay(1000);

  } // end of main while loop

  //delay(50); 
  
} // End of loop() 


void PrintWordClock(int iHourG, int iMinuteG) {
  String sWordTime = "";
  String sLine1 = "";
  String sLine2 = "";

  // get the Words for the current time
  wordClockDisplay(iHourG, iMinuteG, sWordTime);
  // I even tested just this and it still hangs in under 10 time pressing 5
  //sWordTime = "Twenty Five Min Past Twelve";
  
  Serial.println(sWordTime);
  Serial.flush();
  delay(20);

}

void wordClockDisplay(int iHour, int iMinute, String &sWordTime) {
  // word clock stuff
  int iMinPost;
  int iOrgMinute;
 
  iMinPost = 0;
  iOrgMinute = iMinute;
  sWordTime = ""; // this handles > 57 && < 3


  // this would make the minute 45 = 15
  if (iMinute > 33) 
  {
    iMinute = (60 - iMinute);
  } 

  if ((iMinute >= 3) && (iMinute < 7))
  {
    sWordTime = "Five";
    iMinPost = 1;
  }
  else if ((iMinute >= 7) && (iMinute < 13))
  {
    sWordTime = "Ten";
    iMinPost = 1;
  }
  else if ((iMinute >= 13)  && (iMinute < 18))  
  {
    sWordTime = "Quarter";
    iMinPost = 3;
  }
  else if ((iMinute >= 18)  && (iMinute < 23))  
  {
    sWordTime = "Twenty";
    iMinPost = 1;
  }
  else if ((iMinute >= 23)  && (iMinute < 28))  
  {
    sWordTime = "Twenty Five";
    iMinPost = 2;
  }
  else if ((iMinute >= 28)  && (iMinute < 33))  
  {
    sWordTime = "Half";
    iMinPost = 3;
  }

  switch (iMinPost)
  {
  case 1:
    sWordTime += " Minutes";
    break;
  case 2:
    sWordTime += " Min";
    break;
  default:
    break;  
  }

  String sHour = "";
  switch (iHour)
  {
  case 1: 
    sHour = "One";
    break;
  case 2: 
    sHour = "Two";
    break;
  case 3: 
    sHour = "Three";
    break;
  case 4: 
    sHour = "Four";
    break;
  case 5: 
    sHour = "Five";
    break;
  case 6: 
    sHour = "Six";
    break;
  case 7: 
    sHour = "Seven";
    break;
  case 8: 
    sHour = "Eight";
    break;
  case 9: 
    sHour = "Nine";
    break;
  case 10: 
    sHour = "Ten";
    break;
  case 11: 
    sHour = "Eleven";
    break;
  case 12: 
    sHour = "Twelve";
    break;
  default:
    break;  
  }

  // Decide on To or Past
  if ((iOrgMinute > 33) && (iMinPost != 0))
  {
    sWordTime = sWordTime + " To ";
  }
  else if (iMinPost != 0)
  {
    sWordTime = sWordTime + " Past ";
  }

  if (iMinPost != 0)
  {
    sWordTime = sWordTime + sHour;
  }
  else
  {
    sWordTime = sHour + " O'Clock";
  } 
  
  return;  
}