Need help writing GPS data to microSD

I have a Ubox Neo 6 GPS unit and a microSD card connected to an Arduino Nano V3.0. Files can be written to the card and GPS data can be read without any issues. I can read the GPS output in the Serial Monitor properly, however, I cannot seem to write GPS data lines to into individual lines onto the microSD card.

/*
 The circuit:
 * analog sensors on analog ins 0, 1, and 2
 * SD card attached to SPI bus as follows:
 ** MOSI (DI) - pin 11
 ** MISO (DO) - pin 12
 ** CLK (SCK) - pin 13
 ** CS - pin 4
 */

#include <SPI.h>
#include <SD.h>
#include <SoftwareSerial.h>

// setup SD Card Select Pin
const int chipSelect = 4;

// setup gps serial
int gpsTxPin = 8;
int gpsRxPin = 7;
SoftwareSerial gpsSerial(gpsTxPin, gpsRxPin);

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  
  gpsSerial.begin(9600); //adjust for GPS unit
  
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
}

void loop() {
  // make a string for assembling the data to log:
  String datastring = "";

  // Read GPS Data
  while(gpsSerial.available())
  {
    char c = gpsSerial.read();
    datastring += c;
    // Serial.print(c);
  }

  File dataFile = SD.open("gpsdata.txt", FILE_WRITE);

  if (dataFile) {
    //dataFile.println(datastring);
    dataFile.close();
    // print to the serial port too:
    Serial.println(datastring);
  }
  else {
    Serial.println("error opening gpsdata.txt");
  }
}

The file produced has numerous blank lines in between data lines. Where am I going wrong?

Where am I going wrong?

Using the String class.

Collecting all the data available in one iteration of loop() into a String, and then writing the contents of the String to the buffer is pointless. Just write the data to the buffer as you read it.

print() a carriage return and line feed only when the end of a sentence arrives, if the sentence does not already contain a carriage return and/or line feed.

Read "Serial Input Basics" on the Useful Links page. It will show you how to accumulate a line of data into a character array (aka a C [u]s[/u]tring, not the String class). In your sketch, you will just write that line to the SD file. Right now, you are not watching for the end of each line, like PaulS said.

If you also need to parse the GPS lines to get the date, time or location (e.g., for distance calculations), you may want to look at NeoGPS. It is smaller and faster than other libraries, and it has an example for reliably writing the parsed fields into an SD file.

One problem that you may encounter is the SD card write speed. Occasionally, some SD cards take ~100ms to complete a write. This will cause you to lose GPS characters while the write is busy. The NeoGPS SD logging example shows you how to use interrupt processing to avoid losing any GPS data.

Cheers, /dev

Thank you very much for the help. I will modify the code accordingly. In the final design, the GPS will log only a few times a day to save battery, thus write speed may not be an issue.

I didn’t realize I was using println instead of print. Problem solved. Thank you all for all the help.

Working code:

/*
 ** MOSI (DI) - pin 11; MISO (DO) - pin 12; CLK (SCK) - pin 13; CS - pin 4
*/

#include <SPI.h>
#include <SD.h>
#include <SoftwareSerial.h>

const int chipSelect = 4; // setup SD Card Select Pin

// setup gps serial
int gpsTxPin = 8;
int gpsRxPin = 7;
SoftwareSerial gpsSerial(gpsTxPin, gpsRxPin);

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  
  gpsSerial.begin(9600); //adjust for GPS unit
  
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
}

void loop() {
    File dataFile = SD.open("data001.txt", FILE_WRITE);
      // Read GPS Data
      while(gpsSerial.available()){ 
      char c = gpsSerial.read();
      dataFile.print(c);
      Serial.print(c);
      }
      dataFile.close();
}