problems combining millis() and GPS timekeeping

Here's the interesting part. query() is called once by setup() and requests time/location info from the GPS using readline(). That's the only time it's used. The rest of the code is given below.

void query(){
  gpsSerial.begin(4800); // 4800 baud rate
		// send instructions to GPS about data needed
  gpsSerial.print(SERIAL_SET);  delay(250);
  gpsSerial.print(DDM_OFF);  delay(250);
  gpsSerial.print(GGA_ON);  delay(250);
  gpsSerial.print(GLL_OFF);  delay(250);
  gpsSerial.print(GSA_OFF);  delay(250);
  gpsSerial.print(GSV_OFF);  delay(250);
  gpsSerial.print(RMC_OFF);  delay(250);
  gpsSerial.print(VTG_OFF);  delay(250);
  gpsSerial.print(WAAS_OFF);  delay(250);

  int done = 0;
  while(!done){
    readline(); // this reads serial input and updates the buffer
    if(strncmp(buffer, "$GPGGA",6) == 0){
      Serial.print(millis()); Serial.print(","); Serial.println(buffer);
      outfile.print(millis()); outfile.print(","); outfile.println(buffer);
      done = 1;
    }
  }
}

/////////////////////////////////////////////////////////////////////
void readline() { // this reads serial input and updates the buffer
  char c;
  uint8_t bufferidx = 0;
  digitalWrite(red, HIGH);
  int n = 0;
  while (1) {
    n++; if(n > 10000){break;}
    if(gpsSerial.available()){
      c = gpsSerial.read();
      if (c == -1){
        continue;
      }
      if (c == '\n'){
        continue;
      }
      if ((bufferidx == 90-1) || (c == '\r')) { // buffer size 90
        buffer[bufferidx] = 0;
        return;
      }
      buffer[bufferidx++]= c;
    }
    else{
    }
  }
  digitalWrite(red, LOW);
  digitalWrite(green, HIGH);
} // end of readline

Full code:

// user settings

#define SAMPLE_INT 25   // number of ms between samples
#define FLUSH_INT 1000  // number of ms between writing buffer to SD
#define USE_SERIAL 1 // if 1, print info to serial connection at 115200
#define AREF 3.3 // 
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

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

// digital pins for LEDs
#define red 6
#define green 5

// measurement pins
#define CHAN1_PIN 0 
#define CHAN2_PIN 1 
#define CHAN3_PIN 2
#define CHAN1_GND 3 // these are for the pins fixed at 0 volts 
#define CHAN2_GND 4
#define CHAN3_GND 5

#define POWERPIN 7 // for GPS
#define CHIPSELECT 10 // required for SD card use

// Vcc measurement stuff
#define BANDGAPREF 14 // special indicator that we want to measure the bandgap
#define aref_voltage 3.3 // we tie 3.3V to ARef and measure it with a multimeter!
#define bandgap_voltage 1.1 // this is not super guaranteed but its not -too- off

// initialize global variables
uint32_t t = 0;
uint32_t lastflush = 0; 
File outfile;
SoftwareSerial gpsSerial = SoftwareSerial(3, 4);
char buffer[90];
volatile uint32_t pps = 0;
/////////////////////////////////////////////////////////////////////

void readline() { // this reads serial input and updates the buffer
  char c;
  uint8_t bufferidx = 0;
  digitalWrite(red, HIGH);
  int n = 0;
  while (1) {
    n++; if(n > 10000){break;}
    if(gpsSerial.available()){
      c = gpsSerial.read();
      if (c == -1){
        continue;
      }
      if (c == '\n'){
        continue;
      }
      if ((bufferidx == 90-1) || (c == '\r')) { // buffer size 90
        buffer[bufferidx] = 0;
        return;
      }
      buffer[bufferidx++]= c;
    }
    else{
    }
  }
  digitalWrite(red, LOW);
  digitalWrite(green, HIGH);
} // end of readline

/////////////////////////////////////////////////////////////////////
void query(){
  gpsSerial.begin(4800); // 4800 baud rate
		// send instructions to GPS about data needed
  gpsSerial.print(SERIAL_SET);  delay(250);
  gpsSerial.print(DDM_OFF);  delay(250);
  gpsSerial.print(GGA_ON);  delay(250);
  gpsSerial.print(GLL_OFF);  delay(250);
  gpsSerial.print(GSA_OFF);  delay(250);
  gpsSerial.print(GSV_OFF);  delay(250);
  gpsSerial.print(RMC_OFF);  delay(250);
  gpsSerial.print(VTG_OFF);  delay(250);
  gpsSerial.print(WAAS_OFF);  delay(250);

  int done = 0;
  while(!done){
    readline(); // this reads serial input and updates the buffer
    if(strncmp(buffer, "$GPGGA",6) == 0){
      Serial.print(millis()); Serial.print(","); Serial.println(buffer);
      outfile.print(millis()); outfile.print(","); outfile.println(buffer);
      done = 1;
    }
  }
}

/////////////////////////////////////////////////////////////////////
void error(char *str)
{
#if USE_SERIAL
  Serial.print("error: ");
  Serial.println(str);
#endif
  outfile.println(); outfile.println(str);
  outfile.flush();
  digitalWrite(red, HIGH);
  while(1);
}
void PPS(void)
{
  pps++;
}
/*
ISR(INT0_vect)
{
  pps++;
}
*/
//////////////////////////////////////////////////////////////////////
void setup(void)
{
  
  // start LEDs
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  
  // start ground pins for analog channels
  analogWrite(CHAN1_GND, 0);
  analogWrite(CHAN2_GND, 0);
  analogWrite(CHAN3_GND, 0);
  
  // start serial connection, if necessary
#if USE_SERIAL
  Serial.begin(115200);
  Serial.println();
  Serial.print("SD card setup...");
#endif


  // setup card
  pinMode(CHIPSELECT, OUTPUT);
  if(!SD.begin(CHIPSELECT)){
    error("No SD card detected!");
  }

#if USE_SERIAL
  Serial.print("detected...");
#endif

  // create a new file
  char filename[] = "RECORD00.txt";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i/10 + '0';
    filename[7] = i%10 + '0';
    if (! SD.exists(filename)) {
      // only open a new file if it doesn't exist
      outfile = SD.open(filename, FILE_WRITE);
      break; // leave the loop!
    }
  }
  
  if(!outfile) {
    error("Failed to open file!");
  }

#if USE_SERIAL
  Serial.print("writing to file ");
//  Serial.println(filename);
#endif

  // GPS stuff:
  pinMode(3, INPUT);
  pinMode(4, OUTPUT);
  pinMode(POWERPIN, OUTPUT);
  digitalWrite(POWERPIN, LOW);

    // set a PPS interrupt (pin 2)
/*  EICRA = _BV(ISC01);          //external interrupt on falling edge
  EIFR = _BV(INTF0);           //clear the interrupt flag
  EIMSK = _BV(INT0);           //enable external interrupt
  */
  
  Serial.println("Ready!");
  delay(2000);

  query(); // request GPS time
  attachInterrupt(0, PPS, RISING);
  
  outfile.println("time(ms),chan1,chan2,chan3,vcc,ppstime");
#if USE_SERIAL
  Serial.println("time(ms),chan1,chan2,chan3,vcc,ppstime,flush");
#endif 
 
}

void loop(void)
{
  // delay for the amount of time we want between readings
  if((millis() - t) < SAMPLE_INT){ // JFA 2013/1/25 14:28--try to avoid skipped samples by only delaying if it hasn't already reached the next one
    delay((SAMPLE_INT - 1) - (millis() % SAMPLE_INT));
  }
  
  // log milliseconds since starting
  t = millis();
  outfile.print(t); outfile.print(", "); 

#if USE_SERIAL
  Serial.print(t); Serial.print(", "); 
#endif
  
  // read analog channels
  analogRead(CHAN1_PIN); delay(1); int chan1 = analogRead(CHAN1_PIN);
  analogRead(CHAN2_PIN); delay(1); int chan2 = analogRead(CHAN2_PIN);
  analogRead(CHAN3_PIN); delay(1); int chan3 = analogRead(CHAN3_PIN);
  
  // Log the estimated 'VCC' voltage by measuring the internal 1.1v ref
  analogRead(BANDGAPREF); delay(1); int refReading = analogRead(BANDGAPREF);
  float supplyvoltage = (bandgap_voltage * 1024) / refReading;
 
  // write to SD card buffer
  outfile.print(chan1); outfile.print(",");
  outfile.print(chan2); outfile.print(",");
  outfile.print(chan3); outfile.print(",");
  outfile.print(supplyvoltage); outfile.print(",");
  outfile.print(pps);
  outfile.println();
  
  // write to the serial connection
#if USE_SERIAL
  Serial.print(chan1); Serial.print(",");
  Serial.print(chan2); Serial.print(",");
  Serial.print(chan3); Serial.print(",");
  Serial.print(supplyvoltage); Serial.print(",");
  Serial.print(pps);
#endif 

 
  // check to see if it's time to flush SD buffer.  If yes, flush it.  This transfers 2048 bytes.
  if ((millis() - lastflush) < FLUSH_INT){
#if USE_SERIAL
  Serial.println(",0");
#endif 
  }
  else{
    lastflush = millis();
  
    // blink red LED to indicate flush
    digitalWrite(red, HIGH);
    outfile.flush();
    digitalWrite(red, LOW);
  #if USE_SERIAL
    Serial.println(",1");
  #endif 
  }
}

The dependency GPSconfig.h is attached.

GPSconfig.h (1.8 KB)