From 283233cbc3eb48bceec241a304325ac6c9e5c15e Mon Sep 17 00:00:00 2001 From: 135 Date: Wed, 10 Jul 2024 21:08:39 +0300 Subject: [PATCH] Init --- GPS-RTC-Clock.ino | 949 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 949 insertions(+) create mode 100644 GPS-RTC-Clock.ino diff --git a/GPS-RTC-Clock.ino b/GPS-RTC-Clock.ino new file mode 100644 index 0000000..ceb8541 --- /dev/null +++ b/GPS-RTC-Clock.ino @@ -0,0 +1,949 @@ + +#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; + //135Serial.println("R-SM"); + + 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(ddRTC,moRTC,yyRTC); + 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(ddRTC,moRTC,yyRTC); + 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(ddRTC,moRTC,yyRTC); + Serial.println(">REG_OPS"); + StateMachine = REG_OPS; // >>>> State Change! <<<