SparkFun Forums 

Where electronics enthusiasts find answers.

Tips and questions relating to the GPS modules from SFE
#154810
Got the LS20031 to play nice with TineGPS with NO check sum error
Here is the sketch that the LS20031 play nice with TinyGPS with no CheckSum errors for over 8 hours >>
You have to use a logic voltage converter between the to so you can communicate with the LS20031.
The logic voltage converter I am using is from http://www.dsscircuits.com/i2c-level-converter.html.
The cool thing about using this one, is that it does not require pull up resistors on either side of the converter.
Also I have killed a number of the Mosfet voltage converters sitting on my desk. This one survived on my desk for over 6 months.
See http://www.dsscircuits.com/images/schem ... Wiring.pdf for wiring Diagram.

Code: Select all
#include <SoftwareSerial.h>
#define rxPin 3
#define txPin 4
 
 /*you need to go into Arduino -> Libraries-> SoftwareSerial-> SoftwareSerial.h and increase buffersize from 64 to 128. >>
       Open the file named "SoftwareSerial.h" in a text editor and scroll down to line 42, where you should see:
            #define _SS_MAX_RX_BUFF 64 // RX buffer size
       Increase the value 64, to a more reasonable 128 and then save the file. See Wayneholder web page for more information>>
       https://sites.google.com/site/wayneholder/self-driving-rc-car/navigating-with-gps
  */     
#define PMTK_SET_NMEA_UPDATE_HALF_HZ "$PMTK220,2000*1C\r\n" // Every 2000ms (0.5Hz)
#define PMTK_SET_NMEA_UPDATE_1HZ      "$PMTK220,1000*1F\r\n" // Every 1000ms (1Hz)
#define PMTK_SET_NMEA_UPDATE_2HZ      "$PMTK220,500*2B\r\n>" // Every 500ms (2Hz)
#define PMTK_SET_NMEA_UPDATE_5HZ      "$PMTK220,200*2C\r\n"  // Every 200ms (5Hz)
#define PMTK_SET_NMEA_UPDATE_10HZ     "$PMTK220,100*2F\r\n"  // Every 100ms (10Hz)
/* If the command is correct and executed, GPS module will output message $PMTK001,220,3*30<CR><LF>*/
#define PMTK_Set_NMEA_OUTPUT_GLL       "$PMTK314,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n" // turn on only GLL - Geographic position, latitude / longitude
#define PMTK_SET_NMEA_OUTPUT_RMC       "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n" // turn on only RMC - Recommended minimum specific Loran-C data
#define PMTK_SET_NEMA_OUTPUT_VTG       "$PMTK314,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n" // turn on only VTG - Track made good and ground speed
#define PMTK_SET_NEMA_OUTPUT_GGA       "$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n" // turn on only GGA - Global Positioning System Fix Data
#define PMTK_SET_NMEA_OUTPUT_RMCGGA    "$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n" // turn on GPRMC and GPGGA ----- TinyGPS only uses these two, all others can be turned off
#define PMTK_SET_NMEA_OUTPUT_GSA       "$PMTK314,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n" // turn on only GSA - GPS DOP and active satellites
#define PMTK_SET_NMEA_OUTPUT_GSV       "$PMTK314,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n" // turn on only GSV - GPS Satellites in view
#define PMTK_SET_NEMA_OUTPUT_ZDA       "$PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0*29\r\n" // turn on only ZDA - Date & Time - UTC, day, month, year, and local time zone.
#define PMTK_SET_NEMA_OUTPUT_RMCGAAGSA "$PMTK314,0,1,0,1,1,5,0,0,0,0,0,0,0,0,0,0,0,0,0*2C\r\n" // RMC, GGA, GSA at 1Hz and GSV at 0.2Hz
#define PMTK_SET_NMEA_OUTPUT_ALLDATA   "$PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n" // turn on ALL THE DATA for the LS20031- except ZDA
#define PMTK_SET_NMEA_OUTPUT_OFF       "$PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n" // turn off output
/* If the command is correct and executed, GPS module will output message "$PMTK001,314,3*36<CR><LF>" See Flag upabove */
#define PMTK_Q_RELEASE "$PMTK605*31\r\n" /* Query FW release information -- MTK-3301s send firmware release name and version - Note: not sure of accuracy of this information */
  /* if the command is correct and executed, GPS module will output message example >> "$PMTK705,AXN_1.30,29BF,MC-1513,*0E"
     Data field >> "$PMTK705,ReleaseStr,Mod eID,,*0E"
     ReleaseSTr: Firmware release name & version
     ModelID: Model ID  
  */  
/*
 Demonstration sketch for Adafruit i2c/SPI LCD backpack
 using MCP23008 I2C expander - NOTE at this time all LCD functions have been REM out
 ( http://www.ladyada.net/products/i2cspilcdbackpack/index.html )

 This sketch prints "Hello World!" to the LCD
 and shows the time.
 
  The circuit:
 * 5V to Arduino 5V pin
 * GND to Arduino GND pin
 * CLK to Analog #5
 * DAT to Analog #4
*/

// include the library code:
#include <Wire.h>
//#include <LiquidTWI.h>

// Connect via i2c, default address #0 (A0-A2 not jumpered)
// LiquidTWI lcd(0);
#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
   57600-baud serial GPS device hooked up on pins 3(rx) and 4(tx).
