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: 2685

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

Comment by Guy Nicholas on December 20, 2013 at 12:17pm

Greetings, I am trying to change the comm rate on the GPS by sending the message listed in this doc: http://www.gui-soft.com/public_share/ublox-commands.pdf

In my Arduino setup function I do
Serial.begin(9600);

Serial.write(baud115200);

Serial.end();

Serial.begin(115200);

but I get nothing.  Did you ever figure out how to get this thing to accept commands?

Regards, Guy

Comment by Jonathan Dean on December 25, 2013 at 12:59am

It's been a while, but I seem to recall that I did have some success sending it commands. I never tried changing the baud rate because 9600 was fine. I do remember that it accepted strings, not binary values, so I don't know what the data in that PDF you mentioned is actually supposed to be telling it. You may want to check here for the u-blox 6 protocol specification, specifically on page 89 of the PDF (or 77 according to what's printed on the page): according to it, you want proprietary message UBX,41. So your message to the device would be something like "$PUBX,41,1,0007,0007,115200,0,*ZZ" followed by a carriage return and linefeed. The ZZ is the calculated checksum (in two-digit hexadecimal), but I didn't bother to calculate it; you can read about that in the same document. Also, the two 0007 values are the input and output protocol masks. Section 4 of the u-blox document talks about that. You could take that string and convert it to a byte array if you wanted, but the end result would be the same, and it's easier to see (and make changes to) the strings.

I hope that helps you get going in the right direction. If I were you, I'd consider why you need to up the baud rate. The device defaults to one update per second, but even at its max of 5Hz I think 9600 is plenty fast. For instance, the example message collection in the SparkFun datasheet is about 600 bytes. If you received that message 5 times per second, that's only 3,000 bytes. You can customize what messages you want to receive to further reduce how much it spits out at you, making the data transfer even smaller. The only reason to crank up the data rate would be if you were polling like mad, but given the limitations of the device (and GPS in general) that you wouldn't get any additional useful data by being so frantic.

Good luck to you!

Comment

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

Join GarageLab (arduino, electronics, robotics, hacking)

Latest Activity

GarageLab posted a blog post
Friday
Donnie Rose replied to Donnie Rose's discussion Building an auto-boat to keep ducks out of the pool!
"Correction, sorry.  RC receiver is not used with this set up.   Battery & motor hooks…"
Thursday
Donnie Rose posted a discussion
Thursday
Profile IconDonnie Rose and Ransona Company joined GarageLab (arduino, electronics, robotics, hacking)
Thursday
GarageLab posted a blog post
Thursday
Jim Kelley commented on GarageLab's blog post HemaVision Smart Thermal Imager Actually Tells You What that Cool (or Hot) Image Means
"This could be a valuable tool for diagnosing temperature and humidity problems in locations where…"
Thursday
Anthony Parker updated their profile
Wednesday
David Braithwaite added a discussion to the group Raspberry Pi
Tuesday
David Braithwaite joined David's group
Thumbnail

Raspberry Pi

This is a place to discuss all things Raspberry Pi.See More
Tuesday
GarageLab posted a blog post

Artificial bee brain used for vision system of a drone

The Green Brain Project is located in Sheffield, England, and it has one key focus: to simulate a…See More
Tuesday
Profile Iconabraham chemweno, Hetcher, Dan Calef and 1 more joined GarageLab (arduino, electronics, robotics, hacking)
Tuesday
Robbie McCreath commented on GarageLab's blog post Tutorial: Stepper Motor + Easy Driver + Arduino
"Hi there, ive been woking on this tutorial and it is exactly what i need, with use of the serial…"
Apr 13
daniel gabriel left a comment for daniel gabriel
"stop this, i know what is next to, you scammer"
Apr 10
GarageLab posted a blog post

HemaVision Smart Thermal Imager Actually Tells You What that Cool (or Hot) Image Means

HemaImaging it’s working on the HemaVision, a standalone thermal imager that will be able to give…See More
Apr 9
Profile Iconfidel, Mauro Pompetti, FRANK KWABENA and 1 more joined GarageLab (arduino, electronics, robotics, hacking)
Apr 9
Anuradha Ranasinghe is now a member of GarageLab (arduino, electronics, robotics, hacking)
Apr 8
GarageLab posted blog posts
Apr 8
Juan Luis is now a member of GarageLab (arduino, electronics, robotics, hacking)
Apr 7
Profile IconArduino Aficionado and Ilyass Renswoude joined Harold Krueger IV's group
Thumbnail

Makerspace

A group for discussing local makerspaces.See More
Apr 6
teknotellal posted a discussion

How to control 3 led via ESP8266-01?

I want to control 3 led but with ESP8266-01 I can control just 2 led. Each led has a D Flip-Flop.…See More
Apr 6

© 2015   Created by Marcelo Rodrigues.

Badges  |  Report an Issue  |  Terms of Service