Sunday 12 January 2014

GPS

Now here's a more complicated project. A GPS receiver with display of date, time, latitude and longitude. The decoded information from the receiver is:

Screen Shot 2014 01 12 at 12 52 56

The SOG & COG are not meaningful as the receiver is not moving...

The GPS module, wiring and LCD display look like this:

2014 01 12 17 14 43


The display is limited to 16 characters so some information is truncated (no time in seconds for example, no decimal minutes of longitude). Wiring diagram:


Scan 10 Jan 2014 10 13 page2

The GPS receiver outputs various strings of information according to the NMEA specification. Noteable are these:

Screen Shot 2014 01 12 at 17 18 53

The string I am using is the $GPRMC one, which reports the data I need.

Software code
// GPS v3 module and LCD display
// display is limited to 16 x 2, so some data truncated
// Antony Watts 2014

/* GPS Pin connections
Module - Arduino
GND    -     GND
RX     -  Pin 11 TXPIN
TX     -  Pin 10 RXPIN
VCC    -    3.3V !!!!!
*/

// libraries
#include 
#include 

// GPS connections
#define RXPIN 10
#define TXPIN 11
#define BAUD 9600

// $GPRMC field positions in NMEA stream
#define RMCUTC 1
#define RMCLAT 3
#define RMCNS 4
#define RMCLON 5
#define RMCEW 6
#define RMCSOG 7
#define RMCCOG 8
#define RMCDATE 9

// LCD connections
#define RS 2
#define EN 3
#define D4 4
#define D5 5
#define D6 6
#define D7 7

// set up serial comms for GPS
SoftwareSerial gps(RXPIN, TXPIN); // serial comms to GPS UART

// Create LCD object
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);

void setup()
{
  gps.begin(BAUD); // start GPS serial
  lcd.begin(16, 2); // start LCD 16 col x 2 row
}

void loop()
{
  // main data buffers, NMEA read and field extract
  char gpsbuf[200];
  char ebuf[20];
  
  readgps(gpsbuf); // read each $GPxxx NMEAstrings+CRLF into gpsbuf
  
  if(strncmp(gpsbuf, "$GPRMC", 6) == 0)// use $GPRMC string
  { 
    extract(RMCUTC, gpsbuf, ebuf); // get utc
    lcdrpt(ebuf, 9, 0, "**:**"); // display lcd at col 9, row 0
      
    extract(RMCLAT, gpsbuf, ebuf); // get lat
    lcdrpt(ebuf, 0, 1, "** ****");
    
    extract(RMCNS, gpsbuf, ebuf); // get N|S
    lcdrpt(ebuf, 7, 1, "* ");
    
    extract(RMCLON, gpsbuf, ebuf); // get lon
    lcdrpt(ebuf, 9, 1, "*** **");
    
    extract(RMCEW, gpsbuf, ebuf); // get E|W
    lcdrpt(ebuf, 15, 1, "* ");
    
//    extract(RMCSOG, gpsbuf, ebuf); // get SOG
    
//    extract(RMCCOG, gpsbuf, ebuf); // get COG
    
    extract(RMCDATE, gpsbuf, ebuf); // get date
    lcdrpt(ebuf, 0, 0, "**-**-**");
  }
}

// read GPxxx NMEA string into buffer
void readgps(char *buffer) 
{
  int bp;
  char c;
  
  bp = 0;
  do
  {
    c = gps.read();
    if(c == -1) continue; // gps sends -1 when idle
    buffer[bp++] = c;
  } while(c != '\n'); // ends with LF
  buffer[bp] = '\0'; // add '\0'
}

// extract string from field 0-10 from inbuf to outbuf
void extract(int field, char *inbuf, char *outbuf)
{
  int fcount; // field counter
  int ip; // inbuf pointer
  int op; // outbug ptr

  fcount = 0;
  ip = 0;
  op = 0;
  
  while(fcount != field) // find field
  {
    while(inbuf[ip++] != ',');
    fcount++;
  }
  
  while(inbuf[ip] != ',') // copy inbuf to outbuf
  {
    outbuf[op++] = inbuf[ip++];
  }
  outbuf[op] = '\0'; // mark end of string
}

// display inbuf at col row in fmtbuf format
// display: * = use inbuf character, otherwise use fmtbuf character
int lcdrpt(char *inbuf, int col, int row, char *fmtbuf)
{
 int inp; // pointers to inbuf and format
 int fmtp;
 
 inp = 0; // start at buffers beginning
 fmtp = 0;
 
 lcd.setCursor(col, row);// start writing here
 
 while(fmtbuf[fmtp] != '\0') // continue until '\0' of format
 {
   if(fmtbuf[fmtp] == '*') // use inbuf character
   {
     lcd.write(inbuf[inp++]); // write inbuf char to lcd
   }
   else
   {
     lcd.write(fmtbuf[fmtp]); // format character
   }
   fmtp++;
 }
}



No comments: