So many GPS receivers nowadays keep the consumer far removed from the data that they use.  I wanted to get a GPS receiver module but most of them were more than I was willing to spend for a part that I didn't actually have a project for.  SparkFun started selling the GP-635T, which seems to do as much as the more expensive modules but is the least expensive one I've seen so far, and it has a super-simple TTL interface that spits out standard NMEA sentences.

First Version

At first I tried to hook it up using Arduino's SoftwareSerial library, but even at 9600 baud a bunch of data was getting lost.  I plugged the -635's TX straight into the Arduino's RX and all of the sudden I was getting all the data as clean as could be.  The only problem with using the hardware UART is that it's shared with the USB port, so I can't really have any two-way communication.  On the Arduino I used one line of code (other than initialization stuff):

if (Serial.available() ) Serial.write(Serial.read() );

Anything that the -635 gave me I spat right back to the USB port (I didn't hook up the -635's RX pin, so I wasn't echoing data back to it).  This worked perfectly well to give a computer program all of the data that was being produced by the -635, but, honestly, if I wanted a USB GPS receiver I could have just gotten the GP-635U instead of the -635T.  For the time being, though, I focused on developing the computer program to display all of the data.

Up to 12 satellites can be used in calculating the location, and information about 16 is provided (Satellites used in the calculation are highlighted blue in the above screenshot).

Second Version

Although writing code for Windows programs is fun (I think), I wanted to try to make the Arduino do more of the work. I hooked up a 20x4 LCD screen that I had lying around and processed one of the NMEA sentences on the Arduino.  Since a 20x4 screen doesn't have much room I just focused on the RMC (Recommended Minimum Specific GNSS Data) sentence, which gives you the date, time, location, speed, and heading.

The -635 is in the pink baggie taped to the top right of the board in the picture.  Only one wire is hooked from the -635 to the Arduino (pin 0).  The LCD takes a bunch of pins, but since there's no user input I don't really care.  Later I could add a button or two that would let you change what data are displayed or the units used (it defaults to knots, anything else has to be derived from that).

Most of the data displayed on the LCD are simply passed more-or-less directly from the -635, except for the heading which I convert from angle to cardinal heading (it defaults to N if not moving).  Location is displayed in DDD*MM.MMMMM format.

According to the -635's datasheet, you're supposed to be able to change some settings, such as refresh rate (defaults to 1Hz), baud rate, and so on.  It doesn't say how, though.  I've tried sending some input messages to it, but at best I get an "invalid message" response, and at worst I'm just ignored.  I emailed the manufacturer of the actual GPS unit (u-blox) and they directed me to a couple of not helpful documents.  At least they wrote back promptly.

As for the code on the Aduino, I'm embarrassed about the procedure that digests the GPRMC message.  It's not robust, and it pretty much tears apart the sentence with brute force.  The code I used on the computer version (in VB.NET) is much prettier, more compact, more generic, and more robust.  I do appreciate comments on my code (as long as it's a comment or suggestion, and not just a "here's how you should do it").

Code

#include <LiquidCrystal.h>
String inBuffer = ""; //Buffer to hold incoming serial data
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

void setup(){
Serial.begin(9600); //GP-635T defaults to 9600 8N1
pinMode(13, OUTPUT); //LCD backlight pin
digitalWrite(13, HIGH); //Turn on LCD backlight
lcd.begin(20, 4); //Tell the LiquidCrystal library how big our screen is
}

void loop(){
//If any bytes are available, read them into the buffer
while (Serial.available() > 0){
inBuffer.concat((char)Serial.read() );
}
int msgStart = inBuffer.indexOf('$'); //Find beginning of message
int msgEnd = inBuffer.indexOf("\r\n"); //Find end of message
if ( (msgStart >= 0) && (msgEnd > msgStart) ){ //If we found a beginning and and end and the end is after the beginning...
String curMsg = inBuffer.substring(msgStart, msgEnd+1); //Extract the first message
digestMessage(curMsg); //Process the message we found
inBuffer = inBuffer.substring(msgEnd+1); //Remove the current message from the buffer
}
}

void digestMessage(String toDigest){
Serial.println(toDigest); //Spit all messages back to the USB port for the computer
if (toDigest.startsWith("$GPRMC") ){ //Recommended Minimum Specific GNSS Data
String gpsTime, gpsStatus, gpsLatitude, gpsNS, gpsLongitude, gpsEW, gpsSpeed, gpsCourse, gpsDate; //Raw extracted values
String curTime, curLatitude, curLongitude, curDate; //Reformatted values
int firstComma, secondComma; //Locations of field-separator commas
firstComma = toDigest.indexOf(','); //Find the first comma
secondComma = toDigest.indexOf(',', firstComma+1); //Find the next comma after the first
if ( (secondComma > firstComma) && firstComma >= 0){ //If we found one comma and the second one is after the first one...
gpsTime = toDigest.substring(firstComma+1, secondComma); //Extract the time field
curTime = gpsTime.substring(0,2) + ':' + gpsTime.substring(2,4) + ':' + gpsTime.substring(4,6); //Format the time field (HHMMSS.SSS) to HH:MM:SS
}
/*
* The same process is repeated for the rest of the fields.
* NMEA specifies how many fields are in each message, what is in each field,
* and what order the data appear in, so we can be more-or-less comfortable with
* assuming what data we find in a given field.
* Note that this procedure does not verify the checksum of the sentence...
* something to add in the future.
*/
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsStatus = toDigest.substring(firstComma+1, secondComma);
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsLatitude = toDigest.substring(firstComma+1, secondComma);
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsNS = toDigest.substring(firstComma+1, secondComma);
if ( (gpsLatitude.length() > 4) && (gpsNS.length() > 0) )
curLatitude = gpsLatitude.substring(0,2) + "*" + gpsLatitude.substring(2) + "' " + gpsNS;
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsLongitude = toDigest.substring(firstComma+1, secondComma);
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsEW = toDigest.substring(firstComma+1, secondComma);
if ( (gpsLongitude.length() > 4) && (gpsEW.length() > 0) )
curLongitude = gpsLongitude.substring(0,3) + "*" + gpsLongitude.substring(3) + "' " + gpsEW;
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsSpeed = toDigest.substring(firstComma+1, secondComma);
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0)
gpsCourse = toDigest.substring(firstComma+1, secondComma);
firstComma = toDigest.indexOf(',', secondComma);
secondComma = toDigest.indexOf(',', firstComma+1);
if ( (secondComma > firstComma) && firstComma >= 0){
gpsDate = toDigest.substring(firstComma+1, secondComma);
curDate = gpsDate.substring(2,4) + "/" + gpsDate.substring(0, 2) + "/20" + gpsDate.substring(4);
}
lcd.clear(); //Clear the LCD screen
if (gpsStatus.equals("A") ){ //If we have a valid GPS fix...
//Display the data.
//We have to use setCursor because, for some reason, the LCD library treats the LCD rows as
//0, 2, 1, 3 on a 4-line screen

lcd.print(curDate + " " + curTime);
lcd.setCursor(0, 1);
lcd.print("Lat: " + curLatitude);
lcd.setCursor(0, 2);
lcd.print("Lng: " + curLongitude);
lcd.setCursor(0, 3);
lcd.print(degToCardinal(gpsCourse) + " @ " + gpsSpeed + " knots");
} else {
lcd.print("Invalid GPS Fix"); //GPS reports no fix or an invalid fix
}
}
}

/*

* Converts a degree heading to a cardinal compass heading
*/
String degToCardinal(String degs){
char degsC[64];
float degsF;
degs.toCharArray(degsC, degs.length() + 1);
degsF = atof(degsC);
if (degsF > 337.5)
return "N";
if (degsF > 292.5)
return "NW";
if (degsF > 247.5)
return "W";
if (degsF > 202.5)
return "SW";
if (degsF > 157.5)
return "S";
if (degsF > 112.5)
return "SE";
if (degsF > 67.5)
return "E";
if (degsF > 22.5)
return "NE";
if (degsF >= 0)
return "N";
return "?"; //If, somehow, we didn't find a valid heading (less than zero, perhaps)
}

Views: 448

Tags: Arduino, GP-635T, GPS, LCD

Comment

You need to be a member of GarageLab (arduino, electronics, robotics, hacking) to add comments!

Join GarageLab (arduino, electronics, robotics, hacking)

Latest Activity

Profile IconJordan Hanger , Jason, Thomas Evans and 2 more joined GarageLab (arduino, electronics, robotics, hacking)
3 hours ago
abhishek yadav posted a discussion

how to record time between two events using arduion

i have a disk rotating at variable speed(max rpm 600) . i want to know how much time it takes to…See More
19 hours ago
Danny Vigo updated their profile
20 hours ago
Danny Vigo commented on Fernando Gil's blog post Tutorial: Servomotor + Arduino
"Why would you want to connect them in parallel? Are you trying to increase the current? Perhaps to…"
20 hours ago
Danny Vigo replied to SATYA NARAYANA REDDY NIMMAKAYALA's discussion 5 stepper motor control code
"Well if you look in the examples that come included with the Arduino IDE you can find some code…"
21 hours ago
Profile IconEvaristo Ramos, Jr. and Dayan Martinez joined GarageLab (arduino, electronics, robotics, hacking)
yesterday
Christian Rheinnecker posted a status
"New Video Cypress Hill - Rap Superstar https://www.youtube.com/watch?v=VZSFgdrhzQQ"
yesterday
Christian Rheinnecker posted a video

Arduino PrX : Sequencer AM808 VX3 - Demo Cypress Hill - Rap Superstar Beat Play

Demonstration eines Beats auf dem AM808 VX3 Arduino Midi Sequencer Cypress Hill - Rap Superstar Weiter Infos auf http://arduinoprx.de
yesterday
Christian Rheinnecker posted a status
yesterday
Christian Rheinnecker posted a status
yesterday
Shannon Bradley replied to Dennis Melamed's discussion Little Gem Amp Circuit problems
"Im not sure why people turn to IC's for sound or power. I had this little amp kicking around…"
Friday
GarageLab posted blog posts
Friday
Profile IconWoodison Germain, Weerapong Saipetch, Jasmin Ouellet and 8 more joined GarageLab (arduino, electronics, robotics, hacking)
Friday
Numato Lab updated their profile
Friday
Mark Harrison commented on Thulana Vimukthi's blog post GPS GUIDED AUTONOMOUS ROBOT
"Thulana, very excellent project! It is especially nice, as the hardware connections are relatively…"
Thursday
GarageLab posted a blog post

Make your Thor's Hammer

Rather than being a benign foam hammer, this Mjölnir can summon 80,000 volts of electricity thanks…See More
Wednesday
Profile IconMatthew Brown, David Shepard, Numato Lab and 3 more joined GarageLab (arduino, electronics, robotics, hacking)
Wednesday
Terry Ford updated their profile
Wednesday
GarageLab posted blog posts
Tuesday
Profile Icon►Shannon Code, salomão soares, Jeremy Nelson and 5 more joined GarageLab (arduino, electronics, robotics, hacking)
Tuesday

© 2013   Created by Marcelo Rodrigues.

Badges  |  Report an Issue  |  Terms of Service