Go Down

Topic: TinyGPS and hardware serial? (Read 23112 times) previous topic - next topic

RudiAhlers

Hi,

Does anyone know how to use the TinyGPS library (version 12 currently) with hardware serial, instead of software serial?


This is the example sketch:


Code: [Select]

#include <SoftwareSerial.h>

#include <TinyGPS.h>

/* This sample code demonstrates the normal use of a TinyGPS object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 3(rx) and 4(tx).
*/

TinyGPS gps;
SoftwareSerial ss(3, 4);

void setup()
{
  Serial.begin(115200);
  ss.begin(4800);
 
  Serial.print("Simple TinyGPS library v. "); Serial.println(TinyGPS::library_version());
  Serial.println("by Mikal Hart");
  Serial.println();
}

void loop()
{
  bool newData = false;
  unsigned long chars;
  unsigned short sentences, failed;

  // For one second we parse GPS data and report some key values
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (ss.available())
    {
      char c = ss.read();
      // Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
  }

  if (newData)
  {
    float flat, flon;
    unsigned long age;
    gps.f_get_position(&flat, &flon, &age);
    Serial.print("LAT=");
    Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    Serial.print(" LON=");
    Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    Serial.print(" SAT=");
    Serial.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites());
    Serial.print(" PREC=");
    Serial.print(gps.hdop() == TinyGPS::GPS_INVALID_HDOP ? 0 : gps.hdop());
  }
 
  gps.stats(&chars, &sentences, &failed);
  Serial.print(" CHARS=");
  Serial.print(chars);
  Serial.print(" SENTENCES=");
  Serial.print(sentences);
  Serial.print(" CSUM ERR=");
  Serial.println(failed);


But I need to use hardware serial on a MEGA 2560.

tia

PaulS

Quote
Does anyone know how to use the TinyGPS library (version 12 currently) with hardware serial, instead of software serial?

TinyGPS doesn't care where you get the data.

