I built a GPS that displays latitude and longitude on an LCD display with an Arduino.
The project will also display the latitude, longitude and time on the serial monitor of the Arduino IDE when connected by USB. For testing I put everything in a plastic box and powered it with a 9V battery (see photo).
Project photo.

Click to enlarge. Left to right on the breadboard: GPS antenna, GPS module, potentiometer for LCD brightness, LCD display.
Project Fritzing diagram.

Note that the GPS antenna is not shown. I was not able to locate the Fritzing icon for the GPS or antenna.
Project schematic.
None. I was not able to locate the Fritzing icon and Fritzing produced a rats nest for a schematic.
Project sketch.
// GPS displaying lat and lon on LCD and lat, lon and date-time on serial monitor // based on // TinyGPS++ from IDE // LCD example from IDE // September 28, 2018 MGL // Notes // Can be connected via USB for serial monitor output or 9V battery operated for portability in which // case the serial output will go nowhere. #include <TinyGPS++.h> #include <SoftwareSerial.h> #include <LiquidCrystal.h> /* * LCD to Arduino connections LCD pin 4 RS to Arduino digital pin 12 LCD pin 6 E to Arduino digital pin 11 LCD pin 11 D4 to Arduino digital pin 5 LCD pin 12 D5 to Arduino digital pin 4 LCD pin 13 D6 to Arduino digital pin 3 LCD pin 14 D7 to Arduino digital pin 2 LCD pin 5 R/W to GND LCD pin 2 VDD to +5V LCD pin 1 VSS to GND LCD pin 15 A to +5v (backlight) LCD pin 16 K to GND (backlight) 10K potentiometer (for backlight brightness control): one end terminal to +5V one end terminal to GND middle terminal (wiper) to pin 3 VO on LCD */ /* * GPS to Arduino connections GPS TX pin to Arduino RX pin GPS RX pin to Arduino TX pin 9600 baud GPS Vcc pin to +5V GPS GND pin to GND */ // GPS variables and assignments and baud static const int RXPin = 8, TXPin = 7; static const uint32_t GPSBaud = 9600; // The TinyGPS++ object TinyGPSPlus gps; // The serial connection to the GPS device SoftwareSerial ss(RXPin, TXPin); // LCD pins variables and assignments const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2; LiquidCrystal lcd(rs, en, d4, d5, d6, d7); void setup() { Serial.begin(115200); ss.begin(GPSBaud); Serial.println(F("DeviceExample.ino")); Serial.println(F("A simple demonstration of TinyGPS++ with an attached GPS module")); Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion()); Serial.println(F("by Mikal Hart")); Serial.println(); // LCD is 16 columns, 2 rows lcd.begin(16, 2); /* for testing LCD // Print a message to the LCD. lcd.setCursor(0, 0); lcd.print("hello, world"); lcd.setCursor(0, 1); // print the number of seconds since reset: lcd.print(millis() / 1000); */ } void loop() { // This sketch displays information every time a new sentence is correctly encoded. while (ss.available() > 0) if (gps.encode(ss.read())) // call displayInfo() function to print info to serial monitor displayInfo(); // /* // Example code for date and time // lcd.print(gps.date.month()); // lcd.print(F("/")); // lcd.print(gps.date.day()); // lcd.print(F("/")); // lcd.print(gps.date.year()); // lcd.print(F(" ")); // if (gps.time.hour() < 10) Serial.print(F("0")); // lcd.print(gps.time.hour()); // lcd.print(F(":")); // if (gps.time.minute() < 10) Serial.print(F("0")); // lcd.print(gps.time.minute()); // lcd.print(F(":")); // if (gps.time.second() < 10) Serial.print(F("0")); // lcd.print(gps.time.second()); // lcd.print(F(".")); // if (gps.time.centisecond() < 10) Serial.print(F("0")); // lcd.print(gps.time.centisecond()); */ // print info to LCD lcd.setCursor(0, 0); lcd.print("lat "); lcd.print(gps.location.lat(), 6); lcd.setCursor(0, 1); lcd.print("lon "); lcd.print(gps.location.lng(), 6); if (millis() > 5000 && gps.charsProcessed() < 10) { Serial.println(F("No GPS detected: check wiring.")); while(true); } } void displayInfo() { Serial.print(F("Location: ")); if (gps.location.isValid()) { Serial.print(gps.location.lat(), 6); Serial.print(F(",")); Serial.print(gps.location.lng(), 6); } else { Serial.print(F("INVALID")); } Serial.print(F(" Date/Time: ")); if (gps.date.isValid()) { Serial.print(gps.date.month()); Serial.print(F("/")); Serial.print(gps.date.day()); Serial.print(F("/")); Serial.print(gps.date.year()); } else { Serial.print(F("INVALID")); } Serial.print(F(" ")); if (gps.time.isValid()) { if (gps.time.hour() < 10) Serial.print(F("0")); Serial.print(gps.time.hour()); Serial.print(F(":")); if (gps.time.minute() < 10) Serial.print(F("0")); Serial.print(gps.time.minute()); Serial.print(F(":")); if (gps.time.second() < 10) Serial.print(F("0")); Serial.print(gps.time.second()); Serial.print(F(".")); if (gps.time.centisecond() < 10) Serial.print(F("0")); Serial.print(gps.time.centisecond()); } else { Serial.print(F("INVALID")); } Serial.println(); }
Project parts list.
(1) GPS – NEO-6M (for example: DIYmall GPS Module NEO-6M Antenna Receiver 3V-5V 9600 Baud Rate Arduino Quadcopter Drone Speedometer at Amazon for about $20USD https://a.co/d/6Zxl9C3)
(1) LCD – 16 x 2 display
(1) Potentiometer – 10k
Arduino.
Breadboard and jumpers.
9V battery and lead optional for portable use.
Project notes.
Some of the wire colors in the photo do not match the Fritzing diagram as I ran out of red and black jumpers.
I found the accuracy to be about 10 feet.
Hello Mark.
I am trying to do the same project except my LCD display is a control shield.
Mikal’s code works without the shield, but produces asterisks instead of data when I have the shield installed.
I am wondering if the shield somehow clashes with Mikal’s code. Will explore.
Hi John,
I think that would be a good troubleshooting step.
The shield probably has fixed assignments for Input/Output. The program can be modified to match the IO assignments for the shield required for the LCD. Maybe the datasheet for the shield will state the IO pin assignments.
I am new to Arduino and modules and spend a lot of time troubleshooting my projects.
Good luck.
Mark
Hi Mark
You were spot on. I had to solder pins into the holes alongside the mounting pins of the shield. Some of these holes connect to the adjacent mounting pin; some go elsewhere. The data sheet, looking at the traces in the PCB & using a connectivity meter helped me work it out. A good exercise.
Everything’s working for me. Learned much from Mikal’s instructions. I’ve made a speedometre. Am pleased with the accuracy & responsiveness. Will use the control pins to change display to long & lat or perhaps a trip meter.
Thanks for your example, Mark.
John.
Hi Mark.
Yes, I had to work out where the holes where I soldered in new pins connected to.
All good now.
I’ve made a speedometer. Great performance.
John.
Hi John,
Well done. Extending it to a speedometer, GPS and trip meter is even better.
Glad my notes were helpful. I learn the best things from people sharing their experiences and instructional webs sites. And trouble shooting my mistakes.
Fellow maker,
Mark
Mark,
I’ve connected a piezo buzzer that sounds when the speed goes over the various speed zones we have on our roads, 40,50,60,…110 kph. If going 0-3kph over any of those limits and the speed is increasing then the buzzer sounds. ‘m really surprised at the GPS’s responsiveness.
Now I want to make a permanent device using a Nano board assemble in a case.
Have you made use of the TinyGPS++ functions: charsProcessed() and sentencesWithFix() ? These can tell you if you’re getting corrupted messages from the GPS receiver.
May i know how long does this device will running by using 9V battery as power source? can it hold for approximately 3~4 hrs?
Hi Khairil,
I tried a 9v battery as the power source and it did not last for 1 hour. I believe the 9v battery does not have enough power for this project. The Arduino, LCD display, and GPS all require power.
I would recommend a power bank and USB cable for longer use.
Good luck with your projects.
Mark