Serial Monitor output different from SD card reader

Hello,

I have made a code in measuring time, date, longitude and latitude from a sensor. Serial monitor output is correct however, the output written through the SD card is incorrect.

Here's my code:

/*
  Get the high precision geodetic solution for latitude and longitude
  By: Nathan Seidle, Steven Rowland and Paul Clark
  SparkFun Electronics
  
  Modified by: Katrina Cereno
  Klohn Crippen Berger Ltd.
  
  Date: August 24, 2022
  
  License: MIT. See license file for more information but you can
  basically do whatever you want with this code.

  This example shows how to inspect the accuracy of the high-precision
  positional solution. Please see below for information about the units.

*/

#include <SD.h>
#include <Wire.h> //Needed for I2C to GNSS

#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;

#define PIN_SPI_CS 4

long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to u-blox module.
File myFile;

void setup()
{
  Serial.begin(57600);
  while (!Serial)
    ; //Wait for user to open terminal
 
  if (!SD.begin(PIN_SPI_CS)) {
    Serial.println(F("SD CARD FAILED, OR NOT PRESENT!"));
    while (1); // don't do anything more:
  }

  Serial.println(F("SD CARD INITIALIZED."));
  
  Wire.begin();

  if (myGNSS.begin(Wire) == false) //Connect to the u-blox module using Wire port
  {
    Serial.println(F("Please check wiring. Freezing."));
    while (1);
  }
  myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
   myGNSS.setNavigationFrequency(20); //Set output to 20 times a second
}
void loop()
{
  //Query module only every second. Doing it more often will just cause I2C traffic.
  if (millis() - lastTime > 60000)
  {
    lastTime = millis(); //Update the timer
  
    // Print date and time
    Serial.print(myGNSS.getYear());
    Serial.print(F("-"));
    Serial.print(myGNSS.getMonth());
    Serial.print(F("-"));
    Serial.print(myGNSS.getDay());
    Serial.print(F(","));
    Serial.print(myGNSS.getHour());
    Serial.print(F(":"));
    Serial.print(myGNSS.getMinute());
    Serial.print(F(":"));
    Serial.print(myGNSS.getSecond());
    Serial.print(F(","));
    
    // Collect the position data
    int32_t latitude = myGNSS.getHighResLatitude();
    int8_t latitudeHp = myGNSS.getHighResLatitudeHp();
    int32_t longitude = myGNSS.getHighResLongitude();
    int8_t longitudeHp = myGNSS.getHighResLongitudeHp();
   /* int32_t ellipsoid = myGNSS.getElipsoid();
    int8_t ellipsoidHp = myGNSS.getElipsoidHp();
    int32_t msl = myGNSS.getMeanSeaLevel();
    int8_t mslHp = myGNSS.getMeanSeaLevelHp();*/
    uint32_t accuracy = myGNSS.getHorizontalAccuracy();

    // Defines storage for the lat and lon units integer and fractional parts
    int32_t lat_int; // Integer part of the latitude in degrees
    int32_t lat_frac; // Fractional part of the latitude
    int32_t lon_int; // Integer part of the longitude in degrees
    int32_t lon_frac; // Fractional part of the longitude

    // Calculate the latitude and longitude integer and fractional parts
    lat_int = latitude / 10000000; // Convert latitude from degrees * 10^-7 to Degrees
    lat_frac = latitude - (lat_int * 10000000); // Calculate the fractional part of the latitude
    lat_frac = (lat_frac * 100) + latitudeHp; // Now add the high resolution component
    if (lat_frac < 0) // If the fractional part is negative, remove the minus sign
    {
      lat_frac = 0 - lat_frac;
    }
    lon_int = longitude / 10000000; // Convert latitude from degrees * 10^-7 to Degrees
    lon_frac = longitude - (lon_int * 10000000); // Calculate the fractional part of the longitude
    lon_frac = (lon_frac * 100) + longitudeHp; // Now add the high resolution component
    if (lon_frac < 0) // If the fractional part is negative, remove the minus sign
    {
      lon_frac = 0 - lon_frac;
    }

    // Print the lat and lon

    Serial.print(lat_int); // Print the integer part of the latitude
    Serial.print(".");
    printFractional(lat_frac, 9); // Print the fractional part of the latitude with leading zeros
    Serial.print(",");
    Serial.print(lon_int); // Print the integer part of the latitude
    Serial.print(".");
    printFractional(lon_frac, 9); // Print the fractional part of the latitude with leading zeros
 

 
   File dataFile = SD.open("neom8p.txt", FILE_WRITE);
   
   // if the file is available, write to it:
  if (dataFile) {

  dataFile.print(myGNSS.getYear());
  dataFile.print(F("-"));
  dataFile.print(myGNSS.getMonth());
  dataFile.print(F("-"));
  dataFile.print(myGNSS.getDay());
  dataFile.print(F(","));
  dataFile.print(myGNSS.getHour());
  dataFile.print(F(":"));
  dataFile.print(myGNSS.getMinute());
  dataFile.print(F(":"));
  dataFile.print(myGNSS.getSecond());
  dataFile.print(F(","));
  dataFile.print(lat_int); // Print the integer part of the latitude
  dataFile.print(".");
  dataFile.print(lat_frac, 9); // Print the fractional part of the latitude with leading zeros
  dataFile.print(",");
  dataFile.print(lon_int); // Print the integer part of the latitude
  dataFile.print(".");
  dataFile.print(lon_frac, 9); // Print the fractional part of the latitude with leading zeros
  dataFile.println("");
  dataFile.close();
    // prints to the serial port too:
  
  }
  }
}

// Pretty-print the fractional part with leading zeros - without using printf
// (Only works with positive numbers)
void printFractional(int32_t fractional, uint8_t places)
{
  if (places > 1)
  {
    for (uint8_t place = places - 1; place > 0; place--)
    {
      if (fractional < pow(10, place))
      {
        Serial.print("0");
      }
    }
  }
  Serial.print(fractional);
}

Would someone be able to help me fix my code?

Thank you!

In what way is the SD output incorrect ?

The Serial Monitor gives me the correct longitude and latitude (current location) but txt file from SD card is incorrect (few km away from where I am at).

On the face of it that should be impossible because you are printing and saving the same variables

What happens if you move the output to the Serial monitor into the if (dataFile) section of code ?

What happens if you just output the raw values of latitude and longitude rather than your calculated parts of it ?

Would you be able to clarify what you meant with the first suggestion you have mentioned? Thanks.

Write a function that sends the same data to both the serial and SD at the same time. This will insure that nothing happens between the two outputs as well as eliminting 1/2 your code (and 1/2 the error possibilities).

Don't test for the file. If it isn't there nothing bad will happen and you'll be assured that the code is running even if the hw is down.

You have a section of code that writes to the SD if it is available

    // if the file is available, write to it:
    if (dataFile)
    {
      dataFile.print(myGNSS.getYear());
      dataFile.print(F("-"));
      dataFile.print(myGNSS.getMonth());
etc, etc

Print your lat and long values inside that loop instead of outside of it

I have tried this however, it still is giving me incorrect data from SD card. I susoect that it is the "printFractional" function is what's making it complicated. Would you be able to help me how I can dataFile write printFractional numbers?

Thank you.

I have also tried this but still gave me incorrect values from SD card. Please see the reply thread from UKHeliBob. Thanks!

When you do this

    int32_t latitude = myGNSS.getHighResLatitude();

What exactly is returned in the latitude variable ?

int32_t latitude = myGNSS.getHighResLatitude(); gives the following
535882635

it is serial printed (printFractional) as:
53.588263533 (high precision)

What should be printed when latitude equals 535882635 ?