250 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
| // Digital erisian clock - v0.55
 | |
| #include <Arduino.h>
 | |
| #include <TimeLib.h>
 | |
| #include <Thread.h>
 | |
| #include <DS1307RTC.h>
 | |
| #include <SevenSegmentExtended.h>      // DisplayLib // Extended TM1637 library https://github.com/bremme/arduino-tm1637
 | |
| const byte PIN_CLK = 2;                // DisplaySetting // CLK pin
 | |
| const byte PIN_DIO = 3;                // DisplaySetting // DIO pin
 | |
| const byte buttonPin = 4;              // ButtonSetting // Button pin (a 10K resistor is necessary)
 | |
| SevenSegmentExtended display(PIN_CLK, PIN_DIO); // DisplaySetting
 | |
| Thread mainThread = Thread();          // mainThread
 | |
| Thread correctionThread = Thread();    // Time bias correction thread
 | |
| long buttonPressed = 0;                // Button press time counter
 | |
| long previousButtonMillis = 0;         // Time of last button press
 | |
| byte viewMode = 0;                     // View mode after pressing button
 | |
| int buttonInterval = 21600;            // Interval for showing viewMode after pressing button
 | |
| int buttonLongPress = 1728;            // Long button press interval
 | |
| int mainCheck = 108;                   // The main interval is an eighth of a decimal second
 | |
| byte octavo = 0;                       // Eight-count counter
 | |
| byte colon = 0;                        // Colon status
 | |
| float erisiansec;                      // Erisian second
 | |
| // Custom settings:
 | |
| int brightnessPercent = 32;            // Display brightness percentage value
 | |
| long timezoneOffset = (-28800);        // Erisian timezoneOffset. Formula for calculating: ((-5 christian chours) - (GMT hours))
 | |
|                                        // Examples:
 | |
|                                        // GMT+3: ( (-5)-(+3) )*60*60 = -28800
 | |
|                                        // GMT-0:  ( (-5)-(0) )*60*60 = -18000
 | |
|                                        // GMT-3: ( (-5)-(-3) )*60*60 = -7200
 | |
|                                        // GMT-5: ( (-5)-(-5) )*60*60 = 0
 | |
|                                        // GMT-7: ( (-5)-(-7) )*60*60 = 7200
 | |
|                                        // The beginning of Discordian day (0 hours, 0 minutes, 0 seconds) coincides
 | |
|                                        // with the beginning of Christian day on Easter Island on winter time (GMT-5).
 | |
|                                        // Details: https://discordia.fandom.com/wiki/Erisian_Time
 | |
| 
 | |
| // Time bias correction variables:
 | |
| int correctionBias = 11;               // Daily clock correction in seconds
 | |
| long correctionCheck = 300000;
 | |
| byte correctionHour = 3;
 | |
| bool correctionReady = true;
 | |
| 
 | |
| void setup() {
 | |
|   Serial.begin(9600);                  // Initializes the Serial connection @ 9600 baud for debug
 | |
|   display.begin();                     // Display setting, initializes the display
 | |
|   display.setBacklight(brightnessPercent); // Display brightness setting
 | |
|   while (!Serial);                     // Wait until Arduino Serial Monitor opens
 | |
|   setSyncProvider(RTC.get);            // The function to get the time from the RTC
 | |
|   if(timeStatus()!= timeSet) {         // Checking the time setting
 | |
|     Serial.println("Unable to sync with the RTC");
 | |
|     display.print("_time_not_set_");   // Shows warning "time not set"
 | |
|   } else {
 | |
| //    Serial.println("RTC has set the system time");
 | |
|     Serial.println(now());
 | |
|     display.print("HAIL_EriS");        // Shows display initialization
 | |
|   }
 | |
|   pinMode(buttonPin, INPUT);           // Button setting
 | |
|   // Main thread initialization:
 | |
|   mainThread.onRun(mainLoop);
 | |
|   mainThread.setInterval(mainCheck);
 | |
|   // Time bias correction thread initialization:
 | |
|   correctionThread.onRun(correctionLoop);
 | |
|   correctionThread.setInterval(correctionCheck);
 | |
| }
 | |
