0

I've programmed my Arduino Ethernet to receive data from a Skytraq Venus GPS receiver and separate it using TinyGPS, then store it on an SD card. With the SD card inserted, everything else except the time is totally wrong. Once I remove the SD card and reset, the longitude and latitude are still wrong but everything else is correct. I've tried supplying more power, replacing the receiver, antenna, the arduino itself, even switched the serial ports I use but I can't seem to find a solution.

Here's a link for the TinyGPS library and a link for the NewSoftSerial library. And for the schematics, I haven't drawn any yet but I'm using the Arduino Ethernet's SD port as my SD shield. My Skytraq GPS receiver's RX pin is connected to pin 2 on the arduino ethernet and the TX pin is connected to pin 3 on the ethernet. (Ethernet TX/RX has been set to pin 3 and 2 respectively.)

I'm using the Sparkfun Venus GPS with SMA connector from sparkfun.com. I would post the link but it says I need at least 10 reputation to post more than two links. Serial signals at 3.3V and GPS module is a 3.3V module. I use the same sketch with and without the SD Card. SD.begin is called just once and Serial.begin is also called once.

Here's my code:

#include <SoftwareSerial.h> //NewSoftwareSerial Library
#include <TinyGPS.h>        //TinyGPS Library
#include <SPI.h>            //This Library is used by the SD library.
                            //Must be defined before SD library to prevent errors.
#include <SD.h>             //SD Card Library

//NB: To avoid SD Card Errors, use an SD Card whose size is at most 2GB
//and use FAT16 format. Arduino has problems with FAT32 and cards>2GB.

#define RXPIN 2
#define TXPIN 3

const int chipSelect = 4; //This selects the SD card port for read/write

#define GPSBAUD 9600

File logs; //Used to write to SD card later

TinyGPS gps;

//Initialize the Software Serial to recognize
//our UART pins (Read(RX) and Write(TX))
SoftwareSerial read_gps(RXPIN, TXPIN); 

void getdata(TinyGPS &gps);


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);  //Start the serial port
  read_gps.begin(GPSBAUD);  //Start reading from the gps
  
  pinMode(chipSelect, OUTPUT); //Make pin 4 an output pin
  pinMode(10, OUTPUT);  //Pin 10 must always be set to output to avoid errors
  digitalWrite(10, HIGH); //Pin 10 must always be high to prevent errors.
  
  Serial.println("");
  Serial.println("Awaiting Lock");
  Serial.println("");
  
  //Initialize the SD Card
  SD.begin();
  Serial.println("Initializing SD Card. Please Wait.");
  if(!SD.begin(4)){//If card not available or card not recognized
    Serial.println("Failed.");
    return;
  }
  Serial.println("Card Initialized");

}


//the loop function is used to read the data from the gps,
//check for valid data and then separate the data based on our specs.
void loop() {
  // put your main code here, to run repeatedly:
  while(read_gps.available()){//as data is received from the gps
    int c = read_gps.read();
    if(gps.encode(c)){//check if new valid data available
      getgps(gps); //read the valid gps data and process
    }
  }
  
  
  
}

