08 - Project: Precision GPS Clock

## Lab: Precision GPS Clock Build a clock using GPS time signals and an LCD display. **Background:** GPS provides atomic-clock accuracy (~10 ns). Adjust for local timezone. **Libraries:** - TinyGPS++ (Mikal Hart): [GitHub](https://github.com/mikalhart/TinyGPSPlus) - LiquidCrystal (UNO R3): Built-in. - Time (Paul Stoffregen): [GitHub](https://github.com/PaulStoffregen/Time) **Required Hardware:** - GY-NEO6MV2 - Lonely Binary UNO R3 - 1602 LCD **Wiring:** | GY-NEO6MV2 | Lonely Binary UNO R3 | |------------|----------------| | VCC | 5V | | GND | GND | | TX | 2 | | RX | 3 | | LCD 1602 | Lonely Binary UNO R3 | |----------|----------------| | VCC | 5V | | GND | GND | | RS | 7 | | EN | 8 | | D4 | 12 | | D5 | 11 | | D6 | 10 | | D7 | 9 | **Code:** ```cpp #include #include #include #include #include const int offset = 11; // Local Time Zone (e.g., UTC+11 for Sydney) const int rs = 7, en = 8, d4 = 12, d5 = 11, d6 = 10, d7 = 9; LiquidCrystal lcd(rs, en, d4, d5, d6, d7); const int rx = 2, tx = 3, gpsBaud = 9600; SoftwareSerial ss(rx, tx); TinyGPSPlus gps; time_t prevDisplay = 0; uint32_t lastUpdateMillis = 0; void showWelcome() { lcd.clear(); lcd.setCursor(0, 0); lcd.print("== GPS CLOCK =="); lcd.setCursor(0, 1); lcd.print(" Initializing.."); } void showLCDClock() { String strHour = hour() < 10 ? "0" + String(hour()) : String(hour()); String strMinute = minute() < 10 ? "0" + String(minute()) : String(minute()); String strSecond = second() < 10 ? "0" + String(second()) : String(second()); String strMonth = month() < 10 ? "0" + String(month()) : String(month()); String strDay = day() < 10 ? "0" + String(day()) : String(day()); lcd.clear(); lcd.setCursor(0, 0); lcd.print(strHour + ":" + strMinute + ":" + strSecond + " "); lcd.setCursor(0, 1); lcd.print(strMonth + "/" + strDay + "/" + year() + " "); } void showLastUpdate() { unsigned long age = millis() - lastUpdateMillis; lcd.setCursor(0, 1); lcd.print("LAST UPD: "); if (age < 1000) { lcd.print("NOW "); } else if (age < 60000) { lcd.print(String(age / 1000) + "S AGO"); } else if (age < 3600000) { lcd.print(String(age / 60000) + "M AGO"); } else if (age < 86400000) { lcd.print(String(age / 3600000) + "H AGO"); } else { lcd.print("TAKE OUTSIDE!"); } } void setup() { lcd.begin(16, 2); showWelcome(); ss.begin(gpsBaud); } void loop() { while (ss.available() > 0) { if (gps.encode(ss.read())) { if (gps.date.isValid() && gps.time.isValid()) { setTime(gps.time.hour(), gps.time.minute(), gps.time.second(), gps.date.day(), gps.date.month(), gps.date.year()); adjustTime(offset * SECS_PER_HOUR); lastUpdateMillis = millis(); } } } if (timeStatus() != timeNotSet) { if (now() != prevDisplay) { prevDisplay = now(); showLCDClock(); showLastUpdate(); } } } ``` **Code Explanation:** - `setTime()`/`adjustTime()`: Sets and offsets time using Time library. - Ternary operators ensure two-digit formatting. - `millis()` tracks updates; UNO R3 uses it for internal timing (rolls over after ~50 days). **Results:** LCD shows local time and last GPS update. **Tips:** For standalone clocks, add RTC (e.g., DS3231) for backup. **Related Information:** GPS time is leap-second adjusted; compare with NTP for network syncing.