Browse Source

Finished clock functionality

Kevin Lee 5 years ago
parent
commit
5aef45af7a
2 changed files with 125 additions and 134 deletions
  1. 112 130
      Nixie_Firmware_Mbed/main.cpp
  2. 13 4
      Nixie_Firmware_Mbed/main.h

+ 112 - 130
Nixie_Firmware_Mbed/main.cpp

@@ -13,92 +13,92 @@ I2C i2c(PA_10, PA_9);
 bool RtcTick, RefreshTick, RngTick;
 
 typedef enum {
-    Idle = 0,
+    Decrementing = 0,
     Incrementing = 1,
-    Decrementing = 2,
 } DigitState;
 
 typedef struct {
     DigitState CurrentState;
     int Value;
-    int Brightness;
-    int Step;
     bool Updated;
 } Digit;
 
 typedef struct {
     Digit Digits[10];
     bool Refresh;
-    int UpdateRate;
+    int FadeDuration;
 } Tube;
 
 Tube Tubes[4];  // Active per-tube configuration
 Digit Dot;
 
-Ticker RuntimeUpdateTicker, RngUpdateTicker;
-int RuntimeTickerIter, RngTickerIter;
-
-void RtcTickCallback(void) {
-    RtcTick = true;
-}
-
-void RefreshTickCallback(void) {
-    RefreshTick = true;
-}
-
-void RngTickCallback(void) {
-    RngTick = true;
-}
-
-Timeout DotUpdateTick;
+Timeout DotUpdateTimeout;
 void DotUpdateCallback(void) {
-    if (Dot.CurrentState == Incrementing && Dot.Brightness < PCA9685_Max_Brightness) {
-        Dot.Brightness += Dot.Step;
-    } else if (Dot.CurrentState == Decrementing && Dot.Brightness > PCA9685_Min_Brightness) {
-        Dot.Brightness -= Dot.Step;
+    if (Dot.CurrentState == Incrementing && Dot.Value < DOT_MAX) {
+        Dot.Value = (Dot.Value + DOT_FADE_STEP >= DOT_MAX) ? DOT_MAX : Dot.Value + DOT_FADE_STEP;
+    } else if (Dot.CurrentState == Decrementing && Dot.Value > DOT_MIN) {
+        Dot.Value = (Dot.Value - DOT_FADE_STEP <= DOT_MIN) ? DOT_MIN : Dot.Value - DOT_FADE_STEP;
     }
     Dot.Updated = true;
 
-    if (Dot.Brightness == PCA9685_Max_Brightness ||
-        Dot.Brightness == PCA9685_Min_Brightness) {
-        DotUpdateTick.detach();
-    } else {
-        // DotUpdateTick.attach(DotUpdateCallback, (float)1/DOT_FADE_TICKS);
-        DotUpdateTick.attach_us(DotUpdateCallback, 700);
-    }
+    if (Dot.Value != DOT_MAX && Dot.Value != DOT_MIN) {
+        DotUpdateTimeout.attach_us(DotUpdateCallback, DOT_FADE_DURATION_US / REFRESH_RATE_US);
+    } 
 }
 
-void Tube0UpdateCallback(void) {
-
+// Macro the tube callback function as each callback needs to be defined as
+// a unique function (callbacks cannot have arguments and are not reentrant)
+#define TUBE_CALLBACK(x) \
+void Tube##x##UpdateCallback(void) { \
+    int step = (DOT_MAX + (Tubes[x].FadeDuration / REFRESH_RATE_US) - 1) / (Tubes[x].FadeDuration / REFRESH_RATE_US); \
+    bool activeTube = false; \
+    for (int i = 0; i < 10; i++) { \
+        Digit *digit = &Tubes[x].Digits[i]; \
+        if (digit->CurrentState == Incrementing && digit->Value < DIGIT_MAX) { \
+            digit->Value = (digit->Value + step >= DIGIT_MAX) ? DIGIT_MAX : digit->Value + step; \
+            digit->Updated = true; \
+        } else if (digit->CurrentState == Decrementing && digit->Value > DOT_MIN) { \
+            digit->Value = (digit->Value - step <= DIGIT_MIN) ? DIGIT_MIN : digit->Value - step; \
+            digit->Updated = true; \
+        } \
+        activeTube |= (digit->Value != DIGIT_MAX && digit->Value != DIGIT_MIN); \
+    } \
+    if (activeTube) { \
+        Tube##x##UpdateTimeout.attach_us(Tube##x##UpdateCallback, DIGIT_FADE_DURATION_US / REFRESH_RATE_US); \
+    } \
+} 
+
+Timeout Tube0UpdateTimeout;
+TUBE_CALLBACK(0)
+Timeout Tube1UpdateTimeout;
+TUBE_CALLBACK(1)
+Timeout Tube2UpdateTimeout;
+TUBE_CALLBACK(2)
+Timeout Tube3UpdateTimeout;
+TUBE_CALLBACK(3)
+
+void FadeInOutDigit(int T, int D, int Duration) {
+    for (int i = 0; i < 10; i++) {
+        Tubes[T].Digits[i].CurrentState = Decrementing;
+    }
+    if (D != -1) {
+        Tubes[T].Digits[D].CurrentState = Incrementing;
+    }
+    Tubes[T].FadeDuration = Duration;
+
+    if (T == 0) {
+        Tube0UpdateTimeout.attach_us(Tube0UpdateCallback, DIGIT_FADE_DURATION_US / REFRESH_RATE_US);
+    } else if (T == 1) {
+        Tube1UpdateTimeout.attach_us(Tube1UpdateCallback, DIGIT_FADE_DURATION_US / REFRESH_RATE_US);
+    } else if (T == 2) {
+        Tube2UpdateTimeout.attach_us(Tube2UpdateCallback, DIGIT_FADE_DURATION_US / REFRESH_RATE_US);
+    } else if (T == 3) {
+        Tube3UpdateTimeout.attach_us(Tube3UpdateCallback, DIGIT_FADE_DURATION_US / REFRESH_RATE_US);
+    } 
 }
 
-// void RuntimeTickerUpdate(void) {
-
-//     for (int i = 0; i < NUM_TUBES; i++) {
-//         if(!Tube[i].RefreshActive) {
-//             for (int j = 0; j < MAX_FADE_DIGITS; j++) {
-//                 DIGIT *digit = &Tube[i].Digits[j];
-//                 if (digit->Active) {
-//                     if (digit->Increment && digit->Reg < PCA9685_Max_Brightness) {
-//                         digit->Reg += FADE_TICK_STEP;
-//                     } else if (digit->Reg > PCA9685_Min_Brightness) {
-//                         digit->Reg -= FADE_TICK_STEP;
-//                     }
-//                     Tube[i].Updated = true;
-//                 }
-//             }
-//         }
-//     }
-
-//     DotValue = DotIncrement ? DotValue + FADE_TICK_STEP : DotValue - FADE_TICK_STEP;
-//     DotUpdated = true;
-
-//     if (--RuntimeTickerIter == 0) {
-//         RuntimeUpdateTicker.detach();
-//         DotIncrement = !DotIncrement;
-//     }
-// }
-
+Ticker RefreshTicker, RngUpdateTicker;
+int RngTickerIter;
 void RngTickerUpdate(void) {
 
 
@@ -107,12 +107,36 @@ void RngTickerUpdate(void) {
     }
 }
 
+// Callback from DS3231 interrupt (1Hz)
+void RtcTickCallback(void) {
+    RtcTick = true;
+}
+
+// Callback from RefreshTicker (REFRESH_RATE_US)
+void RefreshTickCallback(void) {
+    RefreshTick = true;
+}
+
+void RngTickCallback(void) {
+    RngTick = true;
+}
+
 int main() {
 
     // Initialize pointers in global data structure
-    // for (int i = 0; i < NUM_TUBES; i++) {
-    //     Tube[i].NextDigit = &Tube[i].Digits[0];
-    // }
+    for (int i = 0; i < NUM_TUBES; i++) {
+        for (int j = 0; j < 10; j++) {
+            Tubes[i].Digits[j].CurrentState = Decrementing;
+            Tubes[i].Digits[j].Value = 0;
+            Tubes[i].Digits[j].Updated = false;
+        }
+        Tubes[i].Refresh = false;
+        Tubes[i].FadeDuration = 0;
+    }
+
+    Dot.CurrentState = Decrementing;
+    Dot.Value = 0;
+    Dot.Updated = false;
 
     RtcTick = false;
     RefreshTick = false;
@@ -144,8 +168,7 @@ int main() {
     // i2c.frequency(1000000);
 
     // Setup a ticker to refresh the display at 1kHz
-    Ticker refreshTicker;
-    refreshTicker.attach_us(RefreshTickCallback, DIGIT_REFRESH_RATE_US);
+    RefreshTicker.attach_us(RefreshTickCallback, REFRESH_RATE_US);
 
     // Kick off the RNG ticker at 0.1Hz
     // Ticker rngTicker;
@@ -154,10 +177,6 @@ int main() {
     // DS3231_SetTime(0, 55, 6, true);
     // DS3231_SetDate(0, 2, 12, 18, 0);
 
-    Dot.CurrentState = Decrementing;
-    Dot.Step = DOT_TICK_STEP;
-    Dot.Brightness = 0;
-
     while(1) {
 
         // Animate_Cycle_Basic();
@@ -173,24 +192,17 @@ int main() {
         if (RefreshTick) {
             RefreshTick = false;
 
-            // for (int i = 0; i < NUM_TUBES; i++) {
-            //     if (Tube[i].Updated) {
-            //         Tube[i].Updated = false;
-
-            //         for (int j = 0; j < MAX_FADE_DIGITS; j++) {
-            //             DIGIT *digit = &Tube[i].Digits[j];
-            //             if (digit->Active) {
-            //                 PCA9685_SetDigit(i, digit->Value, digit->Reg);
-            //                 if (digit->Reg == 0 && !digit->Increment) {
-            //                     digit->Active = false;
-            //                 }
-            //             }
-            //         }
-            //     }
-            // }
+            for (int i = 0; i < 4; i++) {
+                for (int j = 0; j < 10; j++) {
+                    if (Tubes[i].Digits[j].Updated) {
+                        PCA9685_SetDigit(i, j, Tubes[i].Digits[j].Value);
+                        Tubes[i].Digits[j].Updated = false;
+                    }
+                }
+            }
 
             if (Dot.Updated) {
-                PCA9685_SetDot(Dot.Brightness);
+                PCA9685_SetDot(Dot.Value);
                 Dot.Updated = false;
             }
         }
@@ -206,54 +218,24 @@ int main() {
             DS3231_GetTime(&nextSecond, &nextMinute, &nextHour);
 
             // Update the display configuration based on the new/previous time
-            // for (int i = 0; i < NUM_TUBES; i++) {
-
-            //     bool Update = false;
-            //     if (i == 0 && (startup || prevHour / 10 != nextHour / 10)) {
-            //         if (nextHour / 10 != 0) {
-            //             Tube[i].NextDigit->Value = nextHour / 10;
-            //             Tube[i].NextDigit->Increment = true;
-            //             Tube[i].NextDigit->Active = true;
-            //         }
-            //         Update = true; // ?
-            //     } else if (i == 1 && (startup || prevHour % 10 != nextHour % 10)) {
-            //         Tube[i].NextDigit->Value = nextHour % 10;
-            //         Tube[i].NextDigit->Increment = true;
-            //         Tube[i].NextDigit->Active = true;
-            //         Update = true;
-            //     } else if (i == 2 && (startup || prevMinute / 10 != nextMinute / 10)) {
-            //         Tube[i].NextDigit->Value = nextMinute / 10;
-            //         Tube[i].NextDigit->Increment = true;
-            //         Tube[i].NextDigit->Active = true;
-            //         Update = true;
-            //     } else if (i == 3 && (startup || prevMinute % 10 != nextMinute % 10)) {
-            //         Tube[i].NextDigit->Value = nextMinute % 10;
-            //         Tube[i].NextDigit->Increment = true;
-            //         Tube[i].NextDigit->Active = true;
-            //         Update = true;
-            //     }
-
-                // Handle display configuration changes for the given tube
-            //     if (Update) {
-            //         if (!startup) {
-            //             Tube[i].PrevDigit->Increment = false;
-            //         }
-            //         Tube[i].PrevDigit = Tube[i].NextDigit;
-            //         Tube[i].NextDigit = Tube[i].NextDigit == &Tube[i].Digits[0] ? 
-            //             &Tube[i].Digits[1] : &Tube[i].Digits[0];
-            //     }
-            // }
+            if (startup || prevHour / 10 != nextHour / 10) {
+                FadeInOutDigit(0, (nextHour / 10 != 0) ? nextHour / 10 : -1 , DIGIT_FADE_DURATION_US);
+            } 
+            if (startup || prevHour % 10 != nextHour % 10) {
+                FadeInOutDigit(1, nextHour % 10, DIGIT_FADE_DURATION_US);
+            } 
+            if (startup || prevMinute / 10 != nextMinute / 10) {
+                FadeInOutDigit(2, nextMinute / 10, DIGIT_FADE_DURATION_US);
+            } 
+            if (startup || prevMinute % 10 != nextMinute % 10) {
+                FadeInOutDigit(3, nextMinute % 10, DIGIT_FADE_DURATION_US);
+            }
 
             Dot.CurrentState = (Dot.CurrentState == Decrementing) ? Incrementing : Decrementing;
-            // DotUpdateTick.attach(DotUpdateCallback, (float)1/DOT_FADE_TICKS);
-            DotUpdateTick.attach_us(DotUpdateCallback, 700);
+            DotUpdateTimeout.attach_us(DotUpdateCallback, DOT_FADE_DURATION_US / REFRESH_RATE_US);
 
             // Clear the startup run-once flag after the first iteration
-            // startup = false;
-
-            // Fade in the new time
-            // RuntimeTickerIter = FADE_TICKS;
-            // RuntimeUpdateTicker.attach(RuntimeTickerUpdate, (float)(DIGIT_REFRESH_RATE_US / 1000) / RuntimeTickerIter);
+            startup = false;
         }
 
         if (RngTick) {

+ 13 - 4
Nixie_Firmware_Mbed/main.h

@@ -18,10 +18,19 @@
 
 #define I2C_MAX_BUFFER 20
 
-#define DOT_FADE_TICKS 1024
-#define DOT_TICK_STEP (PCA9685_Max_Brightness / DOT_FADE_TICKS)
-
-#define DIGIT_REFRESH_RATE_US 1000  // 1KHz display refresh rate
+#define REFRESH_RATE_US 1000  
+
+#define DOT_MIN PCA9685_Min_Brightness
+#define DOT_MAX PCA9685_Max_Brightness
+#define DOT_FADE_DURATION_US 900000
+#define DOT_FADE_TICK (DOT_FADE_DURATION_US / REFRESH_RATE_US)
+#define DOT_FADE_STEP ((DOT_MAX + DOT_FADE_TICK - 1) / DOT_FADE_TICK)
+
+#define DIGIT_MIN PCA9685_Min_Brightness
+#define DIGIT_MAX PCA9685_Max_Brightness
+#define DIGIT_FADE_DURATION_US 1000000
+// #define DIGIT_FADE_TICK (DOT_FADE_DURATION_US / REFRESH_RATE_US)
+// #define DIGIT_FADE_STEP ((DOT_MAX + DIGIT_FADE_TICK - 1) / DIGIT_FADE_TICK)
 
 #define DIGIT_RNG_REFRESH_RATE_S 30
 #define DIGIT_RNG_REFRESH_ITER 20