DIY Nixie clock on perfboard!
How can you resist the glow of a nixie tube? You don't have to, make your own the easy way!
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