*/

TinyGPS gps;
SoftwareSerial nss(rxPin, txPin);

static void gpsdump(TinyGPS &gps);
static bool feedgps();
static void print_float(float val, float invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);

void setup()
{
  Serial.begin(115200);
  nss.begin(57600); // LS20031 baud- 57600
  while (!nss.available()){}
  nss.print(PMTK_SET_NMEA_OUTPUT_RMCGGA); // $GPxxx Messages
  nss.print(PMTK_SET_NMEA_UPDATE_1HZ);     // messages 1 times a second
  nss.print(PMTK_Q_RELEASE);
  Serial.print("Testing TinyGPS library v. "); Serial.println(TinyGPS::library_version());
  Serial.println("by Mikal Hart");
  Serial.println();
  Serial.print("Sizeof(gpsobject) = "); Serial.println(sizeof(TinyGPS));
  Serial.println();
  Serial.println("Sats HDOP Latitude Longitude Fix  Date       Time       Date Alt     Course Speed Card  Distance Course Card  Chars Sentences Checksum");
  Serial.println("          (deg)    (deg)     Age                        Age  (m)     --- from GPS ----  ---- to London  ----  RX    RX        Fail");
  Serial.println("--------------------------------------------------------------------------------------------------------------------------------------");
 // set up the LCD's number of rows and columns: 
  //lcd.begin(16, 2);
  // Print a message to the LCD.
  //lcd.print("hello, world!");
}

void loop()
{
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  // lcd.setCursor(0, 1);
  bool newdata = false;
  unsigned long start = millis();
  // lcd.print(start/1000);
  // Every second we print an update
  while (millis() - start < 1000)
  {
    if (feedgps())
      newdata = true;
  }
  
  gpsdump(gps);
  //lcd.setBacklight(HIGH);
}

static void gpsdump(TinyGPS &gps)
{
  float flat, flon;
  unsigned long age, date, time, chars = 0;
  unsigned short sentences = 0, failed = 0;
  static const float LONDON_LAT = 51.508131, LONDON_LON = -0.128002;
  
  Serial.print(" "); 
  print_int(gps.satellites(), TinyGPS::GPS_INVALID_SATELLITES, 5);
 //lcd.setCursor(0, 2); lcd.print("Satellites: "); lcd.print(gps.satellites());lcd.print(".");
  feedgps();

  print_int(gps.hdop(), TinyGPS::GPS_INVALID_HDOP, 5);
  gps.f_get_position(&flat, &flon, &age);
  print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 9, 5);
  print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 10, 5);
  print_int(age, TinyGPS::GPS_INVALID_AGE, 5);

  print_date(gps);

  print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 8, 2);
  print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
  print_float(gps.f_speed_kmph(), TinyGPS::GPS_INVALID_F_SPEED, 6, 2);
  print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6);
  print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0UL : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);
  print_float(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : TinyGPS::course_to(flat, flon, 51.508131, -0.128002), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
  print_str(flat == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON)), 6);

  gps.stats(&chars, &sentences, &failed);
  print_int(chars, 0xFFFFFFFF, 6);
  print_int(sentences, 0xFFFFFFFF, 10);
  print_int(failed, 0xFFFFFFFF, 9);
  Serial.println();
}

static void print_int(unsigned long val, unsigned long invalid, int len)
{
  char sz[32];
  if (val == invalid)
    strcpy(sz, "*******");
  else
    sprintf(sz, "%ld", val);
  sz[len] = 0;
  for (int i=strlen(sz); i<len; ++i)
    sz[i] = ' ';
  if (len > 0) 
    sz[len-1] = ' ';
  Serial.print(sz);  feedgps();
}

static void print_float(float val, float invalid, int len, int prec)
{
  char sz[32];
  if (val == invalid){
    strcpy(sz, "*******");
    sz[len] = 0;
        if (len > 0) 
          sz[len-1] = ' ';
    for (int i=7; i<len; ++i)
        sz[i] = ' ';
    Serial.print(sz);
  }
  else
  {
    Serial.print(val, prec);
    int vi = abs((int)val);
    int flen = prec + (val < 0.0 ? 2 : 1);
    flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
    for (int i=flen; i<len; ++i)
      Serial.print(" ");
  }
  feedgps();
}

static void print_date(TinyGPS &gps)
{
  int year;
  byte month, day, hour, minute, second, hundredths;
  unsigned long age;
  gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
  if (age == TinyGPS::GPS_INVALID_AGE)
    Serial.print("*******    *******    ");
  else
  {
    char sz[32];
    sprintf(sz, "%02d/%02d/%02d %02d:%02d:%02d   ",
        month, day, year, hour, minute, second);
    Serial.print(sz); //lcd.setCursor(0, 1); lcd.print(sz);
  }
  print_int(age, TinyGPS::GPS_INVALID_AGE, 5);
  feedgps();
}

static void print_str(const char *str, int len)
{
  int slen = strlen(str);
  for (int i=0; i<len; ++i)
    Serial.print(i<slen ? str[i] : ' ');
  feedgps();
}

static bool feedgps()
{
  while (nss.available())
  {
    if (gps.encode(nss.read()))
      return true;
  }
  return false;
}