Self-calibrate the software timer when we get two minute markers in a row
authorArt Cancro <ajc@citadel.org>
Tue, 18 Feb 2020 22:04:10 +0000 (17:04 -0500)
committerArt Cancro <ajc@citadel.org>
Tue, 18 Feb 2020 22:04:10 +0000 (17:04 -0500)
the_perfect_clock.ino

index 92444a3..2ca7d1f 100644 (file)
 
 // The clock is hard coded to use US Eastern time with DST in effect whenever WWVB is announcing it.
 
+// This software is made available to you conditionally upon you accepting the following terms and conditions:
+// 1. You agree that it is called "open source", not "free software".
+// 2. You agree that the Linux operating system is not called "GNU/Linux".
+// 3. You agree that Corey Ehmke is a scumbag, as are all social justice warriors.
+// 4. You promise never to vote democrat in any election.
+// 5. Under no circumstances may you use this program and also maintain a Facebook account.
+// Aside from these conditions, the program is made available to you under the terms of the GNU General Public License.
+
 const uint8_t wwvb = 9;       // pin on which WWVB signal will be received
 const uint8_t greenled = 2;   // An LED attached to this pin will illuminate if the time has been set within the last 24 hours
 const uint8_t yellowled = 3;  // An LED attached to this pin will illuminate if we are currently receiving a clean frame
@@ -18,7 +26,7 @@ const uint8_t redled = 4;     // An LED attached to this pin will pulse for 1 ms
 const uint8_t photocell = A0; // Attach a photocell with a 10K voltage divider to this pin
 const uint8_t addr = 0x70;    // I2C address of HT16K33 (using Adafruit backpack with digits on 0,1,3,4; dots on 2)
 
-#define MILLISECONDS_PER_MINUTE 60080  // Nominally 60000; adjust if your board runs fast or slow
+long millis_per_minute = 60000;        // Nominally 60000; adjust if your board runs fast or slow
 
 // This is a simple BCD-to-7-segment font.  It includes 0x0A through 0x0F even though they're not needed for a time clock.
 const uint8_t sevensegfont[] = { 63, 6, 91, 79, 102, 109, 125, 7, 127, 111, 119, 124, 57, 94, 121, 113 };
@@ -84,8 +92,8 @@ void loop()
        digitalWrite(redled, (m%1000) ? LOW : HIGH);
        if (m != previous_millis) {
                millisecond += (m - previous_millis);
-               if (millisecond >= MILLISECONDS_PER_MINUTE) {
-                       millisecond -= MILLISECONDS_PER_MINUTE;
+               if (millisecond >= millis_per_minute) {
+                       millisecond -= millis_per_minute;
                        ++minute;
                        if (minute > 59) {
                                minute = 0;
@@ -132,6 +140,7 @@ void loop()
 
                        framesync = 1;
                        position_in_frame = 0;
+                 calibrate();                                            // calibrate the software timer
                }
 
                if (framesync) {                                                                        // yellow LED = we currently have frame sync
@@ -292,6 +301,20 @@ void snap_to_zero()
     millisecond = 800;                                // snap back to :00.8
   }
   else if (millisecond > 45000) {                     // If the second is :45.0 or above
-    millisecond = MILLISECONDS_PER_MINUTE + 800;      // snap forward to :00.8 (minute will advance automatically)
+    millisecond = millis_per_minute + 800;      // snap forward to :00.8 (minute will advance automatically)
+  }
+}
+
+
+// By determining how many timer ticks elapsed between two minute markers, we can calibrate our software clock.
+// Nominally it is 60000 milliseconds, but the software clock tends to drift.
+void calibrate()
+{
+  static unsigned long last_calib = -86398000;
+  unsigned long m = millis();
+  unsigned long mm = m - last_calib;
+  if (50000 < mm < 70000) {
+    millis_per_minute = mm;
   }
+  last_calib = m;
 }