Spent Hours - Finally need to ask for help!

I have finally tucked my tail and need ask for some help. I have spent hours trying to troubleshoot my code and just can't seem to figure out. I have been using this code successfully for over a year now, but recently decided to expand the functionality. So here is some quick background.

The code reads data from the serial port (sent from a Victron MPPT controller). The data is formatted like this "TAGVALUE". It then takes the values we are interested in and displays the value on an LCD and to the serial port. Some of the code was borrowed from another user, but is pretty much a clone of the serial data tutorial. Anyway here is the code.

// include the library code
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>

SoftwareSerial mySerial(2, 3); // RX, TX
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display

int CS1;
float V2, I2, VPV2;
const byte numChars = 30;
char receivedChars[numChars];   // an array to store the received data
boolean newData = false;
const char * labelsOfInterest[] = {"V", "I", "VPV", "PPV", "CS"};
const unsigned int maxLabelsOfInterest = sizeof(labelsOfInterest) / sizeof(*labelsOfInterest);
boolean sleep1 = false;


void setup() {
  Serial.begin(19200);
  mySerial.begin(19200); 
  lcd.init(); //initialize the lcd
  lcd.backlight(); //open the backlight
  delay(1000);
  lcd.setCursor(0,0);
  lcd.print("INIT");
  }
  
void loop() {
  //lcd.setCursor(0,0);
  //lcd.print("INIT");
  recvWithEndMarker();
  if (newData) { // we have received a ful line, deal with it
 parseNewData(); // this messes up receivedChars[]
newData = false;
  }
}

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;
    while (mySerial.available() > 0 && newData == false) {
    rc = mySerial.read();
    if (rc != '\r') { // we ignore that character
      if (rc != endMarker) {
        if (rc == '\t') rc = ' '; // change tabs into just a space
        receivedChars[ndx] = rc;
        ndx++; // we go to the next space in our buffer
        if (ndx >= numChars) { // and check bounds.
          ndx = numChars - 1; // that means we will loose the end of long strings
        }
      } else {
        receivedChars[ndx] = '\0'; // terminate the string
        ndx = 0; // ndx is static, so we prepare for next turn
        newData = true;
      }
    }
  }
}

void parseNewData()
{
  const char *delim  = " ";
  char * item;
  boolean labelFound;
  long int labelValue;
  int labelIndex;
item = strtok (receivedChars, delim);
labelFound = false;
  for (int i = 0; i < maxLabelsOfInterest; ++i) {
    if (!strcmp(labelsOfInterest[i], item)) {
     item = strtok(NULL, delim);
      if (item != NULL) {
        labelFound = true;
        labelIndex = i;
       labelValue = atol(item);
break; // ends the for loop as we found a label
      } // end if we had a value for the label
  } // end string compare
  } // end for
  if (labelFound) {
    switch (labelIndex) {
      case 0:
        lcd.setCursor(0,0);
        V2 = labelValue / 1000.00f;
        Serial.print("Battery Volate = ");
        Serial.println(V2);
        lcd.print("BV=");
        lcd.print(V2);
        break;
      case 1:
        I2 = labelValue / 1000.00f;
        if (I2 < 0.05) {
        lcd.setCursor(0,1);
        lcd.print("     SLEEP      ");
        Serial.println("Charger Sleeping ");
        sleep1=true;
        }
        else {
        Serial.print("Current Into Batts = ");
        Serial.println(I2);
        lcd.setCursor(0,1);
        lcd.print("BC=");
        lcd.print(I2);
        lcd.print("  ");
        sleep1=false;
        }
        break;
      case 2:
        VPV2 = labelValue / 1000.0f;
        if (sleep1 == true) {
        Serial.println("Panels Sleeping ");
        }
        else {
        Serial.print("Panel Voltage = ");
        Serial.println(VPV2);
        lcd.setCursor(9,1);
        lcd.print("PV=");
        lcd.print(VPV2);
        }
        break;
      case 3:
        Serial.print("Panel Wattage = ");
        Serial.println(labelValue);
        lcd.setCursor(12,0);
        lcd.print("   ");
        lcd.setCursor(9,0);
        lcd.print("PW=");
        lcd.print(labelValue);
        break;
      case 4:
        CS1=labelValue;
                      switch (CS1) {
                        case 0:
                          Serial.println("Charger is OFF");
                          lcd.setCursor(15,0);
                          lcd.print(" ");
                          CS1 = NULL;
                          break;
                        case 1:
                          Serial.println("Charger is in low power mode");
                          lcd.setCursor(15,0);
                          lcd.print("S");
                          CS1 = NULL;
                          break;
                        case 2:
                          Serial.println("Charger has a fault");
                          lcd.setCursor(15,0);
                          lcd.print("E");
                          CS1 = NULL;
                          break;
                        case 3:
                          Serial.println("Charger is in BULK mode");
                          lcd.setCursor(15,0);
                          lcd.print("B");
                          CS1 = NULL;
                          break;
                        case 4:
                          Serial.println("Charger is in ABSORB mode");
                          lcd.setCursor(15,0);
                          lcd.print("A");
                          CS1 = NULL;
                          break;
                        case 5:
                          Serial.println("Charger is in FLOAT mode");
                          lcd.setCursor(15,0);
                          lcd.print("F");
                          CS1 = NULL;
                          break;
                       case 9:
                          Serial.println("Charger is in INVERT mode");
                          lcd.setCursor(15,0);
                          lcd.print("I");
                          CS1 = NULL;
                          break;
                       }
        Serial.print("Charger State = ");
        Serial.println(labelValue);
        Serial.print("\n");
        delay(3000);
       break;
    }
   } else {
   }
}

Now the problem. I want to display some extra tags (H20, H21, H22, H23). For some reason those tags are getting corrupted shortly after booting up the Arduino. If I watch the receivedChars value I will see those tags show up ONCE right after boot up, then they are completely gone.

I think the problem is because those tags contain numerals in them. I think the "labelValue = atol(item);" is removing the tags, but I'm not %100 sure. I have been pulling my hair out for hours trying to determine the exact issue and how to fix it!

Any suggestions?

Your new tags need to be added to your labelsOfInterest array.

Sorry.. I should have clarified.. I have added the tags to the labelsOfInterest array and that is when I noticed the issue. They were never detected and that is what made me look at the receivedChars array.

Like I said, they show up in the data once after bootup and then don't. However if I look at the rc value (which is the raw serial data) they are there, but completely gone from the receivedChars array!

Better if you post your latest code.

Not really much difference except the addition of the tags in the array and a couple extra case statements. Doesn't matter which code I run (the one I posted, or the new one), the data is still missing from the receivedChars array. Both sets of code behave exactly the same way..

Anyway, here is the updated code.

// include the library code
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>

SoftwareSerial mySerial(2, 3); // RX, TX
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display

int CS1;
float V2, I2, VPV2, MP1, YT1;
const byte numChars = 30;
char receivedChars[numChars];   // an array to store the received data
boolean newData = false;
const char * labelsOfInterest[] = {"V", "I", "VPV", "PPV", "H21", "H20", "CS"};
const unsigned int maxLabelsOfInterest = sizeof(labelsOfInterest) / sizeof(*labelsOfInterest);
boolean sleep1 = false;


void setup() {
  Serial.begin(19200);
  mySerial.begin(19200); 
  lcd.init(); //initialize the lcd
  lcd.backlight(); //open the backlight
  delay(1000);
  lcd.setCursor(0,0);
  lcd.print("INIT");
  }
  
void loop() {
  //lcd.setCursor(0,0);
  //lcd.print("INIT");
  recvWithEndMarker();
  if (newData) { // we have received a ful line, deal with it
 parseNewData(); // this messes up receivedChars[]
newData = false;
  }
}

void recvWithEndMarker() {
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;
    while (mySerial.available() > 0 && newData == false) {
    rc = mySerial.read();
    if (rc != '\r') { // we ignore that character
      if (rc != endMarker) {
        if (rc == '\t') rc = ' '; // change tabs into just a space
        receivedChars[ndx] = rc;
        ndx++; // we go to the next space in our buffer
        if (ndx >= numChars) { // and check bounds.
          ndx = numChars - 1; // that means we will loose the end of long strings
        }
      } else {
        receivedChars[ndx] = '\0'; // terminate the string
        ndx = 0; // ndx is static, so we prepare for next turn
        newData = true;
      }
    }
  }
}

