There are some very cheap GPS receivers on the market today, notably GPS originally designed for plugging into dash-cams. These receivers have a 4-way 3.5mm jack connection, and send out 9600 baud serial data in ASCII format.
You can also buy very cheap Arduino Nano boards and cheap OLED 128x64 pixel displays.
Putting this all together you can have a useful tool for amateur radio to display your latitude, longitude, Maidenhead Locator, date and time. Here are few of the code snippets useful for handling the data
HEADER definitions, libraries, defines and variables
#include "Oled_128X64_I2C.h" #include "SoftwareSerial.h" #include "Wire.h" // GPS connections, #define FROMGPS 12 #define TOGPS 13 #define SW 4 // GPS data buffer char gpsbuf[200]; // data extracted from $GPRMC, ACSII char tm[20]; // time HHMMSS char fix[5]; // fix A|V, init void char dt[20]; // date YYMMDD char la[15]; // latitude char ns[2]; // NS char lo[15]; // longitude char ew[2]; // EW // Maidenhead Locator char mh[10] = ""; // Date, Time Lat & lon decimal byte hrs, mns, sec; byte yr, mth, dy; byte dow; double lat, lon; // Serial object RX TX SoftwareSerial gps(FROMGPS, TOGPS);
CODE for setup
void setup() { // pins pinMode(FROMGPS, INPUT); pinMode(TOGPS, OUTPUT); pinMode(SW, INPUT_PULLUP); // I2C init Wire.begin(); // OLED init, I2C addr 0x3C oled.begin(); // GPS serial init gps.begin(9600); strcpy(fix, "V"); dispUpdate(); }
The basic loop CODE
void loop() { getGPS(); // get GPS, extract data if (strcmp(fix, "A") == 0) { // when GPS Aquired getDateTime(); getMH(); dispUpdate(); } }
And finally the functions
// get RMC line data void getGPS() { do { getline(gpsbuf); } while (strncmp(gpsbuf, "$GPRMC", 6) != 0); // extract strings from $GPRMC fields xtract(gpsbuf, 1, tm); // time HHMMSS xtract(gpsbuf, 2, fix); // fix A or V xtract(gpsbuf, 9, dt); // date YYMMDD xtract(gpsbuf, 3, la); // latitude xtract(gpsbuf, 4, ns); // NS xtract(gpsbuf, 5, lo); // longitude xtract(gpsbuf, 6, ew); // EW } // get a line from the GPS, inc /r/n, add /0 void getline(char *out) { char c; int p; p = 0; // buffer pointer do { if (gps.available() > 0) { // data? c = gps.read(); // read character out[p++] = c; // put in buffer } } while ( c != '\n' ); // stop on /n out[p] = '\0'; // terminate string } // extract field and return string in outbuf void xtract(char *in, int field, char *out) { int ip = 0; // input buffer pointer int op = 0; // output buffer pointer int f = 0; // field counter while (f < field) { // find start of field, ip while (in[ip++] != ','); f++; } while (in[ip] != ',') { // scan to next ',' out[op++] = in[ip++]; // copy in to out } out[op] = '\0'; // terminate out string } // ================ Date & Time, Dow ================= void getDateTime() { // get GPS data in bytes, calc dow hrs = strtob(tm, 0); // HH.... mns = strtob(tm, 2); // ..MM.. sec = strtob(tm, 4); // ....SS dy = strtob(dt, 0); // DD.... mth = strtob(dt, 2); // ..MM.. yr = strtob(dt, 4); // ....YY dow = calcDow(yr, mth, dy); } // convert ASCII (0-99), starting at bp, to byte byte strtob(char *in, int bp) { char out[20]; strncpy(out, in + bp, 2); // copy 2 char return (byte)atoi(out); // return byte } // calc dow byte calcDow(byte year, byte month, byte day) { unsigned long days; unsigned int febs; unsigned int months[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 // days until 1st of month }; days = year * 365; // days up to year febs = year; if (month > 2) febs++; // number of completed Februaries // add in the leap days days += ((febs + 3) / 4); days -= ((febs + 99) / 100); days += ((febs + 399) / 400); days += months[month - 1] + day; return (byte)(((days + 5) % 7)); // sun = 0 } // ====================Maidenhead functions================ // calculate maideng=head locator from lat & lon void getMH() { // extract lat * lon from GPS data xtract(gpsbuf, 3, la); xtract(gpsbuf, 4, ns); xtract(gpsbuf, 5, lo); xtract(gpsbuf, 6, ew); lat = convertPos(la, ns); lon = convertPos(lo, ew); calcMH(mh, lat, lon); } // convert Lat, Lon strings to decimal +/-NS|EW double convertPos(char *pos, char *d) { double pp, mm, ans; int dd; pp = atof(pos); // get in decimal ddmm.mmmmmmm dd = (int)pp / 100; // get degrees part mm = pp - (100 * dd); // get minutes ans = dd + (double)mm / 60.0; // calc decimal degrees if (strcmp(d, "N") == 0 || strcmp(d, "E") == 0) // if positive return ans; else return - ans; // negative } // calc MH from lat & lon void calcMH(char *dst, double fa, double fo) { int a1, a2, a3; int o1, o2, o3; double rd; // Latitude rd = fa + 90.0; a1 = (int)(rd / 10.0); rd = rd - (double)a1 * 10.0; a2 = (int)(rd); rd = rd - (double)a2; a3 = (int)(24.0 * rd); // Longitude rd = fo + 180.0; o1 = (int)(rd / 20.0); rd = rd - (double)o1 * 20.0; o2 = (int)(rd / 2.0); rd = rd - 2.0 * (double)o2; o3 = (int)(12.0 * rd); dst[0] = (char)o1 + 'A'; dst[1] = (char)a1 + 'A'; dst[2] = (char)o2 + '0'; dst[3] = (char)a2 + '0'; dst[4] = (char)o3 + 'A'; dst[5] = (char)a3 + 'A'; dst[6] = '\0'; } // ============Picture Display =============== // picture loop void dispUpdate() { oled.firstPage(); do { dispMsg(55, 0, "GPS"); if (strcmp(fix, "V") == 0) { dispMsgL(10, 25, "NO GPS"); } else if (strcmp(fix, "A") == 0) { dispMsg(10, 12, ns); dispNum(25, 12, lat, 2); dispMsg(75, 12, ew); dispNum(90, 12, lon, 2); dispMsg(45, 25, mh); dispDate(15, 37, dow, dy, mth, yr); dispTime(35, 52, hrs, mns, sec); } } while ( oled.nextPage() ); }
No comments:
Post a Comment