Go Down

Topic: How do you convert a float to string (SOLVED) (Read 129527 times) previous topic - next topic

visualxl

May 30, 2014, 11:07 am Last Edit: Jun 02, 2014, 04:19 am by visualxl Reason: 1
I am having a very tough time converting float to string.

I am getting some data from GPS. The coordinates are in float.

I want something like

Code: [Select]

String gpsString;

//Imma gonna call this function in the loop
void checkGPS() {
    //Assuming we already have the coordinates
   float flat, flong.

   //I want to do something like this
   gpsString ="";  //make sure the string is empty if its not
   gpsString += flat;
   gpsString += " ";
   gpsString += flong.
   Serial.println(gpsString);
}


I have tried a couple of things like without success. Perhaps I did it wrongly, but I could
Code: [Select]

sprintf(gpsString, "Lat: %f", flat);
dtostrf(flat, 8, 6, &gpsString[1]);


Kindly assist with some clear examples.

Thank you in advance.


steinie44

float f = 123.456; // example
string mystring;

mystring = String(f);


UKHeliBob

Here we go again with Strings and strings.

A String is not a string.

A String is an object supported by the String library.  Using them is likely to fragment memory usage which with the limited resources available on the Arduino can cause problems.

A string is an array of chars terminated by a null.  Using them does not fragment memory because they are not continually created and destroyed.

To add to the fun the OP has tried to use a String with the sprintf() function
Code: [Select]
sprintf(gpsString, "Lat: %f", flat);That won't work because the sprintf() function expects a char array as its target.

To add to the fun the Arduino implementation of sprintf() does not support the floating point format (%f)

So, what to do ?
I suppose the first question is why do you want to convert the float in the first place ?
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

econjack

I have to agree with ULHeliBob; avoid the String class like the plague. There are probably a bazillion ways to solve your problem, and one might be:

Code: [Select]

void setup() {
  int i;
  float val;
  char buff[10];
 
  Serial.begin(115200);
  val = 0.0;
  for (i = 0; i < 10; i++) {
    snprintf (buff, sizeof(buff), "%f", val);
    Serial.println(val);
    val += 5.0;
  }
}

void loop() {}


Note you can change the format specifier (i.e., the "%f") if you need different decimal values.

PaulS

Quote
Note you can change the format specifier (i.e., the "%f") if you need different decimal values.

Except that the %f format specifier is not supported on the Arduino. The dtostrf() function uses a different approach with similar results.
The art of getting good answers lies in asking good questions.

visualxl


I have to agree with ULHeliBob; avoid the String class like the plague. There are probably a bazillion ways to solve your problem, and one might be:

Code: [Select]

void setup() {
  int i;
  float val;
  char buff[10];
 
  Serial.begin(115200);
  val = 0.0;
  for (i = 0; i < 10; i++) {
    snprintf (buff, sizeof(buff), "%f", val);
    Serial.println(val);
    val += 5.0;
  }
}

void loop() {}


Note you can change the format specifier (i.e., the "%f") if you need different decimal values.


Hi do I print that?

I tried "Serial.println(buff)", it prints a '?'.

Then, I also tried looping it to print out each character stored,

Code: [Select]

void setup() {
  int i;
  float val;
  char buff[10];
 
  Serial.begin(115200);
  val = 0.0;
  for (i = 0; i < 10; i++) {
    snprintf (buff, sizeof(buff), "%f", val);
    Serial.print("val: ");
    Serial.println(val);
    val += 5.0;
  }
 
  Serial.println("Contents of Buffer: ");
  for (int a=0; a<10; a++) {
    Serial.println(buff[a]);
  }
 
}

void loop() {
}


The output is as below:
Code: [Select]

val: 0.00
val: 5.00
val: 10.00
val: 15.00
val: 20.00
val: 25.00
val: 30.00
val: 35.00
val: 40.00
val: 45.00
Contents of Buffer:
?

luisilva

For what PaulS says you can't do this line:

Code: [Select]

snprintf (buff, sizeof(buff), "%f", val);


I'll do something like:

Code: [Select]

void setup() {
  int i;
  float val;
  int val_int;
  int val_fra;
  char buff[10];
  #define DEC_PLACES 1000
  Serial.begin(115200);
  val = 0.0;
  for (i = 0; i < 10; i++) {
    val_int = (int) val;   // compute the integer part of the float
    val_fra = (int) ((val - (float)val_int) * 1000);   // compute 3 decimal places (and convert it to int)
    snprintf (buff, sizeof(buff), "%d.%d", val_int, val_fra); //
    Serial.println(val);
    val += 5.0;
  }
}

