/* RTC_com.cpp MIT License Copyright (c) 2023 hdrlux */ #include // for all the 'standard' Arduino stuff #include // https://github.com/JChristensen/DS3232RTC #include // https://github.com/PaulStoffregen/Time [valid until year 2099, no 2038 bug] #include "GPS_RTC_Clock.h" #include "RTC_com.h" #define cfg_pin_RTC_SQW 3; #ifndef DEBUG_PORT #define DEBUG_PORT Serial #endif // add the static modifier to limit visibility of these variables to just this file //static int ledPin_PPS = A6; // Pin for RTC PseudoPPS LED [analog PIN used as digital PIN] //static int ledPin_Sync = A7; // Pin for valid RTC Sync static byte RTC_1HZ_PIN = cfg_pin_RTC_SQW; // Pin 3 = NANO INT1, RTC provides a 1Hz interrupt signal on this Pin static time_t last_sync_t = 0; // last sync static byte sync_err_hours = 4; // set to 4 for DS3231M, may be set to 8 for DS3231SN. Warning if no GPS sync after n hours, possible 0.1 sec error. static bool RTCcolon = false; bool SyncErr = true; #include DS3232RTC myRTC(0x68); // cfg_ volatile bool RTC_sec = false; // flag for PseudoPPS volatile bool RTC_sync = false; // flag for RTC sync unsigned long RTCMicros; // blinking timer void rtc_interrupt() { //Serial.print("DEBUG[INT] RTC interrupt "); Serial.println(micros()); RTCMicros = micros(); RTC_sec = true; } void RTC_LED_setup() { //pinMode(ledPin_PPS, OUTPUT); //pinMode(ledPin_Sync, OUTPUT); //digitalWrite(ledPin_PPS, LOW); // LED off //digitalWrite(ledPin_Sync, LOW); // LED off } void RTC_setup() { pinMode(RTC_1HZ_PIN, INPUT_PULLUP); // enable pullup on interrupt pin (RTC SQW pin is open drain) attachInterrupt(digitalPinToInterrupt(RTC_1HZ_PIN), rtc_interrupt, FALLING); // HIGH 500ms after start of second myRTC.begin(); myRTC.squareWave(DS3232RTC::SQWAVE_1_HZ); // 1 Hz square wave RTC_sec = false; } void RTC_loop() { if (RTC_sec) { // do after RTC PseudoPPS interrupt, without interrupt NO time/date to display //DEBUG_PORT.println("DEBUG[RTC_loop()] RTC_sec: " + String(RTC_sec)); //DEBUG_PORT.println("DEBUG[RTC_loop()] RTCMicros: " + String(RTCMicros)); //DEBUG_PORT.println("DEBUG[RTC_loop()] millis: " + String(millis())); lcd.setCursor(13, 0); lcd.print(":"); RTCcolon = true; RTC_sec = false; // clear flag int32_t drift = (int32_t)(GPSMicros - RTCMicros); // % (4294967295UL); // Корректировка переполнения (wrap-around) if (drift > 900000) // Если разница > 0.9 сек drift -= 1000000; // Корректируем на -1 сек else if (drift < -900000) // Если разница < -0.9 сек drift += 1000000; // Корректируем на +1 сек // Отображение дрейфа в правом нижнем углу LCD (16x2) String driftStr = String(drift); // Вычисляем позицию для выравнивания справа: 16 - длина строки lcd.setCursor(16 - driftStr.length(), 1); lcd.print(driftStr); DEBUG_PORT.println("SQW: " + String(RTCMicros) + "; drift: " + String(drift) + "; newSec: " + String(NewSec)); if (abs(drift) > 20000 && !gps_on) RTC_sync = true; //digitalWrite(ledPin_PPS, LOW); // LED off time_t now_t = myRTC.get(); if ((last_sync_t + (sync_err_hours * 3600)) < now_t) { SyncErr = true; //digitalWrite(ledPin_Sync, LOW); // LED off lcd.setCursor(0, 0); lcd.print("r"); } Sec_Flip(now_t); // pass current datetime from RTC in UTC } else if (micros() - RTCMicros >= 500000 && RTCcolon) { lcd.setCursor(13, 0); lcd.print(" "); RTCcolon = false; NewSec = false; } else { NewSec = false; } /*if (millis() > (RTCMicros + 100)) { // do 100ms after PseudoPPS interrupt digitalWrite(ledPin_PPS, HIGH); // LED on }*/ } void SetRTC(time_t t) { myRTC.set(t + 1); // the GPS NMEA output is 1 second behind at PPS !! last_sync_t = t; SyncErr = false; //digitalWrite(ledPin_Sync, HIGH); // LED on DEBUG_PORT.println("RTC set by GPS"); // debug lcd.setCursor(0, 0); lcd.print("R"); char segment[9]; snprintf(segment, sizeof(segment),"%.2u:%.2u:%.2u", hour(t), minute(t), second(t)); lcd.setCursor(0, 1); lcd.print(segment); } //End