dtostrf() help

Hi everyone,

I’ve written this code to send two floating points over the serial as a string, separated by a semi-colon. At the moment this code returns values like:
0.182710.4698 ; 10.4698
0.411215.7008 ; 15.7008
0.730820.9269 ; 20.9269

Which is basically XvalueYvalue ; Yvalue, whereas what I actually want is Xvalue ; Yvalue. How would I make it print in this way?

This is the code so far (ignore the maths, that’s to convert servo angle and ping distance to an x and y value):

#include <Servo.h>
#include <math.h>

Servo myservo;

float xval;
float yval;
float rad;

int distance = 3;  //This is just to test the code, I'll add ping code later
int deg = 0;

char x [6];
char y [6];


void setup(){
  
  myservo.attach(9);
  Serial.begin(9600);
  
}


void loop(){
  while (deg <180){
    myservo.write(deg);
    rad = deg * 0.0174532925;
    xval = 300 - ((distance * cos(rad))*100);   
    yval = (distance * sin(rad)) * 100;
    dtostrf(xval, 6, 4, x);// This is where I get confused, I read that the 6 is the length of the number
    dtostrf(yval, 6, 4, y); // and that the 4 is the number of numbers after decimal point? I'm sure this is wrong?
    Serial.println(String(x) + " ; " + String(y));
    deg++;
  }

}

Thanks.

  1. Your character buffers x and y are 1 character too short, they need to be at least 1 character longer than the number of characters you are writing to them (to allow for the trailing null). Declare them as [7] instead of [6].

  2. Don't use the String class (IMO it should not be part of the Arduino library). It will work OK when used in simple ways like this, but do something more complicated and you are likely to run out of RAM. Use this instead:

Serial.print(x);
Serial.print(" ; ");
Serial.println(y);

Why are you using dtostrf() at all? The Serial.print() function is perfectly capable of sending a float to the serial port.

@ dc42, thanks for the help, I never thought of writing out this way, that makes life much simpler!

@PaulS, I only needed them to try and write all the values as one string - writing them as floating point values works just as well when I'm using dc42's method of printing the values.

Thanks for the help :)

I have a question about dtostrf(). I am trying to get a temperature sensor (lm35) to send data using a ethernet shield to thingspeak. To send data to thingspeak, it must be a string. Right now, I am converting a float to a long to a string. This however removes the decimal points (I think). I am trying to use dtostrf() to convert my float directly to a string so that there are decimal points.

int reading = analogRead(sensorPin);
  float voltage = reading * 5.0;
  voltage /= 1024.0;  
int  temperatureC = (voltage) * 100;
String temperatureS = dtostrf(temperatureC, 2, 2, 10);
String temperature = (tem, DEC);

However it fails to compile because it says "invalid conversion from 'int to 'char*' Does anyone know how I can fix this? Thank You

So, the first question is why you are using dtostrf to convert an int to a string. The dtostrf() function is to convert a double (or float) to a string.

The second question is whether or not you have read the documentation on dtostrf. It appears not.

char * 	dtostrf (double __val, signed char __width, unsigned char __prec, char *__s)

The dtostrf() function converts the double value passed in val into an ASCII representationthat will be stored under s. The caller is responsible for providing sufficient storage in s.

Conversion is done in the format “[-]d.ddd”. The minimum field width of the output string (including the ‘.’ and the possible sign for negative values) is given in width, and prec determines the number of digits after the decimal sign. width is signed value, negative for left adjustment.

The dtostrf() function returns the pointer to the converted string s.

10 is not a buffer that dtostrf can write to, is it?

Sorry for the error. I accidentally had it converting a integer. I am pretty new to arduino programing and I am wondering if you would be able to tell me what to put after my float in the dtostrf() If it is supposed to be dtostrf(FLOAT,WIDTH,PRECSISION,BUFFER); I know the FLOAT in my case would be temperatureC but what would the WIDTH, PRECSISION and BUFFER be? I read the dtostrf() documentation but I don't understand what it means. Thank you for the help.

WIDTH is the number of characters to use in the output. For a value in the range 0.000 to 5.000, the width should be the precision +2. More is OK.

PRECISION is the number of characters after the decimal point. For temperature, 1 would be sufficient.

BUFFER is where the write the characters to.

char buffer[10];
dtostrf(temperatureC, 5, 1, buffer);

There is no reason to make a String out of buffer.

String temperature = (tem, DEC);

This is rubbish. It looks like you took Serial.print(tem, DEC), and stripped the Serial.print off the front. You can't do that, and produce anything meaningful.

