0

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!

4
  • 1
    Does your GPS actually give you floats? 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 use floats, their precision is limited, which may well be the cause of what you are seeing with your fake test data. Jan 13, 2017 at 3:54
  • Are you sure about your result? I'm trying your code and I get "Your coordinates are -23.123456,135.123456". Just in case you didn't notice, you missing one ;
    – duck
    Jan 13, 2017 at 6:41
  • Regarding the limited precision of the float32 format: for numbers in the range [128, 256) (like your longitude), the unit in the last place is about 1.53e-5, which translates to a resolution of 1.7 m on the surface of the Earth. Assigning the longitude to a float can incur a rounding error as large as half an ulp, or about 85 cm. Jan 13, 2017 at 8:31
  • Why not simply use the String member function c_str() to access the char array? message.c_str() arduino.cc/en/Reference/CStr Jan 13, 2017 at 12:18

1 Answer 1

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*log₁₀(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.

8
  • 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. 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
    Jan 13, 2017 at 4:41
  • @ChrisStratton, reflected in Edit 1a Jan 13, 2017 at 7:16
  • @Anwar, please see Edit 1b 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);. Jan 13, 2017 at 8:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.