visualxl

Ahhaaaa!!! Eureka!!

I worked my butt off and tried to read and understand dtostrf at http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#ga060c998e77fb5fc0d3168b3ce8771d42

Modified the codes so its like this. I should modify a couple of things later, but I think I got it right this time right?

Code: [Select]

#include <stdlib.h>

void setup() {
  int i;
  float val;
  char buff[10];
  String valueString = "";
  Serial.begin(115200);
  val = 0.0;
  for (i = 0; i < 10; i++) {
    dtostrf(val, 4, 6, buff);  //4 is mininum width, 6 is precision
    Serial.print("val: ");
    Serial.println(val);
    val += 5.0;
    valueString += buff;
    valueString += ", ";
  }
  Serial.println(valueString);
}

void loop() {
}


So the output is like this:

Code: [Select]

val: 0.00
val: 5.00
val: 10.00
val: 15.00
val: 20.00
val: 25.00
val: 30.00
val: 35.00
val: 40.00
val: 45.00
0.000000, 5.000000, 10.000000, 15.000000, 20.000000, 25.000000, 30.000000, 35.000000, 40.000000, 45.000000,


luisilva

Good work!

Can you change the subject of the post to solved.

Regards.

visualxl

I have changed the subject to solved.

Oh one more question, if I were to call that in a loop, I would need to clear the buffer. How do I clear the buffer??

luisilva

I'm not a guy of C++ so I don't use "String", but I've read here in the forum that is not good use this way to have a strings.

In the way you had write the code, clear the "buffer" with name valueString is done like you already did:
Code: [Select]

  String valueString = "";


If you want to do this in other place than the definition of the variable, it's simply :

Code: [Select]

  valueString = "";


The "buffer" with name buf it's cleared every time you do:

Code: [Select]

dtostrf(val, 4, 6, buff);


If you want to correct your code and do all strings the same way, you can declare the string like:

Code: [Select]

  char valueString[100];


concatenate the string, like:

Code: [Select]

strcat(valueString, buff);
strcat(valueString, ", ");


and clear the string like:

Code: [Select]

strcpy(valueString, "");


Note that the 100 in the line "char valueString[100];", must be a number long enough to hold the entire string.

FarhanAminuddin98

Ahhaaaa!!! Eureka!!

I worked my butt off and tried to read and understand dtostrf at http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#ga060c998e77fb5fc0d3168b3ce8771d42

Modified the codes so its like this. I should modify a couple of things later, but I think I got it right this time right?

Code: [Select]

#include <stdlib.h>

void setup() {
  int i;
  float val;
  char buff[10];
  String valueString = "";
  Serial.begin(115200);
  val = 0.0;
  for (i = 0; i < 10; i++) {
    dtostrf(val, 4, 6, buff);  //4 is mininum width, 6 is precision
    Serial.print("val: ");
    Serial.println(val);
    val += 5.0;
    valueString += buff;
    valueString += ", ";
  }
  Serial.println(valueString);
}

void loop() {
}

 

So the output is like this:

Code: [Select]

val: 0.00
val: 5.00
val: 10.00
val: 15.00
val: 20.00
val: 25.00
val: 30.00
val: 35.00
val: 40.00
val: 45.00
0.000000, 5.000000, 10.000000, 15.000000, 20.000000, 25.000000, 30.000000, 35.000000, 40.000000, 45.000000,


Do you have the complete coding to convert the gps data? ive been trying to figure out how to do this. Im sending the coordinates through LoRa but it seems impossible for me to do it using floats, but its easy enough to send strings data through LoRa. It would be great if you could help me out.


Metallor

You say this is solved but I wouldn't be surprised to see you back here with your program randomly crashing because you ignored the advice to avoid the String class (capital S) in favour of a C-style string.

PaulS

Code: [Select]
    dtostrf(val, 4, 6, buff);  //4 is mininum width, 6 is precision
How do you reasonably expect to print at least one digit before the decimal point, a decimal point, and 6 digits after the decimal place, in a field of width 4?

Yes, I know that it is 4 or more, but your values just look dumb.
The art of getting good answers lies in asking good questions.

Go Up