I am receiving lat and long data from a GPS and want to store these numbers in the middle of a sequence of chars.
E.g. lat = -23.123456
long = 135.123456
I am after something like "Your coordinates are -23.123456,135.123456" as an array of chars.
I have tried:
float latitude = -23.123456;
float longitude = 135.123456;
String one = "Your coordinates are ";
String two = ","
String message = one + latitude + two + longitude;
// Convert String to char array
int str_len = message.length() + 1;
char textmessage[str_len];
message.toCharArray(textmessage,str_len);
Serial.println(textmessage);
but the result is: Your coordinates are -023.12,0135.12
How can I correct this?
Thanks in advance!
1 Answer 1
When formatting serial output is a concern, it's worthwhile to download and use the Streaming.h
contributed library that adds some "syntactic sugar" to Arduino C. That is, at compile time it converts C++-like <<
Serial stream operators to Serial.print
statements, without increasing code size. If you don't have Streaming.h
installed, you can get Streaming5.zip
from arduiniana.org.
At present, Streaming.h
doesn't support setw()
and setfill()
, which in ordinary C++ set a field width and a fill character.
However, it does support four base-conversion specifiers, _HEX, _DEC, _OCT, and _BIN; a _FLOAT function with number of decimal places specified; and endl
.
Thus, to print "Your coordinates are -23.123456, 135.123456" one would write:
Serial << "Your coordinates are " << _FLOAT(latitude,6) << ", " << _FLOAT(longitude,6) << endl;
Note that unlike the String
class, use of Streaming.h
does not entail any dynamic memory management – everything it does happens at compile time – and it does not increase code size – it translates stream-style operations into ordinary .print()
and .println()
calls. It should result in somewhat smaller, faster, and more-robust code, by avoidance of String
. Use of dynamic memory on small-memory embedded systems can be problematic, and this avoids those problems.
Edit 1a: As Chris Stratton points out, Arduino floats don't support 9-digit precision. I think Arduino floating-point arithmetic is intended to comply with IEEE 754, which sets out standards to be used on modern computers that support floating-point arithmetic.
In the binary32 format used to implement IEEE 754 single-precision binary floating-point, significand precision is 24 bits. That equates to about 7.22 decimal digits (ie, 24*log10(2)), so for simple calculations, 7-digit accuracy is realistic, more than that is not.
[Part of] Edit 1b: In the larger scheme of things perhaps there's no need to create and save a formatted string like that. It is not useful for computing – the float values are better for that. It is not needed for communication – another streaming write can be done.
Edit 2 [replaces most of 1b]: Streaming.h doesn't build any strings, but just delivers the text of its <<
-arguments character-by-character to a stream. However, a PString class at arduiniana can build strings from stream inputs, as in the following example code.
#include <Streaming.h>
#include <PString.h>
char buffer[28];
PString pstr(buffer, sizeof(buffer));
void setup() {
Serial.begin(115200);
pstr.begin(); // Empty the buffer
}
void loop() {
int first=50, second=100;
pstr.begin(); // Empty the buffer
pstr << 'X' << first << 'Y' << second << 'T';
pstr += " hihi ";
pstr << millis() << endl;
Serial << pstr;
delay(1000);
}
Here's what some of its output to Serial looks like:
X50Y100T hihi 263198
X50Y100T hihi 264199
X50Y100T hihi 265199
X50Y100T hihi 266201
X50Y100T hihi 267201
X50Y100T hihi 268201
What the sample of code does is first initialize a string buffer, then build part of a character string using streaming operator <<
, then part of it using concatenation, then some more with <<
, then print the string. Note that the strings involved here are in fixed buffers, rather than dynamically allocated buffers like the String class uses.
-
It is possible you may do better than the code in the question, but you will not get the desired precision from an ATmega-based Arduino Uno's
float
.Chris Stratton– Chris Stratton2017年01月13日 03:56:53 +00:00Commented Jan 13, 2017 at 3:56 -
Thanks! However I need to save this printed sequence as an array of chars to be used later in the code. Can this be done from the printed Serial <<... ?Anwar– Anwar2017年01月13日 04:41:08 +00:00Commented Jan 13, 2017 at 4:41
-
@ChrisStratton, reflected in Edit 1aJames Waldby - jwpat7– James Waldby - jwpat72017年01月13日 07:16:04 +00:00Commented Jan 13, 2017 at 7:16
-
@Anwar, please see Edit 1bJames Waldby - jwpat7– James Waldby - jwpat72017年01月13日 07:16:22 +00:00Commented Jan 13, 2017 at 7:16
-
Although the streaming library is a nice syntax candy, you do not need it to specify the number of digits to print. You can also
Serial.print(latitude, 6);
.Edgar Bonet– Edgar Bonet2017年01月13日 08:14:59 +00:00Commented Jan 13, 2017 at 8:14
float
s? Most output text on a serial port; if you do not need to do numeric operations on the values, perhaps you should just treat them as text all the way through. Note that if you do usefloat
s, their precision is limited, which may well be the cause of what you are seeing with your fake test data.;
float
can incur a rounding error as large as half an ulp, or about 85 cm.message.c_str()
arduino.cc/en/Reference/CStr