GPS code integrated with other functions...

Hello all,

I am working on a school project with a couple of my peers and I have a problem with the GPS data printing out improperly every loop when I integrate the code with their code. I believe it is all timing related but I am wondering if someone can help me or point me in the right direction to force the code to hold of in the main loop (or the GPS function) until the GPS data is read, parsed, formatted and printed out to the serial port once and properly. I've tried using a while loop but when I do, the code stays on the GPS function all the time. Please disregard all the millis() code, I wrote all those in to check timing on all the functions...

I believe I can use a while loop or a do-while loop but I am not sure how to implement this. Basically, I need the main loop to run and wait for a valid GPS sentence to be read, parsed, formatted and printed on the serial port when it reaches the serialGPS() function.

The GPS will print out GPS coordinates when the "if (strncmp(buffer, "$GPRMC",6) == 0)" condition is met. However, there are instances when I get invalid coordinates:

Lattitude: 111° 2' 32.87"
Longitude: 0° 0' 0.0"

Lattitude: 8° 12' 0.0"
Longitude: 0° 0' 0.0"

Lattitude: 0° 34' 1.22"
Longitude: 3° 22' 0.0"

Once I change the condition to "while (strncmp(buffer, "$GPRMC",6) == 0)" I get good results as listed below. However It stay in this infinite loop.

Lattitude: 32°N 21' 0.13"
Longitude: 111°W 2' 32.97"

Lattitude: 32°N 21' 0.13"
Longitude: 111°W 2' 32.97"

Lattitude: 32°N 21' 0.13"
Longitude: 111°W 2' 32.97"

Lattitude: 32°N 21' 0.13"
Longitude: 111°W 2' 32.97"

I've tried using a break; but it functions similarly as if I was using the if condition. I also used various baud rates and refresh rates on the GPS but I had not luck. Below is the code I am using with regards to the GPS and the main loop. Any help with this is greatly appreciated!

void loop()
{
  start=millis();
  systemInit(); 
  finished=millis();
  Serial.println("Finished");
  elapsed=finished-start;
  Serial.print(elapsed);
  Serial.println(" milliseconds for System Initialization");
  Serial.println();
  delay(2000);

  while(1)
  {  
    start=millis();
    function1();
    function2();
    function3();
    function4();
    serialGPScomm();
    finished=millis();
    Serial.print("Finisihed");
    Serial.println();
    elapsed=finished-start;
    Serial.print(elapsed);
    Serial.println(" milliseconds for Main Loop");
    Serial.println();
  }
}    

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

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;
  finished=millis();
  Serial.println("Finished");
  elapsed=finished-start;
  Serial.print(elapsed);
  Serial.println(" milliseconds for readline() function");
}

void serialGPScomm()
{
  start=millis();
  uint32_t tmp;
  readline();
  
  //Check if $GPRMC sentence type
  if (strncmp(buffer, "$GPRMC",6) == 0) {
    
  //HHMMSS Time Stamp
  parseptr = buffer+7;
  tmp = parsedecimal(parseptr);
  hour = tmp / 10000;
  minute = (tmp / 100) % 100;
  second = tmp % 100;
    
  parseptr = strchr(parseptr, ',') + 1;
  status = parseptr[0];
  parseptr += 2;
    
  //Acquire Latitude & Longitude data
  
  //Latitude
  latitude = parsedecimal(parseptr);
  if (latitude != 0) 
  {
    latitude *= 10000;
    parseptr = strchr(parseptr, '.')+1;
    latitude += parsedecimal(parseptr);
  }
  
  parseptr = strchr(parseptr, ',') + 1;
  
  //Read Latitude N/S data
  if (parseptr[0] != ',')
  {
    latdir = parseptr[0];
  }
    
  //Longitude
  parseptr = strchr(parseptr, ',')+1;
  longitude = parsedecimal(parseptr);
  if (longitude != 0)
  {
    longitude *= 10000;
    parseptr = strchr(parseptr, '.')+1;
    longitude += parsedecimal(parseptr);
  }
  
  parseptr = strchr(parseptr, ',')+1;
  
  //Read longitude E/W data
  if (parseptr[0] != ',') 
  {
    longdir = parseptr[0];
  }
    

  //Groundspeed
  parseptr = strchr(parseptr, ',')+1;
  groundspeed = parsedecimal(parseptr);

  //Track angle
  parseptr = strchr(parseptr, ',')+1;
  trackangle = parsedecimal(parseptr);

  //Date
  parseptr = strchr(parseptr, ',')+1;
  tmp = parsedecimal(parseptr);
  date = tmp / 10000;
  month = (tmp / 100) % 100;
  year = tmp % 100;
  
  //Output GPS information 
  
// GPS data processed and formated for Display
  
  Serial.print("\n\n");  
  Serial.print("\t");
  Serial.print("Lattitude: \t");
  Serial.print(latitude/1000000, DEC); Serial.print((char)176); 
  if (latdir == 'N')
  {
    Serial.print('N');
  }
  else if (latdir == 'S')
  Serial.print('S');
  Serial.print(' ');
  Serial.print((latitude/10000)%100, DEC); Serial.print('\''); Serial.print(' ');
  Serial.print((latitude%10000)*6/1000, DEC); Serial.print('.');
  Serial.print(((latitude%10000)*6/10)%100, DEC); Serial.print('"'); Serial.print(',');
  Serial.print("\n");
  
  Serial.print("\t");  
  Serial.print("Longitude: \t");
  Serial.print(longitude/1000000, DEC); Serial.print((char)176); 
  if (longdir == 'E')
  {
    Serial.print('E');
  }
  else if (longdir == 'W')
  Serial.print('W');
  Serial.print(' ');
  Serial.print((longitude/10000)%100, DEC); Serial.print('\''); Serial.print(' ');
  Serial.print((longitude%10000)*6/1000, DEC); Serial.print('.');
  Serial.print(((longitude%10000)*6/10)%100, DEC); Serial.println('"');
  Serial.println();
  }
  
  finished=millis();
  Serial.println("Finished");
  elapsed=finished-start;
  Serial.print(elapsed);
  Serial.println(" milliseconds for serialGPS() function");
  Serial.println();
 }

