GPS module help needed

My code stopped working for my GPS module and in trying to troubleshoot it, I have simplified it down to the code below, which still isn't working, it will only display "looping" for serial out.

I have to be over looking something simple, that I'm hoping a second set of eyes will pick up, as when I load a previous iteration of code I have as a baseline, when I had just received and was testing out my NEO-6M GPS hardware, it still works, so the hardware is working, and will print out the time and date derived from the module?

I've compared the 2 pieces of code and I can't figure out what is different. The code below will compile on my Mega 2560, but does not print out "inside gps.encode" nor any of the GPS date time values.

#include <TinyGPS++.h>           // Include TinyGPS++ library
#include <SoftwareSerial.h>      // Include software serial library
//#include <LiquidCrystal.h>       // Include LCD library
 
TinyGPSPlus gps;
 
#define S_RX    11                // Define software serial RX pin
#define S_TX    100                // Define software serial TX pin
 
SoftwareSerial SoftSerial(S_RX, S_TX);    // Configure SoftSerial library
 
// LCD module connections (RS, E, D4, D5, D6, D7)
//LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
 
byte last_second;
char Time[]  = "TIME:00:00:00";
char Date[]  = "DATE:00/00/2000";
 
void setup(void) {
  Serial.begin(9600);
  SoftSerial.begin(9600);
 
  Serial.println("");
    Serial.println("    ***** Start *****    ");
    Serial.println("");


  // set up the LCD's number of columns and rows
  //lcd.begin(16, 2);
 
  //lcd.setCursor(0, 0);
  //lcd.print(Time);                           // Display time
  //lcd.setCursor(0, 1);
  //lcd.print(Date);                           // Display calendar
}
 
void loop() {
 
  Serial.println("looping");
  //while (SoftSerial.available() > 0) {
 
    if (gps.encode(SoftSerial.read())) { 
      Serial.println("inside gps.encode");
      if (gps.time.isValid()) {
        Time[5]  = gps.time.hour()   / 10 + 48;
        Time[6]  = gps.time.hour()   % 10 + 48;
        Time[8]  = gps.time.minute() / 10 + 48;
        Time[9]  = gps.time.minute() % 10 + 48;
        Time[11] = gps.time.second() / 10 + 48;
        Time[12] = gps.time.second() % 10 + 48;
      }
 
      if (gps.date.isValid()) {
        Date[5]  = gps.date.day()    / 10 + 48;
        Date[6]  = gps.date.day()    % 10 + 48;
        Date[8]  = gps.date.month()  / 10 + 48;
        Date[9]  = gps.date.month()  % 10 + 48;
        Date[13] =(gps.date.year()   / 10) % 10 + 48;
        Date[14] = gps.date.year()   % 10 + 48;
      }
 
      int Year = gps.date.year();
      byte Month = gps.date.month();
      byte Day = gps.date.day();
      byte Hour = gps.time.hour();
      byte Minute = gps.time.minute();
      byte Second = gps.time.second();

      Serial.print("Hour: "); Serial.println(Hour);
      Serial.print("Minute: "); Serial.println(Minute);
      Serial.print("Second: "); Serial.println(Second);
      Serial.println("");

      /*if(last_second != gps.time.second()) {
        last_second = gps.time.second();
        lcd.setCursor(0, 0);
        lcd.print(Time);                           // Display time
        lcd.setCursor(0, 1);
        lcd.print(Date);                           // Display calendar
      }*/
 
    }
 
  //}

  delay(5000);
 
}

Two questions:

  1. Why use SoftwareSerial on a Mega when you've got 4 hardware serial ports?

  2. Pin 100?

Hello turbosupramk3

Does the GPS module only see the ceiling in your room or also real GPS satellites?

So what changed between the GPS code working and then not working ?

1 Like

Hi, @turbosupramk3

Have you checked your hardware with a TinyGPS++ Example?

Tom... :grinning: :+1: :coffee: :australia:

It might compile, but I doubt it will work.

Go back to one of the TinyGPSplus library examples.

That is how the original example was set up that I was working with. I don't mind migrating to a hardware serial, however first I want to figure out why this won't work. I chose that pin because I don't need to transmit from the module, however the software serial requires an integer.

Remove the delay(5000) at the bottom of loop(). You are reading 1 character every 5 seconds, causing the SoftwareSerial input buffer to overflow constantly. You will need to check to see if there is data available on SoftwareSerial, since you took out the while() that tests for that.

It would also help to significantly increase the baud rate of Serial, otherwise the amount of time you spend waiting to send text will also cause the SoftwareSerial receive buffer to overflow.