| 
 | |
| void loop() {
 | |
|   // Threads:
 | |
|   if (mainThread.shouldRun())
 | |
|     mainThread.run();
 | |
|   if (correctionThread.shouldRun())
 | |
|     correctionThread.run();
 | |
|   // Time check:
 | |
|   if (timeStatus() != timeSet)
 | |
|     display.print("SEt tiMe");
 | |
| }
 | |
| 
 | |
| void mainLoop() {
 | |
|   // Counting an eighth part of a decimal second:
 | |
|   octavo++;
 | |
|   if (octavo == 8) octavo = 0;
 | |
|   // Update display every decimal second:
 | |
|   if (octavo == 0) {
 | |
|     if (viewMode == 0) {
 | |
|        dtime();
 | |
|     } else if (viewMode == 1) {
 | |
|        dtime();
 | |
|     } else if (viewMode == 2) {
 | |
|        ddate();
 | |
|     } else if (viewMode == 3) {
 | |
|        ddate();
 | |
|     } else if (viewMode == 4) {
 | |
|        dyold();
 | |
|     }
 | |
|   }
 | |
|   // Resets the view mode to the default state after buttonInterval expires:
 | |
|   if (millis() - previousButtonMillis > buttonInterval) viewMode = 0;
 | |
|   // Check the button state:
 | |
|   if (digitalRead(buttonPin) == HIGH) {
 | |
|     buttonPressed = buttonPressed + mainCheck;
 | |
|     if (buttonPressed > buttonLongPress) {
 | |
|       buttonPressed = 0;
 | |
|       longPress();
 | |
|     }
 | |
|   } else {
 | |
|     if (buttonPressed > 0) {
 | |
|       if (viewMode < 4) viewMode += 1;
 | |
|         else viewMode = 0;
 | |
|       buttonPressed = 0;
 | |
|       previousButtonMillis = millis();
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void dtime() {
 | |
|   // Calculating discordian time:
 | |
|   uint32_t timec;
 | |
|   long christiansec;
 | |
|   float dtimeconv;
 | |
|   timec = now() + timezoneOffset;
 | |
|   christiansec = timec % 86400;
 | |
|   dtimeconv = float(86400) / float(christiansec);
 | |
|   erisiansec = float(100000) / dtimeconv;
 | |
|   if (viewMode == 0) dtimeHM();
 | |
|     else if (viewMode == 1) dtimeMS();
 | |
|     else dtimeHM();
 | |
|   colon = !colon;
 | |
|   display.setColonOn(colon);
 | |
| }
 | |
| 
 | |
| void dtimeHM() {
 | |
|   // Displaying of erisian hours and minutes:
 | |
|   int dhour;
 | |
|   dhour = int(erisiansec / float(10000));
 | |
|   int dminute;
 | |
|   dminute = (long(erisiansec) % 10000) / 100;
 | |
|   byte  rawData[4];
 | |
|   rawData[0] = display.encode(' ');
 | |
|   rawData[1] = display.encode(dhour);
 | |
|   rawData[2] = display.encode(dminute / 10);
 | |
|   rawData[3] = display.encode(dminute % 10);
 | |
|   display.printRaw(rawData);
 | |
| }
 | |
| 
 | |
| void dtimeMS() {
 | |
|   // Displaying of erisian minutes and seconds:
 | |
|   int dminute;
 | |
|   dminute = (long(erisiansec) % 10000) / 100;
 | |
|   int dsecond;
 | |
|   dsecond = (long(erisiansec) % 100);
 | |
|   byte  rawData[4];
 | |
|   rawData[0] = display.encode(dminute / 10);
 | |
|   rawData[1] = display.encode(dminute % 10);
 | |
|   rawData[2] = display.encode(dsecond / 10);
 | |
|   rawData[3] = display.encode(dsecond % 10);
 | |
|   display.printRaw(rawData);
 | |
| }
 | |
| 
 | |
| void ddate() {
 | |
|   // Calculating and displaying discordian date:
 | |
|   uint32_t timec;
 | |
|   timec = now() + timezoneOffset;
 | |
|   byte dseason;
 | |
|   short dday;
 | |
|   short daynumber;
 | |
|   short y = year(timec);
 | |
|   short m = month(timec);
 | |
|   short d = day(timec);
 | |
|   // The algorithm for calculating the day's number is from here: https://forum.arduino.cc/index.php?topic=44476.0
 | |
|   int days[]={0,31,59,90,120,151,181,212,243,273,304,334}; // Number of days at the beginning of the month in a not leap year.
 | |
|   String outputstr;
 | |
|   display.setColonOn(0);
 | |
|   if (viewMode == 2) {
 | |
|     if (m == 1 || m == 2) {
 | |
|       daynumber = days[(m - 1)] + d;         // for any type of year, it calculate the number of days for January or February
 | |
|       dday = daynumber;
 | |
|       dseason = 0;
 | |
|     }                                    // Now, try to calculate for the other months
 | |
|     else if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) { //those are the conditions to have a leap year
 | |
|       daynumber = days[(m - 1)] + d + 1;       // if leap year, calculate in the same way but increasing one day
 | |
|       dday = (daynumber % 73) - 1;
 | |
|       dseason = (daynumber - 1) / 73;
 | |
|     }
 | |
|     else {                               // if not a leap year, calculate in the normal way, such as January or February
 | |
|       daynumber = days[(m - 1)] + d;
 | |
|       dday = daynumber % 73;
 | |
|       dseason = daynumber / 73;
 | |
|     }
 | |
|     if ( m == 2 && d == 29 ) outputstr = " tib";
 | |
|       else {
 | |
|         if (dseason == 0) outputstr = "ch";
 | |
|         else if (dseason == 1) outputstr = "di";
 | |
|         else if (dseason == 2) outputstr = "co";
 | |
|         else if (dseason == 3) outputstr = "bu";
 | |
|         else outputstr = "af";
 | |
|         outputstr += (dday / 10);
 | |
|         outputstr += (dday % 10);
 | |
|       }
 | |
|     display.print(outputstr);
 | |
|   } else {
 | |
|     // Calculating and displaying discordian weekday:
 | |
|     byte dweekday;
 | |
|     daynumber = days[(m - 1)] + d;
 | |
|     if (daynumber < 6) dweekday = daynumber;
 | |
|       else dweekday = daynumber % 5;
 | |
|     if ( m == 2 && d == 29 ) outputstr = " tib";
 | |
|       else {
 | |
|         if (dweekday == 1) outputstr = "swee";
 | |
|         else if (dweekday == 2) outputstr = "boom";
 | |
|         else if (dweekday == 3) outputstr = "pung";
 | |
|         else if (dweekday == 4) outputstr = "pric";
 | |
|         else outputstr = "sett";
 | |
|       }
 | |
|     display.print(outputstr);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void dyold() {
 | |
|   // Calculating and displaying discordian yold:
 | |
|   uint32_t timec;
 | |
|   timec = now() + timezoneOffset;
 | |
|   int yold;
 | |
|   yold = year(timec) + 1166;
 | |
|   display.setColonOn(0);
 | |
|   display.print(yold);
 | |
| }
 | |
| 
 | |
| void longPress() {
 | |
|   // Long button press function
 | |
|   display.setColonOn(0);
 | |
|   display.print("HAIL_EriS");
 | |
|   viewMode = 0;
 | |
| }
 | |
| 
 | |
| void correctionLoop() {
 | |
|   if (hour() == correctionHour) {
 | |
|     if (correctionReady) {
 | |
|       // CORRECTION!
 | |
|       tmElements_t RTCtime;
 | |
|       RTC.read(RTCtime);
 | |
|       time_t RTCtimestamp;
 | |
|       RTCtimestamp = makeTime(RTCtime);
 | |
|       tmElements_t timeNew;
 | |
|       time_t newTimestamp = RTCtimestamp - correctionBias;
 | |
|       breakTime(newTimestamp, timeNew);
 | |
|       RTC.write(timeNew);
 | |
|       setSyncProvider(RTC.get);
 | |
|       // CORRECTION!
 | |
|       correctionReady = false;
 | |
|     }
 | |
|   } else correctionReady = true;
 | |
| }
 |