├── Wiring Diagram.JPG ├── README.md ├── Licence.txt ├── ESP8266_Simple_GPS_Reader_01.ino ├── ESP_GPS_Compass_01.ino ├── ESP8266_Simple_GPS_Reader_02.ino └── ESP8266_Simple_GPS_Reader_KPH__03.ino /Wiring Diagram.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/G6EJD/ESP-GPS-Compass/HEAD/Wiring Diagram.JPG -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP-GPS-Compass 2 | A compass display using a ESP8266 or ESP32, TFT display and Neo6M GPS 3 | 4 | Adjust the pin mapping to suit your chosen board 5 | 6 | Select the units as required 7 | -------------------------------------------------------------------------------- /Licence.txt: -------------------------------------------------------------------------------- 1 | This software, the ideas and concepts is Copyright (c) David Bird 2014 and beyond. 2 | 3 | All rights to this software are reserved. 4 | 5 | It is prohibited to redistribute or reproduce of any part or all of the software contents in any form other than the following: 6 | 7 | 1. You may print or download to a local hard disk extracts for your personal and non-commercial use only. 8 | 9 | 2. You may copy the content to individual third parties for their personal use, but only if you acknowledge the author David Bird as the source of the material. 10 | 11 | 3. You may not, except with my express written permission, distribute or commercially exploit the content. 12 | 13 | 4. You may not transmit it or store it in any other website or other form of electronic retrieval system for commercial purposes. 14 | 15 | 5. You MUST include all of this copyright and permission notice ('as annotated') and this shall be included in all copies or substantial portions of the software and where the software use is visible to an end-user. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT. 18 | 19 | FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | 21 | IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /ESP8266_Simple_GPS_Reader_01.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2017 by David Bird. 3 | * 4 | * A system that uses an ESP8266 and NEO-6M GPS Module NEO6MV2 Module to provide a compass. 5 | * 6 | * NOTE: the compass only changes when the GPS module is moving and requires a movement of about 5M to register a change, or depending 7 | * on the CEP (Circular Error Probable) of the GPS signal at the time. 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 10 | * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 11 | * publish, distribute, but not to use it commercially for the purposes of profit making or to sub-license and/or to sell copies of 12 | * the Software or to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 16 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * See more at http://dsbird.org.uk 19 | * 20 | * Copyright (C) 2017 Adafruit, All Rights Reserved. 21 | * 22 | */ 23 | #include 24 | #include 25 | #include "Adafruit_GFX.h" 26 | #include "Adafruit_ILI9341.h" 27 | 28 | // For the ESP8266 D1 Mini use these connections 29 | #define TFT_DC D3 30 | #define TFT_CS D8 31 | #define TFT_MOSI D7 32 | #define TFT_RST D4 33 | #define TFT_CLK D5 34 | #define TFT_LED 3.3v 35 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); // Using only hardware SPI for speed 36 | 37 | // Assign names to common 16-bit color values: 38 | #define BLACK 0x0000 39 | #define BLUE 0x001F 40 | #define RED 0xF800 41 | #define GREEN 0x07E0 42 | #define CYAN 0x07FF 43 | #define YELLOW 0xFFE0 44 | #define ORANGE 0xFD20 45 | #define WHITE 0xFFFF 46 | 47 | String sentence, current_time, lat, lon, azi, fix_quality, num_sats, hdop, altitude, track_true, track_magnetic, speed_knots, speed_kph, speed_mph, date, unused; 48 | float sats, flat, flon, faltitude, fspeed, fbearing; 49 | const int centreX = 230; // Location of the compass display on screen 50 | const int centreY = 120; 51 | const int diameter = 70; // Size of the compass 52 | int dx = centreX, dy = centreY, last_dx = centreX, last_dy = centreY - diameter*0.85, hour, minute, second; 53 | 54 | SoftwareSerial gps(D1, D2); // RX/TX Data Pins, Connect the GPS to D2 and D1 55 | 56 | void setup() { 57 | Serial.begin(115200); 58 | gps.begin(9600); // Begin software serial port that will read the GPS data 59 | tft.begin(); // Start the TFT display 60 | tft.setRotation(3); // Rotate screen by 90° 61 | tft.setTextSize(2); // Set medium text size 62 | tft.setTextColor(YELLOW); 63 | tft.fillScreen(BLUE); 64 | } 65 | 66 | void loop() { 67 | if (gps.available()) { 68 | if (gps.find("GPGGA,")) { //GPGGA,225147.00,5121.87111,N,00207.72174,W,2,09,0.95,47.0,M,48.0,M,,0000*7B 69 | current_time = gps.readStringUntil(','); 70 | hour = current_time.substring(0,2).toInt(); 71 | minute = current_time.substring(2,4).toInt(); 72 | second = current_time.substring(4,6).toInt(); 73 | lat = gps.readStringUntil(','); 74 | flat = lat.toFloat()/100; 75 | String NS = gps.readStringUntil(','); 76 | if (NS == "S") flat = -flat; 77 | lon = gps.readStringUntil(','); 78 | flon = lon.toFloat()/100; 79 | String EW = gps.readStringUntil(','); 80 | if (EW == "W") flon = -flon; 81 | fix_quality = gps.readStringUntil(','); // 0 = Invalid, 1 = GPS fix, 2 = DGPS fix 82 | num_sats = gps.readStringUntil(','); 83 | sats = num_sats.toInt(); 84 | hdop = gps.readStringUntil(','); // Horizontal Dilution of Precision (HDOP) 1.5 Relative accuracy of horizontal position 85 | altitude = gps.readStringUntil(','); // Metres 86 | faltitude = altitude.toFloat(); 87 | unused = gps.readStringUntil('\n'); 88 | } 89 | if (gps.find("GPVTG,")) { //$GPVTG,,T,,M,0.162,N,0.300,K,A*25 90 | track_true = gps.readStringUntil(','); // Track True 91 | track_true += gps.readStringUntil(','); // Track Type 92 | track_magnetic = gps.readStringUntil(','); // Track Magnetic 93 | track_magnetic += gps.readStringUntil(','); // Track Type 94 | speed_knots = gps.readStringUntil(','); // Speed in knots 95 | speed_knots += gps.readStringUntil(','); // Speed units N 96 | speed_kph = gps.readStringUntil(','); // Speed in knots 97 | speed_kph += gps.readStringUntil(','); // Speed units N 98 | speed_mph = String(speed_kph.toFloat()* 0.621371); // Convert kph to MPH 99 | fbearing = track_true.toFloat(); 100 | fspeed = speed_mph.toFloat(); 101 | unused = gps.readStringUntil('\n'); 102 | } 103 | if (gps.find("GPRMC,")) { //$GPRMC,233512.00,A,5121.87041,N,00207.73021,W,0.436,,051217,,,A*68 104 | for (int reading = 1; reading < 9; reading++){ 105 | unused = gps.readStringUntil(','); // T 106 | } 107 | date = gps.readStringUntil(','); // Date 108 | date = date.substring(0,2)+"/"+date.substring(2,4)+"/"+date.substring(4,6); 109 | } 110 | Serial.println("Time\t\tLAT\tLON\tSATS\tAlt\tBearing\tSpeed(MPH)\tDate"); 111 | Serial.println("------------------------------------------------------------------------"); 112 | Serial.print(current_time.substring(0,2)+":"+current_time.substring(2,4)+":"+current_time.substring(4,6)+"\t"); 113 | Serial.print(String(flat,3)+"\t"); 114 | Serial.print(String(flon,3)+"\t"); 115 | Serial.print(num_sats+"\t"); 116 | Serial.print(altitude+"\t"); 117 | Serial.print(String(fbearing)+"\t"); 118 | Serial.print(String(fspeed)+"\t"); 119 | Serial.println(date); 120 | Serial.println(); 121 | } 122 | else 123 | { 124 | Serial.println("Waiting for GPS to acquire signal..."); 125 | } 126 | OLED_display_GPS_data(); 127 | } 128 | 129 | void OLED_display_GPS_data(){ 130 | PrintText(60,0,"G6EJD GPS Compass",CYAN,2); 131 | tft.fillRect(45,40,90,19*4,BLUE); 132 | PrintText(0,45,"LAT:"+String(flat),YELLOW,2); 133 | PrintText(0,63,"LON:"+String(flon),YELLOW,2); 134 | PrintText(0,81,"ALT:"+String(faltitude,1)+"M",YELLOW,2); 135 | PrintText(0,99,"SAT:"+String(sats,0),YELLOW,2); 136 | tft.fillRect(80,220,120,18,BLUE); 137 | PrintText(10,220,"Speed:"+String(fspeed)+"mph",YELLOW,2); 138 | tft.fillRect(240,220,120,18,BLUE); 139 | tft.setCursor(200,220); 140 | tft.print("Azi:"+String(fbearing)); 141 | Display_Compass(); 142 | Display_Date_Time(); 143 | } 144 | 145 | void Display_Compass() { 146 | int dxo, dyo, dxi, dyi; 147 | tft.setCursor(0,0); 148 | tft.drawCircle(centreX,centreY,diameter,WHITE); // Draw compass circle 149 | for (float i = 0; i <360; i = i + 22.5) { 150 | dxo = diameter * cos((i-90)*3.14/180); 151 | dyo = diameter * sin((i-90)*3.14/180); 152 | dxi = dxo * 0.9; 153 | dyi = dyo * 0.9; 154 | tft.drawLine(dxo+centreX,dyo+centreY,dxi+centreX,dyi+centreY,WHITE); 155 | } 156 | PrintText((centreX-5),(centreY-diameter-18),"N",GREEN,2); 157 | PrintText((centreX-5),(centreY+diameter+5) ,"S",GREEN,2); 158 | PrintText((centreX+diameter+5),(centreY-5), "E",GREEN,2); 159 | PrintText((centreX-diameter-15),(centreY-5),"W",GREEN,2); 160 | dx = (0.85*diameter * cos((fbearing-90)*3.14/180)) + centreX; // calculate X position 161 | dy = (0.85*diameter * sin((fbearing-90)*3.14/180)) + centreY; // calculate Y position 162 | draw_arrow(last_dx,last_dy, centreX, centreY, 5, 5,BLUE); // Erase last arrow 163 | draw_arrow(dx,dy, centreX, centreY, 5, 5,YELLOW); // Draw arrow in new position 164 | last_dx = dx; 165 | last_dy = dy; 166 | } 167 | 168 | void draw_arrow(int x2, int y2, int x1, int y1, int alength, int awidth, int colour) { 169 | float distance; 170 | int dx, dy, x2o,y2o,x3,y3,x4,y4,k; 171 | distance = sqrt(pow((x1 - x2),2) + pow((y1 - y2), 2)); 172 | dx = x2 + (x1 - x2) * alength / distance; 173 | dy = y2 + (y1 - y2) * alength / distance; 174 | k = awidth / alength; 175 | x2o = x2 - dx; 176 | y2o = dy - y2; 177 | x3 = y2o * k + dx; 178 | y3 = x2o * k + dy; 179 | x4 = dx - y2o * k; 180 | y4 = dy - x2o * k; 181 | tft.drawLine(x1, y1, x2, y2,colour); 182 | tft.drawLine(x1, y1, dx, dy,colour); 183 | tft.drawLine(x3, y3, x4, y4,colour); 184 | tft.drawLine(x3, y3, x2, y2,colour); 185 | tft.drawLine(x2, y2, x4, y4,colour); 186 | } 187 | 188 | void Display_Date_Time(){ 189 | PrintText(0,150,"Date/Time:",CYAN,2); 190 | tft.fillRect(0,165,130,19*2,BLUE); 191 | PrintText(0,168,(hour<10?"0":"")+String(hour)+":"+(minute<10?"0":"")+String(minute)+":"+(second<10?"0":"")+String(second),GREEN,2); 192 | PrintText(0,188,date,GREEN,2); 193 | } 194 | 195 | void PrintText(int x, int y, String text, int colour, byte text_size){ 196 | tft.setCursor(x,y); 197 | tft.setTextColor(colour); 198 | tft.setTextSize(text_size); 199 | tft.print(text); 200 | tft.setTextColor(YELLOW); // Default colour 201 | tft.setTextSize(2); // Default Text Size 202 | } 203 | 204 | /* 205 | neo-6M Returns the following example sentences 206 | $GPRMC,233512.00,A,5121.87041,N,00207.73021,W,0.436,,051217,,,A*68 207 | $GPVTG,,T,,M,0.436,N,0.808,K,A*22 208 | $GPGGA,233512.00,5121.87041,N,00207.73021,W,1,09,1.48,56.3,M,48.0,M,,*7D 209 | $GPGSA,A,3,26,31,29,25,12,14,06,32,02,,,,2.16,1.48,1.57*00 210 | $GPGSV,4,1,13,02,29,057,22,04,30,275,19,06,10,028,15,12,30,084,16*78 211 | $GPGSV,4,2,13,14,34,249,24,21,01,174,,24,01,143,,25,69,075,35*7B 212 | $GPGSV,4,3,13,26,13,274,22,29,73,172,17,31,51,297,28,32,22,228,25*78 213 | $GPGSV,4,4,13,33,30,196,34*41 214 | $GPGLL,5121.87041,N,00207.73021,W,233512.00,A,A*70 215 | */ 216 | -------------------------------------------------------------------------------- /ESP_GPS_Compass_01.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This software, the ideas and concepts is Copyright (c) David Bird 2021 and beyond. 3 | All rights to this software are reserved. 4 | It is prohibited to redistribute or reproduce of any part or all of the software contents in any form other than the following: 5 | 1. You may print or download to a local hard disk extracts for your personal and non-commercial use only. 6 | 2. You may copy the content to individual third parties for their personal use, but only if you acknowledge the author David Bird as the source of the material. 7 | 3. You may not, except with my express written permission, distribute or commercially exploit the content. 8 | 4. You may not transmit it or store it in any other website or other form of electronic retrieval system for commercial purposes. 9 | 5. You MUST include all of this copyright and permission notice ('as annotated') and this shall be included in all copies 10 | or substantial portions of the software and where the software use is visible to an end-user. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT. 13 | 14 | FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 | 17 | IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 18 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | */ 20 | 21 | #include "TinyGPS++.h" 22 | #include 23 | TinyGPSPlus gps; 24 | 25 | #ifdef ESP32 26 | SoftwareSerial ss(34, 12); //tx,rx for TTGO T-BEAM 27 | #else 28 | SoftwareSerial ss(D1, D2); //tx,rx for Wemos D1 Mini 29 | #endif 30 | 31 | #include 32 | #include "Adafruit_GFX.h" 33 | #include "Adafruit_ILI9341.h" 34 | 35 | // For the ESP8266 D1 Mini use these connections 36 | #define TFT_DC 0 // D3 37 | #define TFT_CS 15 // D8 38 | #define TFT_MOSI 13 // D7 39 | #define TFT_RST 2 // D4 40 | #define TFT_CLK 14 // D5 41 | #define TFT_LED 3.3v 42 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); // Using only hardware SPI for speed 43 | 44 | // Assign names to common 16-bit color values: 45 | #define BLACK 0x0000 46 | #define BLUE 0x001F 47 | #define RED 0xF800 48 | #define GREEN 0x07E0 49 | #define CYAN 0x07FF 50 | #define YELLOW 0xFFE0 51 | #define ORANGE 0xFD20 52 | #define WHITE 0xFFFF 53 | 54 | String Time, Date; 55 | float NumberSats, Latitude, Longitude, Bearing; 56 | float AltitudeMETRES, AltitudeMILES, AltitudeKM, AltitudeFEET; 57 | float SpeedKPH, SpeedMPH, SpeedKNOTS, SpeedMPS; 58 | 59 | const int centreX = 230; // Location of the compass display on screen 60 | const int centreY = 120; 61 | const int diameter = 70; // Size of the compass 62 | int dx = centreX, dy = centreY; 63 | int last_dx = centreX, last_dy = centreY - diameter * 0.85; 64 | 65 | void setup() { 66 | Serial.begin(115200); 67 | ss.begin(9600); // This opens up communications to the GPS 68 | tft.begin(); // Start the TFT display 69 | tft.setRotation(3); // Rotate screen by 90° 70 | tft.setTextSize(2); // Set medium text size 71 | tft.setTextColor(YELLOW); 72 | tft.fillScreen(BLUE); 73 | } 74 | 75 | void loop() { 76 | Latitude = gps.location.lat(); 77 | Longitude = gps.location.lng(); 78 | Date = String(gps.date.day() < 10 ? "0" : "") + String(gps.date.day()) + "/" + String(gps.date.month() < 10 ? "0" : "") + String(gps.date.month()) + "/" + String(gps.date.year()); 79 | //Date = String(gps.date.month()<10?"0":"") + String(gps.date.month()) + "/" + String(gps.date.day()<10?"0":"") + String(gps.date.day()) + "/" + String(gps.date.year()); 80 | Time = String(gps.time.hour() < 10 ? "0" : "") + String(gps.time.hour()) + ":" + 81 | String(gps.time.minute() < 10 ? "0" : "") + String(gps.time.minute()) + ":" + String(gps.time.hour() < 10 ? "0" : "") + String(gps.time.second() < 10 ? "0" : "") + String(gps.time.second()); 82 | Bearing = gps.course.deg(); 83 | SpeedKPH = gps.speed.kmph(); 84 | SpeedMPH = gps.speed.mph(); 85 | SpeedKNOTS = gps.speed.knots(); 86 | SpeedMPS = gps.speed.mps(); 87 | NumberSats = gps.satellites.value(); 88 | AltitudeMETRES = gps.altitude.meters(); 89 | AltitudeKM = gps.altitude.kilometers(); 90 | AltitudeMILES = gps.altitude.miles(); 91 | AltitudeFEET = gps.altitude.feet(); 92 | Serial.println("Time\t\tDate\t\tLAT\tLON\tSATS\tAlt\tBearing\tSpeed(KPH)"); 93 | Serial.println("----------------------------------------------------------------------------------"); 94 | Serial.print(Time + "\t"); 95 | Serial.print(Date + "\t"); 96 | Serial.print(String(Latitude, 3) + "\t"); 97 | Serial.print(String(Longitude, 3) + "\t"); 98 | Serial.print(String(NumberSats) + "\t"); 99 | Serial.print(String(AltitudeMETRES) + "\t"); // Select as required 100 | Serial.print(String(Bearing) + "\t"); 101 | Serial.print(String(SpeedKPH) + "\t"); // Select as required 102 | //Serial.print(String(SpeedMPH) + "\t"); // Select as required 103 | Serial.println("\n"); 104 | DisplayGPSdata(NumberSats, Latitude, Longitude, AltitudeMETRES, SpeedKPH, Bearing); // Select units as required 105 | smartDelay(1000); 106 | if (millis() > 5000 && gps.charsProcessed() < 10) Serial.println(F("No GPS data received: check wiring")); 107 | } 108 | //##################################################################### 109 | void DisplayGPSdata(float dNumberSats, float dLatitude, float dLongitude, float dAltitude, float dSpeed, float dBearing) { 110 | PrintText(60, 0, "G6EJD GPS Compass", CYAN, 2); 111 | tft.fillRect(45, 40, 90, 19 * 4, BLUE); 112 | PrintText(0, 45, "LAT:" + String(dLatitude), YELLOW, 2); 113 | PrintText(0, 63, "LON:" + String(dLongitude), YELLOW, 2); 114 | PrintText(0, 81, "ALT:" + String(dAltitude, 1) + "M", YELLOW, 2); 115 | PrintText(0, 99, "SAT:" + String(dNumberSats, 0), YELLOW, 2); 116 | tft.fillRect(80, 220, 120, 18, BLUE); 117 | PrintText(10, 220, "Speed:" + String(dSpeed) + "kph", YELLOW, 2); 118 | tft.fillRect(240, 220, 120, 18, BLUE); 119 | tft.setCursor(200, 220); 120 | tft.print("Azi: " + Bearing_to_Ordinal(dBearing)); 121 | Display_Compass(dBearing); 122 | Display_Date_Time(); 123 | } 124 | //##################################################################### 125 | void Display_Compass(float dBearing) { 126 | int dxo, dyo, dxi, dyi; 127 | tft.setCursor(0, 0); 128 | tft.drawCircle(centreX, centreY, diameter, WHITE); // Draw compass circle 129 | for (float i = 0; i < 360; i = i + 22.5) { 130 | dxo = diameter * cos((i - 90) * 3.14 / 180); 131 | dyo = diameter * sin((i - 90) * 3.14 / 180); 132 | dxi = dxo * 0.9; 133 | dyi = dyo * 0.9; 134 | tft.drawLine(dxo + centreX, dyo + centreY, dxi + centreX, dyi + centreY, WHITE); 135 | } 136 | PrintText((centreX - 5), (centreY - diameter - 18), "N", GREEN, 2); 137 | PrintText((centreX - 5), (centreY + diameter + 5) , "S", GREEN, 2); 138 | PrintText((centreX + diameter + 5), (centreY - 5), "E", GREEN, 2); 139 | PrintText((centreX - diameter - 15), (centreY - 5), "W", GREEN, 2); 140 | dx = (0.85 * diameter * cos((dBearing - 90) * 3.14 / 180)) + centreX; // calculate X position 141 | dy = (0.85 * diameter * sin((dBearing - 90) * 3.14 / 180)) + centreY; // calculate Y position 142 | draw_arrow(last_dx, last_dy, centreX, centreY, 5, 5, BLUE); // Erase last arrow 143 | draw_arrow(dx, dy, centreX, centreY, 5, 5, YELLOW); // Draw arrow in new position 144 | last_dx = dx; 145 | last_dy = dy; 146 | } 147 | //##################################################################### 148 | void draw_arrow(int x2, int y2, int x1, int y1, int alength, int awidth, int colour) { 149 | float distance; 150 | int dx, dy, x2o, y2o, x3, y3, x4, y4, k; 151 | distance = sqrt(pow((x1 - x2), 2) + pow((y1 - y2), 2)); 152 | dx = x2 + (x1 - x2) * alength / distance; 153 | dy = y2 + (y1 - y2) * alength / distance; 154 | k = awidth / alength; 155 | x2o = x2 - dx; 156 | y2o = dy - y2; 157 | x3 = y2o * k + dx; 158 | y3 = x2o * k + dy; 159 | x4 = dx - y2o * k; 160 | y4 = dy - x2o * k; 161 | tft.drawLine(x1, y1, x2, y2, colour); 162 | tft.drawLine(x1, y1, dx, dy, colour); 163 | tft.drawLine(x3, y3, x4, y4, colour); 164 | tft.drawLine(x3, y3, x2, y2, colour); 165 | tft.drawLine(x2, y2, x4, y4, colour); 166 | } 167 | //##################################################################### 168 | void Display_Date_Time() { 169 | PrintText(0, 150, "Date/Time:", CYAN, 2); 170 | tft.fillRect(0, 165, 130, 19 * 2, BLUE); 171 | PrintText(0, 168, Time, GREEN, 2); 172 | PrintText(0, 188, Date, GREEN, 2); 173 | } 174 | //##################################################################### 175 | String Bearing_to_Ordinal(float bearing) { 176 | if (bearing >= 348.75 || bearing < 11.25) return "N"; 177 | if (bearing >= 11.25 && bearing < 33.75) return "NNE"; 178 | if (bearing >= 33.75 && bearing < 56.25) return "NE"; 179 | if (bearing >= 56.25 && bearing < 78.75) return "ENE"; 180 | if (bearing >= 78.75 && bearing < 101.25) return "E"; 181 | if (bearing >= 101.25 && bearing < 123.75) return "ESE"; 182 | if (bearing >= 123.75 && bearing < 146.25) return "SE"; 183 | if (bearing >= 146.25 && bearing < 168.75) return "SSE"; 184 | if (bearing >= 168.75 && bearing < 191.25) return "S"; 185 | if (bearing >= 191.25 && bearing < 213.75) return "SSW"; 186 | if (bearing >= 213.75 && bearing < 236.25) return "SW"; 187 | if (bearing >= 236.25 && bearing < 258.75) return "WSW"; 188 | if (bearing >= 258.75 && bearing < 281.25) return "W"; 189 | if (bearing >= 281.25 && bearing < 303.75) return "WNW"; 190 | if (bearing >= 303.75 && bearing < 326.25) return "NW"; 191 | if (bearing >= 326.25 && bearing < 348.75) return "NNW"; 192 | return "?"; 193 | } 194 | //##################################################################### 195 | void PrintText(int x, int y, String text, int colour, byte text_size) { 196 | tft.setCursor(x, y); 197 | tft.setTextColor(colour); 198 | tft.setTextSize(text_size); 199 | tft.print(text); 200 | tft.setTextColor(YELLOW); // Default colour 201 | tft.setTextSize(2); // Default Text Size 202 | } 203 | //##################################################################### 204 | static void smartDelay(unsigned long ms) { 205 | unsigned long start = millis(); 206 | do { 207 | while (ss.available()) gps.encode(ss.read()); 208 | } while (millis() - start < ms); 209 | } 210 | -------------------------------------------------------------------------------- /ESP8266_Simple_GPS_Reader_02.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) Copyright (c) 2017 by David Bird. 3 | * 4 | * A system that uses an ESP8266 and NEO-6M GPS Module NEO6MV2 Module to provide a compass. 5 | * 6 | * NOTE: the compass only changes when the GPS module is moving and requires a movement of about 5M to register a change, or depending 7 | * on the CEP (Circular Error Probable) of the GPS signal at the time. 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 10 | * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 11 | * publish, distribute, but not to use it commercially for the purposes of profit making or to sub-license and/or to sell copies of 12 | * the Software or to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 16 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * See more at http://dsbird.org.uk 19 | * 20 | * Copyright (C) 2017 Adafruit, All Rights Reserved. 21 | * 22 | */ 23 | #include 24 | #include 25 | #include "Adafruit_GFX.h" 26 | #include "Adafruit_ILI9341.h" 27 | 28 | // For the ESP8266 D1 Mini use these connections 29 | #define TFT_DC D3 30 | #define TFT_CS D8 31 | #define TFT_MOSI D7 32 | #define TFT_RST D4 33 | #define TFT_CLK D5 34 | #define TFT_LED 3.3v 35 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); // Using only hardware SPI for speed 36 | 37 | // Assign names to common 16-bit color values: 38 | #define BLACK 0x0000 39 | #define BLUE 0x001F 40 | #define RED 0xF800 41 | #define GREEN 0x07E0 42 | #define CYAN 0x07FF 43 | #define YELLOW 0xFFE0 44 | #define ORANGE 0xFD20 45 | #define WHITE 0xFFFF 46 | 47 | String sentence, current_time, lat, lon, azi, fix_quality, num_sats, hdop, altitude, track_true, track_magnetic, speed_knots, speed_kph, speed_mph, date, ordinal_bearing, unused; 48 | float sats, flat, flon, faltitude, fspeed, fbearing; 49 | const int centreX = 230; // Location of the compass display on screen 50 | const int centreY = 120; 51 | const int diameter = 70; // Size of the compass 52 | int dx = centreX, dy = centreY, last_dx = centreX, last_dy = centreY - diameter*0.85, hour, minute, second; 53 | 54 | SoftwareSerial gps(D1, D2); // RX/TX Data Pins, Connect the GPS to D2 and D1 55 | 56 | void setup() { 57 | Serial.begin(115200); 58 | gps.begin(9600); // Begin software serial port that will read the GPS data 59 | tft.begin(); // Start the TFT display 60 | tft.setRotation(3); // Rotate screen by 90° 61 | tft.setTextSize(2); // Set medium text size 62 | tft.setTextColor(YELLOW); 63 | tft.fillScreen(BLUE); 64 | } 65 | 66 | void loop() { 67 | if (gps.available()) { 68 | if (gps.find("GPGGA,")) { //GPGGA,225147.00,5121.87111,N,00207.72174,W,2,09,0.95,47.0,M,48.0,M,,0000*7B 69 | current_time = gps.readStringUntil(','); 70 | hour = current_time.substring(0,2).toInt(); 71 | minute = current_time.substring(2,4).toInt(); 72 | second = current_time.substring(4,6).toInt(); 73 | lat = gps.readStringUntil(','); 74 | flat = lat.toFloat()/100; 75 | String NS = gps.readStringUntil(','); 76 | if (NS == "S") flat = -flat; 77 | lon = gps.readStringUntil(','); 78 | flon = lon.toFloat()/100; 79 | String EW = gps.readStringUntil(','); 80 | if (EW == "W") flon = -flon; 81 | fix_quality = gps.readStringUntil(','); // 0 = Invalid, 1 = GPS fix, 2 = DGPS fix 82 | num_sats = gps.readStringUntil(','); 83 | sats = num_sats.toInt(); 84 | hdop = gps.readStringUntil(','); // Horizontal Dilution of Precision (HDOP) 1.5 Relative accuracy of horizontal position 85 | altitude = gps.readStringUntil(','); // Metres 86 | faltitude = altitude.toFloat(); 87 | unused = gps.readStringUntil('\n'); 88 | } 89 | if (gps.find("GPVTG,")) { //$GPVTG,,T,,M,0.162,N,0.300,K,A*25 90 | track_true = gps.readStringUntil(','); // Track True 91 | track_true += gps.readStringUntil(','); // Track Type 92 | track_magnetic = gps.readStringUntil(','); // Track Magnetic 93 | track_magnetic += gps.readStringUntil(','); // Track Type 94 | speed_knots = gps.readStringUntil(','); // Speed in knots 95 | speed_knots += gps.readStringUntil(','); // Speed units N 96 | speed_kph = gps.readStringUntil(','); // Speed in knots 97 | speed_kph += gps.readStringUntil(','); // Speed units N 98 | speed_mph = String(speed_kph.toFloat()* 0.621371); // Convert kph to MPH 99 | fbearing = track_true.toFloat(); 100 | ordinal_bearing = Bearing_to_Ordinal(fbearing); 101 | fspeed = speed_mph.toFloat(); 102 | unused = gps.readStringUntil('\n'); 103 | } 104 | if (gps.find("GPRMC,")) { //$GPRMC,233512.00,A,5121.87041,N,00207.73021,W,0.436,,051217,,,A*68 105 | for (int reading = 1; reading < 9; reading++){ 106 | unused = gps.readStringUntil(','); // T 107 | } 108 | date = gps.readStringUntil(','); // Date 109 | date = date.substring(0,2)+"/"+date.substring(2,4)+"/"+date.substring(4,6); 110 | } 111 | Serial.println("Time\t\tLAT\tLON\tSATS\tAlt\tBearing\tSpeed(MPH)\tDate"); 112 | Serial.println("------------------------------------------------------------------------"); 113 | Serial.print(current_time.substring(0,2)+":"+current_time.substring(2,4)+":"+current_time.substring(4,6)+"\t"); 114 | Serial.print(String(flat,3)+"\t"); 115 | Serial.print(String(flon,3)+"\t"); 116 | Serial.print(num_sats+"\t"); 117 | Serial.print(altitude+"\t"); 118 | Serial.print(String(fbearing)+"\t"); 119 | Serial.print(String(fspeed)+"\t"); 120 | Serial.println(date); 121 | Serial.println(); 122 | } 123 | else 124 | { 125 | Serial.println("Waiting for GPS to acquire signal..."); 126 | } 127 | OLED_display_GPS_data(); 128 | } 129 | 130 | void OLED_display_GPS_data(){ 131 | PrintText(60,0,"G6EJD GPS Compass",CYAN,2); 132 | tft.fillRect(45,40,90,19*4,BLUE); 133 | PrintText(0,45,"LAT:"+String(flat),YELLOW,2); 134 | PrintText(0,63,"LON:"+String(flon),YELLOW,2); 135 | PrintText(0,81,"ALT:"+String(faltitude,1)+"M",YELLOW,2); 136 | PrintText(0,99,"SAT:"+String(sats,0),YELLOW,2); 137 | tft.fillRect(80,220,120,18,BLUE); 138 | PrintText(10,220,"Speed:"+String(fspeed)+"mph",YELLOW,2); 139 | tft.fillRect(240,220,120,18,BLUE); 140 | tft.setCursor(200,220); 141 | tft.print("Azi: "+ordinal_bearing); 142 | Display_Compass(); 143 | Display_Date_Time(); 144 | } 145 | 146 | void Display_Compass() { 147 | int dxo, dyo, dxi, dyi; 148 | tft.setCursor(0,0); 149 | tft.drawCircle(centreX,centreY,diameter,WHITE); // Draw compass circle 150 | for (float i = 0; i <360; i = i + 22.5) { 151 | dxo = diameter * cos((i-90)*3.14/180); 152 | dyo = diameter * sin((i-90)*3.14/180); 153 | dxi = dxo * 0.9; 154 | dyi = dyo * 0.9; 155 | tft.drawLine(dxo+centreX,dyo+centreY,dxi+centreX,dyi+centreY,WHITE); 156 | } 157 | PrintText((centreX-5),(centreY-diameter-18),"N",GREEN,2); 158 | PrintText((centreX-5),(centreY+diameter+5) ,"S",GREEN,2); 159 | PrintText((centreX+diameter+5),(centreY-5), "E",GREEN,2); 160 | PrintText((centreX-diameter-15),(centreY-5),"W",GREEN,2); 161 | dx = (0.85*diameter * cos((fbearing-90)*3.14/180)) + centreX; // calculate X position 162 | dy = (0.85*diameter * sin((fbearing-90)*3.14/180)) + centreY; // calculate Y position 163 | draw_arrow(last_dx,last_dy, centreX, centreY, 5, 5,BLUE); // Erase last arrow 164 | draw_arrow(dx,dy, centreX, centreY, 5, 5,YELLOW); // Draw arrow in new position 165 | last_dx = dx; 166 | last_dy = dy; 167 | } 168 | 169 | void draw_arrow(int x2, int y2, int x1, int y1, int alength, int awidth, int colour) { 170 | float distance; 171 | int dx, dy, x2o,y2o,x3,y3,x4,y4,k; 172 | distance = sqrt(pow((x1 - x2),2) + pow((y1 - y2), 2)); 173 | dx = x2 + (x1 - x2) * alength / distance; 174 | dy = y2 + (y1 - y2) * alength / distance; 175 | k = awidth / alength; 176 | x2o = x2 - dx; 177 | y2o = dy - y2; 178 | x3 = y2o * k + dx; 179 | y3 = x2o * k + dy; 180 | x4 = dx - y2o * k; 181 | y4 = dy - x2o * k; 182 | tft.drawLine(x1, y1, x2, y2,colour); 183 | tft.drawLine(x1, y1, dx, dy,colour); 184 | tft.drawLine(x3, y3, x4, y4,colour); 185 | tft.drawLine(x3, y3, x2, y2,colour); 186 | tft.drawLine(x2, y2, x4, y4,colour); 187 | } 188 | 189 | void Display_Date_Time(){ 190 | PrintText(0,150,"Date/Time:",CYAN,2); 191 | tft.fillRect(0,165,130,19*2,BLUE); 192 | PrintText(0,168,(hour<10?"0":"")+String(hour)+":"+(minute<10?"0":"")+String(minute)+":"+(second<10?"0":"")+String(second),GREEN,2); 193 | PrintText(0,188,date,GREEN,2); 194 | } 195 | 196 | String Bearing_to_Ordinal(float bearing) { 197 | if (bearing >= 0.0 && bearing < 11.25 ) return "N"; 198 | if (bearing >= 11.25 && bearing < 33.75 ) return "NNE"; 199 | if (bearing >= 33.75 && bearing < 56.25 ) return "NE"; 200 | if (bearing >= 56.25 && bearing < 78.75 ) return "ENE"; 201 | if (bearing >= 78.75 && bearing < 101.25 ) return "E"; 202 | if (bearing >= 101.25 && bearing < 123.75 ) return "ESE"; 203 | if (bearing >= 123.75 && bearing < 146.25 ) return "SE"; 204 | if (bearing >= 146.25 && bearing < 168.75 ) return "SSE"; 205 | if (bearing >= 168.75 && bearing < 191.25 ) return "S"; 206 | if (bearing >= 191.25 && bearing < 213.75 ) return "SSW"; 207 | if (bearing >= 213.75 && bearing < 236.25 ) return "SW"; 208 | if (bearing >= 236.25 && bearing < 258.25 ) return "WSW"; 209 | if (bearing >= 258.25 && bearing < 281.25 ) return "W"; 210 | if (bearing >= 281.25 && bearing < 303.75 ) return "WNW"; 211 | if (bearing >= 303.75 && bearing < 326.25 ) return "NW"; 212 | if (bearing >= 326.25 && bearing < 348.75 ) return "NNW"; 213 | if (bearing >= 348.75 && bearing < 360.00 ) return "N"; 214 | else return "N"; 215 | } 216 | /* 217 | N 348.75 11.25 218 | NNE 11.25 33.75 219 | NE 33.75 56.25 220 | ENE 56.25 78.75 221 | E 78.75 101.25 222 | ESE 101.25 123.75 223 | SE 123.75 146.25 224 | SSE 146.25 168.75 225 | S 168.75 191.25 226 | SSW 191.25 213.75 227 | SW 213.75 236.25 228 | WSW 236.25 258.75 229 | W 258.75 281.25 230 | WNW 281.25 303.75 231 | NW 303.75 326.25 232 | NNW 326.25 348.75 233 | */ 234 | 235 | void PrintText(int x, int y, String text, int colour, byte text_size){ 236 | tft.setCursor(x,y); 237 | tft.setTextColor(colour); 238 | tft.setTextSize(text_size); 239 | tft.print(text); 240 | tft.setTextColor(YELLOW); // Default colour 241 | tft.setTextSize(2); // Default Text Size 242 | } 243 | 244 | /* 245 | neo-6M Returns the following example sentences 246 | $GPRMC,233512.00,A,5121.87041,N,00207.73021,W,0.436,,051217,,,A*68 247 | $GPVTG,,T,,M,0.436,N,0.808,K,A*22 248 | $GPGGA,233512.00,5121.87041,N,00207.73021,W,1,09,1.48,56.3,M,48.0,M,,*7D 249 | $GPGSA,A,3,26,31,29,25,12,14,06,32,02,,,,2.16,1.48,1.57*00 250 | $GPGSV,4,1,13,02,29,057,22,04,30,275,19,06,10,028,15,12,30,084,16*78 251 | $GPGSV,4,2,13,14,34,249,24,21,01,174,,24,01,143,,25,69,075,35*7B 252 | $GPGSV,4,3,13,26,13,274,22,29,73,172,17,31,51,297,28,32,22,228,25*78 253 | $GPGSV,4,4,13,33,30,196,34*41 254 | $GPGLL,5121.87041,N,00207.73021,W,233512.00,A,A*70 255 | */ 256 | -------------------------------------------------------------------------------- /ESP8266_Simple_GPS_Reader_KPH__03.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This software, the ideas and concepts is Copyright (c) David Bird 2021 and beyond. 3 | All rights to this software are reserved. 4 | It is prohibited to redistribute or reproduce of any part or all of the software contents in any form other than the following: 5 | 1. You may print or download to a local hard disk extracts for your personal and non-commercial use only. 6 | 2. You may copy the content to individual third parties for their personal use, but only if you acknowledge the author David Bird as the source of the material. 7 | 3. You may not, except with my express written permission, distribute or commercially exploit the content. 8 | 4. You may not transmit it or store it in any other website or other form of electronic retrieval system for commercial purposes. 9 | 5. You MUST include all of this copyright and permission notice ('as annotated') and this shall be included in all copies 10 | or substantial portions of the software and where the software use is visible to an end-user. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT. 13 | 14 | FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 | 17 | IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 18 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | */ 20 | #include 21 | #include 22 | #include "Adafruit_GFX.h" 23 | #include "Adafruit_ILI9341.h" 24 | 25 | // For the ESP8266 D1 Mini use these connections 26 | #define TFT_DC D3 27 | #define TFT_CS D8 28 | #define TFT_MOSI D7 29 | #define TFT_RST D4 30 | #define TFT_CLK D5 31 | #define TFT_LED 3.3v 32 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); // Using only hardware SPI for speed 33 | 34 | // Assign names to common 16-bit color values: 35 | #define BLACK 0x0000 36 | #define BLUE 0x001F 37 | #define RED 0xF800 38 | #define GREEN 0x07E0 39 | #define CYAN 0x07FF 40 | #define YELLOW 0xFFE0 41 | #define ORANGE 0xFD20 42 | #define WHITE 0xFFFF 43 | 44 | String sentence, current_time, lat, lon, azi, fix_quality, num_sats, hdop, altitude, track_true, track_magnetic, speed_knots, speed_kph, speed_mph, date, ordinal_bearing, unused; 45 | float sats, flat, flon, faltitude, fspeed, fbearing; 46 | const int centreX = 230; // Location of the compass display on screen 47 | const int centreY = 120; 48 | const int diameter = 70; // Size of the compass 49 | int dx = centreX, dy = centreY, last_dx = centreX, last_dy = centreY - diameter*0.85, hour, minute, second; 50 | 51 | SoftwareSerial gps(D1, D2); // RX/TX Data Pins, Connect the GPS to D2 and D1 52 | 53 | void setup() { 54 | Serial.begin(115200); 55 | gps.begin(9600); // Begin software serial port that will read the GPS data 56 | tft.begin(); // Start the TFT display 57 | tft.setRotation(3); // Rotate screen by 90° 58 | tft.setTextSize(2); // Set medium text size 59 | tft.setTextColor(YELLOW); 60 | tft.fillScreen(BLUE); 61 | } 62 | 63 | void loop() { 64 | if (gps.available()) { 65 | if (gps.find("GPGGA,")) { //GPGGA,225147.00,5121.87111,N,00207.72174,W,2,09,0.95,47.0,M,48.0,M,,0000*7B 66 | current_time = gps.readStringUntil(','); 67 | hour = current_time.substring(0,2).toInt(); 68 | minute = current_time.substring(2,4).toInt(); 69 | second = current_time.substring(4,6).toInt(); 70 | lat = gps.readStringUntil(','); 71 | flat = lat.toFloat()/100; 72 | String NS = gps.readStringUntil(','); 73 | if (NS == "S") flat = -flat; 74 | lon = gps.readStringUntil(','); 75 | flon = lon.toFloat()/100; 76 | String EW = gps.readStringUntil(','); 77 | if (EW == "W") flon = -flon; 78 | fix_quality = gps.readStringUntil(','); // 0 = Invalid, 1 = GPS fix, 2 = DGPS fix 79 | num_sats = gps.readStringUntil(','); 80 | sats = num_sats.toInt(); 81 | hdop = gps.readStringUntil(','); // Horizontal Dilution of Precision (HDOP) 1.5 Relative accuracy of horizontal position 82 | altitude = gps.readStringUntil(','); // Metres 83 | faltitude = altitude.toFloat(); 84 | unused = gps.readStringUntil('\n'); 85 | } 86 | if (gps.find("GPVTG,")) { //$GPVTG,,T,,M,0.162,N,0.300,K,A*25 87 | track_true = gps.readStringUntil(','); // Track True 88 | track_true += gps.readStringUntil(','); // Track Type 89 | track_magnetic = gps.readStringUntil(','); // Track Magnetic 90 | track_magnetic += gps.readStringUntil(','); // Track Type 91 | speed_knots = gps.readStringUntil(','); // Speed in knots 92 | speed_knots += gps.readStringUntil(','); // Speed units N 93 | speed_kph = gps.readStringUntil(','); // Speed in knots 94 | speed_kph += gps.readStringUntil(','); // Speed units N 95 | speed_mph = String(speed_kph.toFloat()* 0.621371); // Convert kph to MPH 96 | fbearing = track_true.toFloat(); 97 | ordinal_bearing = Bearing_to_Ordinal(fbearing); 98 | fspeed = speed_kph.toFloat(); 99 | unused = gps.readStringUntil('\n'); 100 | } 101 | if (gps.find("GPRMC,")) { //$GPRMC,233512.00,A,5121.87041,N,00207.73021,W,0.436,,051217,,,A*68 102 | for (int reading = 1; reading < 9; reading++){ 103 | unused = gps.readStringUntil(','); // T 104 | } 105 | date = gps.readStringUntil(','); // Date 106 | date = date.substring(0,2)+"/"+date.substring(2,4)+"/"+date.substring(4,6); 107 | } 108 | Serial.println("Time\t\tLAT\tLON\tSATS\tAlt\tBearing\tSpeed(MPH)\tDate"); 109 | Serial.println("------------------------------------------------------------------------"); 110 | Serial.print(current_time.substring(0,2)+":"+current_time.substring(2,4)+":"+current_time.substring(4,6)+"\t"); 111 | Serial.print(String(flat,3)+"\t"); 112 | Serial.print(String(flon,3)+"\t"); 113 | Serial.print(num_sats+"\t"); 114 | Serial.print(altitude+"\t"); 115 | Serial.print(String(fbearing)+"\t"); 116 | Serial.print(String(fspeed)+"\t"); 117 | Serial.println(date); 118 | Serial.println(); 119 | } 120 | else 121 | { 122 | Serial.println("Waiting for GPS to acquire signal..."); 123 | } 124 | OLED_display_GPS_data(); 125 | } 126 | 127 | void OLED_display_GPS_data(){ 128 | PrintText(60,0,"G6EJD GPS Compass",CYAN,2); 129 | tft.fillRect(45,40,90,19*4,BLUE); 130 | PrintText(0,45,"LAT:"+String(flat),YELLOW,2); 131 | PrintText(0,63,"LON:"+String(flon),YELLOW,2); 132 | PrintText(0,81,"ALT:"+String(faltitude,1)+"M",YELLOW,2); 133 | PrintText(0,99,"SAT:"+String(sats,0),YELLOW,2); 134 | tft.fillRect(80,220,120,18,BLUE); 135 | PrintText(10,220,"Speed:"+String(fspeed)+"kph",YELLOW,2); 136 | tft.fillRect(240,220,120,18,BLUE); 137 | tft.setCursor(200,220); 138 | tft.print("Azi: "+ordinal_bearing); 139 | Display_Compass(); 140 | Display_Date_Time(); 141 | } 142 | 143 | void Display_Compass() { 144 | int dxo, dyo, dxi, dyi; 145 | tft.setCursor(0,0); 146 | tft.drawCircle(centreX,centreY,diameter,WHITE); // Draw compass circle 147 | for (float i = 0; i <360; i = i + 22.5) { 148 | dxo = diameter * cos((i-90)*3.14/180); 149 | dyo = diameter * sin((i-90)*3.14/180); 150 | dxi = dxo * 0.9; 151 | dyi = dyo * 0.9; 152 | tft.drawLine(dxo+centreX,dyo+centreY,dxi+centreX,dyi+centreY,WHITE); 153 | } 154 | PrintText((centreX-5),(centreY-diameter-18),"N",GREEN,2); 155 | PrintText((centreX-5),(centreY+diameter+5) ,"S",GREEN,2); 156 | PrintText((centreX+diameter+5),(centreY-5), "E",GREEN,2); 157 | PrintText((centreX-diameter-15),(centreY-5),"W",GREEN,2); 158 | dx = (0.85*diameter * cos((fbearing-90)*3.14/180)) + centreX; // calculate X position 159 | dy = (0.85*diameter * sin((fbearing-90)*3.14/180)) + centreY; // calculate Y position 160 | draw_arrow(last_dx,last_dy, centreX, centreY, 5, 5,BLUE); // Erase last arrow 161 | draw_arrow(dx,dy, centreX, centreY, 5, 5,YELLOW); // Draw arrow in new position 162 | last_dx = dx; 163 | last_dy = dy; 164 | } 165 | 166 | void draw_arrow(int x2, int y2, int x1, int y1, int alength, int awidth, int colour) { 167 | float distance; 168 | int dx, dy, x2o,y2o,x3,y3,x4,y4,k; 169 | distance = sqrt(pow((x1 - x2),2) + pow((y1 - y2), 2)); 170 | dx = x2 + (x1 - x2) * alength / distance; 171 | dy = y2 + (y1 - y2) * alength / distance; 172 | k = awidth / alength; 173 | x2o = x2 - dx; 174 | y2o = dy - y2; 175 | x3 = y2o * k + dx; 176 | y3 = x2o * k + dy; 177 | x4 = dx - y2o * k; 178 | y4 = dy - x2o * k; 179 | tft.drawLine(x1, y1, x2, y2,colour); 180 | tft.drawLine(x1, y1, dx, dy,colour); 181 | tft.drawLine(x3, y3, x4, y4,colour); 182 | tft.drawLine(x3, y3, x2, y2,colour); 183 | tft.drawLine(x2, y2, x4, y4,colour); 184 | } 185 | 186 | void Display_Date_Time(){ 187 | PrintText(0,150,"Date/Time:",CYAN,2); 188 | tft.fillRect(0,165,130,19*2,BLUE); 189 | PrintText(0,168,(hour<10?"0":"")+String(hour)+":"+(minute<10?"0":"")+String(minute)+":"+(second<10?"0":"")+String(second),GREEN,2); 190 | PrintText(0,188,date,GREEN,2); 191 | } 192 | 193 | String Bearing_to_Ordinal(float bearing) { 194 | if (bearing >= 0.0 && bearing < 11.25 ) return "N"; 195 | if (bearing >= 11.25 && bearing < 33.75 ) return "NNE"; 196 | if (bearing >= 33.75 && bearing < 56.25 ) return "NE"; 197 | if (bearing >= 56.25 && bearing < 78.75 ) return "ENE"; 198 | if (bearing >= 78.75 && bearing < 101.25 ) return "E"; 199 | if (bearing >= 101.25 && bearing < 123.75 ) return "ESE"; 200 | if (bearing >= 123.75 && bearing < 146.25 ) return "SE"; 201 | if (bearing >= 146.25 && bearing < 168.75 ) return "SSE"; 202 | if (bearing >= 168.75 && bearing < 191.25 ) return "S"; 203 | if (bearing >= 191.25 && bearing < 213.75 ) return "SSW"; 204 | if (bearing >= 213.75 && bearing < 236.25 ) return "SW"; 205 | if (bearing >= 236.25 && bearing < 258.25 ) return "WSW"; 206 | if (bearing >= 258.25 && bearing < 281.25 ) return "W"; 207 | if (bearing >= 281.25 && bearing < 303.75 ) return "WNW"; 208 | if (bearing >= 303.75 && bearing < 326.25 ) return "NW"; 209 | if (bearing >= 326.25 && bearing < 348.75 ) return "NNW"; 210 | if (bearing >= 348.75 && bearing < 360.00 ) return "N"; 211 | else return "N"; 212 | } 213 | /* 214 | N 348.75 11.25 215 | NNE 11.25 33.75 216 | NE 33.75 56.25 217 | ENE 56.25 78.75 218 | E 78.75 101.25 219 | ESE 101.25 123.75 220 | SE 123.75 146.25 221 | SSE 146.25 168.75 222 | S 168.75 191.25 223 | SSW 191.25 213.75 224 | SW 213.75 236.25 225 | WSW 236.25 258.75 226 | W 258.75 281.25 227 | WNW 281.25 303.75 228 | NW 303.75 326.25 229 | NNW 326.25 348.75 230 | */ 231 | 232 | void PrintText(int x, int y, String text, int colour, byte text_size){ 233 | tft.setCursor(x,y); 234 | tft.setTextColor(colour); 235 | tft.setTextSize(text_size); 236 | tft.print(text); 237 | tft.setTextColor(YELLOW); // Default colour 238 | tft.setTextSize(2); // Default Text Size 239 | } 240 | 241 | /* 242 | neo-6M Returns the following example sentences 243 | $GPRMC,233512.00,A,5121.87041,N,00207.73021,W,0.436,,051217,,,A*68 244 | $GPVTG,,T,,M,0.436,N,0.808,K,A*22 245 | $GPGGA,233512.00,5121.87041,N,00207.73021,W,1,09,1.48,56.3,M,48.0,M,,*7D 246 | $GPGSA,A,3,26,31,29,25,12,14,06,32,02,,,,2.16,1.48,1.57*00 247 | $GPGSV,4,1,13,02,29,057,22,04,30,275,19,06,10,028,15,12,30,084,16*78 248 | $GPGSV,4,2,13,14,34,249,24,21,01,174,,24,01,143,,25,69,075,35*7B 249 | $GPGSV,4,3,13,26,13,274,22,29,73,172,17,31,51,297,28,32,22,228,25*78 250 | $GPGSV,4,4,13,33,30,196,34*41 251 | $GPGLL,5121.87041,N,00207.73021,W,233512.00,A,A*70 252 | */ 253 | --------------------------------------------------------------------------------