void parseNewData()
{
   const char *delim  = " ";
  char * item;
  boolean labelFound;
  long int labelValue;
  int labelIndex;
item = strtok (receivedChars, delim);
labelFound = false;

//Serial.println ();
  for (int i = 0; i < maxLabelsOfInterest; ++i) {
    if (!strcmp(labelsOfInterest[i], item)) {
     item = strtok(NULL, delim);
      if (item != NULL) {
        labelFound = true;
        labelIndex = i;
       labelValue = atol(item);
     //  Serial.println (labelsOfInterest[i]);
     //  Serial.println (labelIndex);
break; // ends the for loop as we found a label
      } // end if we had a value for the label
  } // end string compare
  } // end for

 if (labelFound) {
    switch (labelIndex) {
      case 0:
        lcd.setCursor(0,0);
        V2 = labelValue / 1000.00f;
       // Serial.print("Battery Voltage = ");
       // Serial.println(V2);
        lcd.print("BV=");
        lcd.print(V2);
        break;
      case 1:
        I2 = labelValue / 1000.00f;
        if (I2 < 0.05) {
        // lcd.setCursor(0,1);
        // lcd.print("     SLEEP      ");
        // Serial.println("Charger Sleeping ");
        sleep1=true;
        }
        else {
     //   Serial.print("Current Into Batts = ");
     //   Serial.println(I2);
        lcd.setCursor(0,1);
        lcd.print("BC=");
        lcd.print(I2);
        lcd.print("  ");
        sleep1=false;
        }
        break;
      case 2:
        VPV2 = labelValue / 1000.0f;
        if (sleep1 == true) {
      //  Serial.println("Panels Sleeping ");
        }
        else {
     //   Serial.print("Panel Voltage = ");
      //  Serial.println(VPV2);
        lcd.setCursor(9,1);
        lcd.print("PV=");
        lcd.print(VPV2);
        }
        break;
        case 3:
     //   Serial.print("Panel Wattage = ");
    //    Serial.println(labelValue);
        lcd.setCursor(12,0);
        lcd.print("   ");
        lcd.setCursor(9,0);
        lcd.print("PW=");
        lcd.print(labelValue);
        break;
      case 4:
        Serial.print("Max Power = ");
        Serial.println(labelValue);
        if (sleep1 == true) {
          lcd.setCursor(0,1);
          lcd.print("MP=");
          lcd.print(labelValue);
          lcd.print("  ");
        }
        else {
        }
        break;
         case 5:
        Serial.print("Yeild Today = ");
        Serial.println(labelValue);
        if (sleep1 == true) {      
         lcd.setCursor(9,1);
         lcd.print("YT=");
         lcd.print(labelValue);
         lcd.setCursor(15,0);
         lcd.print("S");
        }
        else {
        }
        break;  
        case 6:
        CS1=labelValue;
         if (sleep1 == true) {
          lcd.setCursor(15,0);
          lcd.print("S");
         }
          else {
                      switch (CS1) {
                        case 0:
                        Serial.println("Charger is OFF");
                          lcd.setCursor(15,0);
                          lcd.print(" ");
                          CS1 = NULL;
                          break;
                        case 1:
                        Serial.println("Charger is in low power mode");
                          lcd.setCursor(15,0);
                          lcd.print("S");
                          CS1 = NULL;
                          break;
                        case 2:
                        Serial.println("Charger has a fault");
                          lcd.setCursor(15,0);
                          lcd.print("E");
                          CS1 = NULL;
                          break;
                        case 3:
                        Serial.println("Charger is in BULK mode");
                          lcd.setCursor(15,0);
                          lcd.print("B");
                          CS1 = NULL;
                          break;
                        case 4:
                        Serial.println("Charger is in ABSORB mode");
                          lcd.setCursor(15,0);
                          lcd.print("A");
                          CS1 = NULL;
                          break;
                        case 5:
                        Serial.println("Charger is in FLOAT mode");
                          lcd.setCursor(15,0);
                          lcd.print("F");
                          CS1 = NULL;
                          break;
                        case 9:
                        Serial.println("Charger is in INVERT mode");
                          lcd.setCursor(15,0);
                          lcd.print("I");
                          CS1 = NULL;
                          break;
                       }
                       }  
        Serial.print("Charger State = ");
        Serial.println(labelValue);
        Serial.print("\n");
        break;
    }
    }
  }

Your code expects TAGvalue. If I use Serial to provide it that manually, it emits sensible output on Serial.

If your MPPT controller is actually sending TAGvalue, I could see that it would fail.

For some reason those tags are getting corrupted shortly after booting up the Arduino.

That is a sure sign of array bound violations. You are overwriting memory that you don't own.

strtok() modifies the input array, so that is one possibility. Receiving too many characters is another.

wildbill:
Your code expects TAGvalue. If I use Serial to provide it that manually, it emits sensible output on Serial.

If your MPPT controller is actually sending TAGvalue, I could see that it would fail.

If you look at the recvWithEndMarker you will see that the tab is being replaced with a space. This code has worked for a year and half and only started having issues when I tried to add the new tags.

Is this a valid estimate of the number of entries in the array?

const unsigned int maxLabelsOfInterest = sizeof(labelsOfInterest) / sizeof(*labelsOfInterest)

jremington:
That is a sure sign of array bound violations. You are overwriting memory that you don't own.

strtok() modifies the input array, so that is one possibility. Receiving too many characters is another.

I think you are onto something here.. I have had 2 developments today.

First, I moved around my code and consolidated it into a single function (code below). I was able to get those tags to show up sometimes, About %50 of the time they have the right value, and %50 of the time its an incorrect value (not corrupt just wrong, sometimes only a single numeral).

Second.. The moment I enable LCD(lcd.init(); ), the code stops working (tags are gone).

So I think I'm defiantly having some kind of memory issues..

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
const byte numChars = 16;
char receivedChars[numChars];
char receivedChars2[numChars];
boolean newData = false;
char messageFromPC[32] = {0};
int integerFromPC = 0;
int CS1;
float V2, I2, VPV2, MP1, YT1, PW1, CS2;
const char * labelsOfInterest[] = {"V", "I", "VPV", "PPV", "H20", "H21", "CS"};
const unsigned int maxLabelsOfInterest = sizeof(labelsOfInterest) / sizeof(*labelsOfInterest);
boolean sleep1 = false;
char rc;

SoftwareSerial mySerial(2, 3); // RX, TX
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display

void setup() {
 Serial.begin(19200);
 mySerial.begin(19200); 
//  lcd.init(); //initialize the lcd
//  lcd.backlight(); //open the backlight
//  delay(1000);
//  lcd.setCursor(0,0);
//  lcd.print("INIT");
}

void loop() {
 recvWithEndMarker();
}

void recvWithEndMarker() {
const char *delim  = " ";
 char * item;
 boolean labelFound;
 long int labelValue;
 int labelIndex;
 
static byte ndx = 0;
char endMarker = '\n';
char rc;

// if (mySerial.available() > 0) {
          while (mySerial.available() > 0 && newData == false) {
rc = mySerial.read();

if (rc != endMarker) {
 if (rc == '\t') rc = ' ';
 
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
newData = true;
item = strtok (receivedChars, delim);
labelFound = false;
for (int i = 0; i < maxLabelsOfInterest; ++i) {
   if (!strcmp(labelsOfInterest[i], item)) {
     Serial.print (item);
    item = strtok(NULL, delim);
     if (item != NULL) {
       labelFound = true;
       labelIndex = i;
      labelValue = atol(item);
      Serial.print ("=");
      Serial.println (item);
      
break; // ends the for loop as we found a label
     } // end if we had a value for the label
 } // end string compare
 } // end for

// Do some work
if (labelFound) {
   switch (labelIndex) {
     case 0:
       lcd.setCursor(0,0);
       V2 = labelValue / 1000.00f;
      // Serial.print("Battery Volate = ");
      // Serial.println(V2);
       lcd.print("BV=");
       lcd.print(V2);
       break;
     case 1:
       I2 = labelValue / 1000.00f;
       if (I2 < 0.05) {
       lcd.setCursor(0,1);
       lcd.print("     SLEEP      ");
      // Serial.println("Charger Sleeping ");
       sleep1=true;
       }
       else {
      // Serial.print("Current Into Batts = ");
      // Serial.println(I2);
       lcd.setCursor(0,1);
       lcd.print("BC=");
       lcd.print(I2);
       lcd.print("  ");
       sleep1=false;
       }
       break;
     case 2:
       VPV2 = labelValue / 1000.0f;
       if (sleep1 == true) {
      // Serial.println("Panels Sleeping ");
       }
       else {
      // Serial.print("Panel Voltage = ");
      // Serial.println(VPV2);
       lcd.setCursor(9,1);
       lcd.print("PV=");
       lcd.print(VPV2);
       }
       break;
     case 3:
      // Serial.print("Panel Wattage = ");
      // Serial.println(labelValue);
       lcd.setCursor(12,0);
       lcd.print("   ");
       lcd.setCursor(9,0);
       lcd.print("PW=");
       lcd.print(labelValue);
       break;
     case 4:
        YT1 = labelValue / 100.00f;
        Serial.print("Yeild Today = ");
        Serial.println(YT1);
        if (sleep1 == true) {      
        lcd.setCursor(9,1);
        lcd.print("YT=");
        lcd.print(YT1);
        lcd.setCursor(15,0);
        lcd.print("S");
       }
       else {
       }
       break;
     case 5:
       Serial.print("Max Power = ");
       Serial.println(labelValue);
       if (sleep1 == true) {
         lcd.setCursor(0,1);
         lcd.print("MP=");
         lcd.print(labelValue);
         lcd.print("  ");
       }
       else {
       }
       break;
     case 6:
       CS1=labelValue;
                     switch (CS1) {
                       case 0:
                        // Serial.println("Charger is OFF");
                         lcd.setCursor(15,0);
                         lcd.print(" ");
                         CS1 = NULL;
                         break;
                       case 1:
                        // Serial.println("Charger is in low power mode");
                         lcd.setCursor(15,0);
                         lcd.print("S");
                         CS1 = NULL;
                         break;
                       case 2:
                        // Serial.println("Charger has a fault");
                         lcd.setCursor(15,0);
                         lcd.print("E");
                         CS1 = NULL;
                         break;
                       case 3:
                        // Serial.println("Charger is in BULK mode");
                         lcd.setCursor(15,0);
                         lcd.print("B");
                         CS1 = NULL;
                         break;
                       case 4:
                        // Serial.println("Charger is in ABSORB mode");
                         lcd.setCursor(15,0);
                         lcd.print("A");
                         CS1 = NULL;
                         break;
                       case 5:
                        // Serial.println("Charger is in FLOAT mode");
                         lcd.setCursor(15,0);
                         lcd.print("F");
                         CS1 = NULL;
                         break;
                      case 9:
                        // Serial.println("Charger is in INVERT mode");
                         lcd.setCursor(15,0);
                         lcd.print("I");
                         CS1 = NULL;
                         break;
                      }
      // Serial.print("Charger State = ");
      // Serial.println(labelValue);
      // Serial.print("\n");
      delay(3000);
      break;
   }
  } else {
  }
// End of Work

}
}
newData = false;
}

jremington:
Is this a valid estimate of the number of entries in the array?

const unsigned int maxLabelsOfInterest = sizeof(labelsOfInterest) / sizeof(*labelsOfInterest)

I piped it out to the serial port. It shows 7, which is the number of tags I have in the labelsOfInterest array. That value changes depending on how many tags I have in the labelsOfInterest array. So I would say its correct!

Ok... Another new development...

I said screw it, and rewrote the whole code as simply as I could. I got rid of the case statements, and did everything as "if else".. I reused nothing. I even pulled the original code from the serial tutorial on this forum. I also changed the delimiter character, and how the serial input is done. Instead of getting ALL the data, I just got a single line and then processed it.

AND.... Drum roll.... Same result...

At one point I began having the exact same problem, where the serial data array was missing data beyond a certain value. My original code and the issue with the LiquidCrystal library helped me. I began playing around and it quickly became clear that if I reduced my calls to that library (lcd.setCursor, lcd.print, ect) The array would begin to show those lost values.

Its late.. and I'm fried.. but I would love some suggestions.. It HAS to be a memory issue, but I'm not sure how to solve it. Anyway, here is my latest code. If I add any LCD commands in the "if (strstr(receivedChars, "V,"))" part, I lose the H20 and H21 data tags from the receivedChars array. (also, if I remove some of the LCD commands from other parts, I will get more data).

Anyway, here is that rewrite (ya ya, looks like a kindergardener wrote it. I tried to make it simple).

#include <SoftwareSerial.h>
#include <LiquidCrystal_I2C.h>
char rc;
const byte numChars = 40;
char receivedChars[numChars]; // an array to store the received data

float V2, I2, VPV2, MP1, YT1;
boolean newData = false;
boolean sleep1 = false;


SoftwareSerial mySerial(2, 3); // RX, TX
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display

void setup()
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Native USB only
  }
  mySerial.begin(19200);
 lcd.init(); //initialize the lcd
  lcd.backlight(); //open the backlight
  delay(1000);
  lcd.setCursor(0,0);
  lcd.print("INIT");
  
}

void loop() // run over and over
{
recvWithEndMarker();
//parseNewData(); // this messes up receivedChars[]
newData = false;
}

