0

I am working on serial communication between two MCU's particularly teensy(similar to Arduino) for generating fake GPS data. I have been able to write GPS data and read from the other MCU fine but if u look closely, the data that is printed has some ambiguity. The last values are changed somehow and I don't understand why is this because of sprintf command or conversion of float to string or what?

Some help will be appreciated.

Below are the working code and snippet of the serial terminal.

Thank you

float lat = 37.4980608;
char str1[21];

void setup()
{
  Serial3.begin(115200);
  Serial.begin(115200); // Config serial port (USB)

  while(!Serial);
  while(!Serial3);

  Serial.println("Sending gps data");
}

void loop()
{
  sprintf(str1, "%.7f%.7f", lon, lat);
  Serial.println(str1);
  Serial3.write(str1);
  Serial3.flush();
  delay(500);
}

Result

Kani
  • 469
  • 4
  • 13
  • Seems like something to do with the `float` precision. Can you check is you have better results if you do `double lat` and `double lon`? I know 8-bit Arduino boards treat both `float` and `double` with the same `float` precision. Seems like Teensy should be able to treat `double` with `double` precision. – Kani May 31 '19 at 13:05
  • Thanks for quick response, I tried earlier with double data type and with changing the decimal point range from %.5f to %.8f but the problem remains as I increase from %.5f.. I don't know if it's because of sprintf command issue or data type because I believe teensy3.6 has quite good specs but still not sure. – Rakeh Sheikh Jun 02 '19 at 03:46
  • Yeah, seems like Teensy 3.6 has single-precision hardware. So `double` won't be that effective. Probably you need to implement something like what @RamblinRose suggested. – Kani Jun 02 '19 at 15:35

1 Answers1

0

What you are seeing is the compiler's approximation of your floats because their values are exceeding the precision possible with a float (4-bytes). Using a double won't help unless your MCU supports 8-byte doubles; I've not used a teensy but I highly doubt it supports 8-byte doubles.

This is not a clever solution but it should get you pointed in the right direction.

Define a struct that can represent large real number values

typedef struct {
    int whole;
    unsigned long fraction;
} BigNumber;

The you may declare/initialize latitude and longitude l

BigNumber latitude { 126, 9653503 };
BigNumber longitude { 37, 4980608 };

Then printing is easy:

sprintf(strbuf, "%i.%lu %i.%lu", 
    latitude.whole, latitude.fraction, 
    longitude.whole, longitude.fraction
  ); 

However if mathematical operations are necessary - add, subtract, etc. - this won't cut it; find an arbitrary big number library like Nick Gammon's

Lastly, have a care: in your code str1 is too small - there is no accounting for the null terminator appended by sprintf, so you're getting plain lucky your program is not crashing.

RamblinRose
  • 4,883
  • 2
  • 21
  • 33
  • I appreciate your help but I am looking for some solution with my issue quite easy not defining structures or other functions just for one printing stuff as I'm working on other functions in the same script and I want the code to be quite simple. Anyways I'll implement your mentioned method just to check if the other way around works for me. Thank you – Rakeh Sheikh Jun 02 '19 at 03:51