#include "ez8.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "defines.h"
// declare constants
#define E1 1 // PC0
#define E2 2 // PC1
#define RS 4 // PC2
#define RW 8 // PC3
#define UPPER E1 // strobe for upper lines
#define LOWER E2 // strobe for lower lines
#define DELAY \
asm ("NOP"); \
asm ("NOP"); \
asm ("NOP");
#define RMC 1
#define GGA 2
#define CLEAR 1
#define HOME 2
#define ROW1 0x80
#define ROW2 0xC0
#define LATPOSN HOME // upper, row 1 col 0
#define LONPOSN (ROW1 + 18) // upper, row 1 col 18
#define UTCPOSN (ROW2) // upper, row 2 col 0
#define DATEPOSN (ROW2 + 14) // upper, row 2 col 14
#define SATPOSN (ROW2 + 30) // upper, row 2 col 30
#define ALTPOSN HOME // lower, row 1 col 0
#define STATPOSN (ROW1 + 16) // lower, row 1 col 16
#define QUALPOSN (ROW1 + 30) // lower, row 1 col 30
#define MTOFT 3.28084 // meters to feet conversion factor
#define MINTOSEC (UINT)6/(UINT)1000 // minutes to seconds conversion factor
// declare variables
char gpsbuf[84];
char string[41];
char status[8];
char stat[2]; // stat field
char date[7]; // date field
char utc[7]; // UTC field
char latitude[10]; // latitude field
char lathem[2]; // lat hem field
char longitude[11]; // longitude field
char lonhem[2]; // lon hem field
char quality[2]; // quality field
char nrsat[3]; // nbr sat field
char hgt[8]; // height
char altitude[8]; // altitude field
const char cg_minute[10] = {0x78, 8, 8, 8, 0x80,
0x80, 0x80, 0x80, 0x80, 0}; // font pattern for CGRAM (')
char *ptr;
UINT latsec, lonsec;
BYTE temp, flag;
// function prototypes
void LCDCmd(BYTE Epin, BYTE arg);
void LCDData(BYTE Epin, char *arg);
void LCDBusy(BYTE Epin);
char GetChar(void);
void GetGPS(char *dest, char start, char end, BYTE len);
char *GetField(char *src, char *dest, BYTE len);
void Delay(UINT dly);
int main()
{
// initialize I/O ports & UART
PEDD = 0; // port E set as outputs
PCDD = 0; // port C set as outputs
PAAF = 0x30; // port A set PA4,PA5 as alternate function for UART I/O
U0BRH = 0;
U0BRL = 240; // baud rate divisor for 4800 baud
U0CTL0 = 0x40; // enable the receiver
temp = U0STAT0;
temp = U0RXD; // clear rx register
// initialize LCD display
Delay(2160); // 15 mS @ 6.944 uS per count
PCOUT = 0; // select command entry
PEOUT = 0x30; // init command byte
PCOUT = E1 + E2; // assert both enables
DELAY;
PCOUT = 0; // de-assert enables
Delay(591); // 4.1 mS @ 6.944 uS per count
PCOUT = E1 + E2; // assert both enables
DELAY;
PCOUT = 0; // de-assert enables
Delay(15); // 100 uS @ 6.944 uS per count
PCOUT = E1 + E2; // assert both enables
DELAY;
PCOUT = 0; // de-assert enables
Delay(15); // 100 uS @ 6.944 uS per count
LCDCmd(UPPER, 0x38); // 8 bit I/F, 2 line, 8 dot font
LCDCmd(UPPER, 8); // display off, cursor off, blink off
LCDCmd(UPPER, CLEAR); // clear and home
LCDCmd(UPPER, 6); // increment cursor, no shift
LCDCmd(UPPER, 12); // display on
LCDCmd(UPPER, cg_minute[0]); // address CGRAM for font write
LCDData(UPPER, &cg_minute[1]); // write character pattern
LCDCmd(LOWER, 0x38); // 8 bit I/F, 2 line, 8 dot font
LCDCmd(LOWER, 8); // display off, cursor off, blink off
LCDCmd(LOWER, CLEAR); // clear and home
LCDCmd(LOWER, 6); // increment cursor, no shift
LCDCmd(LOWER, 12); // display on
// send signon message to LCD
LCDCmd(LOWER, ROW2); // bottom row
LCDData(LOWER, "------ Brisbane Valley Observatory -----");
flag = 0;
while (1)
{
GetGPS(gpsbuf, '$', '*', sizeof(gpsbuf)); // get a sentence from GPS ($ thru *, ignore parity and CRLF)
if (! strncmp(gpsbuf, "$GPRMC", 6)) // sentence starts with $GPRMC
{
ptr = GetField(gpsbuf + 7, NULL, 0); // get next field but ignore data (skip time field)
ptr = GetField(ptr, stat, sizeof(stat)); // get the stat field
for (temp = 0; temp < 6; temp++)
{
ptr = GetField(ptr, NULL, 0); // skip the next 6 fields
}
GetField(ptr, date, sizeof(date)); // get the date field
flag += RMC; // remember that RMC data has been processed
}
if (! strncmp(gpsbuf, "$GPGGA", 6)) // sentence starts with $GPGGA
{
ptr = GetField(gpsbuf + 7, utc, sizeof(utc)); // get the UTC field
ptr = GetField(ptr, latitude, sizeof(latitude)); // get the latitude field
ptr = GetField(ptr, lathem, sizeof(lathem)); // get the lat hem field
ptr = GetField(ptr, longitude, sizeof(longitude)); // get the longitude field
ptr = GetField(ptr, lonhem, sizeof(lonhem)); // get the lon hem field
ptr = GetField(ptr, quality, sizeof(quality)); // get the quality field
ptr = GetField(ptr, nrsat, sizeof(nrsat)); // get the nbr sat field
ptr = GetField(ptr, NULL, 0); // skip the dilution field
GetField(ptr, hgt, sizeof(hgt)); // get the altitude field
flag += GGA; // remember that GGA data has been processed
}
if (flag == RMC + GGA) // both sentences recieved
{
latsec = (UINT)(atoi(latitude + 5)) * MINTOSEC; // convert ascii latitude minutes to decimal seconds
sprintf(string, "Lat:%.2s\xDF%.2s\x7%2.2u\"%s", // dd°mm'ss"h
latitude, // degrees (0 to 90 degrees)
latitude + 2, // minutes (0 to 60 minutes)
latsec, // seconds (0 to 60 seconds)
lathem); // hemisphere (N or S)
LCDCmd(UPPER, LATPOSN); // set display cursor to posn
LCDData(UPPER, string);
lonsec = (UINT)(atoi(longitude + 6)) * MINTOSEC; // convert ascii longitude minutes to decimal seconds
sprintf(string, "Lon:%.3s\xDF%.2s\x7%2.2u\"%s", // ddd°mm'ss"h
longitude, // degrees (0 to 360 degrees)
longitude + 3, // minutes (0 to 60 minutes)
lonsec, // seconds (0 to 60 seconds)
lonhem); // hemisphere (E or W)
LCDCmd(UPPER, LONPOSN); // set display cursor to posn
LCDData(UPPER, string);
sprintf(string, "UTC:%2.2s:%2.2s:%2.2s", utc, // hours
utc + 2, // minutes
utc + 4); // seconds
LCDCmd(UPPER, UTCPOSN); // set display cursor to posn
LCDData(UPPER, string);
sprintf(string, "Date:%2.2s/%2.2s/%2.2s", date + 2, // month
date, // day
date + 4); // year
LCDCmd(UPPER, DATEPOSN); // set display cursor to posn
LCDData(UPPER, string);
sprintf(string, "NrSat:%s", nrsat);
LCDCmd(UPPER, SATPOSN); // set display cursor to posn
LCDData(UPPER, string);
if (*stat == 'A')
{
strcpy(status, "GPS OK");
sprintf(altitude, "%6.0f", atof(hgt) * MTOFT); // convert meters to feet
}
else
{
strcpy(status, "GPS NG");
strcpy(altitude, "------");
}
sprintf(string, "Altitude:%s", altitude);
LCDCmd(LOWER, ALTPOSN); // set display cursor to posn
LCDData(LOWER, string);
sprintf(string, "Status:%s", status);
LCDCmd(LOWER, STATPOSN); // set display cursor to posn
LCDData(LOWER, string);
sprintf(string, "GPSQual:%s", quality);
LCDCmd(LOWER, QUALPOSN); // set display cursor to posn
LCDData(LOWER, string);
flag = 0;
}
}
}
/***********************************************************
get data from the serial port, starting when the 'start' character is read,
copying to the 'dest' buffer, until the 'end' character is read.
***********************************************************/
void GetGPS(char *dest, char start, char end, BYTE len)
{
BYTE index = 0;
char rxdata;
do
{
rxdata = GetChar();
} while (rxdata != start); // wait for start char
*(dest + index++) = rxdata; // store start char
do
{
rxdata = GetChar();
if (index < (len - 1)) // check for room in buffer
{
*(dest + index++) = rxdata; // store data
}
} while (rxdata != end); // do until end char
*(dest + index) = 0; // terminating null
}
/***********************************************************
get one byte from the serial port (ignore errors)
***********************************************************/
char GetChar(void)
{
while (! (U0STAT0 & 0x80)); // wait for rx data ready
return U0RXD; // fetch the data
}
/***********************************************************
GetField(src, dest) searches string from 'src' until a comma is found,
and then returns a pointer to the character after the comma. If 'dest' is
not NULL, then the characters up to the comma are copied to 'dest' buffer, as well.
***********************************************************/
char *GetField(char *src, char *dest, BYTE len)
{
BYTE index = 0;
while (*src != ',')
{
if (*src == 0) return src; // string ends without comma found
if (dest) // if valid dest pointer
{
if (index < (len - 1)) // check for room in buffer
{
*(dest + index++) = *src; // store data
}
*(dest + index) = 0; // terminating null
}
src++;
}
return (++src); // comma found, increment beyond it
}
/***********************************************************
Write command byte to LCD controller
***********************************************************/
void LCDCmd(BYTE Epin, BYTE arg)
{
LCDBusy(Epin); // wait til not busy
PCOUT = 0; // select command entry
PEOUT = arg; // put byte on the bus
PCOUT = Epin; // assert enable
DELAY;
PCOUT = 0; // de-assert enable
}
/***********************************************************
Write data bytes to LCD controller
***********************************************************/
void LCDData(BYTE Epin, char *arg)
{
while (*arg) // data not null
{
LCDBusy(Epin); // wait til not busy
PCOUT = RS; // select data entry
PEOUT = *arg++; // put byte on the bus
PCOUT = Epin + RS; // assert enable for write
DELAY;
PCOUT = RS; // de-assert enable
}
}
/***********************************************************
Check LCD controller busy status.
***********************************************************/
void LCDBusy(BYTE Epin)
{
PEDD = 0xFF; // set bus port to inputs
PCOUT = RW; // set for status read
PCOUT = Epin + RW; // assert enable
DELAY;
while (PEIN & 0x80); // wait for busy bit to go low
PCOUT = RW; // de-assert enable
PCOUT = 0; // set for write
PEDD = 0; // set bus port to outputs
}
/***********************************************************
Hardware delay using Timer 0
system clock = 18432000, prescale = 128
time resolution = 6.9444 uS per count
***********************************************************/
void Delay(UINT dly)
{
T0H = 0;
T0L = 1; // set starting count
T0RH = (dly & 0xFF00) >> 8;
T0RL = dly & 0xFF; // set reload count
T0CTL = 0xB8; // enable count, prescale 128, one-shot mode
while (T0CTL & 0x80); // wait for timer to disable itself
}