void recvWithEndMarker() {
 static byte ndx = 0;
 char endMarker = '\r';
 char rc;
 char tag;
 int CS1, labelValue;
 
 // if (Serial.available() > 0) {
           while (mySerial.available() > 0 && newData == false) {
 rc = mySerial.read();

 if (rc != endMarker) {
if (rc == '\t') rc = ','; // change tabs into just a space
 receivedChars[ndx] = rc;
 ndx++;
 if (ndx >= numChars) {
 ndx = numChars - 1;
 }
 }
 else {
 receivedChars[ndx] = '\0'; // terminate the string
 ndx = 0;
 newData = true;

// Do work here  
   
   if (strstr(receivedChars, "V,")){
      if (strstr(receivedChars, "VPV,")){  
        // Do nothing
      }
      else {
        if (strstr(receivedChars, "PPV,")){
          //Do Nothong
        }
        else {
        char *sep = strchr(receivedChars, ',');
        *sep = '\0';
        labelValue = atoi(sep + 1);
        V2 = labelValue / 1000.00f;  
        }
      }    
  }

   Serial.println(receivedChars);
    if (strstr(receivedChars, "I,")){
        char *sep = strchr(receivedChars, ',');
        *sep = '\0';
        labelValue = atoi(sep + 1);
        I2 = labelValue / 1000.00f;
                    if (I2 < 0.05) {
                   // Serial.println (I2);
                    sleep1 = true; 
                    }
                     else {
                   // Serial.println (I2);
                    sleep1 = false;
                   // Serial.print("Current Into Batts = ");
                   // Serial.println(I2);
                    lcd.setCursor(0,1);
                    lcd.print("BC=");
                    lcd.print(I2);
                    lcd.print("  ");
                    }
          }

    if (strstr(receivedChars, "VPV,")){  
        char *sep = strchr(receivedChars, ',');
        *sep = '\0';
        labelValue = atoi(sep + 1);
        VPV2 = labelValue / 1000.0f;

      if (sleep1 == false) {
       // Serial.print("Panel Voltage = ");
       //  Serial.println(VPV2);
        lcd.setCursor(9,1);
        lcd.print("PV=");
        lcd.print(VPV2);
        }
        else {
        }  
  } 
  
     if (strstr(receivedChars, "PPV,")){
        char *sep = strchr(receivedChars, ',');
        *sep = '\0';
        labelValue = atoi(sep + 1);
        if (sleep1 == false) {
        lcd.setCursor(12,0);
        lcd.print("   ");
        lcd.setCursor(9,0);
        lcd.print("PW=");
        lcd.print(labelValue);
        }
        else {
         lcd.setCursor(9,0);
         lcd.print("      ");
        }  
    }

    if (strstr(receivedChars, "H21,")){
        char *sep = strchr(receivedChars, ',');
        *sep = '\0';
        labelValue = atoi(sep + 1);
        // Serial.print("Max Power = ");
        // Serial.println(labelValue);
        if (sleep1 == true) {
          lcd.setCursor(0,1);
          lcd.print("MP=");
          lcd.print(labelValue);
          lcd.print("  ");
        }
        else {
        }
    }
 
    if (strstr(receivedChars, "H20,")){
        char *sep = strchr(receivedChars, ',');
        *sep = '\0';
        labelValue = atoi(sep + 1);
        YT1 = labelValue / 100.0f;
        // Serial.print("Yeild Today = ");
        // Serial.println(YT1);
        if (sleep1 == true) {      
         lcd.setCursor(9,1);
         lcd.print("YT=");
         lcd.print(YT1);
        }
    } 
 
    if (strstr(receivedChars, "CS,")){
        char *sep = strchr(receivedChars, ',');
        *sep = '\0';
        labelValue = atoi(sep + 1);
        
        if (sleep1 == true) {
          lcd.setCursor(15,0);
          lcd.print("S");
         }
          else {
                      switch (labelValue) {
                        case 0:
                       // Serial.println("Charger is OFF");
                          lcd.setCursor(15,0);
                          lcd.print(" ");
                          CS1 = NULL;
                          break;
                        case 1:
                       // Serial.println("Charger is in low power mode");
                          lcd.setCursor(15,0);
                          lcd.print("S");
                          CS1 = NULL;
                          break;
                        case 2:
                       // Serial.println("Charger has a fault");
                          lcd.setCursor(15,0);
                          lcd.print("E");
                          CS1 = NULL;
                          break;
                        case 3:
                       // Serial.println("Charger is in BULK mode");
                          lcd.setCursor(15,0);
                          lcd.print("B");
                          CS1 = NULL;
                          break;
                        case 4:
                        // Serial.println("Charger is in ABSORB mode");
                          lcd.setCursor(15,0);
                          lcd.print("A");
                         CS1 = NULL;
                          break;
                        case 5:
                        // Serial.println("Charger is in FLOAT mode");
                         lcd.setCursor(15,0);
                          lcd.print("F");
                          CS1 = NULL;
                          break;
                        case 9:
                        // Serial.println("Charger is in INVERT mode");
                          lcd.setCursor(15,0);
                          lcd.print("I");
                          CS1 = NULL;
                         break;
                        }
          }
    }
 }
}
}

It is very difficult for us to help you debug this program in its present state, because we have no idea what you enter using the serial monitor, or how it is set up.

Also, you have not clearly described the symptoms. For example, what exactly is the evidence that the array "loses values"?

To debug this program sensibly, get rid of all the serial input stuff, and set up the simplest possible decode logic to work with a single data array that is initialized within the program.

Final points:

  1. Misleading comments like the following do not help understand what the program is supposed to do:
if (rc == '\t') rc = ','; // change tabs into just a space
  1. Does the following make sense to you? If so, please explain.
   if (strstr(receivedChars, "V,")){
      if (strstr(receivedChars, "VPV,")){ 
        // Do nothing
      }

jremington:
It is very difficult for us to help you debug this program in its present state, because we have no idea what you enter using the serial monitor, or how it is set up.

I don't enter anything on the serial monitor. The serial data is fed from a Victron MTTP Solar controller (on a software serial port) as stated in my original post. I described the data packed in my original post. Would it help to post a copy of that packet?

Also, you have not clearly described the symptoms. For example, what exactly is the evidence that the array "loses values"?

If I completely remove all the code to do with the LCD then I can use the serial.print command and the data will look exactly like it does if I capture it from an FTDI cable on my computer hooked to the MTTP controller(using PUTTY as the telnet program). If I add the LCD command, then the data will be missing tags near the end. Again, I can post that data packet if it helps

To debug this program sensibly, get rid of all the serial input stuff, and set up the simplest possible decode logic to work with a single data array that is initialized within the program.

Sure.. I will do that tomorrow.. Create an array in the program and populate it with the exact same data that the serial port is feeding.

I'm pretty sure it will just work though. I have a suspicion that it has to do with using both the LCD library and the Software serial library. Of course that will be no help as I need the data on the software serial port.. However, I will try.

Final points:

  1. Misleading comments like the following do not help understand what the program is supposed to do:
if (rc == '\t') rc = ','; // change tabs into just a space

Sorry.. Its a copy an paste issue.. Like I said, I changed the delimiter at one point to make sure that wasn't the issue.

  1. Does the following make sense to you? If so, please explain.
   if (strstr(receivedChars, "V,")){

if (strstr(receivedChars, "VPV,")){
       // Do nothing
     }

Yes.. Since I removed all the logic and case statements, its a necessary evil. Again, dirty coding, but I was trying to make things simple. If you look at the nested "If" statements, you will see why the code is that way. Due to the tags that Victron uses (listed in my original post), this was the easiest way I could think to do it. Since they have 3 tags with a V before data and one of those tags is just a V, this code fires on that V tag and ignores the other tags which are dealt with later in the code..

Again, not the best way to do it, and not the way I did it in the original code. However, it was a rewrite, going back to basics.

Would it help to post a copy of that packet?

It should be included in the test code.

If I add the LCD command, then the data will be missing tags near the end.

Post EVIDENCE for this utterly useless statement.

Since they have 3 tags with a V before data and one of those tags is just a V, this code fires on that V tag and ignores the other tags which are dealt with later in the code..

Wrong. Your search string includes the trailing comma, which makes each tag unique. The logic is completely incorrect.

This is getting tiresome. Good luck with your project.

Use the auto-format function to get all your braces and indents organized properly. It is very good at making your code neat and readable.

If auto-format appears to scramble your code then the code was wrong (missing a brace somewhere.)

Then organise the code into separate functions. You have a giant mess of serial input, decisions and LCD outputs all mixed together. Let recvWithEndMarker() do its job of receiving. When it sets newData then you can do something with that new data. When you have a new something then you can do calculation with it. When you have a new calculation you can update the screen.

Also, why do you set the seperators to null chars? You never do anything with the string on the left of the seperators. The atoi() functions don't look left to check there is a null - that memory is off limits to those functions.

jremington:
This is getting tiresome. Good luck with your project.

LOL... Yup, it sure is.. Please don't bother commenting as I'm pretty sure you have nothing to offer other than try and pump your posts numbers.

MorganS:
Use the auto-format function to get all your braces and indents organized properly. It is very good at making your code neat and readable.

If auto-format appears to scramble your code then the code was wrong (missing a brace somewhere.)

Then organise the code into separate functions. You have a giant mess of serial input, decisions and LCD outputs all mixed together. Let recvWithEndMarker() do its job of receiving. When it sets newData then you can do something with that new data. When you have a new something then you can do calculation with it. When you have a new calculation you can update the screen.

Also, why do you set the seperators to null chars? You never do anything with the string on the left of the seperators. The atoi() functions don't look left to check there is a null - that memory is off limits to those functions.

I think you may have missed the original code (in the first post). Its much better formatted and split into sections.

I rewrote it using completely different logic to try and isolate the problem (which I admitted was a mess).

Anyway.. I appreciate the responses, but I'm going to take another tact.

If there is someone that actually wants to read the post from the beginning, there is an interesting problem here (beyond replies about messy code).

I'm pretty sure you have nothing to offer

I'm not surprised, since you also don't see the obvious errors I identified in the code.

travellerw:
I think you may have missed the original code (in the first post).

I saw it. It is not the code you are using now so what use is it to discuss the old code now?

If you post the code you are using now, I will help you with it.

Some of that help will be style advice. Formatting code to be readable is the most important job for the progmmer who asks for help. More important than making it work, since you are passing that job to me.