Code: [Select]
    while (ss.available())
    {
      char c = ss.read();
      // Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }

Change ss to Serial, to get data from the hardware serial port, instead.
The art of getting good answers lies in asking good questions.

RudiAhlers

Ok, that doesn't make much sense to me. As I understand it, one has to specify which Serial port to use on the MEGA 2560. In this case I have the "Adafriut Ultimate GPS Breakout V3" TX and TX pins connected to the MEGA's Serial2 (i.e. pins 16 & 17)

Changing the "ss" part in that sketch to "Serial2" didn't give any GPS data on the Serial Monitor.

This is what I get:

Quote

Simple TinyGPS library v. 12
by Mikal Hart

CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0


Sembazuru


Ok, that doesn't make much sense to me. As I understand it, one has to specify which Serial port to use on the MEGA 2560. In this case I have the "Adafriut Ultimate GPS Breakout V3" TX and TX pins connected to the MEGA's Serial2 (i.e. pins 16 & 17)

Changing the "ss" part in that sketch to "Serial2" didn't give any GPS data on the Serial Monitor.

This is what I get:

Quote

Simple TinyGPS library v. 12
by Mikal Hart

CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0




Since the last thread dealing with TinyGPS, I did some checking. If you look at the support site for TinyGPS (http://arduiniana.org/libraries/tinygps/) you should see this:
Quote

Feed the object serial NMEA data one character at a time using the encode() method. (TinyGPS does not handle retrieving serial data from a GPS unit.) When encode() returns "true", a valid sentence has just changed the TinyGPS object's internal state.


So, like PaulS stated, TinyGPS doesn't care where the data comes from, and doesn't communicate with any external device. Feed it one character at a time with .encode() and once it has a full sentence it will let you know and have parsed data available. (As long, of course, if it is a recognized sentence and the sentence structure is valid...)

So, just receive the data by what ever communication method is appropriate (hardware UART, SoftwareSerial, Wire, I2C, SPI, etc) and feed the data to TinyGPS.
http://www.catb.org/jargon/html/I/I-didn-t-change-anything-.html

RudiAhlers

Thanx, I understand what you're saying (and what PaulS said), but how do I configure the Arduino to get the data in on pins 16 & 17?

Looking at other GPS libraries, I see some use "Adafruit_GPS GPS(&Serial2);" to tell the Arduino where the GPS data comes from.

I'm using a SIM900 GSM shield on Serial1, and had to "hard code" the Serial1 interface in the GSM.cpp file. The developer has given some clear instructions on how to do that, but I can't figure out how to do something similar with TinyGPS.

I'm using a MEGA 2560, with a Adafruit Ultimate GPS breakout V3 on Serial2, and a IComsat GMS shield on Serial1

Sembazuru


Thanx, I understand what you're saying (and what PaulS said), but how do I configure the Arduino to get the data in on pins 16 & 17?


I'm not trying to be unkind, but I don't think you are understanding what PaulS and I are saying. I don't have a Mega, but aren't pins 16 & 17 Serial2? Access Serial2 just like any other serial device.

Quote

Looking at other GPS libraries, I see some use "Adafruit_GPS GPS(&Serial2);" to tell the Arduino where the GPS data comes from.


But the difference here is TinyGPS doesn't access any external ports. You have to do that yourself in your code. So you would do a Serial2.read() to a buffer variable (datatype char or larger) and then pass that variable to TinyGPS's method .encode(). Keep doing this until the .encode() method returns a true. You have to do the communication with the GPS device yourself in your sketch. I suppose you could skip the buffer variable entirely by putting the serial read inside the method, but then it would probably be best to use a flag variable for the return of the encode method.

Something like (untested code here, I have neither a Mega nor a GPS shield):
Code: [Select]

#include <TinyGPS.h>
TinyGPS gps;
boolean validGPS = false;

void setup()
{
  Serial2.begin(9600); // or what ever the GPS's baudrate is
}

void loop()
{
  if (Serial2.available())
  {
    validGPS = gps.encode(Serial2.read());
  }
  if (validGPS)
  {
    // TinyGPS has told us we have received a valid GPS fix. We can now query it for position/course/time/etc. information.
  }
}


Note, even with a good GPS fix, it will take several loops through loop() to fetch a full NMEA sentence. This is good because it allows the sketch to do OtherThingstm while it waits for GPS fix. An example of non-blocking code. ;)

Quote

I'm using a SIM900 GSM shield on Serial1, and had to "hard code" the Serial1 interface in the GSM.cpp file. The developer has given some clear instructions on how to do that, but I can't figure out how to do something similar with TinyGPS.

I'm using a MEGA 2560, with a Adafruit Ultimate GPS breakout V3 on Serial2, and a IComsat GMS shield on Serial1


As long as the GPS unit on the Adafruit breakout sends standard $GPRMC and/or $GPGGA sentences, it should work with TinyGPS. (I expect that it does, but may need some configuration first. I really don't know it's default state.)

Don't forget to test where the GPS can actually get a fix. TinyGPS ignores NMEA sentences that don't indicate a fix. (i.e. even if the NMEA sentence is properly formed, if the GPS is reporting in those sentences that there is no GPS fix then TinyGPS will ignore that sentence. If it's important to your project, don't forget to keep an eye on fix_age.
http://www.catb.org/jargon/html/I/I-didn-t-change-anything-.html

nickgammon

You would have to clear the validGPS flag. Wouldn't this be easier?

Code: [Select]

void setup()
{
  Serial2.begin(9600); // or what ever the GPS's baudrate is
}

void loop()
  {
  if (Serial2.available())
    {
    if (gps.encode(Serial2.read()))
      {
      // TinyGPS has told us we have received a valid GPS fix. We can now query it for position/course/time/etc. information.
      }  // end of complete sentence parsed
    }    // end of serial data available
  }  // end of loop
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

Sembazuru


You would have to clear the validGPS flag. Wouldn't this be easier?

Code: [Select]

void setup()
{
  Serial2.begin(9600); // or what ever the GPS's baudrate is
}

void loop()
  {
  if (Serial2.available())
    {
    if (gps.encode(Serial2.read()))
      {
      // TinyGPS has told us we have received a valid GPS fix. We can now query it for position/course/time/etc. information.
      }  // end of complete sentence parsed
    }    // end of serial data available
  }  // end of loop



Quite valid. It all depends on application and programming style.

If he only needs one fix it doesn't matter. If stale GPS data is an issue, he can capture the value of fix_age from any of the methods that support it and if the fix_age is older than he wants then he can clear the validGPS flag (or set a new staleGPS flag). If the GPS is continually maintaining a good fix then all his GPS positioning information will be updated every second automatically (as far as his sketch is concerned). All those details are really best decided with his application.

From the TinyGPS website:
Quote

To test whether the data returned is stale, examine the (optional) parameter "fix_age" which returns the number of milliseconds since the data was encoded.
http://www.catb.org/jargon/html/I/I-didn-t-change-anything-.html

nickgammon

The way I read the library code, each time you call encode() you get back true or false. If true, the last character you supplied resulted in a valid fix. Then next time through the loop it won't be valid (it only just started a new sentence) and thus it will be false again. So when you get true you get "new information" when you get back false it is "nothing ready yet".
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

Docedison

There is another issue it can take up to 10 minutes depending on location, GPS doesn't work indoors as well as outside with a clear view of the sky. It can take as much as 10 minutes to update the ephemeris in the GPS receiver so seeing no data usually means not enough data yet for a position fix . I use GPS receivers for time standards in several of my projects along with the Time Library... The TimeGPS sketch doesn't work though. I had a friend re-write it so that it works
Mikal Harts TinyGPS12 has a sketch called test_with_gps_device.pde and I've attached it. I didn't make the changes for a Mega's serial ports however. It is really trivial. The sketch works well and was a big part of the re-written TimeGPS sketch. I know the sketch works, I've used it many times in learning about GPS receivers. I also added a windows program that will display GPS data from a GPS receiver connected to a computer via an USB to TTL serial adapter.
The U-Center software is available as a free download from the U-Blox website and it's data display is really interesting. Also to give you an idea of how well your device is working.

Doc
--> WA7EMS <--
"The solution of every problem is another problem." -Johann Wolfgang von Goethe
I do answer technical questions PM'd to me with whatever is in my clipboard

Sembazuru


The way I read the library code, each time you call encode() you get back true or false. If true, the last character you supplied resulted in a valid fix. Then next time through the loop it won't be valid (it only just started a new sentence) and thus it will be false again. So when you get true you get "new information" when you get back false it is "nothing ready yet".


Hey, thanx. I should have realized that. But, for one run through of loop there will be valid data.

Good point. I'll have to rethink.
http://www.catb.org/jargon/html/I/I-didn-t-change-anything-.html

Sembazuru



The way I read the library code, each time you call encode() you get back true or false. If true, the last character you supplied resulted in a valid fix. Then next time through the loop it won't be valid (it only just started a new sentence) and thus it will be false again. So when you get true you get "new information" when you get back false it is "nothing ready yet".


Hey, thanx. I should have realized that. But, for one run through of loop there will be valid data.

Good point. I'll have to rethink.


Actually, thinking about it, after one epoch (may be several sentences, depending on the configuration of the GPS) is read in, there will most likely be some quiet time from the GPS until the next sentence is started. That quiet time from the GPS will result in quite a few iterations through loop() where the flag will continue to be true. (It doesn't try to send anything to .encode() unless there is something available on the serial port.)

It would be an interesting experiment to pretend like the Serial Monitor is a GPS and feed it valid sentences (I've got a megabytes of them lying around my HDD from GPS testing at work), seeing if the return from .encode() goes back to false on subsequent sentences after 1 good one. Unfortunately I'm in the middle of a move and both my UNOs are packed. I probably wouldn't be able to run this test until after the 4th (and maybe not until the week after depending on how long it takes to unpack).
http://www.catb.org/jargon/html/I/I-didn-t-change-anything-.html

nickgammon

I don't think so, although I haven't tested it.

The thing that triggers the "line complete" (eg. newline character) means that it resets its internal state to "start of new line". It doesn't require a new (additional) character to do that, just the final one from the old line.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

Sembazuru


There is another issue it can take up to 10 minutes depending on location, GPS doesn't work indoors as well as outside with a clear view of the sky. It can take as much as 10 minutes to update the ephemeris in the GPS receiver so seeing no data usually means not enough data yet for a position fix .


Such is the expected effect of working with GPS devices. Most modern GPSs will hold on to the ephemeris data until it expires, and continually refreshes it while in operation. So, once you get one good fix, reacquisition is relatively quick unless the GPS has been off for a while or has moved several miles while off. (I forget off the top of my head how long and/or how far the limits are while off. Could be different depending on the GPS device.) That said, I haven't looked at the datasheet for the AdaFruit Ultimate GPS to see how it handles reacquisition on bootup.

Quote
I use GPS receivers for time standards in several of my projects along with the Time Library... The TimeGPS sketch doesn't work though. I had a friend re-write it so that it works
Mikal Harts TinyGPS12 has a sketch called test_with_gps_device.pde and I've attached it. I didn't make the changes for a Mega's serial ports however. It is really trivial. The sketch works well and was a big part of the re-written TimeGPS sketch. I know the sketch works, I've used it many times in learning about GPS receivers. I also added a windows program that will display GPS data from a GPS receiver connected to a computer via an USB to TTL serial adapter.
The U-Center software is available as a free download from the U-Blox website and it's data display is really interesting. Also to give you an idea of how well your device is working.

Doc


Nifty, I'll have to check out that windows program at some point. I'll see how it compares to Ashtech Evaluate.
http://www.catb.org/jargon/html/I/I-didn-t-change-anything-.html

RudiAhlers



Thanx, I understand what you're saying (and what PaulS said), but how do I configure the Arduino to get the data in on pins 16 & 17?


I'm not trying to be unkind, but I don't think you are understanding what PaulS and I are saying. I don't have a Mega, but aren't pins 16 & 17 Serial2? Access Serial2 just like any other serial device.

Quote

Looking at other GPS libraries, I see some use "Adafruit_GPS GPS(&Serial2);" to tell the Arduino where the GPS data comes from.


But the difference here is TinyGPS doesn't access any external ports. You have to do that yourself in your code. So you would do a Serial2.read() to a buffer variable (datatype char or larger) and then pass that variable to TinyGPS's method .encode(). Keep doing this until the .encode() method returns a true. You have to do the communication with the GPS device yourself in your sketch. I suppose you could skip the buffer variable entirely by putting the serial read inside the method, but then it would probably be best to use a flag variable for the return of the encode method.

Something like (untested code here, I have neither a Mega nor a GPS shield):
Code: [Select]

#include <TinyGPS.h>
TinyGPS gps;
boolean validGPS = false;

void setup()
{
  Serial2.begin(9600); // or what ever the GPS's baudrate is
}

void loop()
{
  if (Serial2.available())
  {
    validGPS = gps.encode(Serial2.read());
  }
  if (validGPS)
  {
    // TinyGPS has told us we have received a valid GPS fix. We can now query it for position/course/time/etc. information.
  }
}


Note, even with a good GPS fix, it will take several loops through loop() to fetch a full NMEA sentence. This is good because it allows the sketch to do OtherThingstm while it waits for GPS fix. An example of non-blocking code. ;)

Quote

I'm using a SIM900 GSM shield on Serial1, and had to "hard code" the Serial1 interface in the GSM.cpp file. The developer has given some clear instructions on how to do that, but I can't figure out how to do something similar with TinyGPS.

I'm using a MEGA 2560, with a Adafruit Ultimate GPS breakout V3 on Serial2, and a IComsat GMS shield on Serial1


As long as the GPS unit on the Adafruit breakout sends standard $GPRMC and/or $GPGGA sentences, it should work with TinyGPS. (I expect that it does, but may need some configuration first. I really don't know it's default state.)

Don't forget to test where the GPS can actually get a fix. TinyGPS ignores NMEA sentences that don't indicate a fix. (i.e. even if the NMEA sentence is properly formed, if the GPS is reporting in those sentences that there is no GPS fix then TinyGPS will ignore that sentence. If it's important to your project, don't forget to keep an eye on fix_age.


Thank you. I suspect there's a problem somewhere but don't yet know what / where. As a test, I connected the GPS (http://www.adafruit.com/products/746) to an Arduino NANO, on ports RX0 and TX0, and also 2 & 3 (D2 & D3?), and tried the sample code from the TinyGPS V12 zip file.
This didn't give me any output on the Serial Monitor either.

There's an "Active Antenna" (http://www.adafruit.com/products/960) connected to it which is outside, and has been outside for a few days now. The backup battery is also in place.

The following sketch does give some output, but there's no output when trying the TinyGPS examples.

Code: [Select]
void setup(){}
void loop(){}




Here's the output from the Serial Monitor:
Quote

$GPRMC,082757.000,A,2615.xx40,S,02819.xx56,E,0.01,205.46,xx0613,,,A*78
$GPRMC,082758.000,A,2615.xx40,S,02819.xx56,E,0.00,205.46,xx0613,,,A*76
$GPRMC,082759.000,A,2615.xx40,S,02819.xx56,E,0.02,205.46,xx0613,,,A*75
$GPRMC,082800.000,A,2615.xx40,S,02819.xx56,E,0.01,205.46,xx0613,,,A*75
$GPRMC,082801.000,A,2615.xx40,S,02819.xx56,E,0.01,205.46,xx0613,,,A*74



P.S. I put the "xx" in for privacy reasons.

Go Up