// GPS TRACKER PROGRAM EXAMPLE - VERSION 1.65 // FOR GPS EXPERIMENTATION // CODE DISPLAYS UTC TIME, NUMBER OF SATs, LATITUDE, LONGTITUDE & MAIDENHEAD LOCATOR // GOOD FOR PORTABLE HAM RADIO CLOCK or OTHER APPLICATIONS // Simply added a timer function to count the time till the GPS module gets its first // info from the Satellites. // PORTIONS OF CODE TAKEN FROM MANY PLACES and LIBRARY EXAMPLES. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation,version 3 of the License. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Based on ATMEGA328P AVR MCU WITH 8 MHz EXTERNAL CRYSTAL // Using SV1AFN's GPS from APRS1 board // Programming through ISP port ON BOARD // Bootloader has been installed using Arduino as ISP Programmer or USB ASP programmer // OLED connected to I2C port #include #include //https://github.com/mikalhart/TinyGPSPlus #include #include //https://github.com/greiman/SSD1306Ascii #include // Ditto #define I2C_ADDRESS 0x3C // 0x3C or 0x3D Depens on your OLED. SSD1306AsciiWire oled; // Good for 128 x 64 0.94 inch I2C WHITE or YELLOW-BLUE OLED // OLED CONNECTS TO I2C PINS SDA & SCL TOP LEFTMOST PINS ON BOARD, +V3.3 & GND PINS 2 & 6 ON ISP CONNECTOR TinyGPSPlus gps; // GPS uses UART's D0, D1 Rx - Tx pins, Baud rate is set @9600 at setup section // UART's pin do not need explicit declaration unsigned long lastTx = 0; char nw, wl; float lastTxLat = 0.00; float lastTxLng = 0.00; float lastTxdistance = 0.0; int previousHeading = 400; int lastbearing = 0; int headingDelta, lastheadingDelta = 0; byte hour = 0, minute = 0, second = 0; int sats = 0; unsigned long secondtimer = 0; unsigned long timer = 0; //int buttonState = 0; //const int buttonPin = 8; // BUTTON GOOD FOR EXTRA PROGRAMMABLE FEATURES - CONNECTS TO S1 and +V3.3 ON BOARD // Not really needed for this project, but a future option. //====================================================================================================== void setup() { Serial.begin(9600); // BEGIN UART @9600 BPS Wire.begin(); // Join the i2c stream Wire.setClock(400000L); // Set 400KHz i2c speed oled.begin(&Adafruit128x64, I2C_ADDRESS); // Set OLED Constructor oled.setFont(lcd5x7); // Select a small size 5x7 font for the OLED oled.setCursor(26,0); // Print start-up message oled.print("www.SV1AFN.com"); // You can substitute your personal info here. oled.setCursor(0,2); oled.print("GPS UTC ClocK Helper"); delay(4000); // put some delay oled.clear(); // Clear the display } //====================================================================================================== void loop() { { if (millis() - secondtimer >= 1000) { second++; secondtimer = millis(); if (second == 60) { second = 0; minute++; if (minute == 60) { minute = 0; hour++; if (hour == 24) { hour = 0; } } } } } while (Serial.available() > 0) { gps.encode(Serial.read()); } if ( gps.time.isUpdated() ) { hour = gps.time.hour(); minute = gps.time.minute(); second = gps.time.second(); } { sats = gps.satellites.value(); } //================================== Triggered by gps location updates ================================ if ( gps.location.isUpdated() ) { lastTxdistance = TinyGPSPlus::distanceBetween( gps.location.lat(), gps.location.lng(), lastTxLat, lastTxLng); lastbearing = (int)TinyGPSPlus::courseTo( lastTxLat, lastTxLng, gps.location.lat(), gps.location.lng()); nw = gps.location.rawLat().negative ? 'S' : 'N'; wl = gps.location.rawLng().negative ? 'W' : 'E'; // Get headings and heading delta headingDelta = abs(lastbearing - (int)gps.course.deg()); if (headingDelta > 180) { headingDelta = 360 - headingDelta; } lastheadingDelta = abs(lastbearing - previousHeading); if (lastheadingDelta > 180) { lastheadingDelta = 360 - lastheadingDelta; } } // endof gps.location.isUpdated() //======================= CONVERSION OF GPS CO-ORDINATES TO MAIDENHEAD LOCATOR ======================== long latt, lonn; lonn = (gps.location.lng() * 100000) + 18000000; // Step 1 latt = (gps.location.lat() * 100000) + 9000000; // Adjust so Locn AA is at the pole char MH[6] = {'A', 'A', '0', '0', 'a', 'a'}; // Initialise our print string MH[0] += lonn / 2000000; // Field MH[1] += latt / 1000000; MH[2] += (lonn % 2000000) / 200000; // Square MH[3] += (latt % 1000000) / 100000; MH[4] += (lonn % 200000) / 8333; // Subsquare .08333 is 5/60 MH[5] += (latt % 100000) / 4166; // .04166 is 2.5/60 String MH_txt = ""; // Build up Maidenhead into a string that's easy to print int i = 0; while (i < 6) { MH_txt += MH[i]; i++; } // endof Maidenhead calculation //======================================== OLED DISPLAY =============================================== oled.setCursor(0,0); // UTC Time will be diplayed here in the format HH:MM:SS oled.print(F("UTC:")); oled.set2X(); // Make font double if (hour < 10) // Add a leading zero oled.print(F("0")); oled.print(hour); oled.print(F(":")); if (minute < 10) // Add a leading zero oled.print(F("0")); oled.print(minute); oled.print(F(":")); if (second < 10) // Add a leading zero oled.print(F("0")); oled.print(second); oled.set1X(); // Make font single oled.setCursor(0,2); oled.print(F("LOC:")); oled.set2X(); // Make font double oled.print(MH_txt); oled.set1X(); // Make font single oled.setCursor(16,5); oled.print(F("LAT : ")); oled.print(gps.location.lat(), 6); oled.setCursor(16, 6); oled.print(F("LONG: ")); oled.print(gps.location.lng(), 6); oled.setCursor(28, 7); oled.print(F("# SATs: ")); if (sats <10) // Add a leading zero oled.print(F("0")); oled.print(sats); }