The module I tested does print out different times for RMC and GGA sentences.
o_O Could I ask what brand, what baud rate, and were the times different by 1 second or a fraction? They usually send the "solution" time, which would be the received GPS time. If they are sending the RTC time, what were they thinking?
That would make it dependent on baud rate.
I posted the function that displays the GPS sentence in reply #4
Ok, not the whole sketch, but it does reveal the problem. Sorry I missed that.
If you read the Troubleshooting section, you may remember that the GPS device emits a batch of sentences consecutively, once per update interval (usually 1 second). Then there is a "quiet time" until the next interval begins. For example, if the GPS is running at 9600 (I can't see that
), then receiving 3 sentences of ~200 chars will take about 200ms. Then the quiet time will be about 800ms, until the next set of sentences begin.
What's happening is that you are taking a 1-second sample of the character data, perhaps 45 seconds apart (I can't see what else you are doing
). In the first call to checkGPS
, you may be getting the last two sentences. 45 seconds later, you read some more during the GPS quiet time and maybe get one new sentence. This mixes old sentences with new sentences, or is "incoherent", time-wise (see this page).
If you are doing other things that prevent the GPS data from being read (I can't see that
), you have a few choices:
1) Read for at least 2 seconds, and make sure that you see the GPS quiet time begin: no characters will available for >10ms or so (depends on baud rate and GPS configuration commands, which I can't see
).
2) Read and parse all the time (e.g., in loop
)to make sure the GPS values have the latest and greatest values, but only use them in checkGPS
3) Use a more robust GPS library with interrupt-driven parsing. 
For option 1, you could use NeoGPS like this in checkGPS
:
boolean checkGPS()
{
uint8_t fixes = 0;
gps_fix fix;
// for a few seconds, parse GPS data for relevant time values;
unsigned long start = millis();
do {
if (gps.available( ss )) {
// A new fix is available, merged together from all 3 sentences.
fix = gps.read();
// skip invalid (empty) fixes and the first partial fix
if ((fix.valid.date && fix.valid.time && fix.valid.location) &&
(fixes++ > 0)) {
// estimate time zone from longitude;
int8_t gpstimezone = fix.longitudeL()/150000000L; // integer degrees * 10,000,000
#ifdef _DEBUG_
Serial.print( F("GPS DATE/TIME=") );
Serial << fix.dateTime; // output format provided by Time.H
Serial.print( F("\nTimezones from GPS data is ") );
Serial.println( gpstimezone );
#endif
// determine if the time is off (and therefore must be set);
if ((fix.dateTime.minutes != minute) || (fix.dateTime.seconds != second))
{
minute = fix.dateTime.minutes;
second = fix.dateTime.seconds;
if (gpsAutoHour)
{
// automatically set the hour based on timezone/longitude;
hour = fix.dateTime.hours + gpstimezone;
// set to summer time if DST is selected;
if (doDST && isSummerTime())
{
#ifdef _DEBUG_
Serial.println( F("Adjusting time for summer (adding an hour)") );
#endif
hour++;
}
// Offsetting hour can push it outside the range 0..23
if (hour > 23)
hour -= 24;
else if (hour < 0)
hour += 24;
}
setTime(hour, minute, second);
#ifdef _DEBUG_
Serial.print( F("RTC synced from GPS to ") );
if (hour < 10) Serial.print( '0' );
Serial.print(hour);
Serial.print(":");
if (minute < 10) Serial.print( '0' );
Serial.print(minute);
Serial.print(":");
if (second < 10) Serial.print( '0' );
Serial.println(second);
#endif
}
// Used the second complete fix, all done!
return true;
}
}
} while (millis() - start < 5000UL);
return false;
}
For option 2, you could use NeoGPS like this:
void loop()
{
// Read all the time, keeping the fix up-to-date
if (gps.available( ss ))
fix = gps.read();
// Sync the RTC every 5 seconds when we have good data
if ((fix.valid.date && fix.valid.time && fix.valid.location) &&
(millis() - lastCheck > 5000UL)) {
lastCheck = millis();
checkGPS();
}
}
The checkGPS
routine would be almost the same, except for the beginning (no while/if tests):
void checkGPS()
{
// estimate time zone from longitude;
int8_t gpstimezone = fix.longitudeL()/150000000L;
#ifdef _DEBUG_
Serial.print( F("GPS DATE/TIME=") );
...
For option 3, you would need the one of the Neo--Serial libraries. I strongly recommend using pins 8 and 9 for the GPS device so you can use AltSoftSerial, but I suspect you are using SoftwareSerial. For this option, you would need NeoSWSerial:
NeoSWSerial ss( ?, ? );
void gpsISR( uint8_t c )
{
gps.handle( c );
}
void setup()
{
Serial.begin( 9600 );
Serial.println( F("florinc") );
ss.attachInterrupt( gpsISR );
ss.begin( 9600 );
lastCheck = millis();
}
void loop()
{
// Keep reading the fixes as the ISR makes them
if (gps.available())
fix = gps.read();
SoftwareSerial blocks interrupts for long periods of time; NeoSWSerial is much more efficient, and allows handling the received characters during the interrupt. AltSoftSerial is better than either. Use it for option 1 or 2, or use NeoICSerial for option 3.
Cheers,
/dev