Components and supplies
Arduino Mega 2560
Tools and machines
Soldering iron (generic)
Apps and platforms
Arduino IDE
Project description
Code
nixie_clock_main_sketch_0_9_ino.c
c_cpp
The sketch with the code of the project. I'm an amateur programmer as well so some things might appear a little spaghetti-like. I tried to comment everything.
1/********************************************************************************************************* 2 ********************************************************************************************************* 3 * Nixie Clock Main Sketch 4 * Version 0.9 5 * Tested with: Arduino IDE 1.8.13 - Arduino AVR Boards 1.8.3 - MD_DS3231 1.3.1 - 6 * Adafruit_NeoPixel 1.7.0 - MD_KeySwitch 1.4.2 - Arduino Mega 2560 R3 7 * 30-04-2021 8 * Leon 9 ********************************************************************************************************/ 10// Libraries needed: 11#include <MD_DS3231.h> // Pre-existing object named RTC (SCL to pin 21, SDA to pin 20) 12#include <Adafruit_NeoPixel.h> 13#include <MD_KeySwitch.h> 14 15// Turn debugging on and off: 16#define DEBUG 0 17#if DEBUG 18#define PRINTS(s) { Serial.print (F(s));} // Print a string 19#define PRINT(s, v) { Serial.print (F(s)); Serial.print (v);} // Print string then value (dec) 20#include <MemoryFree.h> // Library for printing free memory on runtime 21#else 22#define PRINTS(s) // Print a string 23#define PRINT(s, v) // Print a string followed by a value (decimal) 24#endif 25 26// General universal variables: 27bool secondPassFlag = false; // flag for checking if a second has passed 28byte currentSeconds = 0; // variable to hold the value of the current seconds 29byte currentHours = 0; // variable to hold the value of the current hour 30byte previousHours = 0; // variable to hold the value of the previous hour 31bool acpMinRoutineFlag = false; // flag for checking if the acpMinRoutine function is running 32#define ACPNIGHTHOUR 2 // hour that the acp night routine runs (different from night pause) 33#define NIGHTPAUSESTART 3 // start time of the night pause (must be after midnight) 34#define NIGHTPAUSEEND 7 // end time of the night pause (must be after midnight and start time) 35bool setTimeModeFlag = false; // flag for checking if setTimeMode is running 36bool testModeFlag = false; // flag for checking if test mode is running 37bool testPhotoresistorFlag = false; // flag for checking if photoresistor part of test mode is running 38bool acpNightRoutineFlag = false; // flag for checking if the acpNightRoutine function is running 39bool acpNightRoutineOn = false; // flag that's true when the routine is actually displayed 40bool nightLightTrigger = false; // flag for checking if the light in the room is low enough 41bool nightEndTrigger = false; // flag for checking if a night mode end event happened 42bool nightPauseRoutineFlag = false; // flag for checking if the nigthPauseRoutine function runs 43bool nightPauseRoutineOn = false; // flag that's true when the tubes are actually paused 44bool timeSetModeReset = true; // used to reset variables at the first run of timeSetMode function 45byte tempTimeHolder = 0; // hold the time that is displayed currently on setTimeMode 46bool setTimeStageArray [3] = {false}; // array that holds witch steps of the time setting are completed 47 48// Variables for holding the individual digits of time: 49byte hoursFirstDigit = 0; 50byte hoursSecondDigit = 0; 51byte minutesFirstDigit = 0; 52byte minutesSecondDigit = 0; 53byte secondsFirstDigit = 0; 54byte secondsSecondDigit = 0; 55 56// Nixie1: 57// Use pins 36, 32, 30 & 34 of Arduino to connect to pins A, B, C & D of the Nixie1 driver chip 58#define N1A 36 59#define N1B 32 60#define N1C 30 61#define N1D 34 62 63// Nixie2: 64// Use pins 35, 31, 29 & 33 of Arduino to connect to pins A, B, C & D of the Nixie2 driver chip 65#define N2A 35 66#define N2B 31 67#define N2C 29 68#define N2D 33 69 70// Nixie3: 71// Use pins 44, 40, 38 & 42 of Arduino to connect to pins A, B, C & D of the Nixie3 driver chip 72#define N3A 44 73#define N3B 40 74#define N3C 38 75#define N3D 42 76 77// Nixie4: 78// Use pins 43, 39, 37 & 41 of Arduino to connect to pins A, B, C & D of the Nixie4 driver chip 79#define N4A 43 80#define N4B 39 81#define N4C 37 82#define N4D 41 83 84// Nixie5: 85// Use pins 52, 48, 46 & 50 of Arduino to connect to pins A, B, C & D of the Nixie5 driver chip 86#define N5A 52 87#define N5B 48 88#define N5C 46 89#define N5D 50 90 91// Nixie6: 92// Use pins 51, 47, 45 & 49 of Arduino to connect to pins A, B, C & D of the Nixie4 driver chip 93#define N6A 51 94#define N6B 47 95#define N6C 45 96#define N6D 49 97 98// Dots: 99// Use transistor 1 to control dots 1 & 2 and transistor 2 to control dots 2 & 3 100#define TRAN1 28 101#define TRAN2 53 102 103// WS2811 THT RGB LEDs: 104#define WSPIN 23 // Arduino pin for controlling the WS2811 LEDs 105#define WSCOUNT 8 // number of WS2911 LEDs connected together 106Adafruit_NeoPixel wsStrip (WSCOUNT, WSPIN, NEO_RGB + NEO_KHZ800); // create neopixel object 107byte wsMode = 1; // variable to hold the WS2911 LEDs mode - default is 1 108byte wsModeNum = 8; // variable to hold the number (sum) of WS2911 LEDs modes 109bool wsTransition = false; // true if mode transition is on, false if not 110#define WSTRANSTIME 1400UL // transition duration in milliseconds 111bool wsOff = false; // true if the WS2911 LEDs are off, false if they are on 112bool wsWasOn = false; // true if the LEDs were on, false if not 113bool rainbowEffectTrigger = false; // flag for triggering the rainbow effect 114bool colorWipeEffectTrigger = false; // flag for triggering the color wipe effect 115bool colorWheelEffectTrigger = false; // flag for triggering the colorWheel effect 116int redLedArray [8] = {0}; // array to hold the values of the red WS2911 LEDs 117int greenLedArray [8] = {0}; // array to hold the values of the green WS2911 LEDs 118int blueLedArray [8] = {0}; // array to hold the values of the blue WS2911 LEDs 119unsigned long tempColorArray [8] = {0}; // array to hold the values of rainbow or wheel colors 120 121// LDR Photoresistor: 122#define LDRPIN A0 // analog pin that the LDR photoresistor is connected on the Arduino 123unsigned int wsBrightness = 50; // startup brightness of the WS2811 LEDs from 0 to 255 124#define BRIGHTNESSMAX 80 // maximum brightness the LEDs will go depending on room light 125#define BRIGHTNESSMIN 5 // minimum brightness the LEDs will go depending on room light 126 127// Buttons: 128MD_KeySwitch button1 (24, HIGH); // set button 1 to pin 24 129MD_KeySwitch button2 (25, HIGH); // set button 2 to pin 25 130MD_KeySwitch button3 (26, HIGH); // set button 3 to pin 26 131MD_KeySwitch button4 (27, HIGH); // set button 4 to pin 27 132bool repeatOn = false; // true if repeat button pressed 133 134// High voltage power supply: 135#define HVPSUPIN 22 136 137// Functions with default values declaration: 138void wsModeHandler (bool shuffleTrigger = false); 139void colorWipeEffect (bool resetTrigger = false); 140void testMode (bool resetTrigger = false); 141bool psuState (byte order = 2); 142 143/*----------------------------------------------- SETUP: -----------------------------------------------*/ 144void setup () 145{ 146 // Debug setup: 147 #if DEBUG 148 Serial.begin (9600); 149 PRINTS ("\ 150[Nixie Clock]"); 151 #endif 152 153 // Setup the pins that communicate with the nixie chips (K144ID1) us outputs 154 // and write on all the tubes the number 0: 155 // Nixie1: 156 pinMode (N1A, OUTPUT); 157 pinMode (N1B, OUTPUT); 158 pinMode (N1C, OUTPUT); 159 pinMode (N1D, OUTPUT); 160 writeOnNixieX (1, 0); 161 162 // Nixie2: 163 pinMode (N2A, OUTPUT); 164 pinMode (N2B, OUTPUT); 165 pinMode (N2C, OUTPUT); 166 pinMode (N2D, OUTPUT); 167 writeOnNixieX (2, 0); 168 169 // Nixie3: 170 pinMode (N3A, OUTPUT); 171 pinMode (N3B, OUTPUT); 172 pinMode (N3C, OUTPUT); 173 pinMode (N3D, OUTPUT); 174 writeOnNixieX (3, 0); 175 176 // Nixie4: 177 pinMode (N4A, OUTPUT); 178 pinMode (N4B, OUTPUT); 179 pinMode (N4C, OUTPUT); 180 pinMode (N4D, OUTPUT); 181 writeOnNixieX (4, 0); 182 183 // Nixie5: 184 pinMode (N5A, OUTPUT); 185 pinMode (N5B, OUTPUT); 186 pinMode (N5C, OUTPUT); 187 pinMode (N5D, OUTPUT); 188 writeOnNixieX (5, 0); 189 190 // Nixie6: 191 pinMode (N6A, OUTPUT); 192 pinMode (N6B, OUTPUT); 193 pinMode (N6C, OUTPUT); 194 pinMode (N6D, OUTPUT); 195 writeOnNixieX (6, 0); 196 197 // Dots: 198 pinMode (TRAN1, OUTPUT); 199 pinMode (TRAN2, OUTPUT); 200 201 // WS2811 LEDs setup: 202 wsStrip.begin (); // initialize NeoPixel strip object 203 wsStrip.show (); // turn OFF all pixels ASAP 204 wsStrip.setBrightness (wsBrightness); // Set the brightness 205 wsModeHandler (true); 206 207 // LDR Photoresistor: 208 pinMode (LDRPIN, INPUT); 209 210 // Buttons setup: 211 // Button 1: 212 button1.begin(); 213 button1.enableDoublePress (false); 214 button1.enableLongPress (true); 215 button1.enableRepeat (false); 216 button1.enableRepeatResult (false); 217 button1.setDebounceTime (160); 218 button1.setLongPressTime (2000); // set long press time to 2 seconds 219 // Button 2: 220 button2.begin(); 221 button2.enableDoublePress (false); 222 button2.enableLongPress (false); 223 button2.enableRepeat (true); 224 button2.enableRepeatResult (true); 225 button2.setRepeatTime (120); 226 button2.setDebounceTime (140); 227 // Button 3: 228 button3.begin(); 229 button3.enableDoublePress (false); 230 button3.enableLongPress (false); 231 button3.enableRepeat (true); 232 button3.enableRepeatResult (true); 233 button3.setRepeatTime (120); 234 button3.setDebounceTime (140); 235 // Button 4: 236 button4.begin(); 237 button4.enableDoublePress (false); 238 button4.enableLongPress (true); 239 button4.enableRepeat (false); 240 button4.enableRepeatResult (false); 241 button4.setDebounceTime (160); 242 button4.setLongPressTime (2000); // set long press time to 2 seconds 243 244 // High Voltage power supply: 245 pinMode (HVPSUPIN, OUTPUT); 246 psuState (HIGH); // turn on HV psu 247 248 // Command so that the "L" onboard LED of the Arduino MEGA (connected to pin 13) stays off: 249 pinMode (13, OUTPUT); 250} 251 252/*---------------------------------------------- LOOP: -------------------------------------------------*/ 253void loop () 254{ 255 // Run the mode that is currently on or if no specific mode is on, run the default - displayTime: 256 if (setTimeModeFlag == true) 257 { 258 setTimeMode (); 259 } 260 else if (testModeFlag == true) 261 { 262 testMode (); 263 } 264 else if (wsTransition == true) 265 { 266 wsTransitionDisplay (); 267 } 268 else if (acpMinRoutineFlag == true) 269 { 270 acpMinRoutine (); 271 } 272 else if (acpNightRoutineFlag == true) 273 { 274 acpNightRoutine (); 275 } 276 else if (nightPauseRoutineFlag == true) 277 { 278 nightPauseRoutine (); 279 } 280 else 281 { 282 displayTime (); 283 } 284 285 // Run the rainbow effect if it is on: 286 if (rainbowEffectTrigger == true) 287 { 288 rainbowEffect (); 289 } 290 291 // Run the color wipe effect if it is on: 292 if (colorWipeEffectTrigger == true) 293 { 294 colorWipeEffect (); 295 } 296 297 // Run the color wipe effect if it is on: 298 if (colorWheelEffectTrigger == true) 299 { 300 colorWheelEffect (); 301 } 302 303 // Run the function that handles button presses: 304 buttonsHandler (); 305 306 // Run the function that handles the photoresistor: 307 photoresistorHandler (); 308} 309/*------------------------------------------- END OF LOOP ----------------------------------------------*/ 310/********************************************************************************************************* 311 * Functions for managing the RTC time aspects of the clock: 312 ********************************************************************************************************/ 313 314/*------------------------------------------------------------------------------------------------------*/ 315/* Function for doing the necessary steps for displaying the time on the nixie tubes. Also, it manages 316 * various timing events of the clock (dots blinking every second, night modes etc) using the time read 317 * from the DS3231 RTC clock: 318 */ 319void displayTime () 320{ 321 RTC.readTime (); // get the time from the module 322 323 // Hours: 324 currentHours = RTC.h; 325 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 326 if (currentHours == ACPNIGHTHOUR) // check if it is acp night hour and turn it's flag on 327 { 328 acpNightRoutineFlag = true; 329 } 330 else // turn the acp night flag off if not it's hour 331 { 332 acpNightRoutineFlag = false; 333 } 334 if (currentHours >= NIGHTPAUSESTART && currentHours < NIGHTPAUSEEND) // check if it's night pause hours and 335 { // turn it's flag on 336 nightPauseRoutineFlag = true; 337 } 338 else // turn the night pause flag off if not it's hours 339 { 340 nightPauseRoutineFlag = false; 341 } 342 if (acpMinRoutineFlag == false) 343 { 344 writeOnNixieX (1, hoursFirstDigit); 345 writeOnNixieX (2, hoursSecondDigit); 346 previousHours = currentHours; 347 } 348 349 // Minutes: 350 separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit); 351 if (acpMinRoutineFlag == false) 352 { 353 writeOnNixieX (3, minutesFirstDigit); 354 writeOnNixieX (4, minutesSecondDigit); 355 } 356 357 // Seconds: 358 currentSeconds = RTC.s; 359 // Blinking dots every second: 360 if (currentSeconds % 2 == 0) // if the seconds are even turn off dots 361 { 362 dotsOn (false); 363 } 364 else // if the seconds are even turn on dots 365 { 366 dotsOn (true); 367 } 368 separateDoubleDigits (currentSeconds, secondsFirstDigit, secondsSecondDigit); 369 // Acp routine trigger at the 00 seconds and change random LED color if on mode 1: 370 if (secondsFirstDigit == 0 && secondsSecondDigit == 0) 371 { 372 acpMinRoutineFlag = true; 373 if (wsMode == 1 && wsOff == false) 374 { 375 colorWipeEffect (true); // reset color wipe effect to make sure it starts from first LED 376 wsModeHandler (true); // trigger color change if on random mode 377 } 378 } 379 else 380 { 381 writeOnNixieX (5, secondsFirstDigit); 382 writeOnNixieX (6, secondsSecondDigit); 383 } 384} 385 386/*------------------------------------------------------------------------------------------------------*/ 387/* Function for writing the digits on a specific (x) nixie tube - it gets me nixie number and the value 388 * (one digit) that is going to be written: 389 */ 390void writeOnNixieX (byte nixieNum, byte value) 391{ 392 switch (nixieNum) 393 { 394 case 1: 395 sentToNixie (N1A, N1B, N1C, N1D, value); 396 break; 397 case 2: 398 sentToNixie (N2A, N2B, N2C, N2D, value); 399 break; 400 case 3: 401 sentToNixie (N3A, N3B, N3C, N3D, value); 402 break; 403 case 4: 404 sentToNixie (N4A, N4B, N4C, N4D, value); 405 break; 406 case 5: 407 sentToNixie (N5A, N5B, N5C, N5D, value); 408 break; 409 case 6: 410 sentToNixie (N6A, N6B, N6C, N6D, value); 411 break; 412 default: 413 return; 414 } 415} 416 417/*------------------------------------------------------------------------------------------------------*/ 418/* Function for running the anti-cathode-poisoning routine for keeping the nixie tubes in good condition 419 * - it cycles through the digits, about 100ms each digit - 1 second total: 420 */ 421void acpMinRoutine () 422{ 423 // Local variables declaration: 424 static unsigned long lastTime = 0; // millis() memory 425 static byte counter = 0; 426 static byte nixie1_Order [10]; // Arrays for holding the order of the digits based on what 427 static byte nixie2_Order [10]; // is currently on display and the physical order of the digits 428 static byte nixie3_Order [10]; // in the tubes 429 static byte nixie4_Order [10]; 430 byte nixie5_Order [10] = { 5, 6, 1, 0, 7, 9, 3, 8, 4, 2 }; // Since the starting seconds are always 431 byte nixie6_Order [10] = { 9, 3, 8, 4, 2, 5, 6, 1, 0, 7 }; // the same (00) there arrays are fixed 432 static bool firstRunFlag = true; 433 434 // Main code: 435 if (firstRunFlag == true) // check if it is the first run of each routine so to populate the arrays 436 { 437 getOrderIn14 (nixie1_Order, hoursFirstDigit); 438 getOrderIn14 (nixie2_Order, hoursSecondDigit); 439 getOrderIn14 (nixie3_Order, minutesFirstDigit); 440 getOrderIn14 (nixie4_Order, minutesSecondDigit); 441 firstRunFlag = false; 442 } 443 switch (counter) 444 { 445 case 0: 446 if (millis () - lastTime < 120UL) // more than 100ms to make sure that a second passes in total 447 { 448 writeOnNixieX (1, nixie1_Order [0]); 449 writeOnNixieX (2, nixie2_Order [0]); 450 writeOnNixieX (3, nixie3_Order [0]); 451 writeOnNixieX (4, nixie4_Order [0]); 452 writeOnNixieX (5, nixie5_Order [0]); 453 writeOnNixieX (6, nixie6_Order [0]); 454 } 455 else 456 { 457 counter++; 458 lastTime = millis (); 459 } 460 break; 461 case 1: 462 if (millis () - lastTime < 120UL) 463 { 464 writeOnNixieX (1, nixie1_Order [1]); 465 writeOnNixieX (2, nixie2_Order [1]); 466 writeOnNixieX (3, nixie3_Order [1]); 467 writeOnNixieX (4, nixie4_Order [1]); 468 writeOnNixieX (5, nixie5_Order [1]); 469 writeOnNixieX (6, nixie6_Order [1]); 470 } 471 else 472 { 473 counter++; 474 lastTime = millis (); 475 } 476 break; 477 case 2: 478 if (millis () - lastTime < 120UL) 479 { 480 writeOnNixieX (1, nixie1_Order [2]); 481 writeOnNixieX (2, nixie2_Order [2]); 482 writeOnNixieX (3, nixie3_Order [2]); 483 writeOnNixieX (4, nixie4_Order [2]); 484 writeOnNixieX (5, nixie5_Order [2]); 485 writeOnNixieX (6, nixie6_Order [2]); 486 } 487 else 488 { 489 counter++; 490 lastTime = millis (); 491 } 492 break; 493 case 3: 494 if (millis () - lastTime < 120UL) 495 { 496 writeOnNixieX (1, nixie1_Order [3]); 497 writeOnNixieX (2, nixie2_Order [3]); 498 writeOnNixieX (3, nixie3_Order [3]); 499 writeOnNixieX (4, nixie4_Order [3]); 500 writeOnNixieX (5, nixie5_Order [3]); 501 writeOnNixieX (6, nixie6_Order [3]); 502 } 503 else 504 { 505 counter++; 506 lastTime = millis (); 507 } 508 break; 509 case 4: 510 if (millis () - lastTime < 120UL) 511 { 512 writeOnNixieX (1, nixie1_Order [4]); 513 writeOnNixieX (2, nixie2_Order [4]); 514 writeOnNixieX (3, nixie3_Order [4]); 515 writeOnNixieX (4, nixie4_Order [4]); 516 writeOnNixieX (5, nixie5_Order [4]); 517 writeOnNixieX (6, nixie6_Order [4]); 518 } 519 else 520 { 521 counter++; 522 lastTime = millis (); 523 } 524 break; 525 case 5: 526 if (millis () - lastTime < 120UL) 527 { 528 writeOnNixieX (1, nixie1_Order [5]); 529 writeOnNixieX (2, nixie2_Order [5]); 530 writeOnNixieX (3, nixie3_Order [5]); 531 writeOnNixieX (4, nixie4_Order [5]); 532 writeOnNixieX (5, nixie5_Order [5]); 533 writeOnNixieX (6, nixie6_Order [5]); 534 } 535 else 536 { 537 counter++; 538 lastTime = millis (); 539 } 540 break; 541 case 6: 542 if (millis () - lastTime < 120UL) 543 { 544 writeOnNixieX (1, nixie1_Order [6]); 545 writeOnNixieX (2, nixie2_Order [6]); 546 writeOnNixieX (3, nixie3_Order [6]); 547 writeOnNixieX (4, nixie4_Order [6]); 548 writeOnNixieX (5, nixie5_Order [6]); 549 writeOnNixieX (6, nixie6_Order [6]); 550 } 551 else 552 { 553 counter++; 554 lastTime = millis (); 555 } 556 break; 557 case 7: 558 if (millis () - lastTime < 120UL) 559 { 560 writeOnNixieX (1, nixie1_Order [7]); 561 writeOnNixieX (2, nixie2_Order [7]); 562 writeOnNixieX (3, nixie3_Order [7]); 563 writeOnNixieX (4, nixie4_Order [7]); 564 writeOnNixieX (5, nixie5_Order [7]); 565 writeOnNixieX (6, nixie6_Order [7]); 566 } 567 else 568 { 569 counter++; 570 lastTime = millis (); 571 } 572 break; 573 case 8: 574 if (millis () - lastTime < 120UL) 575 { 576 writeOnNixieX (1, nixie1_Order [8]); 577 writeOnNixieX (2, nixie2_Order [8]); 578 writeOnNixieX (3, nixie3_Order [8]); 579 writeOnNixieX (4, nixie4_Order [8]); 580 writeOnNixieX (5, nixie5_Order [8]); 581 writeOnNixieX (6, nixie6_Order [8]); 582 } 583 else 584 { 585 counter++; 586 lastTime = millis (); 587 } 588 break; 589 case 9: 590 if (millis () - lastTime < 120UL) 591 { 592 writeOnNixieX (1, nixie1_Order [9]); 593 writeOnNixieX (2, nixie2_Order [9]); 594 writeOnNixieX (3, nixie3_Order [9]); 595 writeOnNixieX (4, nixie4_Order [9]); 596 writeOnNixieX (5, nixie5_Order [9]); 597 writeOnNixieX (6, nixie6_Order [9]); 598 } 599 else 600 { 601 counter = 0; 602 lastTime = millis (); 603 firstRunFlag = true; 604 acpMinRoutineFlag = false; 605 } 606 break; 607 default: 608 break; 609 } 610} 611 612/*------------------------------------------------------------------------------------------------------*/ 613/* Function for running the anti-cathode-poisoning night routine for keeping the nixie tubes in good 614 * condition - it runs for and hour and cycles between all the numbers for 6 minutes each. It starts 615 * from 9 in order to give the bigger numbers better chance of running because they are usually not 616 * used. Also, the LEDs are turned off for long life and energy savings: 617 */ 618void acpNightRoutine () 619{ 620 // Local variables declaration: 621 static unsigned long lastTime = 0; // millis() memory 622 static bool firstRunFlag = true; 623 static byte currentDay = 0; 624 static bool dailyRunArray [10] = {false}; 625 626 // Main code: 627 if (firstRunFlag == true) // check if it is the first run for the day and reset the run array 628 { 629 firstRunFlag = false; 630 currentDay = RTC.dd; 631 for (int i = 0; i < 10; i++) 632 { 633 dailyRunArray [i] = false; 634 } 635 } 636 637 if (currentDay != RTC.dd) // if the day has changed, reset the first run and night end trigger flags 638 { 639 firstRunFlag = true; 640 nightEndTrigger = false; 641 } 642 643 if (nightLightTrigger == true && nightEndTrigger == false) 644 { 645 acpNightRoutineOn = true; 646 dotsOn (false); 647 if (wsOff == false) // check if the LEDs were on and turn them off 648 { 649 wsWasOn = true; 650 wsOff = true; 651 rainbowEffectTrigger = false; 652 colorWipeEffectTrigger = false; 653 colorWheelEffectTrigger = false; 654 wsStrip.clear (); 655 wsStrip.show (); 656 } 657 if (dailyRunArray [9] == false) 658 { 659 if (millis () - lastTime < 340000UL) // run for about six minutes 660 { 661 writeOnNixieX (1, 9); 662 writeOnNixieX (2, 9); 663 writeOnNixieX (3, 9); 664 writeOnNixieX (4, 9); 665 writeOnNixieX (5, 9); 666 writeOnNixieX (6, 9); 667 } 668 else 669 { 670 lastTime = millis (); 671 dailyRunArray [9] = true; 672 } 673 } 674 else if (dailyRunArray [8] == false) 675 { 676 if (millis () - lastTime < 340000UL) // run for about six minutes 677 { 678 writeOnNixieX (1, 8); 679 writeOnNixieX (2, 8); 680 writeOnNixieX (3, 8); 681 writeOnNixieX (4, 8); 682 writeOnNixieX (5, 8); 683 writeOnNixieX (6, 8); 684 } 685 else 686 { 687 lastTime = millis (); 688 dailyRunArray [8] = true; 689 } 690 } 691 else if (dailyRunArray [7] == false) 692 { 693 if (millis () - lastTime < 340000UL) // run for about six minutes 694 { 695 writeOnNixieX (1, 7); 696 writeOnNixieX (2, 7); 697 writeOnNixieX (3, 7); 698 writeOnNixieX (4, 7); 699 writeOnNixieX (5, 7); 700 writeOnNixieX (6, 7); 701 } 702 else 703 { 704 lastTime = millis (); 705 dailyRunArray [7] = true; 706 } 707 } 708 else if (dailyRunArray [6] == false) 709 { 710 if (millis () - lastTime < 340000UL) // run for about six minutes 711 { 712 writeOnNixieX (1, 6); 713 writeOnNixieX (2, 6); 714 writeOnNixieX (3, 6); 715 writeOnNixieX (4, 6); 716 writeOnNixieX (5, 6); 717 writeOnNixieX (6, 6); 718 } 719 else 720 { 721 lastTime = millis (); 722 dailyRunArray [6] = true; 723 } 724 } 725 else if (dailyRunArray [5] == false) 726 { 727 if (millis () - lastTime < 340000UL) // run for about six minutes 728 { 729 writeOnNixieX (1, 5); 730 writeOnNixieX (2, 5); 731 writeOnNixieX (3, 5); 732 writeOnNixieX (4, 5); 733 writeOnNixieX (5, 5); 734 writeOnNixieX (6, 5); 735 } 736 else 737 { 738 lastTime = millis (); 739 dailyRunArray [5] = true; 740 } 741 } 742 else if (dailyRunArray [4] == false) 743 { 744 if (millis () - lastTime < 340000UL) // run for about six minutes 745 { 746 writeOnNixieX (1, 4); 747 writeOnNixieX (2, 4); 748 writeOnNixieX (3, 4); 749 writeOnNixieX (4, 4); 750 writeOnNixieX (5, 4); 751 writeOnNixieX (6, 4); 752 } 753 else 754 { 755 lastTime = millis (); 756 dailyRunArray [4] = true; 757 } 758 } 759 else if (dailyRunArray [3] == false) 760 { 761 if (millis () - lastTime < 340000UL) // run for about six minutes 762 { 763 writeOnNixieX (1, 3); 764 writeOnNixieX (2, 3); 765 writeOnNixieX (3, 3); 766 writeOnNixieX (4, 3); 767 writeOnNixieX (5, 3); 768 writeOnNixieX (6, 3); 769 } 770 else 771 { 772 lastTime = millis (); 773 dailyRunArray [3] = true; 774 } 775 } 776 else if (dailyRunArray [2] == false) 777 { 778 if (millis () - lastTime < 340000UL) // run for about six minutes 779 { 780 writeOnNixieX (1, 2); 781 writeOnNixieX (2, 2); 782 writeOnNixieX (3, 2); 783 writeOnNixieX (4, 2); 784 writeOnNixieX (5, 2); 785 writeOnNixieX (6, 2); 786 } 787 else 788 { 789 lastTime = millis (); 790 dailyRunArray [2] = true; 791 } 792 } 793 else if (dailyRunArray [1] == false) 794 { 795 if (millis () - lastTime < 340000UL) // run for about six minutes 796 { 797 writeOnNixieX (1, 1); 798 writeOnNixieX (2, 1); 799 writeOnNixieX (3, 1); 800 writeOnNixieX (4, 1); 801 writeOnNixieX (5, 1); 802 writeOnNixieX (6, 1); 803 } 804 else 805 { 806 lastTime = millis (); 807 dailyRunArray [1] = true; 808 } 809 } 810 else if (dailyRunArray [0] == false) 811 { 812 if (millis () - lastTime < 340000UL) // run for about six minutes 813 { 814 writeOnNixieX (1, 0); 815 writeOnNixieX (2, 0); 816 writeOnNixieX (3, 0); 817 writeOnNixieX (4, 0); 818 writeOnNixieX (5, 0); 819 writeOnNixieX (6, 0); 820 } 821 else 822 { 823 lastTime = millis (); 824 dailyRunArray [0] = true; 825 } 826 } 827 else // if the daily run is completed, start again for the remaining time 828 { 829 for (int i = 0; i < 10; i++) 830 { 831 dailyRunArray [i] = false; 832 } 833 } 834 } 835 else // if the conditions are not right, display the time as usual 836 { 837 if (wsWasOn == true) // turn the LEDs back on, if they were previously on 838 { 839 wsOff = false; 840 wsModeHandler (); 841 } 842 acpNightRoutineOn = false; 843 displayTime (); 844 } 845 // Make sure that if the acp night hour ends, we go to night pause routine: 846 if (RTC.h == NIGHTPAUSESTART) 847 { 848 acpNightRoutineFlag = false; 849 nightPauseRoutineFlag = true; 850 } 851} 852 853/*------------------------------------------------------------------------------------------------------*/ 854/* Function for running the night pause routine which turns off the nixie tubes at the night when the 855 * light is low in order to make them last longer. The tubes are turned off by setting the high voltage 856 * power supply pin to low. Also, the WS2811 LEDs are turned off for power saving and long life: 857 */ 858void nightPauseRoutine () 859{ 860 if (nightLightTrigger == true && nightEndTrigger == false) 861 { 862 nightPauseRoutineOn = true; 863 if (wsOff == false) 864 { 865 wsOff = true; 866 wsWasOn = true; 867 rainbowEffectTrigger = false; 868 colorWipeEffectTrigger = false; 869 colorWheelEffectTrigger = false; 870 wsStrip.clear (); 871 wsStrip.show (); 872 } 873 dotsOn (false); 874 psuState (LOW); // turn off HV psu 875 } 876 else 877 { 878 nightPauseRoutineOn = false; 879 psuState (HIGH); // turn on HV psu 880 if (wsWasOn == true) 881 { 882 wsOff = false; 883 wsModeHandler (); 884 } 885 displayTime (); 886 } 887} 888 889/*------------------------------------------------------------------------------------------------------*/ 890/* Function for separating the double digits that hours, minutes and seconds come from the RTC module, 891 * to single digits for writing on the nixie tubes: 892 */ 893void separateDoubleDigits (byte doubleDigit, byte& firstDigit, byte& secondDigit) 894{ 895 firstDigit = doubleDigit / 10; 896 secondDigit = doubleDigit % 10; 897} 898 899/*------------------------------------------------------------------------------------------------------*/ 900/* Function for separating a triple digit to single digits for writing on the nixie tubes: 901 */ 902void separateThreeDigits (unsigned int threeDigit, byte& firstDigit, byte& secondDigit, byte& thirdDigit) 903{ 904 firstDigit = (threeDigit / 100) % 10; 905 secondDigit = (threeDigit / 10) % 10; 906 thirdDigit = threeDigit % 10; 907} 908 909/*------------------------------------------------------------------------------------------------------*/ 910/* Function for separating a quadruple digit to single digits for writing on the nixie tubes: 911 */ 912void separateFourDigits (unsigned int fourDigit, byte& firstDigit, byte& secondDigit, byte& thirdDigit, 913 byte& fourthDigit) 914{ 915 firstDigit = (fourDigit / 1000) % 10; 916 secondDigit = (fourDigit / 100) % 10; 917 thirdDigit = (fourDigit / 10) % 10; 918 fourthDigit = fourDigit % 10; 919} 920 921/*------------------------------------------------------------------------------------------------------*/ 922/* Function for finally sending the value to be displayed to the nixie chips - it gets the numbers of 923 * the four Arduino pins that communicate with the nixie chip and the value to be sent (one digit or for 924 * blanking the number 10): 925 */ 926void sentToNixie (byte a, byte b, byte c, byte d, byte value) 927{ 928 //D is most significant bit 929 //A is least significant bit 930 digitalWrite (d, (value & 0x08) >> 3); 931 digitalWrite (c, (value & 0x04) >> 2); 932 digitalWrite (b, (value & 0x02) >> 1); 933 digitalWrite (a, value & 0x01); 934} 935 936/*------------------------------------------------------------------------------------------------------*/ 937/* Function for turning the dots on (true) or off (false): 938 */ 939void dotsOn (bool onState) 940{ 941 if (onState == true) 942 { 943 digitalWrite (TRAN1, HIGH); 944 digitalWrite (TRAN2, HIGH); 945 } 946 else 947 { 948 digitalWrite (TRAN1, LOW); 949 digitalWrite (TRAN2, LOW); 950 } 951} 952 953/*------------------------------------------------------------------------------------------------------*/ 954/* Function for turning the nixie PSU on (true - 1 - HIGH) or off (false - 0 - LOW) or just getting back 955 * the state that it is currently (2, which is the default): 956 */ 957bool psuState (byte order = 2) 958{ 959 static bool psuStatus = false; 960 if (order == 0) 961 { 962 digitalWrite (HVPSUPIN, LOW); // turn off HV psu 963 psuStatus = false; 964 return psuStatus; 965 } 966 else if (order == 1) 967 { 968 digitalWrite (HVPSUPIN, HIGH); // turn on HV psu 969 psuStatus = true; 970 return psuStatus; 971 } 972 else 973 { 974 return psuStatus; 975 } 976} 977 978/*------------------------------------------------------------------------------------------------------*/ 979/* Function that populates the IN-14 nixie order arrays with the physical order based on the currently 980 * displayed digit (startValue): 981 */ 982void getOrderIn14 (byte *nixieXArrayPosition, byte startValue) 983{ 984 // Local variables declaration: 985 byte rowArray [ ] = { 1, 0, 2, 9, 3, 8, 4, 7, 5, 6 }; // physical order of the digits in the tubes 986 987 // Main code: 988 switch (startValue) 989 { 990 case 0: 991 for (int i = 0; i < 10; i++) 992 { 993 if (i < 9) 994 { 995 nixieXArrayPosition [i] = rowArray [i + 1]; 996 } 997 else if (i >= 9) 998 { 999 nixieXArrayPosition [i] = rowArray [i - 9]; 1000 } 1001 } 1002 return; 1003 case 1: 1004 for (int i = 0; i < 10; i++) 1005 { 1006 nixieXArrayPosition [i] = rowArray [i]; 1007 } 1008 return; 1009 case 2: 1010 for (int i = 0; i < 10; i++) 1011 { 1012 if (i < 8) 1013 { 1014 nixieXArrayPosition [i] = rowArray [i + 2]; 1015 } 1016 else if (i >= 8) 1017 { 1018 nixieXArrayPosition [i] = rowArray [i - 8]; 1019 } 1020 } 1021 return; 1022 case 3: 1023 for (int i = 0; i < 10; i++) 1024 { 1025 if (i < 6) 1026 { 1027 nixieXArrayPosition [i] = rowArray [i + 4]; 1028 } 1029 else if (i >= 6) 1030 { 1031 nixieXArrayPosition [i] = rowArray [i - 6]; 1032 } 1033 } 1034 return; 1035 case 4: 1036 for (int i = 0; i < 10; i++) 1037 { 1038 if (i < 4) 1039 { 1040 nixieXArrayPosition [i] = rowArray [i + 6]; 1041 } 1042 else if (i >= 4) 1043 { 1044 nixieXArrayPosition [i] = rowArray [i - 4]; 1045 } 1046 } 1047 return; 1048 case 5: 1049 for (int i = 0; i < 10; i++) 1050 { 1051 if (i < 2) 1052 { 1053 nixieXArrayPosition [i] = rowArray [i + 8]; 1054 } 1055 else if (i >= 2) 1056 { 1057 nixieXArrayPosition [i] = rowArray [i - 2]; 1058 } 1059 } 1060 return; 1061 case 6: 1062 for (int i = 0; i < 10; i++) 1063 { 1064 if (i < 1) 1065 { 1066 nixieXArrayPosition [i] = rowArray [i + 9]; 1067 } 1068 else if (i >= 1) 1069 { 1070 nixieXArrayPosition [i] = rowArray [i - 1]; 1071 } 1072 } 1073 return; 1074 case 7: 1075 for (int i = 0; i < 10; i++) 1076 { 1077 if (i < 3) 1078 { 1079 nixieXArrayPosition [i] = rowArray [i + 7]; 1080 } 1081 else if (i >= 3) 1082 { 1083 nixieXArrayPosition [i] = rowArray [i - 3]; 1084 } 1085 } 1086 return; 1087 case 8: 1088 for (int i = 0; i < 10; i++) 1089 { 1090 if (i < 5) 1091 { 1092 nixieXArrayPosition [i] = rowArray [i + 5]; 1093 } 1094 else if (i >= 5) 1095 { 1096 nixieXArrayPosition [i] = rowArray [i - 5]; 1097 } 1098 } 1099 return; 1100 case 9: 1101 for (int i = 0; i < 10; i++) 1102 { 1103 if (i < 7) 1104 { 1105 nixieXArrayPosition [i] = rowArray [i + 3]; 1106 } 1107 else if (i >= 7) 1108 { 1109 nixieXArrayPosition [i] = rowArray [i - 7]; 1110 } 1111 } 1112 return; 1113 default: 1114 return; 1115 } 1116} 1117/*------------------------------------------------------------------------------------------------------*/ 1118/********************************************************************************************************* 1119 * Functions for managing the WS2811 RGB LEDs aspects of the clock: 1120 ********************************************************************************************************/ 1121 1122/*------------------------------------------------------------------------------------------------------*/ 1123/* Function for managing the WS2811 RGB LEDs color modes - if the shuffleTrigger parameter is set to 1124 * true the random mode generates a new random color, else it displays the previous random color (used 1125 * with button4 to turn the RGBs on to the previous color for consistency): 1126 */ 1127void wsModeHandler (bool shuffleTrigger = false) 1128{ 1129 switch (wsMode) 1130 { 1131 case 1: // random color mode 1132 rainbowEffectTrigger = false; 1133 colorWheelEffectTrigger = false; 1134 if (shuffleTrigger == true) 1135 { 1136 // Feed the random seed for better randomness: 1137 randomSeed (analogRead (A1)); 1138 int redValue = random (6, 255); // starting from 6 to prevent off state 1139 int greenValue = random (6, 255); 1140 int blueValue = random (6, 255); 1141 for (int i = 0; i < 8; i++) // populate the arrays with the random values 1142 { 1143 redLedArray [i] = redValue; 1144 greenLedArray [i] = greenValue; 1145 blueLedArray [i] = blueValue; 1146 } 1147 colorWipeEffectTrigger = true; 1148 } 1149 else 1150 { 1151 colorWipeEffectTrigger = true; 1152 } 1153 break; 1154 case 2: // red color mode 1155 rainbowEffectTrigger = false; 1156 colorWipeEffectTrigger = true; 1157 colorWheelEffectTrigger = false; 1158 for (int i = 0; i < 8; i++) // populate the arrays with the color red 1159 { 1160 redLedArray [i] = 255; 1161 greenLedArray [i] = 0; 1162 blueLedArray [i] = 0; 1163 } 1164 break; 1165 case 3: // green color mode 1166 rainbowEffectTrigger = false; 1167 colorWipeEffectTrigger = true; 1168 colorWheelEffectTrigger = false; 1169 for (int i = 0; i < 8; i++) // populate the arrays with the color green 1170 { 1171 redLedArray [i] = 0; 1172 greenLedArray [i] = 255; 1173 blueLedArray [i] = 0; 1174 } 1175 break; 1176 case 4: // blue color mode 1177 rainbowEffectTrigger = false; 1178 colorWipeEffectTrigger = true; 1179 colorWheelEffectTrigger = false; 1180 for (int i = 0; i < 8; i++) // populate the arrays with the color blue 1181 { 1182 redLedArray [i] = 0; 1183 greenLedArray [i] = 0; 1184 blueLedArray [i] = 255; 1185 } 1186 break; 1187 case 5: // white color mode 1188 rainbowEffectTrigger = false; 1189 colorWipeEffectTrigger = true; 1190 colorWheelEffectTrigger = false; 1191 for (int i = 0; i < 8; i++) // populate the arrays with the color white 1192 { 1193 redLedArray [i] = 255; 1194 greenLedArray [i] = 255; 1195 blueLedArray [i] = 255; 1196 } 1197 break; 1198 case 6: // multi color mode 1199 rainbowEffectTrigger = false; 1200 colorWipeEffectTrigger = true; 1201 colorWheelEffectTrigger = false; 1202 // Hours LEDs set to red: 1203 redLedArray [0] = 255; 1204 greenLedArray [0] = 0; 1205 blueLedArray [0] = 0; 1206 redLedArray [1] = 255; 1207 greenLedArray [1] = 0; 1208 blueLedArray [1] = 0; 1209 // Dots 1 LEDs set to white: 1210 redLedArray [2] = 255; 1211 greenLedArray [2] = 255; 1212 blueLedArray [2] = 255; 1213 // Minutes LEDs set to green: 1214 redLedArray [3] = 0; 1215 greenLedArray [3] = 255; 1216 blueLedArray [3] = 0; 1217 redLedArray [4] = 0; 1218 greenLedArray [4] = 255; 1219 blueLedArray [4] = 0; 1220 // Dots 2 LEDs set to white: 1221 redLedArray [5] = 255; 1222 greenLedArray [5] = 255; 1223 blueLedArray [5] = 255; 1224 // Minutes LEDs set to blue: 1225 redLedArray [6] = 0; 1226 greenLedArray [6] = 0; 1227 blueLedArray [6] = 255; 1228 redLedArray [7] = 0; 1229 greenLedArray [7] = 0; 1230 blueLedArray [7] = 255; 1231 break; 1232 case 7: // colorWheel mode 1233 rainbowEffectTrigger = false; 1234 colorWheelEffectTrigger = true; 1235 break; 1236 case 8: // rainbow mode 1237 rainbowEffectTrigger = true; 1238 colorWheelEffectTrigger = false; 1239 break; 1240 default: 1241 return; 1242 } 1243} 1244 1245/*------------------------------------------------------------------------------------------------------*/ 1246/* Function for managing the transition effect between WS2811 RGB LEDs modes - it displays on the middle 1247 * nixies the number of the mode that is on: 1248 */ 1249void wsTransitionDisplay () 1250{ 1251 // Local variables declaration: 1252 static unsigned long startTime = 0; // millis() memory 1253 byte firstDigit = 0; 1254 byte secondDigit = 0; 1255 static byte wsModeHolder = 0; 1256 1257 // Main code: 1258 if (wsModeHolder != wsMode) 1259 { 1260 wsModeHolder = wsMode; 1261 startTime = millis (); 1262 } 1263 1264 if (wsModeHolder <= 9) 1265 { 1266 firstDigit = 10; 1267 secondDigit = wsMode; 1268 } 1269 else 1270 { 1271 separateDoubleDigits (wsModeHolder, firstDigit, secondDigit); 1272 } 1273 1274 if (millis () - startTime < WSTRANSTIME) 1275 { 1276 writeOnNixieX (1, 10); 1277 writeOnNixieX (2, 10); 1278 writeOnNixieX (3, firstDigit); 1279 writeOnNixieX (4, secondDigit); 1280 writeOnNixieX (5, 10); 1281 writeOnNixieX (6, 10); 1282 dotsOn (false); 1283 } 1284 else 1285 { 1286 wsTransition = false; 1287 } 1288} 1289 1290/*------------------------------------------------------------------------------------------------------*/ 1291/* Function for running the rainbow WS effect (based on code from strandtest neopixel library example - 1292 * adjusted for real time execution): 1293 */ 1294void rainbowEffect () 1295{ 1296 // Local variables declaration: 1297 static unsigned long lastTime = millis (); 1298 static long firstPixelHue = 0; 1299 static int pixelHue = 0; 1300 1301 // Main code: 1302 // Hue of first pixel runs 5 complete loops through the color wheel. 1303 // Color wheel has a range of 65536 but it's OK if we roll over, so 1304 // just count from 0 to 5*65536. Adding 256 to firstPixelHue each time 1305 // means we'll make 5*65536/256 = 1280 passes before starting over: 1306 if (firstPixelHue < 5 * 65536) 1307 { 1308 if (millis () - lastTime > 26UL) // change colors every 26ms 1309 { 1310 lastTime = millis (); 1311 for (int i = 0; i < wsStrip.numPixels (); i++) 1312 { 1313 // For each pixel in strip... 1314 // Offset pixel hue by an amount to make one full revolution of the 1315 // color wheel (range of 65536) along the length of the strip 1316 // (wsStrip.numPixels() steps): 1317 pixelHue = firstPixelHue + (i * 65536L / wsStrip.numPixels()); 1318 // wsStrip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or 1319 // optionally add saturation and value (brightness) (each 0 to 255). 1320 // Here we're using just the single-argument hue variant. The result 1321 // is passed through wsStrip.gamma32() to provide 'truer' colors 1322 // before assigning to each pixel: 1323 wsStrip.setPixelColor (i, wsStrip.gamma32 (wsStrip.ColorHSV (pixelHue))); 1324 } 1325 wsStrip.show (); // Update strip with new contents 1326 firstPixelHue += 256; 1327 } 1328 } 1329 else 1330 { 1331 firstPixelHue = 0; 1332 } 1333} 1334 1335/*------------------------------------------------------------------------------------------------------*/ 1336/* Function for running the color wipe effect. When the resetTrigger parameter is set to true, the 1337 * counter starts again from the first (0) LED (used when pressing buttons quickly to ensure that the 1338 * new color is applied to all 8 LEDs every time). Default is false which allows the effect to 1339 * increment from LED to next LED: 1340 */ 1341void colorWipeEffect (bool resetTrigger = false) 1342{ 1343 // Local variables declaration: 1344 static unsigned long lastTime = millis (); 1345 static byte counter = 0; 1346 1347 // Main code: 1348 if (resetTrigger == true) 1349 { 1350 counter = 0; 1351 return; 1352 } 1353 if (millis () - lastTime > (unsigned long) WSTRANSTIME / 18) // time between every step - set it 1354 { // to be always done before 1355 lastTime = millis (); // wsTranstionDisplay is completed 1356 if (counter < 8) // during every step set the color to one RGB LED 1357 { 1358 wsStrip.setPixelColor (counter, wsStrip.Color (redLedArray [counter], greenLedArray [counter], 1359 blueLedArray [counter])); 1360 wsStrip.show(); 1361 counter++; 1362 } 1363 else 1364 { 1365 colorWipeEffectTrigger = false; 1366 counter = 0; 1367 } 1368 } 1369} 1370 1371/*------------------------------------------------------------------------------------------------------*/ 1372/* Function for running the colorWheel effect (based on code from strandtest_Wheel neopixel library 1373 * example - adjusted for real time execution): 1374 */ 1375void colorWheelEffect () 1376{ 1377 // Local variables declaration: 1378 static unsigned long lastTime = millis (); 1379 static unsigned int counter = 0; 1380 unsigned int i = 0; 1381 1382 // Main code: 1383 if (counter < 256) 1384 { 1385 if (millis () - lastTime > 50UL) // change colors every 50ms 1386 { 1387 lastTime = millis (); 1388 for (i= 0; i < wsStrip.numPixels (); i++) 1389 { 1390 wsStrip.setPixelColor (i, WheelColors ((i+counter) & 255)); 1391 } 1392 wsStrip.show (); 1393 counter++; 1394 } 1395 } 1396 else 1397 { 1398 counter = 0; 1399 } 1400} 1401 1402/*------------------------------------------------------------------------------------------------------*/ 1403/* Function for calculating and returning the colors to the colorWheelEffect function. Input a value 1404 * 0 to 255 to get a color value. The colors are a transition r - g - b - back to r (code from 1405 * strandtest_Wheel neopixel library example - adjusted for real time execution): 1406 */ 1407unsigned long WheelColors (byte WheelPos) 1408{ 1409 WheelPos = 255 - WheelPos; 1410 if (WheelPos < 85) 1411 { 1412 return wsStrip.Color (255 - WheelPos * 3, 0, WheelPos * 3); 1413 } 1414 if (WheelPos < 170) 1415 { 1416 WheelPos -= 85; 1417 return wsStrip.Color (0, WheelPos * 3, 255 - WheelPos * 3); 1418 } 1419 WheelPos -= 170; 1420 return wsStrip.Color (WheelPos * 3, 255 - WheelPos * 3, 0); 1421} 1422/*------------------------------------------------------------------------------------------------------*/ 1423/********************************************************************************************************* 1424 * Functions for managing the buttons and the photoresistor of the clock: 1425 ********************************************************************************************************/ 1426 1427/*------------------------------------------------------------------------------------------------------*/ 1428/* Function to handle the button presses: 1429 */ 1430void buttonsHandler () 1431{ 1432 // ------------------------------------------ normal button mode: ------------------------------------- 1433 if (setTimeModeFlag == false && testModeFlag == false) 1434 { 1435 // Button 1 (normal mode): 1436 if (button1.read () == MD_KeySwitch::KS_PRESS) 1437 { 1438 // if button is pressed while night modes are on (displayed), set the night end trigger to true: 1439 if (acpNightRoutineOn == true || nightPauseRoutineOn == true) 1440 { 1441 nightEndTrigger = true; 1442 if (psuState () == LOW) 1443 { 1444 psuState (HIGH); // turn on HV psu 1445 } 1446 } 1447 PRINTS ("\ 1448Button 1 pressed."); 1449 } 1450 if (button1.read () == MD_KeySwitch::KS_LONGPRESS) // enter setTimeMode 1451 { 1452 setTimeModeFlag = true; 1453 // turn off the WS LEDs effects on set time mode: 1454 if (rainbowEffectTrigger == true) 1455 { 1456 rainbowEffectTrigger = false; 1457 } 1458 if (colorWipeEffectTrigger == true) 1459 { 1460 colorWipeEffectTrigger = false; 1461 } 1462 if (colorWheelEffectTrigger == true) 1463 { 1464 colorWheelEffectTrigger = false; 1465 } 1466 // Light up only the hours WS LEDs if the LEDs were on, if they were off leave them off: 1467 if (wsOff == false) 1468 { 1469 if (wsMode == 7 || wsMode == 8) // if rainbow or colorWheel mode is on, pass the current color 1470 { // to the rainbow array so we can use them in the setTimeMode 1471 for (int i = 0; i < 8; i++) 1472 { 1473 tempColorArray [i] = wsStrip.getPixelColor (i); 1474 } 1475 wsStrip.setPixelColor (0, tempColorArray [0]); 1476 wsStrip.setPixelColor (1, tempColorArray [1]); 1477 } 1478 else // if not rainbow or wheel mode, the color values are already available in there arrays 1479 { 1480 wsStrip.setPixelColor (0, wsStrip.Color (redLedArray [0], greenLedArray [0], 1481 blueLedArray [0])); 1482 wsStrip.setPixelColor (1, wsStrip.Color (redLedArray [1], greenLedArray [1], 1483 blueLedArray [1])); 1484 } 1485 wsStrip.setPixelColor (2, wsStrip.Color (0, 0, 0)); 1486 wsStrip.setPixelColor (3, wsStrip.Color (0, 0, 0)); 1487 wsStrip.setPixelColor (4, wsStrip.Color (0, 0, 0)); 1488 wsStrip.setPixelColor (5, wsStrip.Color (0, 0, 0)); 1489 wsStrip.setPixelColor (6, wsStrip.Color (0, 0, 0)); 1490 wsStrip.setPixelColor (7, wsStrip.Color (0, 0, 0)); 1491 wsStrip.show(); 1492 } 1493 PRINTS ("\ 1494Button 1 long pressed."); 1495 } 1496 1497 // Button 2 (normal mode): 1498 if (button2.read () == MD_KeySwitch::KS_PRESS) // go to next ws LEDs mode 1499 { 1500 if (wsMode < wsModeNum) 1501 { 1502 wsMode++; 1503 } 1504 else if (wsMode == wsModeNum) 1505 { 1506 wsMode = 1; 1507 } 1508 wsTransition = true; 1509 wsModeHandler (true); 1510 if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed 1511 { 1512 colorWipeEffect (true); // run once to reset the wipe effect 1513 } 1514 // if button is pressed while night modes are on (displayed), set the night end trigger to true: 1515 if (acpNightRoutineOn == true || nightPauseRoutineOn == true) 1516 { 1517 nightEndTrigger = true; 1518 if (psuState () == LOW) 1519 { 1520 psuState (HIGH); // turn on HV psu 1521 } 1522 } 1523 PRINTS ("\ 1524Button 2 pressed."); 1525 } 1526 1527 // Button 3 (normal mode): 1528 if (button3.read () == MD_KeySwitch::KS_PRESS) // go to previous WS LEDs mode 1529 { 1530 if (wsMode > 1) 1531 { 1532 wsMode--; 1533 } 1534 else if (wsMode == 1) 1535 { 1536 wsMode = wsModeNum; 1537 } 1538 wsTransition = true; 1539 wsModeHandler (true); 1540 if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed 1541 { 1542 colorWipeEffect (true); // run once to reset the wipe effect 1543 } 1544 // if button is pressed while night modes are on (displayed), set the night end trigger to true: 1545 if (acpNightRoutineOn == true || nightPauseRoutineOn == true) 1546 { 1547 nightEndTrigger = true; 1548 if (psuState () == LOW) 1549 { 1550 psuState (HIGH); // turn on HV psu 1551 } 1552 } 1553 PRINTS ("\ 1554Button 3 pressed."); 1555 } 1556 1557 // Button 4 (normal mode): 1558 if (button4.read () == MD_KeySwitch::KS_PRESS) // turn WS LEDs on or off 1559 { 1560 if (wsOff == true) 1561 { 1562 wsOff = false; 1563 if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed 1564 { 1565 colorWipeEffect (true); // run once to reset the wipe effect 1566 } 1567 wsModeHandler (); 1568 } 1569 else if (wsOff == false) 1570 { 1571 wsOff = true; 1572 rainbowEffectTrigger = false; 1573 colorWipeEffectTrigger = false; 1574 colorWheelEffectTrigger = false; 1575 wsStrip.clear (); 1576 wsStrip.show (); 1577 } 1578 // if button is pressed while night modes are on (displayed), set the night end trigger to true: 1579 if (acpNightRoutineOn == true || nightPauseRoutineOn == true) 1580 { 1581 nightEndTrigger = true; 1582 if (psuState () == LOW) 1583 { 1584 psuState (HIGH); // turn on HV psu 1585 } 1586 } 1587 PRINTS ("\ 1588Button 4 pressed."); 1589 } 1590 if (button4.read () == MD_KeySwitch::KS_LONGPRESS) // enter test mode 1591 { 1592 testModeFlag = true; 1593 PRINTS ("\ 1594Button 4 long pressed."); 1595 } 1596 } 1597 else if (testModeFlag == false) // ---------------- set time button mode: ---------------------------- 1598 { 1599 // Button 1 (set time mode): 1600 if (button1.read () == MD_KeySwitch::KS_PRESS) // save temp time variable set 1601 { 1602 if (setTimeStageArray [0] == false) 1603 { 1604 RTC.h = tempTimeHolder; 1605 RTC.writeTime (); // save hours 1606 setTimeStageArray [0] = true; 1607 tempTimeHolder = RTC.m; // pass current minutes to temp time variable for manipulation with buttons 1608 // Light up only the minutes WS LEDs if the LEDs were on, if they were off leave them off: 1609 if (wsOff == false) 1610 { 1611 wsStrip.setPixelColor (0, wsStrip.Color (0, 0, 0)); 1612 wsStrip.setPixelColor (1, wsStrip.Color (0, 0, 0)); 1613 wsStrip.setPixelColor (2, wsStrip.Color (0, 0, 0)); 1614 if (wsMode == 7 || wsMode == 8) // if rainbow or color wheel was on, use tempColorArray to 1615 { // retrieve the colors 1616 wsStrip.setPixelColor (3, tempColorArray [3]); 1617 wsStrip.setPixelColor (4, tempColorArray [4]); 1618 } 1619 else // if not rainbow or wheel mode, use the individual color arrays to retrieve the colors 1620 { 1621 wsStrip.setPixelColor (3, wsStrip.Color (redLedArray [3], greenLedArray [3], 1622 blueLedArray [3])); 1623 wsStrip.setPixelColor (4, wsStrip.Color (redLedArray [4], greenLedArray [4], 1624 blueLedArray [4])); 1625 } 1626 wsStrip.setPixelColor (5, wsStrip.Color (0, 0, 0)); 1627 wsStrip.setPixelColor (6, wsStrip.Color (0, 0, 0)); 1628 wsStrip.setPixelColor (7, wsStrip.Color (0, 0, 0)); 1629 wsStrip.show(); 1630 } 1631 } 1632 else if (setTimeStageArray [1] == false) 1633 { 1634 RTC.m = tempTimeHolder; 1635 RTC.writeTime (); // save minutes 1636 setTimeStageArray [1] = true; 1637 tempTimeHolder = RTC.s; // pass current seconds to temp time variable for manipulation with buttons 1638 // Light up only the seconds WS LEDs if the LEDs were on, if they were off leave them off: 1639 if (wsOff == false) 1640 { 1641 wsStrip.setPixelColor (0, wsStrip.Color (0, 0, 0)); 1642 wsStrip.setPixelColor (1, wsStrip.Color (0, 0, 0)); 1643 wsStrip.setPixelColor (2, wsStrip.Color (0, 0, 0)); 1644 wsStrip.setPixelColor (3, wsStrip.Color (0, 0, 0)); 1645 wsStrip.setPixelColor (4, wsStrip.Color (0, 0, 0)); 1646 wsStrip.setPixelColor (5, wsStrip.Color (0, 0, 0)); 1647 if (wsMode == 7 || wsMode == 8) // if rainbow or color wheel was on, use tempColorArray to 1648 { // retrieve the colors 1649 wsStrip.setPixelColor (6, tempColorArray [6]); 1650 wsStrip.setPixelColor (7, tempColorArray [7]); 1651 } 1652 else // if not rainbow mode, use the individual color arrays to retrieve the colors 1653 { 1654 wsStrip.setPixelColor (6, wsStrip.Color (redLedArray [6], greenLedArray [6], 1655 blueLedArray [6])); 1656 wsStrip.setPixelColor (7, wsStrip.Color (redLedArray [7], greenLedArray [7], 1657 blueLedArray [7])); 1658 } 1659 wsStrip.show(); 1660 } 1661 } 1662 else if (setTimeStageArray [2] == false) 1663 { 1664 RTC.s = tempTimeHolder; 1665 RTC.writeTime (); // save seconds 1666 setTimeStageArray [2] = true; 1667 tempTimeHolder = 0; 1668 setTimeModeFlag = false; 1669 timeSetModeReset = true; 1670 if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed 1671 { 1672 colorWipeEffect (true); // run once to reset the wipe effect 1673 } 1674 if (wsOff == false) 1675 { 1676 wsModeHandler (); 1677 } 1678 } 1679 else 1680 { 1681 return; 1682 } 1683 PRINTS ("\ 1684Button 1 pressed."); 1685 } 1686 1687 // Button 2 (set time mode): 1688 switch (button2.read ()) 1689 { 1690 case MD_KeySwitch::KS_PRESS: // button 2 single press - increase temp time variable 1691 if (setTimeStageArray [0] == false) 1692 { 1693 if (tempTimeHolder >= 0 && tempTimeHolder < 23) // increase hours 1694 { 1695 tempTimeHolder++; 1696 } 1697 else 1698 { 1699 tempTimeHolder = 0; 1700 } 1701 } 1702 else 1703 { 1704 if (tempTimeHolder >= 0 && tempTimeHolder < 59) // increase minutes and seconds 1705 { 1706 tempTimeHolder++; 1707 } 1708 else 1709 { 1710 tempTimeHolder = 0; 1711 } 1712 } 1713 PRINTS ("\ 1714Button 2 pressed."); 1715 break; 1716 case MD_KeySwitch::KS_RPTPRESS: // button 2 repeat press - increase temp time variable fast 1717 repeatOn = true; // set to true in order to stop blinking in setTimeMode function 1718 if (setTimeStageArray [0] == false) 1719 { 1720 if (tempTimeHolder >= 0 && tempTimeHolder < 23) // increase hours 1721 { 1722 tempTimeHolder++; 1723 } 1724 else 1725 { 1726 tempTimeHolder = 0; 1727 } 1728 } 1729 else 1730 { 1731 if (tempTimeHolder >= 0 && tempTimeHolder < 59) // increase minutes and seconds 1732 { 1733 tempTimeHolder++; 1734 } 1735 else 1736 { 1737 tempTimeHolder = 0; 1738 } 1739 } 1740 PRINTS ("\ 1741Button 2 repeat pressed."); 1742 break; 1743 default: 1744 break; 1745 } 1746 1747 // Button 3 (set time mode): 1748 switch (button3.read ()) 1749 { 1750 case MD_KeySwitch::KS_PRESS: // button 3 single press - decrease temp time variable 1751 if (setTimeStageArray [0] == false) 1752 { 1753 if (tempTimeHolder > 0 && tempTimeHolder <= 23) // decrease hours 1754 { 1755 tempTimeHolder--; 1756 } 1757 else 1758 { 1759 tempTimeHolder = 23; 1760 } 1761 } 1762 else 1763 { 1764 if (tempTimeHolder > 0 && tempTimeHolder <= 59) // decrease minutes and seconds 1765 { 1766 tempTimeHolder--; 1767 } 1768 else 1769 { 1770 tempTimeHolder = 59; 1771 } 1772 } 1773 PRINTS ("\ 1774Button 3 pressed."); 1775 break; 1776 case MD_KeySwitch::KS_RPTPRESS: // button 3 repeat press - decrease temp time variable fast 1777 repeatOn = true; // set to true in order to stop blinking in setTimeMode function 1778 if (setTimeStageArray [0] == false) 1779 { 1780 if (tempTimeHolder > 0 && tempTimeHolder <= 23) // decrease hours 1781 { 1782 tempTimeHolder--; 1783 } 1784 else 1785 { 1786 tempTimeHolder = 23; 1787 } 1788 } 1789 else 1790 { 1791 if (tempTimeHolder > 0 && tempTimeHolder <= 59) // decrease minutes and seconds 1792 { 1793 tempTimeHolder--; 1794 } 1795 else 1796 { 1797 tempTimeHolder = 59; 1798 } 1799 } 1800 PRINTS ("\ 1801Button 3 repeat pressed."); 1802 break; 1803 default: 1804 break; 1805 } 1806 1807 // Button 4 (set time mode): 1808 if (button4.read () == MD_KeySwitch::KS_PRESS) // exit set time mode 1809 { 1810 setTimeModeFlag = false; 1811 timeSetModeReset = true; 1812 if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed 1813 { 1814 colorWipeEffect (true); // run once to reset the wipe effect 1815 } 1816 if (wsOff == false) 1817 { 1818 wsModeHandler (); 1819 } 1820 PRINTS ("\ 1821Button 4 pressed."); 1822 } 1823 } 1824 else // ----------------------------------------- test mode: ----------------------------------------- 1825 { 1826 // Button 1 (test mode): 1827 if (button1.read () == MD_KeySwitch::KS_PRESS) // switch photoresistor test on and off 1828 { 1829 if (testPhotoresistorFlag == false) 1830 { 1831 testPhotoresistorFlag = true; 1832 if (psuState () == LOW) 1833 { 1834 psuState (HIGH); // turn on HV psu 1835 } 1836 } 1837 else 1838 { 1839 testPhotoresistorFlag = false; 1840 } 1841 PRINTS ("\ 1842Button 1 pressed."); 1843 } 1844 // Button 4 (test mode): 1845 if (button4.read () == MD_KeySwitch::KS_PRESS) // exit test mode 1846 { 1847 testModeFlag = false; 1848 testPhotoresistorFlag = false; 1849 testMode (true); // reset test mode 1850 if (psuState () == LOW) 1851 { 1852 psuState (HIGH); // turn on HV psu 1853 } 1854 if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed 1855 { 1856 colorWipeEffect (true); // run once to reset the wipe effect 1857 } 1858 if (wsOff == false) 1859 { 1860 wsModeHandler (); 1861 } 1862 PRINTS ("\ 1863Button 4 pressed."); 1864 } 1865 } 1866} 1867 1868/*------------------------------------------------------------------------------------------------------*/ 1869/* Function for handling the set time mode: 1870 */ 1871void setTimeMode () 1872{ 1873 // Local variables declaration: 1874 static unsigned long startTime = millis (); // millis() memory 1875 1876 // Main code: 1877 RTC.readTime (); // get the time from the module 1878 1879 if (timeSetModeReset == true) // check if it's the first run of function 1880 { 1881 dotsOn (false); // turn off dots 1882 timeSetModeReset = false; 1883 for (int i = 0; i < 3; i++) // reset array 1884 { 1885 setTimeStageArray [i] = false; 1886 } 1887 // Hours: 1888 tempTimeHolder = RTC.h; // pass current time to temp variable for manipulation with buttons 1889 separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit); 1890 writeOnNixieX (1, hoursFirstDigit); 1891 writeOnNixieX (2, hoursSecondDigit); 1892 1893 // Minutes: 1894 separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit); 1895 writeOnNixieX (3, minutesFirstDigit); 1896 writeOnNixieX (4, minutesSecondDigit); 1897 1898 // Seconds: 1899 separateDoubleDigits (RTC.s, secondsFirstDigit, secondsSecondDigit); 1900 // Acp routine trigger at the 00 seconds and change random LED color if on mode 1: 1901 writeOnNixieX (5, secondsFirstDigit); 1902 writeOnNixieX (6, secondsSecondDigit); 1903 } 1904 else if (setTimeStageArray [0] == false) // blink hours except when on repeat 1905 { 1906 // Hours: 1907 if (repeatOn == false) 1908 { 1909 separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit); 1910 if (millis () - startTime < 500UL) 1911 { 1912 writeOnNixieX (1, hoursFirstDigit); 1913 writeOnNixieX (2, hoursSecondDigit); 1914 } 1915 else if (millis () - startTime < 1000UL) 1916 { 1917 writeOnNixieX (1, 10); 1918 writeOnNixieX (2, 10); 1919 } 1920 else 1921 { 1922 startTime = millis (); 1923 } 1924 } 1925 else // if on repeat button press don't blink 1926 { 1927 separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit); 1928 writeOnNixieX (1, hoursFirstDigit); 1929 writeOnNixieX (2, hoursSecondDigit); 1930 repeatOn = false; 1931 startTime = millis (); 1932 } 1933 1934 // Minutes: 1935 separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit); 1936 writeOnNixieX (3, minutesFirstDigit); 1937 writeOnNixieX (4, minutesSecondDigit); 1938 1939 // Seconds: 1940 separateDoubleDigits (RTC.s, secondsFirstDigit, secondsSecondDigit); 1941 // Acp routine trigger at the 00 seconds and change random LED color if on mode 1: 1942 writeOnNixieX (5, secondsFirstDigit); 1943 writeOnNixieX (6, secondsSecondDigit); 1944 } 1945 else if (setTimeStageArray [1] == false) // if hours set, blink minutes except on repeat 1946 { 1947 // Hours: 1948 separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit); 1949 writeOnNixieX (1, hoursFirstDigit); 1950 writeOnNixieX (2, hoursSecondDigit); 1951 1952 // Minutes: 1953 if (repeatOn == false) 1954 { 1955 separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit); 1956 if (millis () - startTime < 500UL) 1957 { 1958 writeOnNixieX (3, minutesFirstDigit); 1959 writeOnNixieX (4, minutesSecondDigit); 1960 } 1961 else if (millis () - startTime < 1000UL) 1962 { 1963 writeOnNixieX (3, 10); 1964 writeOnNixieX (4, 10); 1965 } 1966 else 1967 { 1968 startTime = millis (); 1969 } 1970 } 1971 else // if on repeat button press don't blink 1972 { 1973 separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit); 1974 writeOnNixieX (3, minutesFirstDigit); 1975 writeOnNixieX (4, minutesSecondDigit); 1976 repeatOn = false; 1977 startTime = millis (); 1978 } 1979 1980 // Seconds: 1981 separateDoubleDigits (RTC.s, secondsFirstDigit, secondsSecondDigit); 1982 // Acp routine trigger at the 00 seconds and change random LED color if on mode 1: 1983 writeOnNixieX (5, secondsFirstDigit); 1984 writeOnNixieX (6, secondsSecondDigit); 1985 } 1986 else if (setTimeStageArray [2] == false) // if hours and minutes set, blink seconds except on repeat 1987 { 1988 // Hours: 1989 separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit); 1990 writeOnNixieX (1, hoursFirstDigit); 1991 writeOnNixieX (2, hoursSecondDigit); 1992 1993 // Minutes: 1994 separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit); 1995 writeOnNixieX (3, minutesFirstDigit); 1996 writeOnNixieX (4, minutesSecondDigit); 1997 1998 // Seconds: 1999 if (repeatOn == false) 2000 { 2001 separateDoubleDigits (tempTimeHolder, secondsFirstDigit, secondsSecondDigit); 2002 if (millis () - startTime < 500UL) 2003 { 2004 writeOnNixieX (5, secondsFirstDigit); 2005 writeOnNixieX (6, secondsSecondDigit); 2006 } 2007 else if (millis () - startTime < 1000UL) 2008 { 2009 writeOnNixieX (5, 10); 2010 writeOnNixieX (6, 10); 2011 } 2012 else 2013 { 2014 startTime = millis (); 2015 } 2016 } 2017 else // if on repeat button press don't blink 2018 { 2019 separateDoubleDigits (tempTimeHolder, secondsFirstDigit, secondsSecondDigit); 2020 writeOnNixieX (5, secondsFirstDigit); 2021 writeOnNixieX (6, secondsSecondDigit); 2022 repeatOn = false; 2023 startTime = millis (); 2024 } 2025 } 2026} 2027 2028/*------------------------------------------------------------------------------------------------------*/ 2029/* Function for running test mode - it first tunrs off the HV power supply then it runs throught all 2030 * the numbers once, blinks the dots and sets the WS2811 LEDs to green then red and finally blue color. 2031 * When button 1 is pressed, it displays the value of the photoresistor readings. If resetTrigger is set 2032 * to true, it resets the function variables to be ready for the next run.: 2033 */ 2034void testMode (bool resetTrigger = false) 2035{ 2036 // Local variables declaration: 2037 static unsigned long lastTime = 0; // millis() memory 2038 static unsigned long lastTimeLight = millis (); // millis() memory for the light part 2039 static byte counter = 0; 2040 unsigned long onTime = 2200; // time in ms that each number stays on 2041 static bool firstRunFlag = true; // flag to check if it's the first run of every instance 2042 unsigned int lightValue = 0; 2043 byte lightValueDigits = 0; 2044 byte lightFirstDigit = 0; 2045 byte lightSecondDigit = 0; 2046 byte lightThirdDigit = 0; 2047 byte lightFourthDigit = 0; 2048 2049 // Main code: 2050 if (resetTrigger == true) // reset variables 2051 { 2052 counter = 0; 2053 firstRunFlag = true; 2054 return; 2055 } 2056 if (firstRunFlag == true) // check if it is the first run of each routine 2057 { 2058 rainbowEffectTrigger = false; 2059 colorWipeEffectTrigger = false; 2060 colorWheelEffectTrigger = false; 2061 for (int i = 0; i < 8; i++) 2062 { 2063 wsStrip.setPixelColor (i, wsStrip.Color (255, 0, 0)); 2064 } 2065 wsStrip.show (); 2066 lastTime = millis (); 2067 dotsOn (false); 2068 firstRunFlag = false; 2069 } 2070 2071 if (testPhotoresistorFlag == false) // normal test part 2072 { 2073 switch (counter) 2074 { 2075 case 0: 2076 if (millis () - lastTime < onTime) // run for "onTime" duration 2077 { 2078 psuState (LOW); // turn off HV psu 2079 } 2080 else 2081 { 2082 counter++; 2083 lastTime = millis (); 2084 dotsOn (true); 2085 psuState (HIGH); // turn on HV psu 2086 } 2087 break; 2088 case 1: 2089 if (millis () - lastTime < onTime) // run for "onTime" duration 2090 { 2091 for (int i = 0; i < 8; i++) 2092 { 2093 writeOnNixieX (i, 0); 2094 } 2095 } 2096 else 2097 { 2098 counter++; 2099 lastTime = millis (); 2100 dotsOn (false); 2101 } 2102 break; 2103 case 2: 2104 if (millis () - lastTime < onTime) // run for "onTime" duration 2105 { 2106 for (int i = 0; i < 8; i++) 2107 { 2108 writeOnNixieX (i, 1); 2109 } 2110 } 2111 else 2112 { 2113 counter++; 2114 lastTime = millis (); 2115 dotsOn (true); 2116 } 2117 break; 2118 case 3: 2119 if (millis () - lastTime < onTime) // run for "onTime" duration 2120 { 2121 for (int i = 0; i < 8; i++) 2122 { 2123 writeOnNixieX (i, 2); 2124 } 2125 } 2126 else 2127 { 2128 counter++; 2129 lastTime = millis (); 2130 dotsOn (false); 2131 for (int i = 0; i < 8; i++) 2132 { 2133 wsStrip.setPixelColor (i, wsStrip.Color (0, 255, 0)); 2134 } 2135 wsStrip.show (); 2136 } 2137 break; 2138 case 4: 2139 if (millis () - lastTime < onTime) // run for "onTime" duration 2140 { 2141 for (int i = 0; i < 8; i++) 2142 { 2143 writeOnNixieX (i, 3); 2144 } 2145 } 2146 else 2147 { 2148 counter++; 2149 lastTime = millis (); 2150 dotsOn (true); 2151 } 2152 break; 2153 case 5: 2154 if (millis () - lastTime < onTime) // run for "onTime" duration 2155 { 2156 for (int i = 0; i < 8; i++) 2157 { 2158 writeOnNixieX (i, 4); 2159 } 2160 } 2161 else 2162 { 2163 counter++; 2164 lastTime = millis (); 2165 dotsOn (false); 2166 } 2167 break; 2168 case 6: 2169 if (millis () - lastTime < onTime) // run for "onTime" duration 2170 { 2171 for (int i = 0; i < 8; i++) 2172 { 2173 writeOnNixieX (i, 5); 2174 } 2175 } 2176 else 2177 { 2178 counter++; 2179 lastTime = millis (); 2180 dotsOn (true); 2181 } 2182 break; 2183 case 7: 2184 if (millis () - lastTime < onTime) // run for "onTime" duration 2185 { 2186 for (int i = 0; i < 8; i++) 2187 { 2188 writeOnNixieX (i, 6); 2189 } 2190 } 2191 else 2192 { 2193 counter++; 2194 lastTime = millis (); 2195 dotsOn (false); 2196 for (int i = 0; i < 8; i++) 2197 { 2198 wsStrip.setPixelColor (i, wsStrip.Color (0, 0, 255)); 2199 } 2200 wsStrip.show (); 2201 } 2202 break; 2203 case 8: 2204 if (millis () - lastTime < onTime) // run for "onTime" duration 2205 { 2206 for (int i = 0; i < 8; i++) 2207 { 2208 writeOnNixieX (i, 7); 2209 } 2210 } 2211 else 2212 { 2213 counter++; 2214 lastTime = millis (); 2215 dotsOn (true); 2216 } 2217 break; 2218 case 9: 2219 if (millis () - lastTime < onTime) // run for "onTime" duration 2220 { 2221 for (int i = 0; i < 8; i++) 2222 { 2223 writeOnNixieX (i, 8); 2224 } 2225 } 2226 else 2227 { 2228 counter++; 2229 lastTime = millis (); 2230 dotsOn (false); 2231 } 2232 break; 2233 case 10: 2234 if (millis () - lastTime < onTime) // run for "onTime" duration 2235 { 2236 for (int i = 0; i < 8; i++) 2237 { 2238 writeOnNixieX (i, 9); 2239 } 2240 } 2241 else 2242 { 2243 counter = 0; 2244 testModeFlag = false; 2245 firstRunFlag = true; 2246 if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed 2247 { 2248 colorWipeEffect (true); // run once to reset the wipe effect 2249 } 2250 if (wsOff == false) 2251 { 2252 wsModeHandler (); 2253 } 2254 } 2255 break; 2256 default: 2257 break; 2258 } 2259 } 2260 else // photoresistor test part 2261 { 2262 dotsOn (false); 2263 if (millis () - lastTimeLight > 500UL) // run every half second 2264 { 2265 lastTimeLight = millis (); 2266 lightValue = analogRead (LDRPIN); 2267 lightValueDigits = numberOfDigits (lightValue); 2268 switch (lightValueDigits) 2269 { 2270 case 1: 2271 writeOnNixieX (1, 0); 2272 writeOnNixieX (2, 0); 2273 writeOnNixieX (3, 0); 2274 writeOnNixieX (4, lightValue); 2275 writeOnNixieX (5, 10); 2276 writeOnNixieX (6, 10); 2277 break; 2278 case 2: 2279 separateDoubleDigits (lightValue, lightFirstDigit, lightSecondDigit); 2280 writeOnNixieX (1, 0); 2281 writeOnNixieX (2, 0); 2282 writeOnNixieX (3, lightFirstDigit); 2283 writeOnNixieX (4, lightSecondDigit); 2284 writeOnNixieX (5, 10); 2285 writeOnNixieX (6, 10); 2286 break; 2287 case 3: 2288 separateThreeDigits (lightValue, lightFirstDigit, lightSecondDigit, lightThirdDigit); 2289 writeOnNixieX (1, 0); 2290 writeOnNixieX (2, lightFirstDigit); 2291 writeOnNixieX (3, lightSecondDigit); 2292 writeOnNixieX (4, lightThirdDigit); 2293 writeOnNixieX (5, 10); 2294 writeOnNixieX (6, 10); 2295 break; 2296 case 4: 2297 separateFourDigits (lightValue, lightFirstDigit, lightSecondDigit, lightThirdDigit, 2298 lightFourthDigit); 2299 writeOnNixieX (1, lightFirstDigit); 2300 writeOnNixieX (2, lightSecondDigit); 2301 writeOnNixieX (3, lightThirdDigit); 2302 writeOnNixieX (4, lightFourthDigit); 2303 writeOnNixieX (5, 10); 2304 writeOnNixieX (6, 10); 2305 break; 2306 default: 2307 break; 2308 } 2309 } 2310 } 2311} 2312 2313/*------------------------------------------------------------------------------------------------------*/ 2314/* Function for handling the photoresistor - read the light in the room and adjust the WS2811 LEDs 2315 * brightness accordingly: 2316 */ 2317void photoresistorHandler () 2318{ 2319 // Local variables declaration: 2320 // WS2811 LEDs brightness part: 2321 static unsigned int count = 0; 2322 static unsigned long lastTime = millis (); 2323 static unsigned int sum = 0; 2324 unsigned int lightMedian = 0; 2325 int countReset = 10; // how many counts (seconds) it takes before changing the brightness 2326 // Night mode part: 2327 static unsigned long nightCount = 0; 2328 static unsigned long lastTimeNightMode = millis (); 2329 static bool nightEnd = false; // check if the night modes time has ended 2330 2331 // Main code: 2332 // WS2811 LEDs brightness part: 2333 if (wsOff == false) // run only if the LEDs are on 2334 { 2335 if (millis () - lastTime > 1000UL) // check the value of the photoresistor every second 2336 { 2337 lastTime = millis (); 2338 count++; 2339 sum = analogRead (LDRPIN) + sum; 2340 lightMedian = sum / count; 2341 } 2342 if (count == countReset) 2343 { 2344 wsBrightness = map (lightMedian, 0, 1023, BRIGHTNESSMIN, BRIGHTNESSMAX); 2345 wsStrip.setBrightness (wsBrightness); 2346 PRINT ("\ 2347Brightness set to: ", wsBrightness) 2348 if (setTimeModeFlag == false && testModeFlag == false) 2349 { 2350 wsModeHandler (); 2351 } 2352 count = 0; 2353 sum = 0; 2354 } 2355 } 2356 2357 // Night mode part: 2358 RTC.readTime (); // get the time from the module - also populate rtc variables at every run 2359 // so that other functions can have updated values without having to read 2360 // the module again and again 2361 // Start checking for the light in the room only at the acp night hour or the night pause time: 2362 if (RTC.h == ACPNIGHTHOUR || (RTC.h >= NIGHTPAUSESTART && RTC.h < NIGHTPAUSEEND)) 2363 { 2364 if (millis () - lastTimeNightMode > 2000UL) // check the value of the photoresistor every 2 seconds 2365 { 2366 PRINT ("\ 2367LDR: ", analogRead (LDRPIN)) 2368 lastTimeNightMode = millis (); 2369 if (analogRead (LDRPIN) < 100) // check if the light in the room is low enough for the night acp 2370 { // and the pause routines to trigger, if not reset 2371 nightCount++; 2372 } 2373 else 2374 { 2375 nightCount = 0; 2376 } 2377 } 2378 if (nightCount >= 15) // if the light is low for many readings (30 seconds) start night mode 2379 { 2380 nightLightTrigger = true; 2381 } 2382 else // but if it gets brighter, end it immediately 2383 { 2384 nightLightTrigger = false; 2385 } 2386 nightEnd = false; 2387 } 2388 else if (RTC.h == NIGHTPAUSEEND) // make sure that the night light and end triggers 2389 { // are false when night time ends 2390 if (nightEnd == false) // a check used for running once 2391 { 2392 nightEnd = true; 2393 nightLightTrigger = false; 2394 nightEndTrigger = false; 2395 if (wsWasOn == true) 2396 { 2397 wsOff = false; 2398 wsModeHandler (); 2399 } 2400 wsWasOn = false; 2401 if (psuState () == LOW) 2402 { 2403 psuState (HIGH); // turn on HV psu 2404 } 2405 } 2406 } 2407} 2408 2409/*------------------------------------------------------------------------------------------------------*/ 2410/* Function for counting the number of digits of the photoresistor value - it gets the reading and 2411 * returns the number of the digits: 2412 */ 2413byte numberOfDigits (unsigned int number) 2414{ 2415 byte digits = 0; 2416 if (number == 0) 2417 { 2418 return 1; 2419 } 2420 while (number != 0) 2421 { 2422 number = number / 10; 2423 digits++; 2424 } 2425 return digits; 2426} 2427/********************************************************************************************************* 2428*********************************************************************************************************/ 2429
Downloadable files
Bottom layer components schematic
This is a components schematic of the bottom layer of the clock. The components that have the "placeholder" marking are not the actual components, just something similar I found.
Bottom layer components schematic
Table with all the pin connections
This is a table that has all the pin connections that exist on the clock - what connects to what, simple and easy.
Table with all the pin connections
Perfboard schematic
This is the schematic of the perfboard - it a real world schematic not an engineering one, meaning that the cable lines are as they will be in the real perfboard - even the ground.
Perfboard schematic
Perfboard components placement schematic
This is a schematic of the components and there place on the perfboard - Designing this helped a lot with figuring out what can fit where.
Perfboard components placement schematic
Perfboard components placement schematic
This is a schematic of the components and there place on the perfboard - Designing this helped a lot with figuring out what can fit where.
Perfboard components placement schematic
Perfboard schematic
This is the schematic of the perfboard - it a real world schematic not an engineering one, meaning that the cable lines are as they will be in the real perfboard - even the ground.
Perfboard schematic
Table with all the pin connections
This is a table that has all the pin connections that exist on the clock - what connects to what, simple and easy.
Table with all the pin connections
Comments
Only logged in users can leave comments
deathorion
0 Followers
•0 Projects
Table of contents
Intro
3
0