Ok, I've modified it as you suggested, however the behavior has not changed as far as what it outputs. Do I have to set anything on the GPS hardware to match the change on the Arduino for the serial speed or will it autonegotiate? It will print this part "inside SoftSerial.available" only with the code below, so it never breaks out of the while loop now, so the serial out reads like below. This line appears to be where it is failing/not evaluating
if (gps.encode(SoftSerial.read()))

11:20:21.357 -> inside SoftSerial.available
11:20:21.430 -> inside SoftSerial.available
11:20:21.430 -> inside SoftSerial.available
11:20:21.464 -> inside SoftSerial.available
11:20:21.514 -> inside SoftSerial.available
11:20:21.545 -> inside SoftSerial.available
11:20:21.599 -> inside SoftSerial.available
11:20:21.599 -> inside SoftSerial.available
11:20:21.628 -> inside SoftSerial.available
11:20:21.656 -> inside SoftSerial.available
11:20:21.687 -> inside SoftSerial.available
11:20:21.687 -> inside SoftSerial.available
11:20:21.752 -> inside SoftSerial.available
11:20:21.752 -> inside SoftSerial.available
11:20:21.783 -> inside SoftSerial.available
11:20:21.818 -> inside SoftSerial.available
11:20:21.852 -> inside SoftSerial.available


#include <TinyGPS++.h>           // Include TinyGPS++ library
#include <SoftwareSerial.h>      // Include software serial library
//#include <LiquidCrystal.h>       // Include LCD library
 
TinyGPSPlus gps;
 
#define S_RX    11                // Define software serial RX pin
#define S_TX    52                // Define software serial TX pin
 
SoftwareSerial SoftSerial(S_RX, S_TX);    // Configure SoftSerial library
 
// LCD module connections (RS, E, D4, D5, D6, D7)
//LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
 
byte last_second;
char Time[]  = "TIME:00:00:00";
char Date[]  = "DATE:00/00/2000";
 
void setup(void) {
  Serial.begin(9600);
  SoftSerial.begin(38400);
 
  Serial.println("");
    Serial.println("    ***** Start *****    ");
    Serial.println("");


  // set up the LCD's number of columns and rows
  //lcd.begin(16, 2);
 
  //lcd.setCursor(0, 0);
  //lcd.print(Time);                           // Display time
  //lcd.setCursor(0, 1);
  //lcd.print(Date);                           // Display calendar
}
 
void loop() {
 
  Serial.println("looping");
  while (SoftSerial.available() > 0) {
    Serial.println("inside SoftSerial.available");
    if (gps.encode(SoftSerial.read())) {
      Serial.println("inside gps.encode");
      if (gps.time.isValid()) {
        Time[5]  = gps.time.hour()   / 10 + 48;
        Time[6]  = gps.time.hour()   % 10 + 48;
        Time[8]  = gps.time.minute() / 10 + 48;
        Time[9]  = gps.time.minute() % 10 + 48;
        Time[11] = gps.time.second() / 10 + 48;
        Time[12] = gps.time.second() % 10 + 48;
      }
 
      if (gps.date.isValid()) {
        Date[5]  = gps.date.day()    / 10 + 48;
        Date[6]  = gps.date.day()    % 10 + 48;
        Date[8]  = gps.date.month()  / 10 + 48;
        Date[9]  = gps.date.month()  % 10 + 48;
        Date[13] =(gps.date.year()   / 10) % 10 + 48;
        Date[14] = gps.date.year()   % 10 + 48;
      }
 
      int Year = gps.date.year();
      byte Month = gps.date.month();
      byte Day = gps.date.day();
      byte Hour = gps.time.hour();
      byte Minute = gps.time.minute();
      byte Second = gps.time.second();

      Serial.print("Hour: "); Serial.println(Hour);
      Serial.print("Minute: "); Serial.println(Minute);
      Serial.print("Second: "); Serial.println(Second);
      Serial.println("");

      /*if(last_second != gps.time.second()) {
        last_second = gps.time.second();
        lcd.setCursor(0, 0);
        lcd.print(Time);                           // Display time
        lcd.setCursor(0, 1);
        lcd.print(Date);                           // Display calendar
      }*/
 
    }
 
  }

  delay(5);
 
}

The library found here TinyGPSPlus - Arduino Reference does work. The baseline piece of code that I have when testing also works. I'm trying to determine why it is not working in my trimmed down (from a project) piece of code that I've posted here, because I can then fix whatever is broken in the larger project.

Leave the speed of the SoftwareSerial port at 9600, my suggestion was to increase the speed of Serial (you will need to change the baud rate in the serial monitor to match).

Do not spend time printing out "Inside SoftSerial.available", that will fill the Serial transmit buffer and cause you to miss characters on SoftwareSerial.

