Go Down

### Topic: dtostrf() help (Read 170290 times)previous topic - next topic

#### Nebula

##### Jan 02, 2012, 07:44 pm
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):

Code: [Select]
#include <Servo.h>
#include <math.h>

Servo myservo;

float xval;
float yval;

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);
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.

#### dc42

#1
##### Jan 02, 2012, 07:54 pm
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:

Code: [Select]

Serial.print(x);
Serial.print(" ; ");
Serial.println(y);
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

#### PaulS

#2
##### Jan 02, 2012, 07:58 pm
Why are you using dtostrf() at all? The Serial.print() function is perfectly capable of sending a float to the serial port.

#### Nebula

#3
##### Jan 02, 2012, 09:08 pm
@ 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

#### jamilm9

#4
##### Jan 04, 2012, 07:45 am
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.
Code: [Select]
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

#### PaulS

#5
##### Jan 04, 2012, 11:25 am
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.

Code: [Select]
char * dtostrf (double __val, signed char __width, unsigned char __prec, char *__s)
Quote
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?

#### jamilm9

#6
##### Jan 04, 2012, 06:15 pm
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.

#### PaulS

#7
##### Jan 04, 2012, 06:45 pm
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.

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

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

Code: [Select]
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.

#### jamilm9

#8
##### Jan 04, 2012, 07:11 pm
Thank you for your help. I finally got it to work. This is the code which worked for me.
Code: [Select]
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.

#### PaulS

#9
##### Jan 04, 2012, 08:11 pm
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?

#### davebaldwin

#10
##### May 25, 2014, 11:58 pm
I am trying to use dtostrf to print out values to a Nokia 5110 LCD.

Here's a snippet of my code:
Code: [Select]

/* 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.

#### PaulS

#11
##### May 26, 2014, 01:52 am
Frankly, printing a float to zero decimal places looks pretty stupid. Just use ints if you don't want the accuracy of the float.

#### davebaldwin

#12
##### May 26, 2014, 02:28 am

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

Thanks!

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.

#### PaulS

#13
##### May 26, 2014, 02:38 am
Quote
Can I pass in an int instead?

You could, but why?

Quote
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.

#### davebaldwin

#14
##### May 26, 2014, 02:41 am
The LCD library I'm using won't print floats. I need to pass in a character array.

Go Up