|
| 1 | +/*----------------------------------------------------------------------------------* |
| 2 | + A simple clock that reads from a DS1302 RTC and shows the time on 4 x 7-segment displays |
| 3 | + Example connection diagram: https://bit.ly/4x7SEG-3x1DOT |
| 4 | +
|
| 5 | + The MIT License |
| 6 | + David Plass 30 Nov 2024 |
| 7 | +
|
| 8 | + Based on example code at https://github.com/marcinsaj/FlipDisc |
| 9 | + by Marcin Saj 15 Jan 2023 |
| 10 | +
|
| 11 | + A dedicated controller or any Arduino board with a power module is required |
| 12 | + to operate the display: |
| 13 | + 1. Dedicated controller - https://bit.ly/AC1-FD |
| 14 | + 2. Or any Arduino board + Pulse Shaper Power Supply - https://bit.ly/PSPS-FD |
| 15 | + ----------------------------------------------------------------------------------*/ |
| 16 | + |
| 17 | +/* The library <FlipDisc.h> uses SPI to control flip-disc displays. |
| 18 | + The user must remember to connect the display inputs marked: |
| 19 | + - DIN - data in - to the MOSI (SPI) output of the microcontroller, |
| 20 | + - CLK - clock - input of the display to the SCK (SPI). |
| 21 | + The displays are connected in series through the built-in connectors, |
| 22 | + only the first display from the left is connected to the Arduino or a dedicated controller. |
| 23 | +
|
| 24 | + It is very important to connect and declare EN, CH, PL pins. |
| 25 | + The declaration of DIN (MOSI) and CLK (SCK) is not necessary, |
| 26 | + because the SPI.h library handles the SPI hardware pins. */ |
| 27 | + |
| 28 | +#include <FlipDisc.h> // https://github.com/marcinsaj/FlipDisc |
| 29 | +#include <RtcDS1302.h> |
| 30 | + |
| 31 | +ThreeWire myWire(2, 3, 4); // IO, SCLK, CE |
| 32 | +RtcDS1302<ThreeWire> Rtc(myWire); |
| 33 | + |
| 34 | +// Standard pin declaration for Arduino Uno and PSPS module |
| 35 | +#define EN_PIN 10 |
| 36 | +#define CH_PIN 8 |
| 37 | +#define PL_PIN 9 |
| 38 | + |
| 39 | +// Note, MOSI (DataIn), Clk (SCK) are defaulted to 11 and 13, respectively. |
| 40 | + |
| 41 | +RtcDateTime last; |
| 42 | + |
| 43 | +void setup() |
| 44 | +{ |
| 45 | + Serial.begin(57600); |
| 46 | + |
| 47 | + Serial.print("compiled: "); |
| 48 | + Serial.print(__DATE__); |
| 49 | + Serial.println(__TIME__); |
| 50 | + |
| 51 | + /* Flip.Pin(); it is the most important function and first to call before everything else. |
| 52 | + The function is used to declare pin functions. Before starting the device, double check |
| 53 | + that the declarations and connection are correct. If the connection of the control outputs |
| 54 | + is incorrect, the display may be physically damaged. */ |
| 55 | + Flip.Pin(EN_PIN, CH_PIN, PL_PIN); |
| 56 | + |
| 57 | + /* Flip.Init(display1, display2, ... display8); it is the second most important function. |
| 58 | + Initialization function for a series of displays. The function has 1 default argument and 7 optional arguments. |
| 59 | + The function also prepares SPI. Correct initialization requires code names of the serially |
| 60 | + connected displays: |
| 61 | + - D7SEG - 7-segment display |
| 62 | + - D2X1 - 2x1 display |
| 63 | + - D3X1 - 3x1 display |
| 64 | + - D1X3 - 1x3 display |
| 65 | + - D1X7 - 1x7 display */ |
| 66 | + Flip.Init(D7SEG, D7SEG, D7SEG, D7SEG); |
| 67 | + |
| 68 | + /* The function is used to set the delay effect between flip discs. |
| 69 | + The default value without calling the function is 0. Can be called multiple times |
| 70 | + anywhere in the code. Recommended delay range: 0 - 100ms, max 255ms */ |
| 71 | + Flip.Delay(10); |
| 72 | + |
| 73 | + /* The function is used to test all declared displays - turn on and off all displays */ |
| 74 | + Flip.Test(); |
| 75 | + delay(500); |
| 76 | + |
| 77 | + Flip.Matrix_7Seg(I, N, I, T); |
| 78 | + delay(500); |
| 79 | + Flip.Matrix_7Seg(R, T, C, CLR); |
| 80 | + delay(500); |
| 81 | + |
| 82 | + Rtc.Begin(); |
| 83 | + |
| 84 | + RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__); |
| 85 | + printDateTime(compiled); |
| 86 | + Serial.println(); |
| 87 | + |
| 88 | + if (!Rtc.IsDateTimeValid()) |
| 89 | + { |
| 90 | + // Common Causes: |
| 91 | + // 1) first time you ran and the device wasn't running yet |
| 92 | + // 2) the battery on the device is low or even missing |
| 93 | + |
| 94 | + Serial.println("RTC lost confidence in the DateTime!"); |
| 95 | + Flip.Matrix_7Seg(S, E, T, CLR); |
| 96 | + delay(1000); |
| 97 | + Rtc.SetDateTime(compiled); |
| 98 | + } |
| 99 | + |
| 100 | + if (Rtc.GetIsWriteProtected()) |
| 101 | + { |
| 102 | + Serial.println("RTC was write protected, enabling writing now"); |
| 103 | + Rtc.SetIsWriteProtected(false); |
| 104 | + Flip.Matrix_7Seg(R, T, W, P); |
| 105 | + delay(1000); |
| 106 | + } |
| 107 | + |
| 108 | + if (!Rtc.GetIsRunning()) |
| 109 | + { |
| 110 | + Serial.println("RTC was not actively running, starting now"); |
| 111 | + Rtc.SetIsRunning(true); |
| 112 | + Flip.Matrix_7Seg(S, T, R, T); |
| 113 | + delay(1000); |
| 114 | + } |
| 115 | + |
| 116 | + RtcDateTime now = Rtc.GetDateTime(); |
| 117 | + if (now < compiled) |
| 118 | + { |
| 119 | + Serial.println("RTC is older than compile time! (Updating DateTime)"); |
| 120 | + Rtc.SetDateTime(compiled); |
| 121 | + Flip.Matrix_7Seg(R, T, U, P); |
| 122 | + delay(1000); |
| 123 | + } |
| 124 | + else if (now > compiled) |
| 125 | + { |
| 126 | + Serial.println("RTC is newer than compile time. (this is expected)"); |
| 127 | + } |
| 128 | + last = Rtc.GetDateTime(); |
| 129 | + showTime(last); |
| 130 | +} |
| 131 | + |
| 132 | +void showTime(RtcDateTime now) { |
| 133 | + printDateTime(now); |
| 134 | + Serial.println(); |
| 135 | + |
| 136 | + int hour = now.Hour(); |
| 137 | + if (hour > 12) { |
| 138 | + hour -= 12; |
| 139 | + } |
| 140 | + int hr10 = hour / 10; |
| 141 | + int hr1 = hour % 10; |
| 142 | + int min10 = now.Minute() / 10; |
| 143 | + int min1 = now.Minute() % 10; |
| 144 | + Serial.print("Clock is: "); Serial.print(hr10); Serial.print(hr1); Serial.print(":"); Serial.print(min10); Serial.println(min1); |
| 145 | + |
| 146 | + // Clear first digit if zero. |
| 147 | + if (hr10 == 0) { |
| 148 | + hr10 = CLR; |
| 149 | + } |
| 150 | + |
| 151 | + // Set each digit of the clock. |
| 152 | + /* Function to control up to eight 7-segment displays. |
| 153 | + The first argument is the default and the others are optional. |
| 154 | + This function allows you to display numbers and symbols |
| 155 | + Flip.Matrix_7Seg(data1,data2,data3,data4,data5,data6,data7,data8); */ |
| 156 | + Flip.Matrix_7Seg(hr10, hr1, min10, min1); |
| 157 | +} |
| 158 | + |
| 159 | +void loop() |
| 160 | +{ |
| 161 | + RtcDateTime now = Rtc.GetDateTime(); |
| 162 | + if (now.Hour() != last.Hour() || now.Minute() != last.Minute()) { |
| 163 | + // Hour or minute is different; update the whole clock. |
| 164 | + showTime(now); |
| 165 | + last = now; |
| 166 | + } else if (now.Second() != last.Second()) { |
| 167 | + /* An example of calling the function to set disc no.19 of the first 7-Segment display */ |
| 168 | + /* 0 1 2 3 4 |
| 169 | + 19 5 |
| 170 | + 18 6 |
| 171 | + 17 20 21 22 7 |
| 172 | + 16 8 |
| 173 | + 15 9 |
| 174 | + 14 13 12 11 10 */ |
| 175 | + // Flip one disc in the leftmost column to indicate 10s of seconds |
| 176 | + for (int i = 0; i <= now.Second() / 10; i++) { |
| 177 | + Flip.Disc_7Seg(1, 14 + i, 1); // last argument can be 0 to turn off |
| 178 | + } |
| 179 | + } |
| 180 | + |
| 181 | + /* 7-Segment displays allow the display of numbers and symbols. |
| 182 | + Symbols can be displayed using their code name or number e.g. 37/DEG - "°" Degree symbol |
| 183 | + The full list of symbols can be found in the FlipDisc.h library repository https://github.com/marcinsaj/FlipDisc |
| 184 | + Code names for symbols: |
| 185 | + - 0-9 |
| 186 | + - 1/VLR - " |" - Vertical line - right |
| 187 | + - 8/ALL - Set all discs |
| 188 | + - 10/CLR - Clear display |
| 189 | + - 11/A |
| 190 | + - 12/B |
| 191 | + - 13/C |
| 192 | + - 14/D |
| 193 | + - 15/E |
| 194 | + - 16/F |
| 195 | + - 17/G |
| 196 | + - 18/H |
| 197 | + - 19/I |
| 198 | + - 20/J |
| 199 | + - 21/K |
| 200 | + - 22/L |
| 201 | + - 23/M |
| 202 | + - 24/N |
| 203 | + - 25/O |
| 204 | + - 26/P |
| 205 | + - 27/Q |
| 206 | + - 28/R |
| 207 | + - 29/S |
| 208 | + - 30/T |
| 209 | + - 31/U |
| 210 | + - 32/V |
| 211 | + - 33/W |
| 212 | + - 34/X |
| 213 | + - 35/Y |
| 214 | + - 36/Z |
| 215 | + - 37/DEG - "°" - Degree symbol |
| 216 | + - 37/PFH - "%" - Percent first half symbol |
| 217 | + - 38/PSH - "%" - Percent second half symbol |
| 218 | + - 39/HLU - "¯" - Horizontal line - upper |
| 219 | + - 40/HLM - "-" - Horizontal line - middle |
| 220 | + - 41/HLL - "_" - Horizontal line - lower |
| 221 | + - 42/HLT - "=" - Horizontal line - upper & lower |
| 222 | + - 43/HLA - "≡" - All three lines |
| 223 | + - 40/MIN - "-" - Minus symbol |
| 224 | + - 44/VLL - "| " - Vertical line - left |
| 225 | + - 45/VLA - "||" - All Vertical lines */ |
| 226 | +} |
| 227 | + |
| 228 | +#define countof(a) (sizeof(a) / sizeof(a[0])) |
| 229 | + |
| 230 | +void printDateTime(const RtcDateTime& dt) |
| 231 | +{ |
| 232 | + char datestring[26]; |
| 233 | + |
| 234 | + snprintf_P(datestring, |
| 235 | + countof(datestring), |
| 236 | + PSTR("%02u/%02u/%04u %02u:%02u:%02u"), |
| 237 | + dt.Month(), |
| 238 | + dt.Day(), |
| 239 | + dt.Year(), |
| 240 | + dt.Hour(), |
| 241 | + dt.Minute(), |
| 242 | + dt.Second() ); |
| 243 | + Serial.print(datestring); |
| 244 | +} |
0 commit comments