GPS Module
with Arduino
d. bodnar revised 03-02-2015
I have been experimenting with a small
GPS module that was purchased from
Amazon for about $25.00. It also
available on
eBay and from
other vendors for nearly half the
price. These units work well and can easily be interfaced to an
Arduino.
|
Hardware Setup There are four connections to the GPS module, VCC (3-5 volts), ground, Transmit (TX) and Receive (RX). The TX and RX are standard serial signals. The default speed is 9600 baud. I have tested this module at both 3.7 and 5 volts. There is a 3.3 volt regulator on the board just under the "VCC RX TX" labels. RX and TX connect to the Arduino TX and RX pins, if hardware serial is being used, or to two other pins, determined in the software, if software serial is used. |
|
Notes on GPS data
sentences:
$GPRMC,122947.00,A,4023.16420,N,08002.99191,W,0.054,,140215,,,A*6C |
|
Software for Testing The program that I used for testing is available in the examples folder for TinyGPS++, a libray that you must install. Note that the RX and TX pins are swapped in this code and the baud rate has been changed from 4800 to 9600. #include <TinyGPS++.h> #include <SoftwareSerial.h> /* This sample code demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object. It requires the use of SoftwareSerial, and assumes that you have a 4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx). */ static const int RXPin = 3, TXPin = 4; // changed from RXPin = 4 and TRPin = 3 static const uint32_t GPSBaud = 9600; // baud rate changed from 4800 // The TinyGPS++ object TinyGPSPlus gps; // The serial connection to the GPS device SoftwareSerial ss(RXPin, TXPin); void setup() { Serial.begin(115200); ss.begin(GPSBaud); Serial.println(F("FullExample.ino")); Serial.println(F("An extensive example of many interesting TinyGPS++ features")); Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion()); Serial.println(F("by Mikal Hart")); Serial.println(); Serial.println(F("Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum")); Serial.println(F(" (deg) (deg) Age Age (m) --- from GPS ---- ---- to London ---- RX RX Fail")); Serial.println(F("---------------------------------------------------------------------------------------------------------------------------------------")); } void loop() { static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002; printInt(gps.satellites.value(), gps.satellites.isValid(), 5); printInt(gps.hdop.value(), gps.hdop.isValid(), 5); printFloat(gps.location.lat(), gps.location.isValid(), 11, 6); printFloat(gps.location.lng(), gps.location.isValid(), 12, 6); printInt(gps.location.age(), gps.location.isValid(), 5); printDateTime(gps.date, gps.time); printFloat(gps.altitude.meters(), gps.altitude.isValid(), 7, 2); printFloat(gps.course.deg(), gps.course.isValid(), 7, 2); printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2); printStr(gps.course.isValid() ? TinyGPSPlus::cardinal(gps.course.value()) : "*** ", 6); unsigned long distanceKmToLondon = (unsigned long)TinyGPSPlus::distanceBetween( gps.location.lat(), gps.location.lng(), LONDON_LAT, LONDON_LON) / 1000; printInt(distanceKmToLondon, gps.location.isValid(), 9); double courseToLondon = TinyGPSPlus::courseTo( gps.location.lat(), gps.location.lng(), LONDON_LAT, LONDON_LON); printFloat(courseToLondon, gps.location.isValid(), 7, 2); const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon); printStr(gps.location.isValid() ? cardinalToLondon : "*** ", 6); printInt(gps.charsProcessed(), true, 6); printInt(gps.sentencesWithFix(), true, 10); printInt(gps.failedChecksum(), true, 9); Serial.println(); smartDelay(1000); if (millis() > 5000 && gps.charsProcessed() < 10) Serial.println(F("No GPS data received: check wiring")); } // This custom version of delay() ensures that the gps object // is being "fed". static void smartDelay(unsigned long ms) { unsigned long start = millis(); do { while (ss.available()) gps.encode(ss.read()); } while (millis() - start < ms); } static void printFloat(float val, bool valid, int len, int prec) { if (!valid) { while (len-- > 1) Serial.print('*'); Serial.print(' '); } else { Serial.print(val, prec); int vi = abs((int)val); int flen = prec + (val < 0.0 ? 2 : 1); // . and - flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1; for (int i=flen; i<len; ++i) Serial.print(' '); } smartDelay(0); } static void printInt(unsigned long val, bool valid, int len) { char sz[32] = "*****************"; if (valid) sprintf(sz, "%ld", val); sz[len] = 0; for (int i=strlen(sz); i<len; ++i) sz[i] = ' '; if (len > 0) sz[len-1] = ' '; Serial.print(sz); smartDelay(0); } static void printDateTime(TinyGPSDate &d, TinyGPSTime &t) { if (!d.isValid()) { Serial.print(F("********** ")); } else { char sz[32]; sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year()); Serial.print(sz); } if (!t.isValid()) { Serial.print(F("******** ")); } else { char sz[32]; sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second()); Serial.print(sz); } printInt(d.age(), d.isValid(), 5); smartDelay(0); } static void printStr(const char *str, int len) { int slen = strlen(str); for (int i=0; i<len; ++i) Serial.print(i<slen ? str[i] : ' '); smartDelay(0); }
|
|
Output Example The serial output on the Arduino terminal is shown here. Make sure that you change the baud rate on the terminal to 115200. FullExample.ino An extensive example of many interesting TinyGPS++ features Testing TinyGPS++ library v. 0.92 by Mikal Hart Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum (deg) (deg) Age Age (m) --- from GPS ---- ---- to London ---- RX RX Fail --------------------------------------------------------------------------------------------------------------------------------------- **** **** ********** *********** **** ********** ******** **** ****** ****** ***** *** ******** ****** *** 70 0 0 7 125 40.386100 -80.049896 251 02/15/2015 12:33:04 417 354.50 0.00 0.06 N 5987 49.38 NE 511 2 5 7 125 40.386100 -80.049896 259 02/15/2015 12:33:05 424 354.30 0.00 0.22 N 5987 49.38 NE 953 4 9 7 125 40.386096 -80.049896 267 02/15/2015 12:33:06 432 354.40 0.00 0.20 N 5987 49.38 NE 1395 6 13 7 125 40.386096 -80.049896 277 02/15/2015 12:33:07 442 354.40 0.00 0.11 N 5987 49.38 NE 1836 8 16 7 125 40.386096 -80.049896 286 02/15/2015 12:33:08 452 354.70 0.00 0.04 N 5987 49.38 NE 2277 10 19 7 125 40.386096 -80.049896 292 02/15/2015 12:33:09 458 354.80 0.00 0.04 N 5987 49.38 NE 2718 12 23 7 125 40.386096 -80.049896 303 02/15/2015 12:33:10 467 355.00 0.00 0.13 N 5987 49.38 NE 3159 14 25 7 125 40.386100 -80.049896 312 02/15/2015 12:33:11 476 355.20 0.00 0.06 N 5987 49.38 NE 3600 16 30 7 125 40.386100 -80.049896 319 02/15/2015 12:33:12 485 355.40 0.00 0.11 N 5987 49.38 NE 4042 18 34
|
|
Software revision for LCD and 4800 baud GPS_LCD_Display-v2.ino The software below works well with the GPS unit and an LCD display - note that I had to reduce the baud rate of the GPS from 9600 to 4800 to avoid checksum errors. The baud rate was changed using u-Center software and following the documentation steps to change baud rate. NOTE: I used View / Configuration View / PRT (Ports) - after changing to 4800 it asked if I wanted to write the change. (for the BangGood.com GPS use this program to change the baud rate - see notes in ratings page on BangGood.)
#include <TinyGPS++.h> #include <SoftwareSerial.h> #include <Wire.h> #include <LCD.h> #include <LiquidCrystal_I2C.h> #define I2C_ADDR 0x27 // <<----- Add your address here. Find it from I2C Scanner #define BACKLIGHT_PIN 3 #define En_pin 2 #define Rw_pin 1 #define Rs_pin 0 #define D4_pin 4 #define D5_pin 5 #define D6_pin 6 #define D7_pin 7 int potPin = A3; // select the input pin for the potentiometer int potValue = 0; // variable to store the value coming from the pot byte buffer[10]; LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin); /* This sample code demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object. It requires the use of SoftwareSerial, and assumes that you have a 4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx). */ static const int RXPin = 3, TXPin = 4; static const uint32_t GPSBaud = 4800; // The TinyGPS++ object TinyGPSPlus gps; // The serial connection to the GPS device SoftwareSerial ss(RXPin, TXPin); void setup() { lcd.begin (20, 4); // <<----- My LCD was 16x2 lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE); // Switch on the backlight lcd.setBacklight(HIGH); lcd.home (); // go home lcd.print("GPS Test Display"); lcd.setCursor(0,1); lcd.print("d. bodnar 02-17-15"); lcd.setCursor(0,2); lcd.print("Units = MPH & Feet"); Serial.begin(115200); ss.begin(GPSBaud); Serial.println(F("FullExample.ino")); Serial.println(F("An extensive example of many interesting TinyGPS++ features")); Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion()); Serial.println(F("by Mikal Hart")); Serial.println(); Serial.println(F("Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum")); Serial.println(F(" (deg) (deg) Age Age (m) --- from GPS ---- ---- to London ---- RX RX Fail")); Serial.println(F("---------------------------------------------------------------------------------------------------------------------------------------")); } void loop() { static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002; printInt(gps.satellites.value(), gps.satellites.isValid(), 5); printInt(gps.hdop.value(), gps.hdop.isValid(), 5); printFloat(gps.location.lat(), gps.location.isValid(), 11, 6); printFloat(gps.location.lng(), gps.location.isValid(), 12, 6); printInt(gps.location.age(), gps.location.isValid(), 5); printDateTime(gps.date, gps.time); printFloat(gps.altitude.meters(), gps.altitude.isValid(), 7, 2); printFloat(gps.course.deg(), gps.course.isValid(), 7, 2); printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2); printStr(gps.course.isValid() ? TinyGPSPlus::cardinal(gps.course.value()) : "*** ", 6); unsigned long distanceKmToLondon = (unsigned long)TinyGPSPlus::distanceBetween( gps.location.lat(), gps.location.lng(), LONDON_LAT, LONDON_LON) / 1000; printInt(distanceKmToLondon, gps.location.isValid(), 9); double courseToLondon = TinyGPSPlus::courseTo( gps.location.lat(), gps.location.lng(), LONDON_LAT, LONDON_LON); printFloat(courseToLondon, gps.location.isValid(), 7, 2); const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon); printStr(gps.location.isValid() ? cardinalToLondon : "*** ", 6); printInt(gps.charsProcessed(), true, 6); printInt(gps.sentencesWithFix(), true, 10); printInt(gps.failedChecksum(), true, 9); // Serial.println(); Serial.print(" 6 dig test "); Serial.println(gps.location.lat(), 6); smartDelay(1000); if (millis() > 5000 && gps.charsProcessed() < 10) Serial.println(F("No GPS data received: check wiring")); lcd.clear(); float Satellites = gps.satellites.value(); lcd.setCursor(0, 0); lcd.print("Sat.= "); lcd.print(Satellites, 0); lcd.setCursor(10, 0); float hdop = gps.hdop.value(); lcd.print("dop= "); lcd.print(hdop, 0); lcd.setCursor(0, 1); float SpeedM = gps.speed.mps(); lcd.print("Speed= "); lcd.print(SpeedM, 1); lcd.setCursor(0, 2); float altitude = gps.altitude.feet(); lcd.print("alt.= "); lcd.print(altitude, 0); lcd.setCursor(0, 3); float latitude = gps.location.lat(); lcd.print(latitude, 6); lcd.setCursor(10, 3); float longitude = gps.location.lng(); lcd.print(longitude, 6); } // This custom version of delay() ensures that the gps object // is being "fed". static void smartDelay(unsigned long ms) { unsigned long start = millis(); do { while (ss.available()) gps.encode(ss.read()); } while (millis() - start < ms); } static void printFloat(float val, bool valid, int len, int prec) { if (!valid) { while (len-- > 1) Serial.print('*'); Serial.print(' '); } else { Serial.print(val, prec); int vi = abs((int)val); int flen = prec + (val < 0.0 ? 2 : 1); // . and - flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1; for (int i = flen; i < len; ++i) Serial.print(' '); } smartDelay(0); } static void printInt(unsigned long val, bool valid, int len) { char sz[32] = "*****************"; if (valid) sprintf(sz, "%ld", val); sz[len] = 0; for (int i = strlen(sz); i < len; ++i) sz[i] = ' '; if (len > 0) sz[len - 1] = ' '; Serial.print(sz); smartDelay(0); } static void printDateTime(TinyGPSDate &d, TinyGPSTime &t) { if (!d.isValid()) { Serial.print(F("********** ")); } else { char sz[32]; sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year()); Serial.print(sz); } if (!t.isValid()) { Serial.print(F("******** ")); } else { char sz[32]; sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second()); Serial.print(sz); } printInt(d.age(), d.isValid(), 5); smartDelay(0); } static void printStr(const char *str, int len) { int slen = strlen(str); for (int i = 0; i < len; ++i) Serial.print(i < slen ? str[i] : ' '); smartDelay(0); }
|
|