I'm making some progress trying to determine the issue with if (gps.encode(SoftSerial.read())) not working. With my else statement, I am getting characters, presumably that pieced together are coordinates, dates, times, etc.

I don't understand C enough to know how to troubleshoot this part

class TinyGPSPlus
{
public:
  TinyGPSPlus();
  bool encode(char c); // process one character received from GPS
  TinyGPSPlus &operator << (char c) {encode(c); return *this;}

11:45:21.242 -> read: G

11:45:21.274 -> inside SoftSerial.available

11:45:21.307 -> Gps encode fail

11:45:21.307 -> read: R

11:45:21.307 -> inside SoftSerial.available

11:45:21.340 -> Gps encode fail

11:45:21.372 -> read: C

11:45:21.373 -> inside SoftSerial.available

11:45:21.405 -> Gps encode fail

11:45:21.438 -> read: 1

11:45:21.438 -> inside SoftSerial.available

11:45:21.470 -> Gps encode fail

11:45:21.470 -> read: 4

11:45:21.504 -> inside SoftSerial.available

11:45:21.540 -> Gps encode fail

11:45:21.540 -> read: 2

11:45:21.540 -> inside SoftSerial.available

11:45:21.574 -> Gps encode fail

11:45:21.605 -> read: .

11:45:21.605 -> inside SoftSerial.available

11:45:21.638 -> Gps encode fail

11:45:21.638 -> read: 0

11:45:21.669 -> inside SoftSerial.available

11:45:21.700 -> Gps encode fail

11:45:21.700 -> read: A

#include <TinyGPS++.h>           // Include TinyGPS++ library
#include <SoftwareSerial.h>      // Include software serial library
//#include <LiquidCrystal.h>       // Include LCD library
 
TinyGPSPlus gps;
 
#define S_RX    11                // Define software serial RX pin
#define S_TX    52                // Define software serial TX pin
 
SoftwareSerial SoftSerial(S_RX, S_TX);    // Configure SoftSerial library
 
// LCD module connections (RS, E, D4, D5, D6, D7)
//LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
 
byte last_second;
char Time[]  = "TIME:00:00:00";
char Date[]  = "DATE:00/00/2000";
 
void setup(void) {
  Serial.begin(9600);
  SoftSerial.begin(9600);
 
  Serial.println("");
    Serial.println("    ***** Start *****    ");
    Serial.println("");


  // set up the LCD's number of columns and rows
  //lcd.begin(16, 2);
 
  //lcd.setCursor(0, 0);
  //lcd.print(Time);                           // Display time
  //lcd.setCursor(0, 1);
  //lcd.print(Date);                           // Display calendar
}
 
void loop() {
 
  Serial.println("looping");
  while (SoftSerial.available() > 0) {
    Serial.println("inside SoftSerial.available");
    if (gps.encode(SoftSerial.read())) 
    {
      Serial.println("inside gps.encode");
      if (gps.time.isValid()) {
        Time[5]  = gps.time.hour()   / 10 + 48;
        Time[6]  = gps.time.hour()   % 10 + 48;
        Time[8]  = gps.time.minute() / 10 + 48;
        Time[9]  = gps.time.minute() % 10 + 48;
        Time[11] = gps.time.second() / 10 + 48;
        Time[12] = gps.time.second() % 10 + 48;
      }
 
      if (gps.date.isValid()) {
        Date[5]  = gps.date.day()    / 10 + 48;
        Date[6]  = gps.date.day()    % 10 + 48;
        Date[8]  = gps.date.month()  / 10 + 48;
        Date[9]  = gps.date.month()  % 10 + 48;
        Date[13] =(gps.date.year()   / 10) % 10 + 48;
        Date[14] = gps.date.year()   % 10 + 48;
      }
 
      int Year = gps.date.year();
      byte Month = gps.date.month();
      byte Day = gps.date.day();
      byte Hour = gps.time.hour();
      byte Minute = gps.time.minute();
      byte Second = gps.time.second();

      Serial.print("Hour: "); Serial.println(Hour);
      Serial.print("Minute: "); Serial.println(Minute);
      Serial.print("Second: "); Serial.println(Second);
      Serial.println("");

      /*if(last_second != gps.time.second()) {
        last_second = gps.time.second();
        lcd.setCursor(0, 0);
        lcd.print(Time);                           // Display time
        lcd.setCursor(0, 1);
        lcd.print(Date);                           // Display calendar
      }*/
 
    }
    else
    {
        Serial.println("Gps encode fail");
        char chr = SoftSerial.read();
        char myStr[3];
        myStr[0] = chr;
        myStr[1] = '\0';
        Serial.print("read: "); Serial.println(myStr);
    }
 
  }

  delay(5);
 
}

Remove this line:

    Serial.println("inside SoftSerial.available");

Remove the entire else statement

    else
    {
      Serial.println("Gps encode fail");
      char chr = SoftSerial.read();
      char myStr[3];
      myStr[0] = chr;
      myStr[1] = '\0';
      Serial.print("read: "); Serial.println(myStr);
    }

I put those in for troubleshooting, I get nothing without those except "looping"

The issue is that you are filling up the SoftwareSerial receive buffer and losing characters.
gps.encode(SoftSerial.read()) takes one character at a time and feeds it into the gps library. gps.encode() will return a logical "true" value when it has a valid NMEA sentence, otherwise it returns a logical"false".

Try this code:

#include <TinyGPS++.h>           // Include TinyGPS++ library
#include <SoftwareSerial.h>      // Include software serial library
//#include <LiquidCrystal.h>       // Include LCD library

TinyGPSPlus gps;

#define S_RX    11                // Define software serial RX pin
#define S_TX    52                // Define software serial TX pin

SoftwareSerial SoftSerial(S_RX, S_TX);    // Configure SoftSerial library

// LCD module connections (RS, E, D4, D5, D6, D7)
//LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

byte last_second;
char Time[]  = "TIME:00:00:00";
char Date[]  = "DATE:00/00/2000";

void setup(void) {
  Serial.begin(9600);
  SoftSerial.begin(9600);

  Serial.println("");
  Serial.println("    ***** Start *****    ");
  Serial.println("");


  // set up the LCD's number of columns and rows
  //lcd.begin(16, 2);

  //lcd.setCursor(0, 0);
  //lcd.print(Time);                           // Display time
  //lcd.setCursor(0, 1);
  //lcd.print(Date);                           // Display calendar
}

void loop() {
  while (SoftSerial.available() > 0) {
    if (gps.encode(SoftSerial.read()))
    {
      Serial.println("inside gps.encode");
      if (gps.time.isValid()) {
        Time[5]  = gps.time.hour()   / 10 + 48;
        Time[6]  = gps.time.hour()   % 10 + 48;
        Time[8]  = gps.time.minute() / 10 + 48;
        Time[9]  = gps.time.minute() % 10 + 48;
        Time[11] = gps.time.second() / 10 + 48;
        Time[12] = gps.time.second() % 10 + 48;
      }

      if (gps.date.isValid()) {
        Date[5]  = gps.date.day()    / 10 + 48;
        Date[6]  = gps.date.day()    % 10 + 48;
        Date[8]  = gps.date.month()  / 10 + 48;
        Date[9]  = gps.date.month()  % 10 + 48;
        Date[13] = (gps.date.year()   / 10) % 10 + 48;
        Date[14] = gps.date.year()   % 10 + 48;
      }

      int Year = gps.date.year();
      byte Month = gps.date.month();
      byte Day = gps.date.day();
      byte Hour = gps.time.hour();
      byte Minute = gps.time.minute();
      byte Second = gps.time.second();

      Serial.print("Hour: "); Serial.println(Hour);
      Serial.print("Minute: "); Serial.println(Minute);
      Serial.print("Second: "); Serial.println(Second);
      Serial.println("");

      /*if(last_second != gps.time.second()) {
        last_second = gps.time.second();
        lcd.setCursor(0, 0);
        lcd.print(Time);                           // Display time
        lcd.setCursor(0, 1);
        lcd.print(Date);                           // Display calendar
        }*/
    }
  }
}

Thank you, it works, is there a post or link where I can understand in depth how I was doing that so I can learn and don't do it inadvertently again in the future?

Was it receiving a complete sentence and then not processing it fast enough so that more characters were being added to a buffer, invalidating the complete GPS sentence?

I think your final problem was that you were printing "looping" every time loop() executed, which will not work when you are using 9600 baud on both Serial and SoftwareSerial, because that causes too much delay and leads to overflow in the SoftwareSerial receive buffer.

At 9600 baud, it takes about 65mS to fill the receive buffer, so anything that causes a long delay can be a problem. Printing to Serial causes a problem because once the transmit buffer is full, print() has to wait for characters to be sent, during which time the SoftwareSerial buffer is filling up.

Doing lots of printing to Serial() will cause software serial to miss characters.

Miss one character in a NMEA sentence and it will be rejected by the encode().

You need to read characters for the GPS, and encode() the characters, until the GPS library reports that there has been update to the time and date, then and only then print stuff out.

1 Like

I made some changes to the larger project with Serial.print frequency and added the while loop back in now that I understand its function, and it is working again.

Do you think increasing Serial.begin(9600); to Serial.begin(38400); a full proof way of keeping this from happening again?

That can help, I generally use 115200.

2 Likes