Notes About Working with Various Arduino & Netduino Microcontroller Boards

Saturday, June 15, 2013

Adafruit Ultimate GPS Breakout & the Arduino Due

I've been fiddling around the last few days with various GPS modules, including the Adafruit Ultimate GPS Breakout (v. 3). The notes below cover the use of this GPS module with the Arduino Due. This example parses the $GPRMC NMEA sentence and pulls out the N latitude and W longitude. The output is formatted as degrees, minutes, and seconds.  To keep the example simple, the output just goes to the serial console.

I haven't gone mobile with the application yet.  To help with GPS reception at my desk, I am using this external cable antenna and antenna adapter.


Connections


GPS Breakout  Arduino Due
TX            D19 (RX1)
RX            D18 (TX1)
GND           GND
VIN           3.3V 

The Arduino Due's Serial2 (pins RX2, TX2) or Serial3 (pins RX3, RX3) could also be used.

Code


#include <string.h>

// variable for NMEA sentence 
String sentence = "";

void setup() {
  // For output to serial monitor
  Serial.begin(9600);
  // Connection to GPS
  Serial1.begin(9600);
}

void loop() {
  if (Serial1.available() > 0) {
    char c = Serial1.read();
    // Check if end of NMEA sentence
    if(c == '\n') {
      // Check if $GPRMC NMEA sentence
      if(sentence.startsWith("$GPRMC")) {
        char data[150];
        char *dataPtr = data;
        char *value; 
        sentence.toCharArray(data, sentence.length());
        int i = 0;
        // Tokenize each line into values using comma delimiter.
        // Returns NULL when no more tokens.
        // strtok_r is part of C standard library.
        while ((value = strtok_r(dataPtr, ",", &dataPtr)) != NULL) { 
          // 4th value is north latitude, 6th is west longitude
          if(i == 3 || i == 5) {
            int degMin = atoi(value);
            int degree = (int) degMin / 100;
            int minutes = degMin - (degree * 100);
            float seconds = (float) (atof(value) - (float) degMin) * 60.0;
            String label;
            if(i == 3)
              label = " N";
            else
              label = " W";  
            char secBuffer[6];
            dtostrf(seconds, 6, 3, secBuffer);
            char location[100];
            sprintf(location, "%02d\xB0 %02d' %s\"", degree, minutes, secBuffer);
            Serial.println(location + label);
          } 
          i++;
        }
        Serial.println();
      }
      sentence = "";
    }
    else {
      // Append character if not end of sentence
      sentence += c;
    }
  }
}

// Arduino IDE libraries do not include dtostrf() 
char *dtostrf (double val, signed char width, unsigned char prec, char *sout) {
  char fmt[20];
  sprintf(fmt, "%%%d.%df", width, prec);
  sprintf(sout, fmt, val);
  return sout;
}


4 comments:

  1. Hi Brad, I'm working on a similar project. Thanks for sharing.

    ReplyDelete
  2. yhank you I now need to extract other data...

    ReplyDelete
  3. Brad - I know this is a old post but.... is there a way with the DUE to call that loop routine in a function off a interrupt (I know DUE doesn't do interrupts like the AVR versions...
    I was using SIGNAL(TIMER0_COMPA_vect) but that doesn't work anymore...

    ReplyDelete