How do I get GPS timestamp to Millisecond accuracy with NMEAGPS.h?

The code below works fine. Every second, it displays the current time. What I am not sure is whether I can pick timing at a faster rate, because “fix.dateTime_cs”, displays 0 all the time. Is there a way I can increase the frequency to 2 times a second? Now, I would want to add an interrupt, such that when AS3935_PIN is RISING, it picks the GPS, timing to an accuracy of Microseconds (or better Millisecond). How do I make changes to the code below to achieve that?

#include "NeoSWSerial.h"
#define RX_PIN 7
#define TX_PIN 8
#define AS3935_PIN 9
NeoSWSerial gpsPort( RX_PIN, TX_PIN ); 

// Since it's hooked to a GPS, try NeoGPS for parsing...
#include <NMEAGPS.h>
NMEAGPS gps;
gps_fix fix;

void gpsPortISR()
{
  NeoSWSerial::rxISR( *portInputRegister( digitalPinToPort( RX_PIN ) ) );
     //  This is uglier than passing PIND, but it works for any RX_PIN you choose.
}

void setup()
{
  Serial.begin( 9600 );
  gpsPort.begin( 9600 );
  enableInterrupt( RX_PIN, gpsPortISR, CHANGE);
  enableInterrupt(AS3935_PIN,GPSdata,CHANGE);
}

void loop()
{
 GPSdata();
}
void GPSdata()
{
   if (gps.available( gpsPort )) {
    fix = gps.read();
      if (fix.valid.time ) {

         Serial.print("Date:");
          Serial.print(fix.dateTime.year);
          Serial.print("/");
        Serial.print(fix.dateTime.month,10);
        Serial.print("/");
        Serial.print(fix.dateTime.date,10);
        Serial.print(", Time(UTC):");
        Serial.print(fix.dateTime.hours,10);
        Serial.print(":");
        Serial.print(fix.dateTime.minutes,10);
        Serial.print(":");
        Serial.print(fix.dateTime.seconds);
        Serial.print(".");
        Serial.print(fix.dateTime_cs);
        Serial.print(" - Week Day:");
        Serial.print(fix.dateTime.day,10);
        Serial.println();
    }
  } 
}

it picks the GPS, timing to an accuracy of Microseconds (or better Millisecond)

Once a second, I'm going to tell you what time it was the last time I checked. What resolution can you reasonably expect?

PaulS:
Once a second, I'm going to tell you what time it was the last time I checked. What resolution can you reasonably expect?

Well, you can use millis() to get a little finer than that... :wink:

mwangilbert:
"fix.dateTime_cs" displays 0

Yes, the GPS device aligns the updates to the start of each second. After it gets a good fix, it always sends an update with .00 seconds.

Is there a way I can increase the frequency to 2 times a second?

Yes, but if you are just trying to time an event, you don't need to do that.

when AS3935_PIN is RISING, it picks the GPS, timing to an accuracy of Microseconds (or better Millisecond).

Call gps.UTCus() at any time to get the microsecond offset from the current GPS fix time. But...

You have to choose how to "capture" when each second starts:

It would be best to connect the PPS (Pulse-per-second) pin of the GPS device to one of the Arduino's Input Capture pins. That would be the most accurate, by far, down to a handful of microseconds. NeoGPS allows you to set the current UTC microsecond. There are several ways to use the TIMESTAMP_FROM_PPS option to set it.

Calculating milliseconds from the arrival of the GPS sentence could be off by a few milliseconds between each sentence. Each sentence is also delayed from the real UTC time by ~80ms, depending on sentence length. Each sentence starts arriving after the exact 1-second interval with some variability, around 100us. There is a NeoGPS option to use that (TIMESTAMP_FROM_INTERVAL) instead of the PPS pin.

BTW, each crystal is a slightly different frequency, which leads to slightly different Arduino micros() values -- the "Arduino microsecond" can be a little longer or shorter than a real microsecond. You can use the TIMESTAMP options to "detect" the difference. You could use a running average over a window. That calculated Arduino-us-per-GPS-us could be used to adjust the return value from gps.UTCus() or micros().

If you're ok with a few ms variability, just enable TIMESTAMP_FROM_INTERVAL and use gps.UTCms(). Be aware that you have to be a little careful about using gps.UTCms() at the beginning of each time interval, up to about 80ms. The new sentence won't have arrived yet, so the last fix.dateTime.seconds will still have the previous second. See the SyncTime.ino example for the proper calculations.

Try some things, and please ask if you get stuck.

Cheers,
/dev