serial communication and nummeric data type

Im having trouble with serial communication and numeric data type
Im sending a line, where the first 2 characters are a code, and the rest is the value for a variable (variable depending on the given code)
the problem is that with big numbers i get a different value that the one that was sent
for example, if i type on the serial monitor 12500, i get the right number (12 for code, and 500 for the value).
but if i type 12500500500 i get printed 12 for code and 500500510 (i don know where that 10 comes from)
i've tried using int, double, float, but no luck.
what am i doing wrong? what am i missing?
thanks in advance!!

heres the code:

String incomingMessage;
int theCode;
float theValue = 0.000000000000000001;

void setup() {
 Serial.begin(9600);
}

void loop() {
 listenToSerial();
 delay(100);
}

void listenToSerial() {
 if (Serial.available() > 0) {
   incomingMessage = Serial.readString();
   theCode = incomingMessage.substring(0, 2).toInt();
   theValue = (incomingMessage.substring(2)).toFloat();
   Serial.println("code: " + String(theCode) + "     >>" + String(theValue));
 }
}

I think you should be using either the long or unsigned long data type for theValue. And use strtol() or strtoul() to convert the text.

...R

Please use code tags when posting code.

i don know where that 10 comes from

Possibly from the line feed character. See the Serial Input Basics tutorial.

On the Uno, Nano, etc. use of Strings leads to memory problems and program crashes, so avoid them.

Nothing wrong with using Strings, but in the code below I have removed the delays and the readString() which blocks.

I assume you are running on an 8bit Arduino (UNO/Mega2560)
These have 32bit float/double which only hold ~7.25digits. Your input has 9 digits hence the loss in precision.
Works fine on an ESP32 or ESP8266 using toDouble()

String incomingMessage;
int theCode;
double theValue = 0.0;

void setup() {
  Serial.begin(9600);
  for (int i = 10; i > 0; i--) {
    delay(500);
    Serial.print(i); Serial.print(' ');
  }
  Serial.println();
  Serial.println("Ready for input. Set monitor to Newline");
  incomingMessage.reserve(100); // pre-allocate space for the String
}

bool listenToSerial() {
  if (Serial.available() > 0) {
    char c = Serial.read();
    if (c == '\n') {
      return true; // end of line
    }
    // else
    incomingMessage += c;
    if (incomingMessage.length() > 100) {
      // either
      // incommingMessage = ""; // dump this long unterminated message and start again
      //OR
      return true; // try processing this text
    }
  }
  return false; // not full msg yet
}

void loop() {
  if (listenToSerial()) {
    // got msg parse it
    theCode = incomingMessage.substring(0, 2).toInt();
    theValue = (incomingMessage.substring(2)).toDouble();
    Serial.println("code: " + String(theCode) + "     >>" + String(theValue));
    incomingMessage = ""; // clear after processing
  }
}
code: 12     >>500500500.00

The include float.h, tells you the number of digits you can get without rounding for a float (FLT_DIG) and a double (DBL_DIG)

#include <float.h>

  Serial.print("FLT_DIG : "); Serial.println(FLT_DIG);
  Serial.print("DBL_DIG : "); Serial.println(DBL_DIG);

For ESP8266
FLT_DIG : 6
DBL_DIG : 15

For Uno
FLT_DIG : 6
DBL_DIG : 6

thanks
i used it and it worked!!
i had to make an intermediate step which was making a char array, but now im getting the right numbers!

Robin2:
I think you should be using either the long or unsigned long data type for theValue. And use strtol() or strtoul() to convert the text.

...R

i modified the post (newby here!)
and thanks for all the info. i'll study it

jremington:
Please use code tags when posting code.

Nothing wrong with using Strings

Some of the extensive problems with using Strings on AVR based Arduinos are documented here.

@jremington
Thanks for the link.
I should have said “Nothing wrong with Strings in this case.”

strtol is no improvement over
theValue = (incomingMessage.substring(2)).toInt();
if you don’t add the error checking to the returned **endPtr

SafeString toLong() wraps up strol() in a simple function, that does that error checking for you.

#include <SafeString.h>
String incomingMessage;
int theCode;
long theValue = 0;

void setup() {
  Serial.begin(9600);
  for (int i = 10; i > 0; i--) {
    delay(500);
    Serial.print(i); Serial.print(' ');
  }
  Serial.println();
  Serial.println("Ready for input. Set monitor to Newline");
  incomingMessage.reserve(100); // pre-allocate space for the String
}

bool listenToSerial() {
  if (Serial.available() > 0) {
    char c = Serial.read();
    if (c == '\n') {
      return true; // end of line
    }
    // else
    incomingMessage += c;
    if (incomingMessage.length() >= 100) {
      // either
      // incommingMessage = ""; // dump this long unterminated message and start again
      //OR
      return true; // try processing this text
    }
  }
  return false; // not full msg yet
}

void loop() {
  if (listenToSerial()) {
    // got msg parse it
    theCode = incomingMessage.substring(0, 2).toInt();
    String valStr = incomingMessage.substring(2);
    cSFP(sfVal, (char*)valStr.c_str());  // create a temp SafeString to wrap the text in valStr
    if (sfVal.toLong(theValue)) {
      Serial.println("code: " + String(theCode) + "     >>" + String(theValue));
    } else {
      Serial.println("code: " + String(theCode) + "     >>" + "bad value '" + sfVal.c_str() + "'");
    }
    incomingMessage = "";
  }
}

Some sample output
22123456789

code: 22     >>123456789

22123456789012345

code: 22     >>bad value '123456789012345'

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