TinyGPS Library

TinyGPS, by Mikal Hart, converts NEMA format global positioning data into easy-to-use variables for Latitude, Longitude, Time and other information.

Download: Included with the Teensyduino Installer
Latest Developments on Github

Hardware Requirements

TinyGPS only converts data. You must use UART Serial or NewSoftSerial or some other way to obtain the NEMA format data to feed into TinyGPS. Even though TinyGPS doesn't require any hardware, in practice, you will need a GPS module for the data source.


In this photo, a PMB-648 GPS module from Parallax was used. Since these GPS modules can run from either 5 or 3.3 volt power, and they feature TTL level serial signals that can connect directly to the Teensy's RX and TX pins, connecting them to Teensy is very easy.


For use with Teensy 3.0, most GPS modules output a 3.3 volt "TTL level" signal, even when powered from 5 volts.


TTL level output is actually 2.8 volts, even with 5V power.

Basic Usage

TinyGPS gps

Create the TinyGPS object, giving it a name of your choice. While you could create multiple TinyGPS objects, it's unlikely you would need to decode more than one NEMA format data stream.

gps.encode(c)

Each byte of NEMA data must be giving to TinyGPS by using encode(). True is returned when new data has been fully decoded and can be used.

gps.get_position(&latitude, &longitude, &age)

Get the position, where latitude and longitude are variables of long type, and the values are multiplied by 10,000. The age variable must be unsigned long type.

gps.f_get_position(&flatitude, &flongitude, &age)

Get the position, where latitude and longitude are variables of float type, and the actual values are returned. Float types are easier to use, but result in larger and slower code. The age variable must be unsigned long type.

Many other variables can be obtained. Please refer to the official TinyGPS page for complete documentation, or the example code to see how these are used.

Example Program


This example is a slightly modified version of the test program that comes in the examples directory with TinyGPS. It uses Teensy's real serial port (UART) instead of NewSoftSerial. Teensy also can transmit data rapidly on USB, so extra checking for input data that would be needed on Arduino's slow Serial object has been removed.

#include <TinyGPS.h>

/* This sample code demonstrates the normal use of a TinyGPS object. */
TinyGPS gps;

/* On Teensy, the UART (real serial port) is always best to use. */
/* Unlike Arduino, there's no need to use NewSoftSerial because */
/* the "Serial" object uses the USB port, leaving the UART free. */
HardwareSerial Uart = HardwareSerial();

void gpsdump(TinyGPS &gps);
void printFloat(double f, int digits = 2);

void setup()
{
  Serial.begin(115200);
  Uart.begin(4800);
  
  delay(1000);
  Serial.print("Testing TinyGPS library v. "); Serial.println(TinyGPS::library_version());
  Serial.println("by Mikal Hart");
  Serial.println();
  Serial.print("Sizeof(gpsobject) = "); Serial.println(sizeof(TinyGPS));
  Serial.println();
}

void loop()
{
  bool newdata = false;
  unsigned long start = millis();

  // Every 5 seconds we print an update
  while (millis() - start < 5000) {
    if (Uart.available()) {
      char c = Uart.read();
      // Serial.print(c);  // uncomment to see raw GPS data
      if (gps.encode(c)) {
        newdata = true;
        // break;  // uncomment to print new data immediately!
      }
    }
  }
  
  if (newdata) {
    Serial.println("Acquired Data");
    Serial.println("-------------");
    gpsdump(gps);
    Serial.println("-------------");
    Serial.println();
  }
}