void getgps(TinyGPS &gps)
{
  float latitude, longitude;
  
  gps.f_get_position(&latitude, &longitude); //Feature of tinygps.
                                             //Gets the latitude and longitude
  
  Serial.print("Latitude: "); Serial.print(latitude);
  Serial.print("\nLongitude: "); Serial.print(longitude);
  
  int yr;
  byte mnth, dy, hr, minu, sec, hundredths;
  gps.crack_datetime(&yr, &mnth, &dy, &hr, &minu, &sec, &hundredths); //Gets the date and time and separates them
                                                                      //into individual components.
  
  Serial.print("\nDate: "); Serial.print(mnth, DEC); Serial.print("/");
  Serial.print(dy, DEC); Serial.print("/"); Serial.print(yr);
  Serial.print("   \nTime: "); Serial.print(hr, DEC); Serial.print(":");
  Serial.print(minu, DEC); Serial.print(":"); Serial.print(sec, DEC);
  Serial.print("."); Serial.println(hundredths, DEC);
  
  
  
  Serial.print("Altitude(metres): "); Serial.println(gps.f_altitude());
  
  Serial.print("Speed(kmph): "); Serial.println(gps.f_speed_kmph());
  Serial.println();
  
  logs = SD.open("datalogs.csv", FILE_WRITE);  //open the datalog file on the sd card. If it doesn't exist on the card, create it.
  
  if(logs){//Start writing data to SD Card
    Serial.print("Writing to datalogs...");
    logs.println("\nLatitude: "); logs.print(latitude);
    logs.print("\nLongitude: "); logs.print(longitude);
    logs.print("\nDate: "); logs.print(mnth, DEC); logs.print("/");
    logs.print(dy, DEC); logs.print("/"); logs.print(yr);
    logs.print("   \nTime: "); logs.print(hr, DEC); logs.print(":");
    logs.print(minu, DEC); logs.print(":"); logs.print(sec, DEC);
    logs.print("."); logs.println(hundredths, DEC);
    logs.print("Altitude(metres): "); logs.println(gps.f_altitude());
  
    logs.print("Speed(kmph): "); logs.println(gps.f_speed_kmph());
    logs.print("\n");
    logs.println();
    
    logs.close(); //close the file
    Serial.println("done.");
    Serial.println("\n");
  }
  else{
    Serial.println("Error opening file.");
  }
    
    
  
  unsigned long chars;
  unsigned short sentences, failed_checksum;
  gps.stats(&chars, &sentences, &failed_checksum);
}
9
  • Please provide schematics and the configuration/setup of your sketch. Also include links to libraries that you are using --- and I bet you will soon have helping hands. Apr 1, 2016 at 21:09
  • link for the TinyGPS library link for the NewSoftSerial library. And for the schematics, I haven't drawn any yet but I'm using the Arduino Ethernet's SD port as my SD shield. My Skytraq GPS receiver's RX pin is connected to pin 2 on the arduino ethernet and the TX pin is connected to pin 3 on the ethernet. (Ethernet TX/RX has been set to pin 3 and 2 respectively.)
    – M.ar
    Apr 2, 2016 at 0:56
  • Please update the question instead. And do not forget to add at least the setup/configuration code. Apr 2, 2016 at 10:10
  • Sorry, my mistake. I've updated the question and included my code as well.
    – M.ar
    Apr 2, 2016 at 17:23
  • Please use code format. Edit and use the code {} button. Apr 2, 2016 at 18:22

1 Answer 1

1

You're trying to do too much (SD and Serial print operations) at the wrong time (GPS character receiving).

Most GPS devices will send several "sentences" per second, in a batch. TinyGPS.encode returns true after each sentence, so your code will try to write multiple sentences per second to the SD card. But it takes so long to open/write/close the SD card (and print to Serial) that the input buffer fills up and overflows. Here's a detailed description of what is happening.

You must wait until the GPS "quiet time" begins. Even then, you could have trouble, depending on how much data you need to save and print.

It may be possible to make it work with TinyGPS, but I eventually gave up in frustration and wrote the NeoGPS library to help address these problems. It can be configured to save just the data you need (via the configuration files), and it can be used to detect when the quiet time begins (see NMEAorder.ino and NMEAfused.ino). It uses much less RAM and takes much less time to parse the GPS characters. This will be important if you try to add the Ethernet libraries to the sketch.

If you still have trouble getting all the information written during the quiet time, you can use a companion library (e.g., NeoSWSerial) to handle the GPS characters during the RX interrupt.

Regardless, I would suggest replacing SoftwareSerial with NeoSWSerial. It, too, is much more efficient than the CPU-killer SoftwareSerial. It won't fix the main problem, but it will pay off later.

10
  • Would it still be doing too much if I just took out the writes to the serial monitor and just left the sd writes in there?
    – M.ar
    Apr 3, 2016 at 19:55
  • @M.ar, yes, still too much. The links (blue text) in my answer describe what's happening and how to make it work.
    – slash-dev
    Apr 3, 2016 at 20:32
  • I tried running the NMEA example using SoftwareSerial to define the gps port and it says "java.io.IOException: Access is denied.."
    – M.ar
    Apr 3, 2016 at 21:20
  • Never mind. Figured out what I did wrong. I'll try to do the writes during the quiet time. I'll let you know how that goes.
    – M.ar
    Apr 3, 2016 at 23:19
  • Quick question. What do I set trace to if I don't want it to be serial? In this case, i want the output to go to the SD card.
    – M.ar
    Apr 4, 2016 at 16:53

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.