#include //for RTC comms over I2C #include //for LED output to Max7219 module #include #include //VERSION 7: NANO PIN ASSIGNMENTS, adds simple count up timer, LED dimmer, shows GPS PPS status. // Commit Date: 23-June-2020 // RTC always has UTC time and date //Nano pins: D10-D13, SPI for Max; A3/D17(SQW), A4(SDA) and A5(SCL) for I2C to DS3231 RTC. // D0,D1(serial) D2(PPS) for GPS. D3 for IR receiver interrupt. // 135 LiquidCrystal_I2C lcd(0x27, 16, 2, 6, 5); SoftwareSerial GPS(3, 4); //STATE MACHINE SETUP// enum { DEBUG, BOOTUP, REG_OPS, TOGGLE_DISPLAY, COUNTER, CHECK_PPS, GPS_INIT, GPS_PPS_SYNC, GPS_NMEA_SYNC } StateMachine; //PIN DEFS & ADDRESSES// const byte RTC_SQW_Pin = 17; //same as A3 pin (using analog pin as digital for RTC SQW) const byte GPS_PPS_Pin = 2; // for receiving the GPS PPS signal const byte ir_pin = 3; //Interrupt pin for IR receiver data pin. const byte ChipSelectPin = 10; // For Max7219. We set the SPI Chip Select/Slave Select Pin here. 10 for uno/nano. 53 for mega const int RTC_I2C_ADDRESS = 0x68; // Must be data type [int] to keep wire.h happy. Sets RTC DS3231 i2C address. //TIMERS AND EDGE DETECTORS// unsigned long GPS_INIT_t0, t0, t1, t2; //for timers byte RTC_SQW_Current = LOW; byte RTC_SQW_Prev = LOW; byte GPS_PPS_Current = HIGH; byte GPS_PPS_Prev = HIGH; //ISR HANDLERS// volatile unsigned int pulseChangeTime; //long or int? volatile byte pulseFlag = 0; //UTC offset handlers// //ie, Time Zones and Daylight Savings (summer) Time // bool UTC_offset_enable = true; // False for UTC time. True for local time. const char offsetStandardHr = -5; const char offsetStandardMin = 0; const char offsetDSTHr = -4; const char offsetDSTMin = 0; const byte startDST[4] = {2,0,3,2}; // {nth,day of week,month,hh} use [0..6] for [Sunday...Saturday] const byte startStandard[4] = {1,0,11,2}; // {nth,day of week,month,hh} [0..6] for [Sunday...Saturday] // set n=5 for 5th or last. Assume DST starts/stops at 2am local time const byte days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; // mapping days of the 12 months const int currentCentury = 2000; /* globals that store our offset values*/ int offYYYY; byte offMO; byte offDD; byte offHH; byte offMM; byte offSS; //RTC date+time holders// byte ssRTC, mmRTC, hhRTC, dowRTC, ddRTC, moRTC, ctyRTC, yyRTC; byte countSS, countMM, countHH; //GPS UTC date+time handlers// byte hhGPS, mmGPS, ssGPS, ddGPS, moGPS; int yyyyGPS = 0; bool newGPS_dateAvail = false; bool newGPS_timeAvail = false; bool NMEA_processFlag = false; bool GGA_msg = false; bool RMC_msg = false; bool ZDA_msg = false; bool msgStart = false; bool GPS_sec_primed = false; bool PPS_done = false; byte byteIndex = 0; bool counter_enable = true; /* ----------------------- MAX STUFF ALL HERE ---------------------------vvvvvv ICSP BLOCK PINOUT 5 3 1 6 4 2 ===MAPPING SPI HARDWARE AND ARDUINO'S TO MAX7219 MODULES=== 7219 MODULE: DIN LOAD(CS) CLK (*n/a*) SPI: MOSI SS SCK MISO UNO/NANO: 11/ICSP-4 10 13/ICSP-3 12/ICSP-1 MEGA: 51/ICSP-4 53 52/ICSP-3 50/ICSP-1 * [CS(SS) can actually be any unused PIN on the uController, but these are the typical conventions.] */ // Max7219 digit bitmaps for digit registers 0x01 to 0x08 const byte dp = 0b10000000; // Decimal Point. Do bitwise OR to combine with any digit to add decimal point const byte blank = 0b00000000; const byte hyphen = 0b00000001; const byte excl = 0b10100000; //exclamation point! // 0b0abcdefg const byte A = 0b01110111; const byte B = 0b00011111; const byte C = 0b01001110; const byte D = 0b00111101; const byte E = 0b01001111; const byte F = 0b01000111; const byte G = 0b01111011; const byte H = 0b00110111; const byte I = 0b00110000; const byte J = 0b00111100; const byte L = 0b00001110; const byte N = 0b00010101; const byte O = 0b00011101; const byte P = 0b01100111; const byte Q = 0b01110011; const byte R = 0b00000101; const byte S = 0b01011011; const byte T = 0b00001111; const byte U = 0b00011100; const byte M, K, V, W, X = 0b00000000; const byte Y = 0b00111011; const byte Z = 0b01101101; byte char_library[28] = {blank,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,hyphen}; //array of digits 0-9 with corresponding segment bit maps byte digit[10] = {0b01111110, //0 0b00110000, //1 0b01101101, //2 0b01111001, //3 0b00110011, //4 0b01011011, //5 0b01011111, //6 0b01110000, //7 0b01111111, //8 0b01110011}; //9 // 0b0abcdefg // -- a // f | | b // g -- // e | | c // d -- //0b0abcdefg // Max7219 Address Registers const byte reg_nonop = 0x00; // generally not used const byte reg_d1 = 0x01; // "Digit0" in the datasheet const byte reg_d2 = 0x02; // "Digit1" in the datasheet const byte reg_d3 = 0x03; // "Digit2" in the datasheet const byte reg_d4 = 0x04; // "Digit3" in the datasheet const byte reg_d5 = 0x05; // "Digit4" in the datasheet const byte reg_d6 = 0x06; // "Digit5" in the datasheet const byte reg_d7 = 0x07; // "Digit6" in the datasheet const byte reg_d8 = 0x08; // "Digit7" in the datasheet const byte reg_decode = 0x09; // 0x00 no decode, to 0xFF decode all; use a bit map to toggle, ie 0b00000010 const byte reg_intensity = 0x0A; // min 0x00, max 0x0F... 16 duty-cycle options. 0x07 middle. const byte reg_scanlimit = 0x0B; // from 0x00 to 0x07 (sets number of digits being scanned) const byte reg_shutdown = 0x0C; // 0x00 shutdown mode, 0x01 normal ops const byte reg_displaytest = 0X0F; // 0x00 normal ops, 0x01 display test mode void SPIwrite (byte reg_address, byte regdata) { //Writes 2 bytes to SPI. This is optimized for Max7219 Comms. digitalWrite(ChipSelectPin,LOW); // take the CS/SS pin low to select the chip SPI.transfer(reg_address); SPI.transfer(regdata); digitalWrite(ChipSelectPin,HIGH); // take the CS/SS pin high to deselect the chip } //end of SPIwrite void setAllDigitsTo (byte set_digit) { //this sets all the digits to set_digit for (byte i=1;i<=8;i++) { SPIwrite(i,set_digit); } //end for } //end of setAllDigitsTo() void initializeMax7219() { //reset the Max by activating shutdown mode SPIwrite(reg_shutdown,0x00); // 0x00 shutdown, 0x01 normal ops //initialize each digit with known values setAllDigitsTo(hyphen); //set intensity SPIwrite(reg_intensity, 0x07); // min 0x00, max 0x0F... 16 duty-cycle options. 0x07 middle. //set scan limit SPIwrite(reg_scanlimit, 0x07); // from 0x00 to 0x07 (sets number of digits being scanned) //set decode SPIwrite(reg_decode, 0b00000000); // built-in decode, from 0x00 [all off] to 0xFF [all on] (bit map toggles digits 1-8). //flash a display test SPIwrite(reg_displaytest, 0x01); // 0x00 normal ops, 0x01 display test mode delay(100); //end the test SPIwrite(reg_displaytest, 0x00); // 0x00 normal ops, 0x01 display test mode delay(100); //exit shutdown mode. resume normal ops SPIwrite(reg_shutdown,0x01); // 0x00 shutdown, 0x01 normal ops delay (100); } //end of initializeMax7219 void maxDisplay(byte a, byte b, byte c, byte d, byte e, byte f, byte g, byte h) { SPIwrite(8,a); SPIwrite(7,b); SPIwrite(6,c); SPIwrite(5,d); SPIwrite(4,e); SPIwrite(3,f); SPIwrite(2,g); SPIwrite(1,h); } //**** ISR ROUTINE ****// void ISR_pulse_detected() { pulseChangeTime = micros(); pulseFlag = 1; } //end of ISR_pulse_detected() //**** UNIVERSAL FUNCTIONS ****// byte bcd2dec(byte n) { // Converts binary coded decimal to normal decimal numbers return ((n/16 * 10) + (n % 16)); } //end of bcd2dec() byte dec2bcd(byte n) { //n must be in range [0..99] incl // Converts normal decimal to binary coded decimal. Speed optimized. // return ((n / 10 * 16) + (n % 10)); <----- slower method. // see https://forum.arduino.cc/index.php?topic=185235.msg1372439#msg1372439 uint16_t a = n; byte b = (a*103) >> 10; return n + b*6; } //end of dec2bcd() void clearGPSInputBuffer() { while (GPS.available() > 0) { GPS.read(); }//end while } //end of clearGPSInputBuffer() //**** DISPLAY HANDLERS **** // void displayRTC_timeOnMax(byte rtc_h, byte rtc_m, byte rtc_s) { //receiving [0-99] decimals from caller lcd.setCursor(0,0); // Установка курсора в начало первой строки if(rtc_h < 10) lcd.print("0"); lcd.print(rtc_h); lcd.print(":"); if(rtc_m < 10) lcd.print("0"); lcd.print(rtc_m); lcd.print(":"); if(rtc_s < 10) lcd.print("0"); lcd.print(rtc_s); //Serial.print(rtc_h); Serial.print(":"); Serial.print(rtc_m); Serial.print(":"); Serial.println(rtc_s); //maxDisplay(digit[(rtc_h/10)%10],digit[rtc_h%10],hyphen, // digit[(rtc_m/10)%10],digit[rtc_m%10],hyphen, // digit[(rtc_s/10)%10],digit[rtc_s%10]); } //end of displayRTC_timeOnMax() void serialRTC_timeOnMax(byte rtc_h, byte rtc_m, byte rtc_s) { //receiving [0-99] decimals from caller if(rtc_h < 10) Serial.print("0"); Serial.print(rtc_h); Serial.print(":"); if(rtc_m < 10) Serial.print("0"); Serial.print(rtc_m); Serial.print(":"); if(rtc_s < 10) Serial.print("0"); Serial.println(rtc_s); } //end of serialRTC_timeOnMax() //**** GPS HANDLERS **** // bool PPS_detect() { // top of the second for ublox 6 GPS (default setting) is rising edge of PPS time pulse GPS_PPS_Prev = GPS_PPS_Current; GPS_PPS_Current = digitalRead(GPS_PPS_Pin); return (GPS_PPS_Prev == LOW && GPS_PPS_Current == HIGH); //returns true if PPS has gone high! } // end of PPS_detect() void processNMEA() { byte inByte; if (GPS.available() > 0) { //do all of this only if byte ready to read inByte = GPS.read(); byteIndex++; // we only increment index if we read a byte switch (byteIndex) { case 1 ... 3: break; case 4: GGA_msg = (inByte == 'G'); RMC_msg = (inByte == 'R'); ZDA_msg = (inByte == 'Z'); break; case 5: GGA_msg = (GGA_msg && inByte == 'G'); RMC_msg = (RMC_msg && inByte == 'M'); ZDA_msg = (ZDA_msg && inByte == 'D'); break; case 6: GGA_msg = (GGA_msg && inByte == 'A'); RMC_msg = (RMC_msg && inByte == 'C'); ZDA_msg = (ZDA_msg && inByte == 'A'); NMEA_processFlag = (GGA_msg || RMC_msg || ZDA_msg); // if we have any of these, we keep processing break; case 7: break; case 8: // hour tens hhGPS = (inByte - '0')*10; break; case 9: //hour units hhGPS += (inByte - '0'); break; case 10: // min tens mmGPS = (inByte - '0')*10; break; case 11: //min units mmGPS += (inByte - '0'); break; case 12: // sec tens ssGPS = (inByte - '0')*10; break; case 13: //sec units ssGPS += (inByte - '0'); //**AT THIS POINT WE HAVE GPS TIME**// CAN ACTUALLY UPDATE RTC! newGPS_timeAvail = true; NMEA_processFlag = ZDA_msg; //if we have ZDA, this is true and we keep processing. break; case 14 ... 17: //** WILL NEED TO TUNE THIS TO ACTUAL OUTPUT OF NEO 6M break; case 18: //day tens ddGPS = (inByte - '0')*10; break; case 19: //day units ddGPS += (inByte - '0'); break; case 20: break; case 21: //mo tens moGPS = (inByte - '0')*10; break; case 22: //mo units moGPS += (inByte - '0'); break; case 23: break; case 24: yyyyGPS = (inByte - '0')*1000; break; case 25: yyyyGPS += (inByte - '0')*100; break; case 26: yyyyGPS += (inByte - '0')*10; break; case 27: yyyyGPS += (inByte - '0'); newGPS_dateAvail = true; //all date fields now read NMEA_processFlag = false; //and no need to process further break; default: NMEA_processFlag = false; } //end switch byteIndex } //end if GPS available } //end of processNMEA /* // 123456789012345678901234567||| [27] GPS unit gives 2 decimals on time // $GPGGA,hhmmss.tt,... // /* $GPGGA, $GPRMC: $GPRMC,hhmmss.tt,... // $GPZDA: $GPZDA,hhmmss.tt,dd,mm,yyyy,... */ //**** UTC TIMEZONE OFFSET AND DST HANDLERS ****// void offsetAdj(int y, byte mo, byte d, byte h, byte m, char offsetHr, char offsetMin) { offMM = (m + offsetMin + 120) % 60; if (m + offsetMin > 59) { offsetHr ++; } if (m + offsetMin < 0) { offsetHr --; } offHH = (h + offsetHr + 24) % 24; offDD = d; offYYYY = y; offMO = mo; if (offsetHr + h < 0) { //Do a decrement if (d > 1) { offDD--; } else { //rollover offDD = days[((mo+11-1)%12+1)] + (mo==2 && isLeap(y)); offMO--; if (mo == 1) { offMO = 12; offYYYY = y - 1; }//end if } } //end if for decrement day if (offsetHr + h >= 24) { // Do an increment if (d == (days[mo] + (mo == 2 && isLeap(y)))) { //ie, if d is last day of month offDD = 1; offMO++; if (mo == 12) { offMO = 1; offYYYY = y + 1; } }//end if else { offDD = d+1; } } //end if increment day } //end offsetAdj bool isLeap (byte y) { return ((y%4==0) || (!(y%100==0) && (y%400==0))); } //end isLeap() byte dowDate(int y, byte n, byte dow_target, byte m) { // returns date number in month of nth day of week in month char temp = 1; // char because could be negative. Set at 1 for 1st of month. byte maxDays = days[m]; // number of days in given month if (m==2) { maxDays = days[m] + isLeap(y); } byte startDOW = dow(y,m,1); //gets dow of 1st of given month temp += dow_target - dow(y,m,1); if (temp < 0) { temp += 7; } //end if temp += 7*(n-1); if (temp > maxDays) { temp -= 7; } return temp; } //end dowDate() byte dow(int y, byte m, byte d) { //pass non-leading zero values static byte t[] = {0,3,2,5,0,3,5,1,4,6,2,4}; y -= m < 3; return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7; // returns [0..6] for [Sunday...Saturday] } //end of dow() void getLocalTime(int y, byte mo, byte d, byte h, byte m) { // **this function sets offMO, offDD, offYYYY, offHH, offMM to local time** // we first get a baseline offset // NOTE: int y is being passed as RTC's 2-digit date. if (yyyyGPS == 0) { // Converting RTC 2 digit date to 4 digit: y += currentCentury; // takes our 2-digit year and converts to 4 digit } else { // or if GPS signal available, we just use that y = yyyyGPS; // uses GPS 4-digit year if available } offsetAdj(y,mo,d,h,m,offsetStandardHr,offsetStandardMin); // next we do our DST checks, and recalc offset if DST is in effect if (offMO > startDST[2] && offMO < startStandard[2]) { offsetAdj(y,mo,d,h,m,offsetDSTHr,offsetDSTMin); } //end if else if (offMO == startDST[2]) { byte dowDateDST = dowDate(y,startDST[0],startDST[1],startDST[2]); if (offDD > dowDateDST) { offsetAdj(y,mo,d,h,m,offsetDSTHr,offsetDSTMin); } //end if else if (offDD == dowDateDST && offHH >= startDST[3]) { offsetAdj(y,mo,d,h,m,offsetDSTHr,offsetDSTMin); } //end else if } //end else if else if (offMO == startStandard[2]) { byte dowDateStd = dowDate(y,startStandard[0],startStandard[1],startStandard[2]); if (offDD < dowDateStd) { offsetAdj(y,mo,d,h,m,offsetDSTHr,offsetDSTMin); }// end if else if (offDD == dowDateStd && offHH < (startStandard[3]-1)) { offsetAdj(y,mo,d,h,m,offsetDSTHr,offsetDSTMin); }// end else if } //end else if } //end getLocalTime() //**** RTC HANDLERS ****// void getRTC() { //reads all current time/date data from DS3231 chip via I2C // ssRTC, mmRTC, hhRTC, dowRTC, ddRTC, moRTC, ctyRTC, yyRTC; byte temp_buffer; Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0x00); //set register points to address 00h on DS3231 Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 7); // need 7 reads to clear this. ssRTC = bcd2dec(Wire.read()); // read reg 0 [range 00-59] mmRTC = bcd2dec(Wire.read()); // read reg 1 [range 00-59] hhRTC = bcd2dec(Wire.read() & 0b00111111); // read reg 2 and mask out BITS 7-8 dowRTC = bcd2dec(Wire.read()); // read reg 3 [range 1-7] ddRTC = bcd2dec(Wire.read()); // read reg 4 [range 01-31] temp_buffer = bcd2dec(Wire.read()); // read reg 5 moRTC = bcd2dec(temp_buffer & 0b00011111); ctyRTC = temp_buffer >> 7; yyRTC = bcd2dec(Wire.read()); //read reg 6 [range 00-99] } //end of getRTC() bool RTC_detect() { //Detects DS3231 SQW falling edge RTC_SQW_Prev = RTC_SQW_Current; RTC_SQW_Current = digitalRead(RTC_SQW_Pin); return (RTC_SQW_Prev == HIGH && RTC_SQW_Current == LOW); } //end of detect_RTC void displayRTCDate() { // adjusts to local date if flag set getRTC(); // updates ssRTC, mmRTC, hhRTC, dowRTC, ddRTC, moRTC, ctyRTC, yyRTC; if (UTC_offset_enable == false) { // if flag false, we do UTC time and date displayRTC_timeOnMax(ddRTC,moRTC,yyRTC); // displays UTC date } //end if else { // else requests local offset time getLocalTime(yyRTC,moRTC,ddRTC,hhRTC,mmRTC); // updates offDD,offMO,offYYYY displayRTC_timeOnMax(offDD,offMO,offYYYY % 100); } } //end displayRTCDate void countUp() { RTC_SQW_Prev = RTC_SQW_Current; RTC_SQW_Current = digitalRead(RTC_SQW_Pin); if (counter_enable && RTC_SQW_Prev == HIGH && RTC_SQW_Current == LOW) { //tests for falling edge countSS++; if (countSS == 60) { countSS = 0; countMM++; } //end if if (countMM == 60) { countMM = 0; countHH++; } //end if if (countHH == 100) { countHH = 0; } displayRTC_timeOnMax(countHH,countMM,countSS); } //end if } //end of countUp void displayRTC() { //updates display if new RTC time. Detects DS3231 SQW falling edge then trigger display of time update RTC_SQW_Prev = RTC_SQW_Current; RTC_SQW_Current = digitalRead(RTC_SQW_Pin); if (RTC_SQW_Prev == HIGH && RTC_SQW_Current == LOW) { //test for falling edge //Serial.print("RTC_SQW_Prev vs RTC_SQW_Current:"); Serial.print(RTC_SQW_Prev); Serial.print("-"); Serial.println(RTC_SQW_Current); //lcd.setCursor(0, 1); //lcd.print("SQW: "); //lcd.print(RTC_SQW_Prev); //lcd.print(" => "); //lcd.print(RTC_SQW_Current); getRTC(); // updates ssRTC, mmRTC, hhRTC, dowRTC, ddRTC, moRTC, ctyRTC, yyRTC; if (UTC_offset_enable == false) { // flag requests UTC time displayRTC_timeOnMax(hhRTC,mmRTC,ssRTC); } //end if else { // flag requests local offset time getLocalTime(yyRTC,moRTC,ddRTC,hhRTC,mmRTC); displayRTC_timeOnMax(offHH,offMM,ssRTC); } //end else } //end if } // end of displayRTC() void displayRTC_now() { //immediate retrieve and display of RTC time registers getRTC(); // updates ssRTC, mmRTC, hhRTC, dowRTC, ddRTC, moRTC, ctyRTC, yyRTC; displayRTC_timeOnMax(hhRTC,mmRTC,ssRTC); } // end of displayRTC() void sendRTC(byte reg_addr, byte byte_data) { Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(reg_addr); //set register pointer to address on DS3231 Wire.write(byte_data); Wire.endTransmission(); } //end of sendRTC() byte getSingleRTC(byte reg_addr) { //returns a single raw byte from the provided address register Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(reg_addr); //set to reg address on DS3231 Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 1); return (Wire.read()); } //end of getRTC_BCD() void setRTC_Time(byte hh, byte mm, byte ss) { //must be [0-99] // example use: setRTC_Time(23,49,50); //hh,mm,ss Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0x00); //set register pointer to address on DS3231 Wire.write(dec2bcd(ss)); //set seconds Wire.write(dec2bcd(mm)); //set minutes Wire.write(dec2bcd(hh)); //set hours. Bit 6 low keeps at 24hr mode. So can leave as is. Wire.endTransmission(); } //end of setRTC_Time() void setRTC_Date(int yyyy, byte mo, byte dd) { Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0x04); //set register pointer to address on DS3231 Wire.write(dec2bcd(dd)); //set date. sending the last 2 digits only. Wire.write(dec2bcd(mo)); //set month. ignore century as don't have any use for that. Wire.write(dec2bcd(yyyy % 100)); //set year. sending the 2 LS digits only. Wire.endTransmission(); } //end of setRTC_Time() //**** STATE MACHINE **** // void RunStateMachine() { byte temp_buffer; switch (StateMachine) { case DEBUG: //remember, it's looping! Serial.println("DEBUG"); if (RTC_detect()) { t1=micros(); } else { Serial.println("No RTC detected."); } if (PPS_detect()) { t2=micros(); } else { Serial.println("No PPS detected."); } break; //end DEBUG case // ------------------------------ case BOOTUP: Serial.println("BOOTUP"); sendRTC(0x0E,0x00); // enables the 1Hz pulse on RTC DS3231's SQW pin delay(50); temp_buffer = getSingleRTC(0x02); //get hour byte from addr 0x02. Bit 6: LOW (0) = 24 hr mode. HIGH (1) = 12 hr. if ((temp_buffer & 0b01000000) != 0) { //if Bit 6 is HIGH, i.e., if 24 hour time is *not* set, then... getRTC(); // grab time if (mmRTC > 58 && ssRTC > 58) { // checking to make sure not near an hours rollover. break; //keep breaking until we roll over the seconds } //end if else { sendRTC(0x02,temp_buffer ^ 0b01000000); //set BIT 6 low to enable 24 hr time } //end else } //end if //StateMachine = DEBUG; // >>>> State Change! <<<>>> State Change! <<<GPS_INIT"); StateMachine = GPS_INIT; // >>>> State Change! <<<GPS_PPS_SYNC"); StateMachine = GPS_PPS_SYNC; // >>>> State Change! <<< 4000) { //timeout this state after 4 secs if no PPS detected getRTC(); serialRTC_timeOnMax(hhRTC,mmRTC,ssRTC); Serial.println(">GPS_NMEA_SYNC"); StateMachine = GPS_NMEA_SYNC; // >>>> State Change! <<<REG_OPS"); StateMachine = REG_OPS; // >>>> State Change! <<< 0) { if (GPS.read() == '$') { //start of NMEA message NMEA_processFlag = true; //we only want to start processing at beginning of message GGA_msg = false; RMC_msg = false; ZDA_msg = false; byteIndex = 1; } //end if } //end if } //end else if (millis() - GPS_INIT_t0 > 14000) { //timeout this state after 10 secs if no PPS detected getRTC(); serialRTC_timeOnMax(hhRTC,mmRTC,ssRTC); Serial.println(">REG_OPS"); StateMachine = REG_OPS; // >>>> State Change! <<<>>> State Change! <<< 0) { if (GPS.read() == '$') { //start of NMEA message NMEA_processFlag = true; GGA_msg = false; RMC_msg = false; ZDA_msg = false; byteIndex = 1; } //end if } //end if } //end else if (millis() - GPS_INIT_t0 > 14000) { //timeout this state after 10 secs if no PPS detected getRTC(); serialRTC_timeOnMax(hhRTC,mmRTC,ssRTC); Serial.println(">REG_OPS"); StateMachine = REG_OPS; // >>>> State Change! <<<