void gpsdump(TinyGPS &gps)
{
  long lat, lon;
  float flat, flon;
  unsigned long age, date, time, chars;
  int year;
  byte month, day, hour, minute, second, hundredths;
  unsigned short sentences, failed;

  gps.get_position(&lat, &lon, &age);
  Serial.print("Lat/Long(10^-5 deg): "); Serial.print(lat); Serial.print(", "); Serial.print(lon); 
  Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");
  
  // On Arduino, GPS characters may be lost during lengthy Serial.print()
  // On Teensy, Serial prints to USB, which has large output buffering and
  //   runs very fast, so it's not necessary to worry about missing 4800
  //   baud GPS characters.

  gps.f_get_position(&flat, &flon, &age);
  Serial.print("Lat/Long(float): "); printFloat(flat, 5); Serial.print(", "); printFloat(flon, 5);
  Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");

  gps.get_datetime(&date, &time, &age);
  Serial.print("Date(ddmmyy): "); Serial.print(date); Serial.print(" Time(hhmmsscc): ");
    Serial.print(time);
  Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");

  gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
  Serial.print("Date: "); Serial.print(static_cast<int>(month)); Serial.print("/"); 
    Serial.print(static_cast<int>(day)); Serial.print("/"); Serial.print(year);
  Serial.print("  Time: "); Serial.print(static_cast<int>(hour)); Serial.print(":"); 
    Serial.print(static_cast<int>(minute)); Serial.print(":"); Serial.print(static_cast<int>(second));
    Serial.print("."); Serial.print(static_cast<int>(hundredths));
  Serial.print("  Fix age: ");  Serial.print(age); Serial.println("ms.");

  Serial.print("Alt(cm): "); Serial.print(gps.altitude()); Serial.print(" Course(10^-2 deg): ");
    Serial.print(gps.course()); Serial.print(" Speed(10^-2 knots): "); Serial.println(gps.speed());
  Serial.print("Alt(float): "); printFloat(gps.f_altitude()); Serial.print(" Course(float): ");
    printFloat(gps.f_course()); Serial.println();
  Serial.print("Speed(knots): "); printFloat(gps.f_speed_knots()); Serial.print(" (mph): ");
    printFloat(gps.f_speed_mph());
  Serial.print(" (mps): "); printFloat(gps.f_speed_mps()); Serial.print(" (kmph): ");
    printFloat(gps.f_speed_kmph()); Serial.println();

  gps.stats(&chars, &sentences, &failed);
  Serial.print("Stats: characters: "); Serial.print(chars); Serial.print(" sentences: ");
    Serial.print(sentences); Serial.print(" failed checksum: "); Serial.println(failed);
}

void printFloat(double number, int digits)
{
  // Handle negative numbers
  if (number < 0.0) {
     Serial.print('-');
     number = -number;
  }

  // Round correctly so that print(1.999, 2) prints as "2.00"
  double rounding = 0.5;
  for (uint8_t i=0; i<digits; ++i)
    rounding /= 10.0;
  
  number += rounding;

  // Extract the integer part of the number and print it
  unsigned long int_part = (unsigned long)number;
  double remainder = number - (double)int_part;
  Serial.print(int_part);

  // Print the decimal point, but only if there are digits beyond
  if (digits > 0)
    Serial.print("."); 

  // Extract digits from the remainder one at a time
  while (digits-- > 0) {
    remainder *= 10.0;
    int toPrint = int(remainder);
    Serial.print(toPrint);
    remainder -= toPrint;
  }
}

Timing Required For Reliable Data

NEMA format GPS data is usually transmitted at 4800 baud, in 8N1 format. The resulting maximum incoming speed is 480 bytes per second. By default, Teensyduino's UART Serial buffers up to 64 bytes, or 0.133 seconds of incoming data.

If your program must perform some operation for more than 0.13 seconds, it should check for new data and give it to TinyGPS with gps.encode() within that time period.

Alternately, the buffer size may be increased. Inside hardware/teensy/cores/teensy/HardwareSerial.cpp, the buffer size is defined with:

  #define RX_BUFFER_SIZE 64
  static volatile uint8_t rx_buffer[RX_BUFFER_SIZE];
  static volatile uint8_t rx_buffer_head = 0;
  static volatile uint8_t rx_buffer_tail = 0;

The buffer may be increased to as much as 255 bytes.

TinyGPS Documentation

The official TinyGPS page by Mikal Hart has very detailed information about using TinyGPS.