Moderator edit: colour tags replaced by code tags.

The loop() function is called in an infinite loop. When I see someone adding an infinite loop inside loop(), warning bells go off.

The call to systemInit() belongs in setup(), not loop. Then, you wouldn't need the infinite loop in loop().

The TinyGPS library handles accumulating serial data from the GPS, and returning true or false, when the TinyGPS instance has a complete sentence that can be parsed. It does not require a blocking call to read a complete sentence, as your code does. Why are you not using it?

Where is the code for function1(), function2(), etc.?

The while loop inside the void loop is that actual program that runs all the time. Yes, I could put the systemInit() in the void setup section, I just have it in the main loop because it is not really a setup, just some sequencing on a display one of my peers included. As for why I am not using the tinyGPS library, well I just chose not to. I could use it, but everything is already done... The code I have is just me experimenting and trying to learn how to control the code.

Thanks

eliajaz:
Once I change the condition to "while (strncmp(buffer, "$GPRMC",6) == 0)" I get good results as listed below. However It stay in this infinite loop.

  readline();

  //Check if $GPRMC sentence type
  if (strncmp(buffer, "$GPRMC",6) == 0) {

You aren't re-reading the line, so of course it will repeat the same data.

    function1();
    function2();
    function3();
    function4();

Better function names please. Next you will be using variable1, variable2, variable3, and so on.

  while(1)
  {  
  }

I agree with PaulS here. Restructure so that setup goes in setup, then you don't have to have a loop inside loop.

  while (1) {
    c=Serial1.read();
    if (c == -1)
      continue;

Better read up on Serial1.available().

Thanks for the feedback...

Actually, I did read up on the Serial1.available and am familiar with how it works. I am simply avoiding reading the data in the main loop, modular code approach for easier code integration with my teammates... I know that most put setup stuff in the void setup() similar to what I would do in the systemInit() call. This is the way we have it setup in the code for the actual system we are working on. However, there is nothing wrong with it in the void loop(), works just fine to run everything and see it in the serial monitor do to the fact that I don't have a lot of the hardware that is setup or tested in the systemInit, again test purposes. As for the issue I was having "The GPS will print out GPS coordinates when the "if (strncmp(buffer, "$GPRMC",6) == 0)" condition is met. However, there are instances when I get invalid coordinates: ", I was able to correct the problem by using a do, while loop... Just as I predicted, it worked like a charm... Basically, I scan the data until the delimiter I am looking for comes in and then I process the data. The only thing left to do is include a time out in the event no data is being received from the GPS. Tiny GPS library is great, learn a lot from it as well. I just felt this implementation gave me the opportunity to work with the data more thats all... Thanks again!

static void serialGPScomm()
{
//start=millis();
uint32_t tmp;

do
{
readline();

} while (strncmp(buffer, "$GPRMC",6) != 0);
//Check if $GPRMC sentence type
if (strncmp(buffer, "$GPRMC",6) == 0) {

...

}

The blue link to the library on this page makes things much easier: