GPS Clock

Hey yall,

This is my first post here. I am very new to the arduino community, and development in general. My first project is a GPS Clock that alternates between Time and Date. And also toggles a letter in the corner from A to V, depending on the validity of the fix, and outputs serial data to a SerLCD. My problem is when the GPS has a valid lock the date changes from the correct date 9/8/10 to 0/0/7 or 0/0/5 or something like that. Once it looses its fix the date goes back to normal. I think it has to do with how I am parsing the NMEA statement. I got the bulk of the code from a ladyada project on her site. I cut out all the Long Lat statements.

Here is the code im using…

// A simple sketch to read GPS data and parse the $GPRMC string 
// see for more info

#include <NewSoftSerial.h>

NewSoftSerial mySerial =  NewSoftSerial(2, 3);
#define powerpin 4
int LedPin = 13;
#define GPSRATE 4800
//#define GPSRATE 38400


// GPS parser for 406a
#define BUFFSIZ 90 // plenty big
char buffer[BUFFSIZ];
char *parseptr;
char buffidx;
uint8_t hour, minute, second, year, month, date;
uint32_t latitude, longitude;

char latdir, longdir;
char status;

long previousMillis = 0; 
long interval = 6000;   
void setup() 
{ 
pinMode(LedPin, OUTPUT);
  
  if (powerpin) {
    pinMode(powerpin, OUTPUT);
  }
  pinMode(13, OUTPUT);
  Serial.begin(9600);
  mySerial.begin(GPSRATE); 
  // prints title with ending line break 
Serial.print(0x7C, BYTE); 
Serial.print(157, BYTE);
delay(500);
Serial.print(0xFE, BYTE);
Serial.print(0x01, BYTE);
Serial.print(0xFE, BYTE);
Serial.print(128, BYTE);
Serial.print("GPS parser");
Serial.print(0xFE, BYTE);
Serial.print(191, BYTE);
Serial.print("By: Burns");
 delay(1000);

   digitalWrite(powerpin, LOW);         // pull low to turn on!
} 
 
 
void loop() 
{ 
  uint32_t tmp;
  
  //Serial.print("\n\rread: ");
  readline();
  
  // check if $GPRMC (global positioning fixed data)
  if (strncmp(buffer, "$GPRMC",6) == 0) {

    
    // hhmmss time data
    parseptr = buffer+7;
    tmp = parsedecimal(parseptr); 
    hour = tmp / 10000;
    minute = (tmp / 100) % 100;
    second = tmp % 100;
   
 //fix data 
    parseptr = strchr(parseptr, ',') + 1;
    status = parseptr[0];
    parseptr += 2;

    
    // date
    parseptr = strchr(parseptr, ',')+7;
    tmp = parsedecimal(parseptr); 
    date = tmp / 10000;
    month = (tmp / 100) % 100;
    year = tmp % 100;
    
  

    

      if (millis() - previousMillis > interval) 
    {
    previousMillis = millis(); 
    Serial.print(0xFE, BYTE);
    Serial.print(0x01, BYTE);
    Serial.print("DATE");
    Serial.print(0xFE, BYTE);
    Serial.print(191, BYTE);
    Serial.print(date, DEC);
    Serial.print('/');
    Serial.print(month, DEC);
    Serial.print('/');
    Serial.print(year, DEC);
        Serial.print(0xFE, BYTE);
    Serial.print(143, BYTE);
    Serial.print(status);
    delay(2000);
  }
    else{
      Serial.print(0xFE, BYTE);
   Serial.print(0x01, BYTE);
   Serial.print("TIME -ZULU-");
    Serial.print(0xFE, BYTE);
    Serial.print(191, BYTE);
    Serial.print(hour, DEC); Serial.print(':');
    Serial.print(minute, DEC); Serial.print(':');
    Serial.print(second, DEC);
        Serial.print(0xFE, BYTE);
    Serial.print(143, BYTE);
    Serial.print(status);
  }   
   
    if
      (status == 'A')
      
     digitalWrite(LedPin, HIGH);
    }
    else{
      digitalWrite(LedPin, LOW);
    }

   
  }
  //Serial.println(buffer);
}

uint32_t parsedecimal(char *str) {
  uint32_t d = 0;
  
  while (str[0] != 0) {
   if ((str[0] > '9') || (str[0] < '0'))
     return d;
   d *= 10;
   d += str[0] - '0';
   str++;
  }
  return d;
}

void readline(void) {
  char c;
  
  buffidx = 0; // start at begninning
  while (1) {
      c=mySerial.read();
      if (c == -1)
        continue;
      //Serial.print(c);
      if (c == '\n')
        continue;
      if ((buffidx == BUFFSIZ-1) || (c == '\r')) {
        buffer[buffidx] = 0;
        return;
      }
      buffer[buffidx++]= c;
  }

}

Thanks guys,
Steven

In parsedecimal, you have this:

while (str[0] != 0)

When reading the data from the GPS, you do not NULL terminate the string, so str will not point to NULL (which should be represented as '\0', not 0) until str has advanced beyond the end of the space allocated for the array.

Have you tried printing the entire GPS string, to verify that you are extracting the right part as the time and date?

Have you tried printing the string passed to parsedecimal to make sure that the data you want to extract is really at the start of the string?

Have you tried printing the value returned by parsedecimal to see if it is reasonable?