Memory Problem with Nano

try something like this

char buffer[80] = "<  5.2C  56%  4.97>"; // simulate what you received as a char buffer

bool extractValues(char * message, double& temperature, long& humidity, double& somethingElse) {
  char* endPtr;

  char * startMarkPtr = strchr(message, '<'); // search for the first occurence of <
  char * endMarkPtr = strrchr(message, '>'); // search for the last occurence of >
  // does the message seem correct?
  if (startMarkPtr == nullptr || endMarkPtr == nullptr || endMarkPtr <= startMarkPtr ) return false;
  Serial.println(F("message looks correct"));

  // try reading the temperature as a floating point number after the start mark
  char * startOfParsingPtr = startMarkPtr + 1; // we start parsing after the >
  temperature = strtod(startOfParsingPtr, &endPtr); // https://cplusplus.com/reference/cstdlib/strtod/
  if (endPtr == startOfParsingPtr) return false; // the parse failed
  Serial.println(F("temperature extracted"));

  // try reading the humidity
  startOfParsingPtr = endPtr+1; // we are after the temperature, there is a C to skip (space is not an issue)
  humidity = strtol(startOfParsingPtr, &endPtr, 10); // https://cplusplus.com/reference/cstdlib/strtol/
  if (endPtr == startOfParsingPtr) return false; // the parse failed
  Serial.println(F("humidity extracted"));

  // try reading the last field as a floating point number after the start mark
  startOfParsingPtr = endPtr+1; // we are after the humidity, there is a % to skip (space is not an issue)
  somethingElse = strtod(startOfParsingPtr, &endPtr);
  if (endPtr == startOfParsingPtr) return false; // the parse failed
  Serial.println(F("somethingElse extracted"));

  return true;
}

void setup() {
  Serial.begin(115200);
  double temp, sthg;
  long hum;

  if (extractValues(buffer, temp, hum, sthg)) {
    Serial.print(F("Temperature = "));  Serial.println(temp, 3);
    Serial.print(F("Humidity = "));     Serial.print(hum); Serial.println(F("%"));
    Serial.print(F("Something Else = "));  Serial.println(sthg, 5);
  } else {
    Serial.println(F("Error parsing message"));
  }
}

void loop() {}

Hopefully the code is verbose enough for you to see what's going on.

Extracting a floating point value is done using strtod() and extracting a integral value (long) is done with strtol()

Those functions take a pointer to pointer argument that let you know where the parsing stopped extracting the value. So if the pointer did not move from the start place, it means nothing relevant could be read and that whatever is in the buffer at that place does not work.

side note:

Ideally you would check for a trailing null char before doing

startOfParsingPtr = startMarkPtr + 1;

I don't check if the endPtr would have reached the end of the string (would be needed before skipping the C and %) because I know there is a '>' somewhere further so at worst I hit that character when parsing and adding one would place me on the trailing null char.

If you also wanted to be very sure about the message structure, you would test to see if 'C' and '%' were present in the parsing.


This might feel a bit involved but understanding how strod() and strol() work (and related functions) is not rocket science and that will save you ~1KB of flash memory that is used by the String class's underlying functions (if you get rid of all the Strings).

if you were on a 32 bit MCU like an ESP32, you'd have more flash memory and you could use sscacnf() to extract the fields (on your Nano sscanf can't extract the floating point value that's why we use strod()

void setup() {
  Serial.begin(115200);

  char buffer[80] = "<  5.2C  56%  4.97>"; // simulate what you received as a char buffer
  double temp, sthg;
  long hum;
  if (sscanf(buffer, "<%lfC %d%\% %lf>", &temp, &hum, & sthg) == 3) { // if we extracted 3 values according to the format
    Serial.print(F("Temperature = "));  Serial.println(temp, 3);
    Serial.print(F("Humidity = "));     Serial.print(hum); Serial.println(F("%"));
    Serial.print(F("Something Else = "));  Serial.println(sthg, 5);
  } else {
    Serial.println(F("Error parsing message"));
  }
}

void loop() {}

of course sscanf() is using up more flash (similar to what you'd get with the String class)

1 Like