/*
Connections:
GPS TX -> Arduino 0 (disconnect to upload this sketch)
GPS RX -> Arduino 1
Screen SDA -> Arduino A4
Screen SCL -> Arduino A5
*/
#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_NO_ACK|U8G_I2C_OPT_FAST); // Fast I2C / TWI
#define GPS Serial
const unsigned char UBLOX_INIT[] PROGMEM = {
// Disable NMEA
0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x24, // GxGGA off
0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x2B, // GxGLL off
0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x02,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x32, // GxGSA off
0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x39, // GxGSV off
0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x04,0x00,0x00,0x00,0x00,0x00,0x01,0x04,0x40, // GxRMC off
0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x05,0x00,0x00,0x00,0x00,0x00,0x01,0x05,0x47, // GxVTG off
// Disable UBX
0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0xDC, //NAV-PVT off
0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xB9, //NAV-POSLLH off
0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0xC0, //NAV-STATUS off
// Enable UBX
0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x07,0x00,0x01,0x00,0x00,0x00,0x00,0x18,0xE1, //NAV-PVT on
//0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x13,0xBE, //NAV-POSLLH on
//0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x14,0xC5, //NAV-STATUS on
// Rate
0xB5,0x62,0x06,0x08,0x06,0x00,0x64,0x00,0x01,0x00,0x01,0x00,0x7A,0x12, //(10Hz)
//0xB5,0x62,0x06,0x08,0x06,0x00,0xC8,0x00,0x01,0x00,0x01,0x00,0xDE,0x6A, //(5Hz)
//0xB5,0x62,0x06,0x08,0x06,0x00,0xE8,0x03,0x01,0x00,0x01,0x00,0x01,0x39 //(1Hz)
};
const unsigned char UBX_HEADER[] = { 0xB5, 0x62 };
struct NAV_PVT {
unsigned char cls;
unsigned char id;
unsigned short len;
unsigned long iTOW; // GPS time of week of the navigation epoch (ms)
unsigned short year; // Year (UTC)
unsigned char month; // Month, range 1..12 (UTC)
unsigned char day; // Day of month, range 1..31 (UTC)
unsigned char hour; // Hour of day, range 0..23 (UTC)
unsigned char minute; // Minute of hour, range 0..59 (UTC)
unsigned char second; // Seconds of minute, range 0..60 (UTC)
char valid; // Validity Flags (see graphic below)
unsigned long tAcc; // Time accuracy estimate (UTC) (ns)
long nano; // Fraction of second, range -1e9 .. 1e9 (UTC) (ns)
unsigned char fixType; // GNSSfix Type, range 0..5
char flags; // Fix Status Flags
unsigned char reserved1; // reserved
unsigned char numSV; // Number of satellites used in Nav Solution
long lon; // Longitude (deg)
long lat; // Latitude (deg)
long height; // Height above Ellipsoid (mm)
long hMSL; // Height above mean sea level (mm)
unsigned long hAcc; // Horizontal Accuracy Estimate (mm)
unsigned long vAcc; // Vertical Accuracy Estimate (mm)
long velN; // NED north velocity (mm/s)
long velE; // NED east velocity (mm/s)
long velD; // NED down velocity (mm/s)
long gSpeed; // Ground Speed (2-D) (mm/s)
long heading; // Heading of motion 2-D (deg)
unsigned long sAcc; // Speed Accuracy Estimate
unsigned long headingAcc; // Heading Accuracy Estimate
unsigned short pDOP; // Position dilution of precision
short reserved2; // Reserved
unsigned long reserved3; // Reserved
};
NAV_PVT pvt;
void calcChecksum(unsigned char* CK) {
memset(CK, 0, 2);
for (int i = 0; i < (int)sizeof(NAV_PVT); i++) {
CK[0] += ((unsigned char*)(&pvt))[i];
CK[1] += CK[0];
}
}
long numGPSMessagesReceived = 0;
bool processGPS() {
static int fpos = 0;
static unsigned char checksum[2];
const int payloadSize = sizeof(NAV_PVT);
while ( GPS.available() ) {
byte c = GPS.read();
if ( fpos < 2 ) {
if ( c == UBX_HEADER[fpos] )
fpos++;
else
fpos = 0;
}
else {
if ( (fpos-2) < payloadSize )
((unsigned char*)(&pvt))[fpos-2] = c;
fpos++;
if ( fpos == (payloadSize+2) ) {
calcChecksum(checksum);
}
else if ( fpos == (payloadSize+3) ) {
if ( c != checksum[0] )
fpos = 0;
}
else if ( fpos == (payloadSize+4) ) {
fpos = 0;
if ( c == checksum[1] ) {
return true;
}
}
else if ( fpos > (payloadSize+4) ) {
fpos = 0;
}
}
}
return false;
}
void setup()
{
GPS.begin(9600);
u8g.setColorIndex(1);
// send configuration data in UBX protocol
for(unsigned int i = 0; i < sizeof(UBLOX_INIT); i++) {
GPS.write( pgm_read_byte(UBLOX_INIT+i) );
delay(5); // simulating a 38400baud pace (or less), otherwise commands are not accepted by the device.
}
}
long gSpeed = 0;
int numSV = 0;
unsigned long lastScreenUpdate = 0;
char speedBuf[16];
char satsBuf[16];
char* spinner = "/-\\|";
byte screenRefreshSpinnerPos = 0;
byte gpsUpdateSpinnerPos = 0;
void loop() {
if ( processGPS() ) {
numSV = pvt.numSV;
gSpeed = pvt.gSpeed;
gpsUpdateSpinnerPos = (gpsUpdateSpinnerPos + 1) % 4;
}
unsigned long now = millis();
if ( now - lastScreenUpdate > 100 ) {
updateScreen();
lastScreenUpdate = now;
screenRefreshSpinnerPos = (screenRefreshSpinnerPos + 1) % 4;
}
}
void draw() {
//u8g.setScale2x2(); don't do this!
u8g.setFont(u8g_font_courB24);
u8g.drawStr( 36, 45, speedBuf);
//u8g.undoScale();
u8g.setFont(u8g_font_fur11);
u8g.drawStr( 2, 12, satsBuf);
}
void updateScreen() {
int kmh = gSpeed * 0.0036;
sprintf(speedBuf, "%3d", kmh);
sprintf(satsBuf, "%c %c %d", spinner[screenRefreshSpinnerPos], spinner[gpsUpdateSpinnerPos], numSV);
u8g.firstPage();
do {
draw();
} while( u8g.nextPage() );
}