// Auto-setting 7 time zone clock
// By Alan De Windt
// November 2022
#include <DCF77.h> //https://github.com/thijse/Arduino-DCF77
// Custom update to line 42 of DCF77.cpp from...
// pinMode(dCF77Pin, INPUT);
// to
// pinMode(dCF77Pin, INPUT_PULLUP);
// ...as DCF77 module signal goes to ground/LOW when signal is received, but otherwise "floats" so
// INPUT_PULLUP activates the built-in pull-up resistor which pulls the line up HIGH
#include <TimeLib.h> //https://github.com/PaulStoffregen/Time
#include <Timezone.h> //https://github.com/JChristensen/Timezone
#include <TM1637Display.h> //https://github.com/avishorp/TM1637
#define DCF_PIN 2 // Connection pin to DCF 77 device
#define DCF_INTERRUPT 0 // Interrupt number associated with pin
DCF77 DCF = DCF77(DCF_PIN,DCF_INTERRUPT,false);
TimeChangeRule rDST1 = {"CDT", Second, Sun, Mar, 2, -300}; // Fort Worth Daylight Savings Time
TimeChangeRule rST1 = {"CST", First, Sun, Nov, 2, -360}; // Fort Worth Standard Time
TimeChangeRule rDST2 = {"EDT", Second, Sun, Mar, 2, -240}; // New York Daylight Savings Time
TimeChangeRule rST2 = {"EST", First, Sun, Nov, 2, -300}; // New York Standard Time
TimeChangeRule rDST3 = {"BST", Last, Sun, Mar, 1, 60}; // London Daylight Savings Time
TimeChangeRule rST3 = {"GMT", Last, Sun, Oct, 2, 0}; // London Standard Time
TimeChangeRule rDST4 = {"CEST", Last, Sun, Mar, 2, 120}; // Zurich Daylight Savings Time
TimeChangeRule rST4 = {"CET", Last, Sun, Oct, 3, 60}; // Zurich Standard Time
TimeChangeRule rST5 = {"IST", Last, Sun, Oct, 1, 330}; // Pune Standard Time - No DST
TimeChangeRule rST6 = {"HKT", Last, Sun, Oct, 1, 480}; // Hong Kong Standard Time - No DST
TimeChangeRule rST7 = {"JST", Last, Sun, Mar, 1, 540}; // Tokyo Standard Time - No DST
Timezone Timezones[] { (rDST1, rST1), (rDST2, rST2), (rDST3, rST3), (rDST4, rST4), (rST5), (rST6), (rST7) };
const int localTimezone = 3; // Array pointer to local time zone -> Zurich
time_t time(time_t *timer);
time_t varTime;
const int numDigitDisplays = 7; // Number of 4 digit 7-segment display panels
const int numDigits = numDigitDisplays * 4; // Total number of 7-segment digits available
TM1637Display DigitDisplay[] { TM1637Display(28, 29), TM1637Display(47, 46), TM1637Display(45, 44), TM1637Display(26, 27), TM1637Display(43, 42), TM1637Display(24, 25), TM1637Display(41, 40) };
int timeZoneLabels[] = {23, 20, 21, 18, 19, 16 , 17};
// Array to keep track of the current intensity set for each of the 7-segment displays
int displayIntensity[numDigitDisplays];
// We will use this array to represent what is currently shown in each of the 7-segment digits
// Think of this as the "display memory"
byte digitShown[numDigits];
// We will use this array to prepare what we want to show in each of the 7-segment digits
// Various functions will then use these two arrays to transition from what is currently being shown
// to what we want to show
byte digitToShow[numDigits];
// Binary 7-segment values corresponding to each decimal number
const byte digitToSegment[] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
const byte SEG_COLON = 0b10000000;
int prevMinute = 0;
int nextAnimation = 0;
int nextLabelAnimation = 4;
const int menuButton = 22;
boolean lastMenuButton = HIGH;
boolean currentMenuButton = HIGH;
boolean showDateAndTime = false;
unsigned long startTime;
const int DATA[1] = {31}; // Rotary encoder data pin
const int CLK[1] = {30}; // Rotary encoder clock pin
void setup() {
randomSeed(analogRead(0));
//Serial.begin(9600);
//Serial.println("Starting...");
DCF.Start();
setSyncInterval(30);
setSyncProvider(getDCFTime);
pinMode(menuButton, INPUT_PULLUP);
pinMode(CLK[0], INPUT_PULLUP);
pinMode(DATA[0], INPUT_PULLUP);
// Initialize time zone label pins
for (int i = 0; i < numDigitDisplays; i++) {
pinMode(timeZoneLabels[i], OUTPUT);
}
// Blank out all displays and set default intensity
initDisplayIntensities();
initDisplays();
// Load 8's in array of what we want to display
for (int i = 0; i < numDigits; i++) {
digitToShow[i] = digitToSegment[8];
}
// Now show all 8's by "printing" segments (like a print head) from center outwards
printFromCenter(0);
delay(2000);
// Load nothing in array of what we want to display
for (int i = 0; i < numDigits; i++) {
digitToShow[i] = 0;
}
// Now show nothing by removing segments from exterior inwards
printFromExterior(0);
for (int i = 0; i < numDigitDisplays; i++) {
digitalWrite(timeZoneLabels[i], LOW);
}
delay(1000);
// Show random animation until time is acquired
animationRandomPatterns();
// Load acquired times in array of what we want to display
loadTimes();
// Now show times by printing segments from center outwards
printFromCenter(15);
updateAllDisplays();
}
void loadTimes() {
int p = 0, digitValue;
for (int i = 0; i < numDigitDisplays; i++) {
varTime = Timezones[i].toLocal(now());
if (hour(varTime) > 9) {
digitValue = hour(varTime) / 10;
} else {
digitValue = 0;
}
digitToShow[p] = digitToSegment[digitValue];
p++;
if (hour(varTime) > 0) {
digitValue = hour(varTime) - ((hour(varTime) / 10) * 10);
} else {
digitValue = hour(varTime);
}
digitToShow[p] = digitToSegment[digitValue] + SEG_COLON;
p++;
if (minute(varTime) > 9) {
digitValue = minute(varTime) / 10;
} else {
digitValue = 0;
}
digitToShow[p] = digitToSegment[digitValue];
p++;
if (minute(varTime) > 0) {
digitValue = minute(varTime) - ((minute(varTime) / 10) * 10);
} else {
digitValue = minute(varTime);
}
digitToShow[p] = digitToSegment[digitValue];
p++;
}
}
void updateAllDisplays() {
int p = 0;
for (int i = 0; i < numDigitDisplays; i++) {
for (int j = 0; j < 4; j++) {
byte Segments[] = { digitToShow[p] };
DigitDisplay[i].setSegments(Segments, 1, j);
digitShown[p] = digitToShow[p];
p++;
}
}
}
void turnOnOffLabels() {
// Cycle through each 4 digit 7-segment display
for (int i = 0; i < numDigitDisplays; i++) {
int firstDigit = i * 4;
// If something should be shown...
if (digitToShow[firstDigit] > 0) {
//...and it is fully shown...
if ( (digitShown[firstDigit] == digitToShow[firstDigit]) &&
(digitShown[firstDigit + 1] == digitToShow[firstDigit + 1]) &&
(digitShown[firstDigit + 2] == digitToShow[firstDigit + 2]) &&
(digitShown[firstDigit + 3] == digitToShow[firstDigit + 3]) ) {
// then turn on the label
digitalWrite(timeZoneLabels[i], HIGH);
}
} else { // Otherwise if nothing should be shown
// ...and nothing is currently shown...
if ( (digitShown[firstDigit] == 0) &&
(digitShown[firstDigit + 1] == 0) &&
(digitShown[firstDigit + 2] == 0) &&
(digitShown[firstDigit + 3] == 0) ) {
// then turn off the label
digitalWrite(timeZoneLabels[i], LOW);
}
}
}
}
void printRandomSegment(int delayMillis) {
// Count number of digits currently shown (in digitShown array) that don't match what we want to show (in digitToShow array)
int digitsLeft = 0;
for (int i = 0; i < numDigits; i++) {
if (digitShown[i] != digitToShow[i]) { digitsLeft++; }
}
while (digitsLeft > 0) {
long randomDigit = random(4);
long randomDisplay = random(numDigitDisplays);
int p = (randomDisplay * 4) + randomDigit;
if (digitShown[p] != digitToShow[p]) {
int varDigitShown = digitShown[p];
int varDigitToShow = digitToShow[p];
int bitPositionValue = 1; // Decimal value of 1st bit position
int diffValueFound[8];
int diffValuesFound = 0;
for (int i = 0; i < 8; i++) {
if ((varDigitShown & 1) != (varDigitToShow & 1)) {
if (varDigitToShow & 1) {
diffValueFound[diffValuesFound] = bitPositionValue; // Store bit position decimal value in next available array position
} else {
diffValueFound[diffValuesFound] = (bitPositionValue * -1); // Store bit position decimal value in next available array position
}
diffValuesFound++;
}
varDigitShown >>= 1;
varDigitToShow >>= 1;
bitPositionValue = bitPositionValue * 2; // Calculate decimal value of next bit position
}
// Turn a random bit off
digitShown[p] = digitShown[p] + diffValueFound[random(diffValuesFound)];
byte Segments[] = { digitShown[p] };
DigitDisplay[randomDisplay].setSegments(Segments, 1, randomDigit);
if (digitShown[p] == digitToShow[p]) {
digitsLeft--;
turnOnOffLabels();
}
delay(delayMillis);
}
}
}
void printFromCenter(int delayMillis) {
// Compute starting position for left and right "print head"
int rightDigit = (numDigits / 2);
for (int leftDigit = (numDigits / 2) - 1; leftDigit >= 0; leftDigit--) {
// Compute 4-digit display panel number for left digit
int leftDisplay = leftDigit / 4;
// Compute digit number within 4-digit display panel for left digit
int leftDigitPanelPos = leftDigit - (leftDisplay * 4);
// Compute 4-digit display panel number for right digit
int rightDisplay = rightDigit / 4;
// Compute digit number within 4-digit display panel for right digit
int rightDigitPanelPos = rightDigit - (rightDisplay * 4);
// Show right-most vertical segments in left digit
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_COLON);
delay(delayMillis);
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_B);
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_C);
delay(delayMillis);
// Show left-most vertical segments in right digit
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_F);
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_E);
delay(delayMillis);
// Show center vertical segments in left digit
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_A);
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_G);
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_D);
delay(delayMillis);
// Show center vertical segments in right digit
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_A);
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_G);
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_D);
delay(delayMillis);
// Show left-most vertical segments in left digit
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_F);
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_E);
delay(delayMillis);
// Show right-most vertical segments in right digit
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_B);
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_C);
delay(delayMillis);
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_COLON);
delay(delayMillis);
turnOnOffLabels();
rightDigit++;
}
}
void printFromExterior(int delayMillis) {
// Compute starting position for left and right "print head"
int rightDigit = numDigits - 1;
for (int leftDigit = 0 ; leftDigit <= (numDigits / 2) - 1; leftDigit++) {
// Compute 4-digit display panel number for left digit
int leftDisplay = leftDigit / 4;
// Compute digit number within 4-digit display panel for left digit
int leftDigitPanelPos = leftDigit - (leftDisplay * 4);
// Compute 4-digit display panel number for right digit
int rightDisplay = rightDigit / 4;
// Compute digit number within 4-digit display panel for right digit
int rightDigitPanelPos = rightDigit - (rightDisplay * 4);
// Show left-most vertical segments in left digit
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_F);
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_E);
delay(delayMillis);
// Show right-most vertical segments in right digit
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_COLON);
delay(delayMillis);
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_B);
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_C);
delay(delayMillis);
// Show center vertical segments in left digit
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_A);
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_G);
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_D);
delay(delayMillis);
// Show center veritcal segments in right digit
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_A);
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_G);
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_D);
delay(delayMillis);
// Show right-most vertical segments in left digit
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_B);
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_C);
delay(delayMillis);
printOneSegment(leftDigit, leftDisplay, leftDigitPanelPos, SEG_COLON);
delay(delayMillis);
// Show left-most vertical segments in right digit
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_F);
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_E);
printOneSegment(rightDigit, rightDisplay, rightDigitPanelPos, SEG_COLON);
delay(delayMillis);
turnOnOffLabels();
rightDigit--;
}
}
void printFromLeft(int delayMillis, boolean suppressLabels) {
int p = 0;
for (int i = 0; i < numDigitDisplays; i++) {
for (int j = 0; j < 4; j++) {
printOneSegment(p, i, j, SEG_F);
printOneSegment(p, i, j, SEG_E);
delay(delayMillis);
printOneSegment(p, i, j, SEG_A);
printOneSegment(p, i, j, SEG_G);
printOneSegment(p, i, j, SEG_D);
delay(delayMillis);
printOneSegment(p, i, j, SEG_B);
printOneSegment(p, i, j, SEG_C);
delay(delayMillis);
printOneSegment(p, i, j, SEG_COLON);
delay(delayMillis);
p++;
}
if (!suppressLabels) {
turnOnOffLabels();
}
}
}
void printOneSegment(int p, int i, int j, byte segmentToShow) {
// If the segment is present in the digit that should be shown...
if ((digitToShow[p] & segmentToShow) == segmentToShow) {
// If the segment is not currently being shown...
if ((digitShown[p] & segmentToShow) == 0) {
// ...then we should add it / show it
digitShown[p] = digitShown[p] | segmentToShow;
}
// ...else the segment is not present in the digit that should be shown...
} else {
// If the digit currently shown has the segment...
if ((digitShown[p] & segmentToShow) == segmentToShow) {
// ...then we should remove it / turn it off
digitShown[p] = digitShown[p] ^ segmentToShow;
}
}
byte Segments[] = { digitShown[p] };
DigitDisplay[i].setSegments(Segments, 1, j);
}
void displayTimesByCountingAcrossAllDisplays(int delayMillis) {
// Load all times into a String object
String timeString = "";
for (int i = 0; i < numDigitDisplays; i++) {
varTime = Timezones[i].toLocal(now());
if (hour(varTime) < 10) {
timeString += "0" + String(hour(varTime));
} else {
timeString += String(hour(varTime));
}
if (minute(varTime) < 10) {
timeString += "0" + String(minute(varTime));
} else {
timeString += String(minute(varTime));
}
}
// Cycle through numbers 0 to 9
for (int i = 0; i < 10; i++) {
// Cycle through each digit from left to right
for (int j = 0; j < numDigits; j++) {
// If the number we want to show is less than or equal to the number that needs to be shown then show it, otherwise it is already shown
if (int(timeString.charAt(j)) - 48 >= i) {
int displayNum = j / 4;
int positionNum = j - (displayNum * 4);
DigitDisplay[displayNum].showNumberDec(i, true, 1, positionNum);
}
delay(delayMillis);
}
}
// Turn on all of the time zone labels
turnAllLabelsOn();
loadTimes();
updateAllDisplays();
}
void displayTimesByCountingUp() {
for (int i = 0; i < numDigitDisplays; i++) {
varTime = Timezones[i].toLocal(now());
int intHour = hour(varTime);
for (int j = 0; j <= intHour; j++) {
DigitDisplay[i].showNumberDec(j, true, 2, 0);
delay(15);
}
delay(250);
int intMinute = minute(varTime);
for (int j = 0; j <= intMinute; j++) {
DigitDisplay[i].showNumberDecEx(j, 0b11100000, true, 2, 2);
delay(15);
}
digitalWrite(timeZoneLabels[i], HIGH);
delay(250);
}
loadTimes();
updateAllDisplays();
}
void displayTimesByCountingUpDigitByDigit() {
for (int i = 0; i < numDigitDisplays; i++) {
varTime = Timezones[i].toLocal(now());
int intHour = 0;
if (hour(varTime) > 9) {
intHour = hour(varTime) / 10;
for (int j = 0; j <= intHour; j++) {
DigitDisplay[i].showNumberDec(j, true, 1, 0);
delay(15);
}
} else {
DigitDisplay[i].showNumberDec(0, true, 1, 0);
delay(15);
}
delay(250);
int intHour2 = hour(varTime) - (intHour * 10);
for (int j = 0; j <= intHour2; j++) {
DigitDisplay[i].showNumberDec(j, true, 1, 1);
delay(15);
}
delay(250);
int intMinute = 0;
if (minute(varTime) > 9) {
intMinute = minute(varTime) / 10;
for (int j = 0; j <= intMinute; j++) {
DigitDisplay[i].showNumberDecEx(j, 0b11100000, true, 1, 2);
delay(15);
}
} else {
DigitDisplay[i].showNumberDecEx(0, 0b11100000, true, 1, 2);
delay(15);
}
delay(250);
int intMinute2 = minute(varTime) - (intMinute * 10);
for (int j = 0; j <= intMinute2; j++) {
DigitDisplay[i].showNumberDec(j, true, 1, 3);
delay(15);
}
digitalWrite(timeZoneLabels[i], HIGH);
delay(250);
}
loadTimes();
updateAllDisplays();
}
void animationRandomPatterns() {
while(timeStatus() == timeNotSet) {
long randomDigit = random(4);
long randomDisplay = random(numDigitDisplays);
byte randomNum[] = { random(1,128) };
byte noDigit[] = { 0 };
long randomWait = random(15,50);
DigitDisplay[randomDisplay].setSegments(randomNum, 1, randomDigit);
delay(randomWait * 2);
for (int i = 6; i >= 0; i--) {
DigitDisplay[randomDisplay].setBrightness(i, true);
DigitDisplay[randomDisplay].setSegments(randomNum, 1, randomDigit);
delay(randomWait);
}
DigitDisplay[randomDisplay].setBrightness(7, true);
DigitDisplay[randomDisplay].setSegments(noDigit, 1, randomDigit);
}
delay(500);
initDisplays();
initDisplayIntensities();
}
void initDisplays() {
// Clear all 7-segment displays and set to default brightness
for (int i = 0; i < numDigitDisplays; i++) {
DigitDisplay[i].clear();
digitalWrite(timeZoneLabels[i], LOW);
}
// Reflect empty displays in array keeping track of current digits shown
for (int i = 0; i < numDigits; i++) {
digitShown[i] = 0;
}
}
void initDisplayIntensities() {
for (int i = 0; i < numDigitDisplays; i++) {
DigitDisplay[i].setBrightness(0, true);
displayIntensity[i] = 0;
}
}
void loadLocalDateAndTime() {
varTime = Timezones[localTimezone].toLocal(now());
// Load date and time into as String object
String localDateAndTime = String(year(varTime));
if (month(varTime) < 10) {
localDateAndTime += "0" + String(month(varTime));
} else {
localDateAndTime += String(month(varTime));
}
if (day(varTime) < 10) {
localDateAndTime += "0" + String(day(varTime));
} else {
localDateAndTime += String(day(varTime));
}
// Add spaces for number of 4 digit panels between 2nd panel and last panel
for (int i = 0; i < (numDigitDisplays - 3); i++) {
localDateAndTime += " ";
}
if (hour(varTime) < 10) {
localDateAndTime += "0" + String(hour(varTime));
} else {
localDateAndTime += String(hour(varTime));
}
if (minute(varTime) < 10) {
localDateAndTime += "0" + String(minute(varTime));
} else {
localDateAndTime += String(minute(varTime));
}
// Load this into the array of what needs to be shown
for (int i = 0; i < localDateAndTime.length(); i++) {
if (localDateAndTime.charAt(i) != " ") {
digitToShow[i] = digitToSegment[int(localDateAndTime.charAt(i)) - 48];
} else {
digitToShow[i] = 0;
}
}
}
void showTimesWithAnimation() {
nextAnimation++;
if (nextAnimation > 6) {
nextAnimation = 0;
}
switch (nextAnimation) {
case 0: // From center
loadTimes();
printFromCenter(15);
break;
case 1: // From left
loadTimes();
printFromLeft(15,false);
break;
case 2: // Random segment
loadTimes();
printRandomSegment(5);
break;
case 3: // By counting up two digits at a time
displayTimesByCountingUp();
break;
case 4: // By counting up one digit at a time
displayTimesByCountingUpDigitByDigit();
break;
case 5: // From exterior
loadTimes();
printFromExterior(15);
break;
case 6: // By counting up across all displays at once
displayTimesByCountingAcrossAllDisplays(30);
break;
}
loadTimes();
updateAllDisplays();
}
void removeTimesWithAnimation() {
for (int i = 0; i < numDigits; i++) {
digitToShow[i] = 0;
}
switch (nextAnimation) {
case 0: // From center
printFromExterior(15);
break;
case 1: // From left
printFromLeft(15,false);
break;
case 2: // Random segment
printRandomSegment(5);
break;
case 3: // By counting up two digits at a time
printRandomSegment(5);
break;
case 4: // By counting up one digit at a time
printRandomSegment(5);
break;
case 5: // From exterior
printFromCenter(15);
break;
case 6: // From exterior
printFromCenter(15);
break;
}
initDisplays();
}
void turnAllLabelsOff() {
for (int i = 0; i < numDigitDisplays; i++) {
digitalWrite(timeZoneLabels[i], LOW);
}
}
void turnAllLabelsOn() {
for (int i = 0; i < numDigitDisplays; i++) {
digitalWrite(timeZoneLabels[i], HIGH);
}
}
void loop() {
static int8_t val[2];
// Update time only if minute has changed
if ( prevMinute != minute() ) {
prevMinute = minute();
// If local date and time are not currently shown...
if (!showDateAndTime) {
// Update all timezones shown
loadTimes();
updateAllDisplays();
// Animate labels at top of hour and 30 minutes into the hour during business hours of weekdays
// Get local time
varTime = Timezones[localTimezone].toLocal(now());
// If now is a weekday (Monday - Friday)
if ((weekday(varTime) > 1) && (weekday(varTime) < 7)) {
// ...and now is between 8:00 and 17:59
if ((hour(varTime) > 7) && (hour(varTime) < 18)) {
// ...and we are at the top of the hour or 30 minutes into the hour...
if ((minute(varTime) == 0) || (minute(varTime) == 30)) {
switch (nextLabelAnimation) {
case 0: // Random flash
turnAllLabelsOff();
for (int j = 0; j < 150; j++) {
long randomLabel = random(numDigitDisplays);
digitalWrite(timeZoneLabels[randomLabel], HIGH);
delay(50);
digitalWrite(timeZoneLabels[randomLabel], LOW);
delay(50);
}
break;
case 1: // Flash several times fast then pause before repeating
for (int k = 0; k < 15; k++) {
for (int j = 0; j < 6; j++) {
turnAllLabelsOff();
delay(50);
turnAllLabelsOn();
delay(50);
}
turnAllLabelsOff();
delay(400);
}
break;
case 2: // "Kit" car effect
turnAllLabelsOff();
for (int j = 0; j < (15000 / (numDigitDisplays * 100)); j++) {
for (int i = 0; i < numDigitDisplays; i++) {
digitalWrite(timeZoneLabels[i], HIGH);
delay(50);
digitalWrite(timeZoneLabels[i], LOW);
}
for (int i = numDigitDisplays - 1; i >= 0; i--) {
digitalWrite(timeZoneLabels[i], HIGH);
delay(50);
digitalWrite(timeZoneLabels[i], LOW);
}
}
break;
case 3: // All flashing on & off
for (int j = 0; j < (15000 / 200); j++) {
turnAllLabelsOff();
delay(100);
turnAllLabelsOn();
delay(100);
}
break;
case 4: // All flashing progressively faster and faster
int delayMillis = 250;
int numLoops = 1;
do {
for (int j = 0; j < numLoops; j++) {
turnAllLabelsOff();
delay(delayMillis);
turnAllLabelsOn();
delay(delayMillis);
}
delayMillis = delayMillis - 30;
numLoops = numLoops * 2;
} while (delayMillis > 0);
break;
}
turnAllLabelsOn();
nextLabelAnimation++;
if (nextLabelAnimation > 4) {
nextLabelAnimation = 0;
}
}
}
}
} else { // Local date and time are shown...
// ...so update it
updateAllDisplays();
}
}
// Remove local date and time if it has been shown for 10 seconds already
if ((showDateAndTime) && (millis() > (startTime + 10000))) {
initDisplays();
delay(250);
showTimesWithAnimation();
showDateAndTime = false;
}
// Read rotary encoder and process if it has been moved
val[0] = read_rotary(0);
if (val[0] != 0) {
if (val[0] < 0) { // Lower intensity of displays if turned counter-clockwise
for (int i = 0; i < numDigitDisplays; i++) {
displayIntensity[i] = displayIntensity[i] - 1;
if ( displayIntensity[i] < 0 ) {displayIntensity[i] = 0;}
DigitDisplay[i].setBrightness(displayIntensity[i], true);
}
} else { // Increase intensity of displays if turned clockwise
for (int i = 0; i < numDigitDisplays; i++) {
displayIntensity[i] = displayIntensity[i] + 1;
if ( displayIntensity[i] > 7 ) {displayIntensity[i] = 7;}
DigitDisplay[i].setBrightness(displayIntensity[i], true);
}
}
updateAllDisplays();
}
// Rotary push button
currentMenuButton = debounce(lastMenuButton, menuButton);
if (lastMenuButton == HIGH && currentMenuButton == LOW) { // If pushbutton has been pushed...
if (!showDateAndTime) { // Show local date and time if not currently being shown
// Load local date and time and then show it
initDisplays();
delay(250);
loadLocalDateAndTime();
updateAllDisplays();
digitalWrite(timeZoneLabels[localTimezone], HIGH);
startTime = millis();
showDateAndTime = true;
} else { // Otherwise remove local date and time
initDisplays();
delay(250);
showTimesWithAnimation();
showDateAndTime = false;
}
}
lastMenuButton = currentMenuButton;
}
unsigned long getDCFTime()
{
time_t DCFtime = DCF.getUTCTime(); // Convert from UTC
if (DCFtime!=0) {
return DCFtime;
}
return 0;
}
// Rotary encoder processor (bullet proof!!!)
// A valid CW or CCW move returns 1 or -1, invalid returns 0
int8_t read_rotary(int i) {
static uint8_t prevNextCode[1] = {0};
static uint16_t store[1] = {0};
static int8_t rot_enc_table[] = {0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0};
prevNextCode[i] <<= 2;
if (digitalRead(DATA[i])) prevNextCode[i] |= 0x02;
if (digitalRead(CLK[i])) prevNextCode[i] |= 0x01;
prevNextCode[i] &= 0x0f;
// If valid then store as 16 bit data.
if (rot_enc_table[prevNextCode[i]] ) {
store[i] <<= 4;
store[i] |= prevNextCode[i];
if ((store[i]&0xff)==0x2b) return -1;
if ((store[i]&0xff)==0x17) return 1;
}
return 0;
}
// Button debouncer
boolean debounce(boolean last, int pin) {
boolean current = digitalRead(pin);
if (last != current) {
delay(5);
current = digitalRead(pin);
}
return current;
}
Comments
Please log in or sign up to comment.