Thank you for your help. I finally got it to work. This is the code which worked for me.

 int reading = analogRead(sensorPin);
  float voltage = reading * 5.0;
  voltage /= 1024.0;  
float  temperatureC = (voltage) * 100;
char buffer[10];
String tem = dtostrf(temperatureC, 5, 2, buffer);
String temper = (tem);

Here is the chart: https://www.thingspeak.com/channels/1531/charts/2

Once again, thank you.

What kind of temperature sensor are you using that discerns temperature variations as small as 0.01 degrees?

Why are you converting the char array to a String object?

Why are you then copying that String object?

I am trying to use dtostrf to print out values to a Nokia 5110 LCD.

Here's a snippet of my code:

/* Get distance to the destination */
double distance_meters = TinyGPSPlus::distanceBetween(tinygps.location.lat(), tinygps.location.lng(), DEST_LATITUDE, DEST_LONGITUDE);
 /* get bearing to destination */
double bearing = TinyGPSPlus::courseTo(tinygps.location.lat(), tinygps.location.lng(), DEST_LATITUDE, DEST_LONGITUDE);

Serial.print("Distance to dest: ");
Serial.println(distance_meters);      

// generate chars for easy printing
int dist_m_int = (int)distance_meters;
float dist_km = distance_meters / 1000.0;   
int dist_km_int = (int)dist_km;   
int bearing_int = (int)bearing;

// generate char arrays for printing to LCD screen
char m_buffer[sizeof(dist_m_int)+1];
char km_buffer[sizeof(dist_km_int)+1];
char brng_buffer[sizeof(bearing_int)+1];

dtostrf(distance_meters, 1, 0, m_buffer);
dtostrf(dist_km, 1, 0, km_buffer);
dtostrf(bearing, 1, 0, brng_buffer);

What I'm seeing (and can verify in the serial monitor) is that the distance_meters value coming out of the GPS function is reasonable (say, ~2017 kilometres), but then m_buffer seems to get a value of ~20137. I've tried this for several different locations (i.e. different distances) and I am consistently getting values in the char buffer that are off by a factor of 10.

However, brng_buffer content, however, is exactly as expected. Which seems ridiculous to me since the instructions processing the distance_meters and bearing values look to be exactly the same.

Any ideas? I've been stuck on this for a couple of days. Thanks in advance.

Frankly, printing a float to zero decimal places looks pretty stupid. Just use ints if you don't want the accuracy of the float.

PaulS: Frankly, printing a float to zero decimal places looks pretty stupid.

Thanks!

PaulS: Just use ints if you don't want the accuracy of the float.

Use ints where? The dtostrf function documentation indicates a double (same as float) is required as the first argument. Can I pass in an int instead? I am using the sizeof(int var) to size the char buffers because I only want to see integers on the LCD.

Can I pass in an int instead?

You could, but why?

I am using the sizeof(int var) to size the char buffers because I only want to see integers on the LCD.

Why, then, do you need to use floats? Why do you need to use dtostrf()? Just use the print() method of the LCD class to print to the LCD, whether you are printing floats or ints.

The LCD library I'm using won't print floats. I need to pass in a character array.

The LCD library I'm using won't print floats.

But, you don't want to print floats.

davebaldwin: The LCD library I'm using won't print floats. I need to pass in a character array.

That is either nonsense, or time to move to a proper library. It is definitely time to be more forthcoming with your code.

If you want to print floats, you should be able to so - without dtostrf(). I have never been able to understand why there has ever been a need for this float to string conversion stuff, or why anybody thinks they need it now. I can only assume it is some nasty legacy from the past when Arduino was incapable of handling floats.

The only time I have ever seen a need for Arduino to feed strings was when a receiving non-Arduino programme demanded it I'm not aware of any hardware device that demands to be fed with strings.

Another thread is here http://forum.arduino.cc/index.php?topic=212255.msg1558900#msg1558900

I used dtostrf to pass an integer to a routine I wrote. It requires a char array that I then use chop each letter into vertical stripes to display on an LED cube.

Worked a treat for me. Kept me away from using String.

I used dtostrf to pass an integer to a routine I wrote.

Why would you use double to string, formatted to deal with an integer?

Because it worked perfectly, I was planning on looking in to other more appropriate options later.

What would you use to tun an int into char array? I'm guessing there is itostrf, I didn't bother checking as this worked, and it was 4am, I was grumpy and I was calling this a win.