Components and supplies
DHT11 Temperature & Humidity Sensor (4 pins)
ATMEGA328P-PU
DS3231MZ+
HV5812P-G
Apps and platforms
Arduino IDE
EasyEDA
Project description
Code
VFD_Clock-Main_Sketch-0.3.5.ino
c_cpp
The code for the clock using the Arduino IDE. I plan to optimize it a bit and add some new features in the future. I tried to comment everything to make sense but keep in mind that I'm an amateur and self taught so it might be a little messy.
1/*************************************************************************************************************** 2 *************************************************************************************************************** 3 VFD Clock Main Sketch 4 Version 0.3.5 5 Tested with: Arduino IDE 1.8.16 - Arduino AVR Boards 1.8.4 - MD_DS3231 1.3.1 - Adafruit_NeoPixel 1.7.0 - 6 MD_KeySwitch 1.4.2 - DHT sensor library 1.4.3 - ATMega328P-PU with Arduino UNO R3 bootloader 7 (for uploading code with the FTDI board select Tools-> Board:-> "Ardruino Uno") 8 17-05-2022 9 Leon 10 **************************************************************************************************************/ 11// Libraries needed: 12#include <MD_DS3231.h> // Pre-existing object named RTC (SCL to pin A5, SDA to pin A4) 13#include <Adafruit_NeoPixel.h> 14#include <MD_KeySwitch.h> 15#include "DHT.h" 16#include <SPI.h> 17 18// Turn debugging on and off: 19#define DEBUG 1 20#if DEBUG 21#define PRINTS(s) { Serial.print (F(s));} // Print a string 22#define PRINT(s, v) { Serial.print (F(s)); Serial.print (v);} // Print string then value (dec) 23#include <MemoryFree.h> // Library for printing free memory on runtime 24#else 25#define PRINTS(s) // Print a string 26#define PRINT(s, v) // Print a string followed by a value (decimal) 27#endif 28 29// General universal variables: 30byte currentHours = 0; // variable to hold the value of the current hour 31byte currentSeconds = 0; // variable to hold the value of the current seconds 32 33// Variables for holding the individual digits of time: 34byte hoursFirstDigit = 0; 35byte hoursSecondDigit = 0; 36byte minutesFirstDigit = 0; 37byte minutesSecondDigit = 0; 38 39// VFD tubes: 40#define NUM_DIGITS 2 // define number of display digits. 41const byte Blank = 9; // Output to HV5812P-G 'BLANK' input 42const byte strobe = 10; // Output to HV5812P-G 'STROBE' input 43byte timeBuffer [4]; // array to hold the time digits 44byte vfdDisplayMode = 0; 45// mode 0 = 24h time display 46// mode 1 = 12h time display 47// mode 2 = temperature & humidity only display (without time) 48// mode 3 = display temp & humidity once (used when turning tempDisplayOn to true) 49// mode 4 = set time in 24h mode 50// mode 5 = set time in 12h mode 51bool previousDisplayMode = 0; // variable to hold the previous display mode 52bool tempDisplayOn = true; // show temp and humidity periodically on modes 0 and 1 53bool vfdCycleEffectOn = false; // trigger for vfd cycle effect 54bool vfdDashEffectOn = false; // trigger for vfd dash effect - used to indicate "OFF" 55bool vfdDotEffectOn = false; // trigger for vfd dot effect - used to indicate "ON" 56byte effectBuffer [4]; // array to hold the effects digits 57bool setTimeModeFlag = false; // flag for checking if setTimeMode is running 58bool timeSetModeReset = true; // used to reset variables at the first run of timeSetMode function 59byte tempTimeHolder = 0; // hold the time that is displayed currently on setTimeMode 60bool setTimeStageArray [3] = {false}; // array that holds which steps of the time setting are completed 61bool setTimeAm = false; // if am = true, if pm = false - used in 12h set time mode 62 63// Array with the bit-pattern for each tube Grid - the grids are MULTIPLEXED: 1 and 3 VFDs are on 64// together while 2 and 4 VFDs are off and in reverse: 65const byte grids [2] = 66{ 67 B00000101, 68 B00001010, 69}; 70 71// Array with the bit-pattern for each and 7-segment number character: 72const byte symbols [25] = 73{ 74 B01110111, // 0 75 B00100100, // 1 76 B01011101, // 2 77 B01101101, // 3 78 B00101110, // 4 79 B01101011, // 5 80 B01111011, // 6 81 B00100101, // 7 82 B01111111, // 8 83 B01101111, // 9 84 B00000000, // 10 (Blank) 85 B01011000, // 11 (c celsius) 86 B01010011, // 12 (C Celsius) 87 B00001111, // 13 (top half on) 88 B01111000, // 14 (bottom half on) 89 B10000000, // 15 (. dot - used to signal ON) 90 B11111111, // 16 (all segments on) 91 B00001000, // 17 (- dash used to signal OFF) 92 B00100000, // 18 (from 18 to 24 are the cycle effect bit-patterns) 93 B01000000, // 19 94 B00010000, // 20 95 B00000010, // 21 96 B00000001, // 22 97 B00000100, // 23 98 B00100000, // 24 99}; 100 101// DHT11 temperature and humidity sensor: 102#define DHTPIN 7 // pin the sensor is connected to 103DHT dht (DHTPIN, DHT11); 104byte tempFirstDigit = 0; 105byte tempSecondDigit = 0; 106byte tempThirdDigit = 0; 107byte tempBuffer [4]; // array to hold the temp digits 108byte humidityFirstDigit = 0; 109byte humiditySecondDigit = 0; 110byte humidityBuffer [4]; // array to hold the humidity digits 111float originalTemp = 0; // hold the temperature before compensating for electronics heat 112float compensatedTemp = 0; // hold temperature after compensating for electronics 113const float tempCompensation = 1.80; // degrees in c to compensate for electronics heat 114 115// Dots: 116#define DOTS_PIN A1 117#define DOTS_NUM 2 118Adafruit_NeoPixel dots (DOTS_NUM, DOTS_PIN, NEO_RGB + NEO_KHZ800); 119#define AM_LED 12 120#define PM_LED A2 121 122// WS LEDs: 123#define WS_PIN 2 124#define WS_NUM 4 125Adafruit_NeoPixel ws (WS_NUM, WS_PIN, NEO_RGB + NEO_KHZ800); 126byte wsMode = 1; // variable to hold the WS2911 LEDs mode - default is 1 127byte wsModeNum = 5; // variable to hold the number (sum) of WS2911 LEDs modes 128bool wsTransition = false; // true if mode transition is on, false if not 129#define WSTRANSTIME 1800UL // transition duration in milliseconds 130bool wsOff = false; // true if the WS2911 LEDs are off, false if they are on 131bool wsWasOn = false; // true if the LEDs were on, false if not 132bool rainbowEffectTrigger = false; // flag for triggering the rainbow effect 133bool colorWipeEffectTrigger = false; // flag for triggering the color wipe effect 134bool colorWheelEffectTrigger = false; // flag for triggering the colorWheel effect 135int redLedArray [4] = {0}; // array to hold the values of the red WS2911 LEDs 136int greenLedArray [4] = {0}; // array to hold the values of the green WS2911 LEDs 137int blueLedArray [4] = {0}; // array to hold the values of the blue WS2911 LEDs 138unsigned long tempColorArray [4] = {0}; // array to hold the values of rainbow or wheel colors 139 140// LDR Photoresistor: 141#define LDRPIN A3 // analog pin that the LDR photoresistor is connected on the Arduino 142#define VFD_BRIGHT_MAX 0 // full brightness 143#define VFD_BRIGHT_MIN 250 // fully dimmed 144byte vfdBrightness = 120; // startup brightness of VFDs (half brightness) 145#define WS_BRIGHT_MAX 100 // maximum brightness the LEDs will go depending on room light 146#define WS_BRIGHT_MIN 10 // minimum brightness the LEDs will go depending on room light 147byte wsBrightness = 44; // startup brightness of the WS2811 LEDs (half brightness) 148#define DOTS_BRIGHT_MAX 60 // maximum brightness the dots will go depending on room light 149#define DOTS_BRIGHT_MIN 10 // minimum brightness the dots will go depending on room light 150byte dotsBrightness = 24; // startup brightness of the dots (half brightness) 151 152// Buttons: 153MD_KeySwitch button1 (3, LOW); // set button 1 to pin 3 154MD_KeySwitch button2 (4, LOW); // set button 2 to pin 4 155MD_KeySwitch button3 (5, LOW); // set button 3 to pin 5 156MD_KeySwitch button4 (6, LOW); // set button 4 to pin 6 157bool repeatOn = false; // true if repeat button pressed 158 159// Functions with default values declaration: 160void vfdHandler (bool reset = false); 161void displayTime (bool mode12hours = false); 162void colorWipeEffect (bool resetTrigger = false); 163 164/*-------------------------------------------------- SETUP: --------------------------------------------------*/ 165void setup () 166{ 167 // Debug setup: 168#if DEBUG 169 Serial.begin (9600); 170 PRINTS ("\ 171[VFD Clock]"); 172#endif 173 174 // Set Fast PWM frequency on pin 9 [and 10] (for dimming display): 175 TCCR1B = (TCCR1B & 0b11111000) | 0x1; 176 177 // start SPI: 178 SPI.begin (); 179 180 // VFDs setup: 181 pinMode (strobe, OUTPUT); 182 pinMode (Blank, OUTPUT); 183 analogWrite (Blank, 255); // Set vfd brightness to zero at startup 184 185 // DHT11 temperature and humidity sensor: 186 dht.begin (); 187 188 // Dots setup: 189 dots.begin (); // INITIALIZE NeoPixel strip object (REQUIRED) 190 dots.setBrightness (dotsBrightness); // set default brightness 191 dots.clear (); // set all pixel colors to 'off' 192 dots.show (); // send the updated pixel colors to the hardware 193 194 // WS LEDs setup: 195 ws.begin (); // initialize NeoPixel strip object 196 ws.show (); // turn OFF all pixels ASAP 197 ws.setBrightness (wsBrightness); // Set the brightness 198 wsHandler (); 199 200 // AM-PM LEDs setup: 201 pinMode (AM_LED, OUTPUT); 202 pinMode (PM_LED, OUTPUT); 203 digitalWrite (AM_LED, LOW); 204 digitalWrite (PM_LED, LOW); 205 206 // LDR Photoresistor setup: 207 pinMode (LDRPIN, INPUT); 208 209 // Buttons setup: 210 // Keep in mind library restriction: debounce time < Long Press Time < Repeat time 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 (true); 223 button2.enableRepeat (false); 224 button2.enableRepeatResult (false); 225 button2.setDebounceTime (160); 226 button2.setLongPressTime (2000); // set long press time to 2 seconds 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 (180); 234 button3.setDebounceTime (160); 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 245/*------------------------------------------------- LOOP: ----------------------------------------------------*/ 246void loop () 247{ 248 // Run the handlers: 249 vfdHandler (); 250 buttonsHandler (); 251 photoresistorHandler (); 252 253 // Run the color wipe effect if it is on: 254 if (colorWipeEffectTrigger == true) 255 { 256 colorWipeEffect (); 257 } 258 259 // Run the rainbow effect if it is on: 260 if (rainbowEffectTrigger == true) 261 { 262 rainbowEffect (); 263 } 264 265 // Run the color wheel effect if it is on: 266 if (colorWheelEffectTrigger == true) 267 { 268 colorWheelEffect (); 269 } 270} 271/*---------------------------------------------- END OF LOOP -------------------------------------------------*/ 272 273/*------------------------------------------------------------------------------------------------------------*/ 274/* Function for handling what is displayed in the VFD tubes including timing of events and set time modes. 275 When called with reset = true, variables are reset: 276*/ 277void vfdHandler (bool reset = false) 278{ 279 // Local variables declaration: 280 static unsigned long lastTime = 0; // time keeping for time display 281 static unsigned long lastTimeCyrcleEffect = 0; // time keeping for cycle effect 282 static unsigned long lastTimeDashEffect = 0; // time keeping for dash effect 283 static unsigned long lastTimeDotEffect = 0; // time keeping for dot effect 284 static unsigned long startTime = millis (); // time keeping for blinking digits on set time modes 285 static bool dashEffectFirstRun = true; 286 static bool dotEffectFirstRun = true; 287 static bool tempFirstRun = true; // used to read temperature only once per cycle 288 static bool humidityFirstRun = true; // used to read humidity only once per cycle 289 unsigned long DELAY = 4400; // time that the temp and humidity will be displayed 290 static byte effectCounter = 0; // keep track of the stage of the cycle effect 291 292 // Main code: 293 RTC.readTime (); // get the time from the module 294 295 // Reset variables and exit: 296 if (reset == true) 297 { 298 lastTime = millis (); 299 reset = false; 300 tempFirstRun = true; 301 humidityFirstRun = true; 302 digitalWrite (AM_LED, LOW); 303 digitalWrite (PM_LED, LOW); 304 return; 305 } 306 307 // Execute effects: 308 if (vfdCycleEffectOn == true) // dot effect 309 { 310 if (millis () - lastTimeCyrcleEffect < 60UL) // run for X seconds 311 { 312 effectBuffer [0] = 18 + effectCounter; 313 effectBuffer [1] = 18 + effectCounter; 314 effectBuffer [2] = 18 + effectCounter; 315 effectBuffer [3] = 18 + effectCounter; 316 updateDisplay (effectBuffer); 317 } 318 else 319 { 320 lastTimeCyrcleEffect = millis (); 321 effectCounter++; 322 } 323 if (effectCounter == 7) 324 { 325 effectCounter = 0; 326 vfdCycleEffectOn = false; 327 } 328 return; 329 } 330 else if (vfdDashEffectOn == true) // dash effect, only one effect active simultaneously 331 { 332 if (dashEffectFirstRun == true) 333 { 334 lastTimeDashEffect = millis (); 335 dashEffectFirstRun = false; 336 } 337 if (millis () - lastTimeDashEffect < 1000UL) // run for X seconds 338 { 339 effectBuffer [0] = 17; 340 effectBuffer [1] = 17; 341 effectBuffer [2] = 17; 342 effectBuffer [3] = 17; 343 updateDisplay (effectBuffer); 344 } 345 else 346 { 347 vfdDashEffectOn = false; 348 dashEffectFirstRun = true; 349 } 350 return; 351 } 352 else if (vfdDotEffectOn == true) // dot effect, only one effect active simultaneously 353 { 354 if (dotEffectFirstRun == true) 355 { 356 lastTimeDotEffect = millis (); 357 dotEffectFirstRun = false; 358 } 359 if (millis () - lastTimeDotEffect < 1000UL) // run for X seconds 360 { 361 effectBuffer [0] = 15; 362 effectBuffer [1] = 15; 363 effectBuffer [2] = 15; 364 effectBuffer [3] = 15; 365 updateDisplay (effectBuffer); 366 } 367 else 368 { 369 vfdDotEffectOn = false; 370 dotEffectFirstRun = true; 371 } 372 return; 373 } 374 375 switch (vfdDisplayMode) 376 { 377 378 case 0: // -------------------------------- 24h time display: -------------------------------- 379 if (tempDisplayOn == false) // display only time 380 { 381 displayTime (); 382 } 383 else // display temperature and humidity at DELAY intervals 384 { 385 if (RTC.s > 10 && RTC.s <= 10 + (DELAY / 1000) * 2 || RTC.s > 30 && RTC.s <= 30 + (DELAY / 1000) * 2) 386 { 387 if (millis () - lastTime < DELAY) // run for delay seconds 388 { 389 if (tempFirstRun == true) 390 { 391 tempFirstRun = false; 392 displayTemp (true); 393 vfdCycleEffectOn = true; 394 } 395 else 396 { 397 displayTemp (false); 398 } 399 } 400 else if (millis () - lastTime < DELAY * 2) 401 { 402 if (humidityFirstRun == true) 403 { 404 humidityFirstRun = false; 405 displayHumidity (true); 406 vfdCycleEffectOn = true; 407 } 408 else 409 { 410 displayHumidity (false); 411 } 412 } 413 else 414 { 415 lastTime = millis (); 416 tempFirstRun = true; 417 humidityFirstRun = true; 418 } 419 } 420 else 421 { 422 displayTime (); 423 } 424 } 425 break; 426 427 case 1: // -------------------------------- 12h time display: -------------------------------- 428 if (tempDisplayOn == false) // just display time 429 { 430 displayTime (true); 431 } 432 else // display temperature and humidity at DELAY intervals 433 { 434 if (RTC.s > 10 && RTC.s <= 10 + (DELAY / 1000) * 2 || RTC.s > 40 && RTC.s <= 40 + (DELAY / 1000) * 2) 435 { 436 if (millis () - lastTime < DELAY) // run for DELAY seconds 437 { 438 if (tempFirstRun == true) 439 { 440 tempFirstRun = false; 441 displayTemp (true); 442 vfdCycleEffectOn = true; 443 } 444 else 445 { 446 displayTemp (false); 447 } 448 } 449 else if (millis () - lastTime < DELAY * 2) 450 { 451 if (humidityFirstRun == true) 452 { 453 humidityFirstRun = false; 454 displayHumidity (true); 455 vfdCycleEffectOn = true; 456 } 457 else 458 { 459 displayHumidity (false); 460 } 461 } 462 else 463 { 464 lastTime = millis (); 465 tempFirstRun = true; 466 humidityFirstRun = true; 467 } 468 } 469 else 470 { 471 displayTime (true); 472 } 473 } 474 break; 475 476 case 2: // ---------------------- Temperature and humidity only display mode: ------------------------ 477 if (millis () - lastTime < DELAY) // run for DELAY seconds 478 { 479 if (tempFirstRun == true) 480 { 481 tempFirstRun = false; 482 displayTemp (true); 483 vfdCycleEffectOn = true; 484 } 485 else 486 { 487 displayTemp (false); 488 } 489 } 490 else if (millis () - lastTime < DELAY * 2) 491 { 492 if (humidityFirstRun == true) 493 { 494 humidityFirstRun = false; 495 displayHumidity (true); 496 vfdCycleEffectOn = true; 497 } 498 else 499 { 500 displayHumidity (false); 501 } 502 } 503 else 504 { 505 lastTime = millis (); 506 tempFirstRun = true; 507 humidityFirstRun = true; 508 } 509 break; 510 511 case 3: // ---------------------------- Display temp and humidity once: ---------------------------- 512 if (millis () - lastTime < DELAY + 1000UL) // run for DELAY + 1 seconds 513 { 514 if (tempFirstRun == true) 515 { 516 tempFirstRun = false; 517 displayTemp (true); 518 vfdCycleEffectOn = true; 519 } 520 else 521 { 522 displayTemp (false); 523 } 524 } 525 else if (millis () - lastTime < (DELAY + 1000UL) * 2) 526 { 527 if (humidityFirstRun == true) 528 { 529 humidityFirstRun = false; 530 displayHumidity (true); 531 vfdCycleEffectOn = true; 532 } 533 else 534 { 535 displayHumidity (false); 536 } 537 } 538 else 539 { 540 tempFirstRun = true; 541 humidityFirstRun = true; 542 // to prevent showing temperature two times in a row, skip showing it if it is to close to 543 // previous display: 544 if (RTC.s > 6 && RTC.s <= 12 + ((DELAY + 1000) / 1000) * 2 545 || RTC.s > 36 && RTC.s <= 42 + ((DELAY + 1000) / 1000) * 2) 546 { 547 if (previousDisplayMode == 0) 548 { 549 displayTime (); 550 } 551 else 552 { 553 displayTime (true); 554 } 555 } 556 else 557 { 558 vfdDisplayMode = previousDisplayMode; 559 } 560 } 561 break; 562 case 4: // -------------------------------- 24h set time mode: -------------------------------- 563 if (timeSetModeReset == true) // check if it's the first run of set time 564 { 565 timeSetModeReset = false; 566 for (int i = 0; i < 3; i++) // reset array 567 { 568 setTimeStageArray [i] = false; 569 } 570 tempTimeHolder = RTC.h; // pass current time to temp variable for manipulation with buttons 571 dots.clear (); // set off dots 572 dots.show (); 573 } 574 else if (setTimeStageArray [0] == false) // blink hours except when on repeat 575 { 576 // Hours: 577 if (repeatOn == false) 578 { 579 separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit); 580 if (millis () - startTime < 500UL) 581 { 582 timeBuffer [0] = hoursFirstDigit; 583 timeBuffer [1] = hoursSecondDigit; 584 } 585 else if (millis () - startTime < 1000UL) 586 { 587 timeBuffer [0] = 10; // 10 = blank 588 timeBuffer [1] = 10; // 10 = blank 589 } 590 else 591 { 592 startTime = millis (); 593 } 594 } 595 else // on repeat button press don't blink 596 { 597 separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit); 598 timeBuffer [0] = hoursFirstDigit; 599 timeBuffer [1] = hoursSecondDigit; 600 repeatOn = false; 601 startTime = millis (); 602 } 603 604 // Minutes: 605 separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit); 606 timeBuffer [2] = minutesFirstDigit; 607 timeBuffer [3] = minutesSecondDigit; 608 } 609 else if (setTimeStageArray [1] == false) // if hours set, blink minutes except on repeat 610 { 611 // Hours: 612 separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit); 613 timeBuffer [0] = hoursFirstDigit; 614 timeBuffer [1] = hoursSecondDigit; 615 616 // Minutes: 617 if (repeatOn == false) 618 { 619 separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit); 620 if (millis () - startTime < 500UL) 621 { 622 timeBuffer [2] = minutesFirstDigit; 623 timeBuffer [3] = minutesSecondDigit; 624 } 625 else if (millis () - startTime < 1000UL) 626 { 627 timeBuffer [2] = 10; // 10 = blank 628 timeBuffer [3] = 10; // 10 = blank 629 } 630 else 631 { 632 startTime = millis (); 633 } 634 } 635 else // on repeat button press don't blink 636 { 637 separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit); 638 timeBuffer [2] = minutesFirstDigit; 639 timeBuffer [3] = minutesSecondDigit; 640 repeatOn = false; 641 startTime = millis (); 642 } 643 } 644 updateDisplay (timeBuffer); // update the display 645 break; 646 case 5: // -------------------------------- 12h set time mode: -------------------------------- 647 if (timeSetModeReset == true) // check if it's the first run of set time 648 { 649 timeSetModeReset = false; 650 for (int i = 0; i < 3; i++) // reset array 651 { 652 setTimeStageArray [i] = false; 653 } 654 // Keep the status of the am/pm LEDs for consistency when setting them and translate the 655 // time from 24h to 12h to display correctly: 656 if (RTC.h == 0) 657 { 658 tempTimeHolder = 12; // pass current time to temp variable for manipulation with buttons 659 setTimeAm = true; 660 } 661 else if (RTC.h < 12) 662 { 663 tempTimeHolder = RTC.h; // pass current time to temp variable for manipulation with buttons 664 setTimeAm = true; 665 } 666 else if (RTC.h == 12) 667 { 668 tempTimeHolder = RTC.h; // pass current time to temp variable for manipulation with buttons 669 setTimeAm = false; 670 } 671 else 672 { 673 tempTimeHolder = RTC.h - 12; // pass current time to temp variable for manipulation with buttons 674 setTimeAm = false; 675 } 676 dots.clear (); // turn off dots 677 dots.show (); 678 } 679 else if (setTimeStageArray [0] == false) // blink hours except when on repeat 680 { 681 // Hours: 682 if (repeatOn == false) 683 { 684 separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit); 685 if (millis () - startTime < 500UL) 686 { 687 if (hoursFirstDigit == 0) // don't show zero 688 { 689 timeBuffer [0] = 10; // 10 = blank 690 } 691 else 692 { 693 timeBuffer [0] = hoursFirstDigit; 694 } 695 timeBuffer [1] = hoursSecondDigit; 696 } 697 else if (millis () - startTime < 1000UL) 698 { 699 timeBuffer [0] = 10; // 10 = blank 700 timeBuffer [1] = 10; // 10 = blank 701 } 702 else 703 { 704 startTime = millis (); 705 } 706 } 707 else // on repeat button press don't blink 708 { 709 separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit); 710 if (hoursFirstDigit == 0) // don't show zero 711 { 712 timeBuffer [0] = 10; // 10 = blank 713 } 714 else 715 { 716 timeBuffer [0] = hoursFirstDigit; 717 } 718 timeBuffer [1] = hoursSecondDigit; 719 repeatOn = false; 720 startTime = millis (); 721 } 722 723 // Minutes: 724 separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit); 725 timeBuffer [2] = minutesFirstDigit; 726 timeBuffer [3] = minutesSecondDigit; 727 } 728 else if (setTimeStageArray [1] == false) // if hours set, blink minutes except on repeat 729 { 730 // Hours: 731 if (RTC.h == 0) // convert 24h to 12h for displaying properly 732 { 733 separateDoubleDigits (12, hoursFirstDigit, hoursSecondDigit); 734 } 735 else if (RTC.h > 12) 736 { 737 separateDoubleDigits (RTC.h - 12, hoursFirstDigit, hoursSecondDigit); 738 } 739 else 740 { 741 separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit); 742 } 743 744 if (hoursFirstDigit == 0) // don't show zero 745 { 746 timeBuffer [0] = 10; // 10 = blank 747 } 748 else 749 { 750 timeBuffer [0] = hoursFirstDigit; 751 } 752 timeBuffer [1] = hoursSecondDigit; 753 754 // Minutes: 755 if (repeatOn == false) 756 { 757 separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit); 758 if (millis () - startTime < 500UL) 759 { 760 timeBuffer [2] = minutesFirstDigit; 761 timeBuffer [3] = minutesSecondDigit; 762 } 763 else if (millis () - startTime < 1000UL) 764 { 765 timeBuffer [2] = 10; // 10 = blank 766 timeBuffer [3] = 10; // 10 = blank 767 } 768 else 769 { 770 startTime = millis (); 771 } 772 } 773 else // if on repeat button press don't blink 774 { 775 separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit); 776 timeBuffer [2] = minutesFirstDigit; 777 timeBuffer [3] = minutesSecondDigit; 778 repeatOn = false; 779 startTime = millis (); 780 } 781 } 782 else if (setTimeStageArray [2] == false) // if minutes set, blink AM/PM 783 { 784 // Hours: 785 if (RTC.h == 0) // convert 24h to 12h for displaying properly 786 { 787 separateDoubleDigits (12, hoursFirstDigit, hoursSecondDigit); 788 } 789 else if (RTC.h > 12) 790 { 791 separateDoubleDigits (RTC.h - 12, hoursFirstDigit, hoursSecondDigit); 792 } 793 else 794 { 795 separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit); 796 } 797 798 if (hoursFirstDigit == 0) // don't show zero 799 { 800 timeBuffer [0] = 10; // 10 = blank 801 } 802 else 803 { 804 timeBuffer [0] = hoursFirstDigit; 805 } 806 timeBuffer [1] = hoursSecondDigit; 807 808 // Minutes: 809 separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit); 810 timeBuffer [2] = minutesFirstDigit; 811 timeBuffer [3] = minutesSecondDigit; 812 813 // AM/PM LEDs: 814 if (millis () - startTime < 500UL) 815 { 816 if (setTimeAm == true) 817 { 818 digitalWrite (AM_LED, HIGH); 819 digitalWrite (PM_LED, LOW); 820 } 821 else 822 { 823 digitalWrite (AM_LED, LOW); 824 digitalWrite (PM_LED, HIGH); 825 } 826 } 827 else if (millis () - startTime < 1000UL) 828 { 829 830 digitalWrite (AM_LED, LOW); 831 digitalWrite (PM_LED, LOW); 832 } 833 else 834 { 835 startTime = millis (); 836 } 837 } 838 updateDisplay (timeBuffer); // update the display 839 break; 840 default: 841 break; 842 } 843} 844 845/*------------------------------------------------------------------------------------------------------------*/ 846/* Function for displaing the time on the VFD tubes and blinking the dots. When called with true, the time 847 is displayed with 12 hours: 848*/ 849void displayTime (bool mode12hours = false) 850{ 851 // Local variables declaration: 852 853 // Main code: 854 // Hours: 855 currentHours = RTC.h; 856 if (mode12hours == false) 857 { 858 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 859 timeBuffer [0] = hoursFirstDigit; 860 timeBuffer [1] = hoursSecondDigit; 861 } 862 else 863 { 864 if (currentHours < 12) 865 { 866 switch (currentHours) 867 { 868 case 0: 869 currentHours = 12; 870 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 871 timeBuffer [0] = hoursFirstDigit; 872 timeBuffer [1] = hoursSecondDigit; 873 break; 874 case 1: 875 case 2: 876 case 3: 877 case 4: 878 case 5: 879 case 6: 880 case 7: 881 case 8: 882 case 9: 883 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 884 timeBuffer [0] = 10; // blank 885 timeBuffer [1] = hoursSecondDigit; 886 break; 887 case 10: 888 case 11: 889 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 890 timeBuffer [0] = hoursFirstDigit; 891 timeBuffer [1] = hoursSecondDigit; 892 break; 893 default: 894 break; 895 } 896 digitalWrite (AM_LED, HIGH); 897 digitalWrite (PM_LED, LOW); 898 } 899 else 900 { 901 switch (currentHours) 902 { 903 case 12: 904 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 905 timeBuffer [0] = hoursFirstDigit; 906 timeBuffer [1] = hoursSecondDigit; 907 break; 908 case 13: 909 case 14: 910 case 15: 911 case 16: 912 case 17: 913 case 18: 914 case 19: 915 case 20: 916 case 21: 917 currentHours = currentHours - 12; 918 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 919 timeBuffer [0] = 10; // blank 920 timeBuffer [1] = hoursSecondDigit; 921 break; 922 case 22: 923 case 23: 924 currentHours = currentHours - 12; 925 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 926 timeBuffer [0] = hoursFirstDigit; 927 timeBuffer [1] = hoursSecondDigit; 928 break; 929 default: 930 break; 931 } 932 digitalWrite (AM_LED, LOW); 933 digitalWrite (PM_LED, HIGH); 934 } 935 } 936 937 // Minutes: 938 separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit); 939 timeBuffer [2] = minutesFirstDigit; 940 timeBuffer [3] = minutesSecondDigit; 941 942 // Blinking dots every second: 943 currentSeconds = RTC.s; 944 if (currentSeconds % 2 == 0) // if the seconds are even turn off dots 945 { 946 dots.clear (); // Set all pixel colors to 'off' 947 dots.show (); // Send the updated pixel colors to the hardware 948 } 949 else // if the seconds are even turn on dots 950 { 951 dots.setPixelColor (0, 28, 200, 52); 952 dots.setPixelColor (1, 28, 200, 52); 953 dots.show (); // Send the updated pixel colors to the hardware 954 } 955 updateDisplay (timeBuffer); 956} 957 958/*------------------------------------------------------------------------------------------------------------*/ 959/* Function for displaying the temperature on the VFDs. When called with firstRun true the reading of the 960 temperature and the compensation happens: 961*/ 962void displayTemp (bool firstRun) 963{ 964 // Local variables declaration: 965 int intTemp = 0; 966 static unsigned long lastTime = 0; 967 968 // Main code: 969 if (firstRun == true) // run every DELAY seconds 970 { 971 digitalWrite (AM_LED, LOW); 972 digitalWrite (PM_LED, LOW); 973 originalTemp = dht.readTemperature (); 974 compensatedTemp = originalTemp - tempCompensation; 975 intTemp = compensatedTemp * 10; 976 separateThreeDigits (intTemp, tempFirstDigit, tempSecondDigit, tempThirdDigit); 977 tempBuffer [0] = tempFirstDigit; 978 tempBuffer [1] = tempSecondDigit; 979 tempBuffer [2] = tempThirdDigit; 980 tempBuffer [3] = 11; // c symbol 981 dots.setPixelColor (0, 28, 205, 52); 982 dots.setPixelColor (1, 0, 0, 0); 983 dots.show(); // send the updated pixel colors to the hardware 984 return; // skip first display update for effects to end 985 } 986 updateDisplay (tempBuffer); 987} 988 989/*------------------------------------------------------------------------------------------------------------*/ 990/* Function for displaying on the VFDs. When called with firstRun true the reading of the 991 temperature and the compensation happens: 992*/ 993void displayHumidity (bool firstRun) 994{ 995 // Local variables declaration: 996 static unsigned long lastTime = 0; 997 float dewPointTemp = 0; 998 int originalHumidity = 0; 999 int compensatedHumidity = 0; 1000 1001 // Main code: 1002 if (firstRun == true) // run every seconds 1003 { 1004 digitalWrite (AM_LED, LOW); 1005 digitalWrite (PM_LED, LOW); 1006 originalHumidity = dht.readHumidity (); 1007 dewPointTemp = (originalTemp - (14.55 + 0.114 * originalTemp) * (1 - (0.01 * originalHumidity)) 1008 - pow (((2.5 + 0.007 * originalTemp) * (1 - (0.01 * originalHumidity))), 3) 1009 - (15.9 + 0.117 * originalTemp) * pow ((1 - (0.01 * originalHumidity)), 14)); 1010 compensatedHumidity = 100 * (exp((17.625 * dewPointTemp) / (243.04 + dewPointTemp)) 1011 / exp ((17.625 * compensatedTemp) / (243.04 + compensatedTemp))); 1012 separateDoubleDigits (compensatedHumidity, humidityFirstDigit, humiditySecondDigit); 1013 humidityBuffer [0] = humidityFirstDigit; 1014 humidityBuffer [1] = humiditySecondDigit; 1015 humidityBuffer [2] = 13; // top half on 1016 humidityBuffer [3] = 14; // bottom half on 1017 dots.clear (); 1018 dots.show (); // send the updated pixel colors to the hardware 1019 return; // skip first display update for effects to end 1020 } 1021 updateDisplay (humidityBuffer); 1022} 1023 1024/*------------------------------------------------------------------------------------------------------------*/ 1025/* Function for separating the double digits that hours and minutes come from the RTC module, 1026 to single digits for writing on the VFD tubes: 1027*/ 1028void separateDoubleDigits (byte doubleDigit, byte& firstDigit, byte& secondDigit) 1029{ 1030 firstDigit = doubleDigit / 10; 1031 secondDigit = doubleDigit % 10; 1032} 1033 1034/*------------------------------------------------------------------------------------------------------------*/ 1035/* Function for separating a triple digit to single digits for writing on the VFD tubes: 1036*/ 1037void separateThreeDigits (unsigned int threeDigit, byte& firstDigit, byte& secondDigit, byte& thirdDigit) 1038{ 1039 firstDigit = (threeDigit / 100) % 10; 1040 secondDigit = (threeDigit / 10) % 10; 1041 thirdDigit = threeDigit % 10; 1042} 1043 1044/*------------------------------------------------------------------------------------------------------------*/ 1045/* Function for managing the multiplexing of the grids and displaying the values from the buffers on the VFDs: 1046*/ 1047void updateDisplay (byte inputArray []) 1048{ 1049 static int grid = 0; // hold which grid is to be updated 1050 1051 analogWrite (Blank, 255); // Blank display while updating registers 1052 show (inputArray, grid); 1053 analogWrite (Blank, vfdBrightness); // Set display brightness according to LDR value. 1054 grid++; // Advance to the next grid (ie next tube) next time around. 1055 if (grid > (NUM_DIGITS - 1)) // Reset grid counter after all grids have been updated 1056 { 1057 grid = 0; 1058 } 1059} 1060 1061/*------------------------------------------------------------------------------------------------------------*/ 1062/* Function for actually sending the values of the display buffers to the VFDs chip for displaying using SPI 1063 communication: 1064*/ 1065void show (byte theDisplay [], byte activeGrid) 1066{ 1067 static byte count = 0; 1068 digitalWrite (strobe, LOW); 1069 SPI.transfer (grids [activeGrid]); 1070 SPI.transfer (symbols [theDisplay [count]]); 1071 SPI.transfer (symbols [theDisplay [count + 2]]); 1072 digitalWrite (strobe, HIGH); 1073 count = count + 1; 1074 if (count >= 2) 1075 { 1076 count = 0; 1077 } 1078} 1079 1080/*------------------------------------------------------------------------------------------------------------*/ 1081 1082/*------------------------------------------------------------------------------------------------------------*/ 1083/* Function for managing the WS2811 RGB LEDs color modes: 1084 */ 1085void wsHandler () 1086{ 1087 switch (wsMode) 1088 { 1089 case 1: // red color mode 1090 rainbowEffectTrigger = false; 1091 colorWipeEffectTrigger = true; 1092 colorWheelEffectTrigger = false; 1093 for (int i = 0; i < 4; i++) // populate the arrays with the color red 1094 { 1095 redLedArray [i] = 255; 1096 greenLedArray [i] = 0; 1097 blueLedArray [i] = 0; 1098 } 1099 break; 1100 case 2: // green color mode 1101 rainbowEffectTrigger = false; 1102 colorWipeEffectTrigger = true; 1103 colorWheelEffectTrigger = false; 1104 for (int i = 0; i < 4; i++) // populate the arrays with the color green 1105 { 1106 redLedArray [i] = 0; 1107 greenLedArray [i] = 255; 1108 blueLedArray [i] = 0; 1109 } 1110 break; 1111 case 3: // blue color mode 1112 rainbowEffectTrigger = false; 1113 colorWipeEffectTrigger = true; 1114 colorWheelEffectTrigger = false; 1115 for (int i = 0; i < 4; i++) // populate the arrays with the color blue 1116 { 1117 redLedArray [i] = 0; 1118 greenLedArray [i] = 0; 1119 blueLedArray [i] = 255; 1120 } 1121 break; 1122 case 4: // colorWheel mode 1123 rainbowEffectTrigger = false; 1124 colorWheelEffectTrigger = true; 1125 break; 1126 case 5: // rainbow mode 1127 rainbowEffectTrigger = true; 1128 colorWheelEffectTrigger = false; 1129 break; 1130 default: 1131 return; 1132 } 1133} 1134 1135/*------------------------------------------------------------------------------------------------------------*/ 1136/* Function for running the color wipe effect. When the resetTrigger parameter is set to true, the 1137 * counter starts again from the first (0) LED (used when pressing buttons quickly to ensure that the 1138 * new color is applied to all 4 LEDs every time). Default is false which allows the effect to 1139 * increment from LED to next LED: 1140 */ 1141void colorWipeEffect (bool resetTrigger = false) 1142{ 1143 // Local variables declaration: 1144 static unsigned long lastTime = millis (); 1145 static byte counter = 0; 1146 1147 // Main code: 1148 if (resetTrigger == true) 1149 { 1150 counter = 0; 1151 return; 1152 } 1153 if (millis () - lastTime > (unsigned long) WSTRANSTIME / 18) // time between every step - set it 1154 { // to be always done before 1155 lastTime = millis (); // wsTranstionDisplay is completed 1156 if (counter < 4) // during every step set the color to one RGB LED 1157 { 1158 ws.setPixelColor (counter, ws.Color (redLedArray [counter], greenLedArray [counter], 1159 blueLedArray [counter])); 1160 ws.show(); 1161 counter++; 1162 } 1163 else 1164 { 1165 colorWipeEffectTrigger = false; 1166 counter = 0; 1167 } 1168 } 1169} 1170 1171/*------------------------------------------------------------------------------------------------------*/ 1172/* Function for running the rainbow WS effect (based on code from strandtest neopixel library example - 1173 * adjusted for real time execution): 1174 */ 1175void rainbowEffect () 1176{ 1177 // Local variables declaration: 1178 static unsigned long lastTime = millis (); 1179 static long firstPixelHue = 0; 1180 static int pixelHue = 0; 1181 1182 // Main code: 1183 // Hue of first pixel runs 5 complete loops through the color wheel. 1184 // Color wheel has a range of 65536 but it's OK if we roll over, so 1185 // just count from 0 to 5*65536. Adding 256 to firstPixelHue each time 1186 // means we'll make 5*65536/256 = 1280 passes before starting over: 1187 if (firstPixelHue < 5 * 65536) 1188 { 1189 if (millis () - lastTime > 26UL) // change colors every 26ms 1190 { 1191 lastTime = millis (); 1192 for (int i = 0; i < ws.numPixels (); i++) 1193 { 1194 // For each pixel in strip... 1195 // Offset pixel hue by an amount to make one full revolution of the 1196 // color wheel (range of 65536) along the length of the strip 1197 // (ws.numPixels() steps): 1198 pixelHue = firstPixelHue + (i * 65536L / ws.numPixels()); 1199 // ws.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or 1200 // optionally add saturation and value (brightness) (each 0 to 255). 1201 // Here we're using just the single-argument hue variant. The result 1202 // is passed through ws.gamma32() to provide 'truer' colors 1203 // before assigning to each pixel: 1204 ws.setPixelColor (i, ws.gamma32 (ws.ColorHSV (pixelHue))); 1205 } 1206 ws.show (); // Update strip with new contents 1207 firstPixelHue += 256; 1208 } 1209 } 1210 else 1211 { 1212 firstPixelHue = 0; 1213 } 1214} 1215 1216/*------------------------------------------------------------------------------------------------------------*/ 1217/* Function for running the colorWheel effect (based on code from strandtest_Wheel neopixel library 1218 * example - adjusted for real time execution): 1219 */ 1220void colorWheelEffect () 1221{ 1222 // Local variables declaration: 1223 static unsigned long lastTime = millis (); 1224 static unsigned int counter = 0; 1225 unsigned int i = 0; 1226 1227 // Main code: 1228 if (counter < 256) 1229 { 1230 if (millis () - lastTime > 50UL) // change colors every 50ms 1231 { 1232 lastTime = millis (); 1233 for (i= 0; i < ws.numPixels (); i++) 1234 { 1235 ws.setPixelColor (i, WheelColors ((i+counter) & 255)); 1236 } 1237 ws.show (); 1238 counter++; 1239 } 1240 } 1241 else 1242 { 1243 counter = 0; 1244 } 1245} 1246 1247/*------------------------------------------------------------------------------------------------------------*/ 1248/* Function for calculating and returning the colors to the colorWheelEffect function. Input a value 1249 * 0 to 255 to get a color value. The colors are a transition r - g - b - back to r (code from 1250 * strandtest_Wheel neopixel library example - adjusted for real time execution): 1251 */ 1252unsigned long WheelColors (byte WheelPos) 1253{ 1254 WheelPos = 255 - WheelPos; 1255 if (WheelPos < 85) 1256 { 1257 return ws.Color (255 - WheelPos * 3, 0, WheelPos * 3); 1258 } 1259 if (WheelPos < 170) 1260 { 1261 WheelPos -= 85; 1262 return ws.Color (0, WheelPos * 3, 255 - WheelPos * 3); 1263 } 1264 WheelPos -= 170; 1265 return ws.Color (WheelPos * 3, 255 - WheelPos * 3, 0); 1266} 1267 1268/*------------------------------------------------------------------------------------------------------------*/ 1269 1270/*------------------------------------------------------------------------------------------------------------*/ 1271/* Function for handling the photoresistor - read the light in the room and adjust the WS2811 LEDs 1272 and the VFDs brightness accordingly: 1273*/ 1274void photoresistorHandler () 1275{ 1276 // Local variables declaration: 1277 // WS2811 LEDs brightness part: 1278 static unsigned int count = 0; 1279 static unsigned long lastTime = millis (); 1280 static unsigned int sum = 0; 1281 unsigned int lightMedian = 0; 1282 int countReset = 10; // how many counts (seconds) it takes before changing the brightness 1283 1284 // Main code: 1285 // Check the values of the light in the room once every seconds, count the median light and after 1286 // countReset seconds set the new brightness to VFDs and LEDs: 1287 if (millis () - lastTime > 1000UL) // check the value of the photoresistor every second 1288 { 1289 lastTime = millis (); 1290 count++; 1291 sum = analogRead (LDRPIN) + sum; 1292 lightMedian = sum / count; 1293 } 1294 if (count == countReset) 1295 { 1296 // Set new brightness to backlight LEDs: 1297 wsBrightness = map (lightMedian, 0, 1023, WS_BRIGHT_MIN, WS_BRIGHT_MAX); 1298 ws.setBrightness (wsBrightness); 1299 ws.show (); 1300 // Set new brightness to dot LEDs: 1301 dotsBrightness = map (lightMedian, 0, 1023, DOTS_BRIGHT_MIN, DOTS_BRIGHT_MAX); 1302 dots.setBrightness (dotsBrightness); 1303 dots.show (); 1304 // Set new brightness to VFD tybes part: 1305 vfdBrightness = map (lightMedian, 0, 1023, VFD_BRIGHT_MIN, VFD_BRIGHT_MAX); 1306 count = 0; 1307 sum = 0; 1308 } 1309} 1310/*------------------------------------------------------------------------------------------------------------*/ 1311 1312/*------------------------------------------------------------------------------------------------------------*/ 1313/* Function to handle the button presses: 1314*/ 1315void buttonsHandler () 1316{ 1317 // --------------------------------------------- normal button mode: ---------------------------------------- 1318 if (setTimeModeFlag == false) 1319 { 1320 // Button 1 (normal mode): 1321 if (button1.read () == MD_KeySwitch::KS_PRESS) // switch between 12hour and 24hour modes 1322 { 1323 if (vfdDisplayMode == 2) 1324 { 1325 vfdDisplayMode = previousDisplayMode; // go to mode before entering mode 2 (12h or 24h) 1326 vfdHandler (true); 1327 vfdDashEffectOn = true; 1328 } 1329 else if (vfdDisplayMode == 1) 1330 { 1331 vfdDisplayMode = 0; 1332 vfdHandler (true); 1333 } 1334 else if (vfdDisplayMode == 0) 1335 { 1336 vfdDisplayMode = 1; 1337 vfdHandler (true); 1338 } 1339 PRINTS ("\ 1340Button 1 pressed."); 1341 } 1342 if (button1.read () == MD_KeySwitch::KS_LONGPRESS) // enter set time mode 1343 { 1344 if (vfdDisplayMode == 0) // 24h set time mode 1345 { 1346 vfdDisplayMode = 4; 1347 setTimeModeFlag = true; 1348 } 1349 else if (vfdDisplayMode == 1) // 12h set time mode 1350 { 1351 vfdDisplayMode = 5; 1352 setTimeModeFlag = true; 1353 } 1354 // Disable button 2 long press in order to register repeat presses in set time modes (MD_KeySwitch 1355 // library restriction): 1356 button2.enableLongPress (false); 1357 button2.enableRepeat (true); 1358 button2.enableRepeatResult (true); 1359 button2.setRepeatTime (180); 1360 button2.setLongPressTime (170); // because it needs to be smaller that reapeat time 1361 PRINTS ("\ 1362Button 1 long pressed."); 1363 } 1364 1365 // Button 2 (normal mode): 1366 if (button2.read () == MD_KeySwitch::KS_PRESS) // turn on and off temp & humidity periodic display 1367 { 1368 if (vfdDisplayMode == 2) 1369 { 1370 vfdDisplayMode = previousDisplayMode; // go to mode before entering mode 2 (12h or 24h) 1371 vfdDashEffectOn = true; 1372 return; 1373 } 1374 if (tempDisplayOn == false) 1375 { 1376 tempDisplayOn = true; 1377 vfdHandler (true); 1378 vfdDotEffectOn = true; 1379 previousDisplayMode = vfdDisplayMode; 1380 vfdDisplayMode = 3; 1381 } 1382 else 1383 { 1384 tempDisplayOn = false; 1385 vfdDisplayMode = previousDisplayMode; 1386 vfdDashEffectOn = true; 1387 } 1388 PRINTS ("\ 1389Button 2 pressed."); 1390 } 1391 if (button2.read () == MD_KeySwitch::KS_LONGPRESS) // go to mode 2 (temp & humidity only) on longpress 1392 { 1393 previousDisplayMode = vfdDisplayMode; // keep mode before entering mode 2 (12h or 24h) 1394 vfdDisplayMode = 2; 1395 vfdDotEffectOn = true; 1396 PRINTS ("\ 1397Button 2 long pressed."); 1398 } 1399 1400 // Button 3 (normal mode): 1401 if (button3.read () == MD_KeySwitch::KS_PRESS) // go to next ws LEDs mode 1402 { 1403 if (wsMode < wsModeNum) 1404 { 1405 wsMode++; 1406 } 1407 else if (wsMode == wsModeNum) 1408 { 1409 wsMode = 1; 1410 } 1411 wsTransition = true; 1412 wsHandler (); 1413 if (wsMode != 4 && wsMode != 5) // in modes 4 and 5 wipe effect is off so no reset needed 1414 { 1415 colorWipeEffect (true); // run once to reset the wipe effect 1416 } 1417 PRINTS ("\ 1418Button 3 pressed."); 1419 } 1420 1421 // Button 4 (normal mode): 1422 if (button4.read () == MD_KeySwitch::KS_PRESS) // turn WS LEDs on or off 1423 { 1424 if (wsOff == true) 1425 { 1426 wsOff = false; 1427 if (wsMode != 4 && wsMode != 5) // in modes 4 and 5 wipe effect is off so no reset needed 1428 { 1429 colorWipeEffect (true); // run once to reset the wipe effect 1430 } 1431 wsHandler (); 1432 } 1433 else if (wsOff == false) 1434 { 1435 wsOff = true; 1436 rainbowEffectTrigger = false; 1437 colorWipeEffectTrigger = false; 1438 colorWheelEffectTrigger = false; 1439 ws.clear (); 1440 ws.show (); 1441 } 1442 } 1443 } 1444 else // ------------------------------------- set time button mode: ----------------------------------------- 1445 { 1446 // Button 1 (set time mode): 1447 if (button1.read () == MD_KeySwitch::KS_PRESS) // save temp time variable that was set 1448 { 1449 if (setTimeStageArray [0] == false) 1450 { 1451 if (vfdDisplayMode == 4) // on 24h mode save the time 1452 { 1453 RTC.h = tempTimeHolder; 1454 RTC.writeTime (); // save hours 1455 } 1456 if (vfdDisplayMode == 5) // on 12h mode time needs conversion before saving 1457 { 1458 if (setTimeAm == true) 1459 { 1460 if (tempTimeHolder == 12) 1461 { 1462 RTC.h = 0; // translate to 24h the state of am or pm 1463 } 1464 else 1465 { 1466 RTC.h = tempTimeHolder; 1467 } 1468 } 1469 else 1470 { 1471 if (tempTimeHolder < 12) 1472 { 1473 RTC.h = tempTimeHolder + 12; // translate to 24h the state of am or pm 1474 } 1475 else 1476 { 1477 RTC.h = tempTimeHolder; 1478 } 1479 } 1480 RTC.writeTime (); 1481 } 1482 setTimeStageArray [0] = true; 1483 tempTimeHolder = RTC.m; // pass current minutes to temp time variable for manipulation with buttons 1484 } 1485 else if (setTimeStageArray [1] == false) // save minutes that were set 1486 { 1487 RTC.m = tempTimeHolder; 1488 RTC.s = 0; // seconds always set to 0 when setting minutes 1489 RTC.writeTime (); // save minutes 1490 setTimeStageArray [1] = true; 1491 if (vfdDisplayMode == 4) // exit back to 24h mode 1492 { 1493 vfdDisplayMode = 0; 1494 tempTimeHolder = 0; 1495 setTimeModeFlag = false; 1496 timeSetModeReset = true; 1497 vfdHandler (true); 1498 vfdDotEffectOn = true; 1499 // Enable button 2 long press in order to register long presses in normal modes (MD_KeySwitch 1500 // library restriction): 1501 button2.enableLongPress (true); 1502 button2.enableRepeat (false); 1503 button2.enableRepeatResult (false); 1504 button2.setLongPressTime (2000); 1505 } 1506 } 1507 else if (setTimeStageArray [2] == false) // save AM/PM and exit back to 12h mode 1508 { 1509 if (setTimeAm == true) 1510 { 1511 if (RTC.h == 12) 1512 { 1513 RTC.h = 0; // translate to 24h the state of am or pm 1514 RTC.writeTime (); 1515 } 1516 vfdDisplayMode = 1; 1517 tempTimeHolder = 0; 1518 setTimeModeFlag = false; 1519 timeSetModeReset = true; 1520 vfdHandler (true); 1521 vfdDotEffectOn = true; 1522 } 1523 else 1524 { 1525 if (RTC.h < 12) 1526 { 1527 RTC.h = RTC.h + 12; // translate to 24h the state of am or pm 1528 RTC.writeTime (); 1529 } 1530 vfdDisplayMode = 1; 1531 tempTimeHolder = 0; 1532 setTimeModeFlag = false; 1533 timeSetModeReset = true; 1534 vfdHandler (true); 1535 vfdDotEffectOn = true; 1536 } 1537 // Enable button 2 long press in order to register long presses in normal modes (MD_KeySwitch 1538 // library restriction): 1539 button2.enableLongPress (true); 1540 button2.enableRepeat (false); 1541 button2.enableRepeatResult (false); 1542 button2.setLongPressTime (2000); 1543 } 1544 else 1545 { 1546 return; 1547 } 1548 PRINTS ("\ 1549Button 1 pressed."); 1550 } 1551 1552 // Button 2 (set time mode): 1553 switch (button2.read ()) 1554 { 1555 case MD_KeySwitch::KS_PRESS: // button 2 single press - increase temp time variable 1556 if (setTimeStageArray [0] == false) 1557 { 1558 if (vfdDisplayMode == 4) // 24h mode 1559 { 1560 if (tempTimeHolder >= 0 && tempTimeHolder < 23) // increase hours 1561 { 1562 tempTimeHolder++; 1563 } 1564 else 1565 { 1566 tempTimeHolder = 0; 1567 } 1568 } 1569 if (vfdDisplayMode == 5) // 12h mode 1570 { 1571 if (tempTimeHolder >= 1 && tempTimeHolder < 12) // increase hours 1572 { 1573 tempTimeHolder++; 1574 } 1575 else 1576 { 1577 tempTimeHolder = 1; 1578 } 1579 } 1580 } 1581 else if (setTimeStageArray [1] == false) 1582 { 1583 if (tempTimeHolder >= 0 && tempTimeHolder < 59) // increase minutes 1584 { 1585 tempTimeHolder++; 1586 } 1587 else 1588 { 1589 tempTimeHolder = 0; 1590 } 1591 } 1592 else // set am or pm 1593 { 1594 if (setTimeAm == true) 1595 { 1596 setTimeAm = false; 1597 digitalWrite (AM_LED, LOW); 1598 digitalWrite (PM_LED, HIGH); 1599 } 1600 else 1601 { 1602 setTimeAm = true; 1603 digitalWrite (AM_LED, HIGH); 1604 digitalWrite (PM_LED, LOW); 1605 } 1606 } 1607 PRINTS ("\ 1608Button 2 pressed."); 1609 break; 1610 case MD_KeySwitch::KS_RPTPRESS: // button 2 repeat press - increase temp time variable fast 1611 repeatOn = true; // set to true in order to stop blinking in setTimeMode function 1612 if (setTimeStageArray [0] == false) 1613 { 1614 if (vfdDisplayMode == 4) // 24h mode 1615 { 1616 if (tempTimeHolder >= 0 && tempTimeHolder < 23) // increase hours 1617 { 1618 tempTimeHolder++; 1619 } 1620 else 1621 { 1622 tempTimeHolder = 0; 1623 } 1624 } 1625 if (vfdDisplayMode == 5) // 12h mode 1626 { 1627 if (tempTimeHolder >= 1 && tempTimeHolder < 12) // increase hours 1628 { 1629 tempTimeHolder++; 1630 } 1631 else 1632 { 1633 tempTimeHolder = 1; 1634 } 1635 } 1636 } 1637 else 1638 { 1639 if (tempTimeHolder >= 0 && tempTimeHolder < 59) // increase minutes 1640 { 1641 tempTimeHolder++; 1642 } 1643 else 1644 { 1645 tempTimeHolder = 0; 1646 } 1647 } 1648 PRINTS ("\ 1649Button 2 repeat pressed."); 1650 break; 1651 default: 1652 break; 1653 } 1654 1655 // Button 3 (set time mode): 1656 switch (button3.read ()) 1657 { 1658 case MD_KeySwitch::KS_PRESS: // button 3 single press - decrease temp time variable 1659 if (setTimeStageArray [0] == false) 1660 { 1661 if (vfdDisplayMode == 4) // 24h mode 1662 { 1663 if (tempTimeHolder > 0 && tempTimeHolder <= 23) // decrease hours 1664 { 1665 tempTimeHolder--; 1666 } 1667 else 1668 { 1669 tempTimeHolder = 23; 1670 } 1671 } 1672 if (vfdDisplayMode == 5) // 12h mode 1673 { 1674 if (tempTimeHolder > 1 && tempTimeHolder <= 12) // decrease hours 1675 { 1676 tempTimeHolder--; 1677 } 1678 else 1679 { 1680 tempTimeHolder = 12; 1681 } 1682 } 1683 } 1684 else if (setTimeStageArray [1] == false) 1685 { 1686 if (tempTimeHolder > 0 && tempTimeHolder <= 59) // decrease minutes 1687 { 1688 tempTimeHolder--; 1689 } 1690 else 1691 { 1692 tempTimeHolder = 59; 1693 } 1694 } 1695 else // set am or pm 1696 { 1697 if (setTimeAm == true) 1698 { 1699 setTimeAm = false; 1700 digitalWrite (AM_LED, LOW); 1701 digitalWrite (PM_LED, HIGH); 1702 } 1703 else 1704 { 1705 setTimeAm = true; 1706 digitalWrite (AM_LED, HIGH); 1707 digitalWrite (PM_LED, LOW); 1708 } 1709 } 1710 1711 PRINTS ("\ 1712Button 3 pressed."); 1713 break; 1714 case MD_KeySwitch::KS_RPTPRESS: // button 3 repeat press - decrease temp time variable fast 1715 repeatOn = true; // set to true in order to stop blinking in setTimeMode function 1716 if (setTimeStageArray [0] == false) 1717 { 1718 if (vfdDisplayMode == 4) // 24h mode 1719 { 1720 if (tempTimeHolder > 0 && tempTimeHolder <= 23) // decrease hours 1721 { 1722 tempTimeHolder--; 1723 } 1724 else 1725 { 1726 tempTimeHolder = 23; 1727 } 1728 } 1729 if (vfdDisplayMode == 5) // 12h mode 1730 { 1731 if (tempTimeHolder > 1 && tempTimeHolder <= 12) // decrease hours 1732 { 1733 tempTimeHolder--; 1734 } 1735 else 1736 { 1737 tempTimeHolder = 12; 1738 } 1739 } 1740 } 1741 else 1742 { 1743 if (tempTimeHolder > 0 && tempTimeHolder <= 59) // decrease minutes 1744 { 1745 tempTimeHolder--; 1746 } 1747 else 1748 { 1749 tempTimeHolder = 59; 1750 } 1751 } 1752 PRINTS ("\ 1753Button 3 repeat pressed."); 1754 break; 1755 default: 1756 break; 1757 } 1758 1759 // Button 4 (set time mode): 1760 if (button4.read () == MD_KeySwitch::KS_PRESS) // exit set time mode 1761 { 1762 setTimeModeFlag = false; 1763 timeSetModeReset = true; 1764 if (vfdDisplayMode == 4) // exit back to 24h mode 1765 { 1766 vfdDisplayMode = 0; 1767 } 1768 else if (vfdDisplayMode == 5) // exit back to 12h mode 1769 { 1770 vfdDisplayMode = 1; 1771 } 1772 vfdHandler (true); 1773 if (setTimeStageArray [0] == true) // if even one variable is set, show dot effect 1774 { 1775 vfdDotEffectOn = true; 1776 } 1777 else // if nothing is set, show dash effect 1778 { 1779 vfdDashEffectOn = true; 1780 } 1781 // Enable button 2 long press in order to register long presses in normal modes (MD_KeySwitch 1782 // library restriction): 1783 button2.enableLongPress (true); 1784 button2.enableRepeat (false); 1785 button2.enableRepeatResult (false); 1786 button2.setLongPressTime (2000); 1787 PRINTS ("\ 1788Button 4 pressed."); 1789 } 1790 } 1791} 1792 1793/*************************************************************************************************************** 1794***************************************************************************************************************/ 1795
VFD_Clock-Main_Sketch-0.3.5.ino
c_cpp
The code for the clock using the Arduino IDE. I plan to optimize it a bit and add some new features in the future. I tried to comment everything to make sense but keep in mind that I'm an amateur and self taught so it might be a little messy.
1/*************************************************************************************************************** 2 *************************************************************************************************************** 3 VFD Clock Main Sketch 4 Version 0.3.5 5 Tested with: Arduino IDE 1.8.16 - Arduino AVR Boards 1.8.4 - MD_DS3231 1.3.1 - Adafruit_NeoPixel 1.7.0 - 6 MD_KeySwitch 1.4.2 - DHT sensor library 1.4.3 - ATMega328P-PU with Arduino UNO R3 bootloader 7 (for uploading code with the FTDI board select Tools-> Board:-> "Ardruino Uno") 8 17-05-2022 9 Leon 10 **************************************************************************************************************/ 11// Libraries needed: 12#include <MD_DS3231.h> // Pre-existing object named RTC (SCL to pin A5, SDA to pin A4) 13#include <Adafruit_NeoPixel.h> 14#include <MD_KeySwitch.h> 15#include "DHT.h" 16#include <SPI.h> 17 18// Turn debugging on and off: 19#define DEBUG 1 20#if DEBUG 21#define PRINTS(s) { Serial.print (F(s));} // Print a string 22#define PRINT(s, v) { Serial.print (F(s)); Serial.print (v);} // Print string then value (dec) 23#include <MemoryFree.h> // Library for printing free memory on runtime 24#else 25#define PRINTS(s) // Print a string 26#define PRINT(s, v) // Print a string followed by a value (decimal) 27#endif 28 29// General universal variables: 30byte currentHours = 0; // variable to hold the value of the current hour 31byte currentSeconds = 0; // variable to hold the value of the current seconds 32 33// Variables for holding the individual digits of time: 34byte hoursFirstDigit = 0; 35byte hoursSecondDigit = 0; 36byte minutesFirstDigit = 0; 37byte minutesSecondDigit = 0; 38 39// VFD tubes: 40#define NUM_DIGITS 2 // define number of display digits. 41const byte Blank = 9; // Output to HV5812P-G 'BLANK' input 42const byte strobe = 10; // Output to HV5812P-G 'STROBE' input 43byte timeBuffer [4]; // array to hold the time digits 44byte vfdDisplayMode = 0; 45// mode 0 = 24h time display 46// mode 1 = 12h time display 47// mode 2 = temperature & humidity only display (without time) 48// mode 3 = display temp & humidity once (used when turning tempDisplayOn to true) 49// mode 4 = set time in 24h mode 50// mode 5 = set time in 12h mode 51bool previousDisplayMode = 0; // variable to hold the previous display mode 52bool tempDisplayOn = true; // show temp and humidity periodically on modes 0 and 1 53bool vfdCycleEffectOn = false; // trigger for vfd cycle effect 54bool vfdDashEffectOn = false; // trigger for vfd dash effect - used to indicate "OFF" 55bool vfdDotEffectOn = false; // trigger for vfd dot effect - used to indicate "ON" 56byte effectBuffer [4]; // array to hold the effects digits 57bool setTimeModeFlag = false; // flag for checking if setTimeMode is running 58bool timeSetModeReset = true; // used to reset variables at the first run of timeSetMode function 59byte tempTimeHolder = 0; // hold the time that is displayed currently on setTimeMode 60bool setTimeStageArray [3] = {false}; // array that holds which steps of the time setting are completed 61bool setTimeAm = false; // if am = true, if pm = false - used in 12h set time mode 62 63// Array with the bit-pattern for each tube Grid - the grids are MULTIPLEXED: 1 and 3 VFDs are on 64// together while 2 and 4 VFDs are off and in reverse: 65const byte grids [2] = 66{ 67 B00000101, 68 B00001010, 69}; 70 71// Array with the bit-pattern for each and 7-segment number character: 72const byte symbols [25] = 73{ 74 B01110111, // 0 75 B00100100, // 1 76 B01011101, // 2 77 B01101101, // 3 78 B00101110, // 4 79 B01101011, // 5 80 B01111011, // 6 81 B00100101, // 7 82 B01111111, // 8 83 B01101111, // 9 84 B00000000, // 10 (Blank) 85 B01011000, // 11 (c celsius) 86 B01010011, // 12 (C Celsius) 87 B00001111, // 13 (top half on) 88 B01111000, // 14 (bottom half on) 89 B10000000, // 15 (. dot - used to signal ON) 90 B11111111, // 16 (all segments on) 91 B00001000, // 17 (- dash used to signal OFF) 92 B00100000, // 18 (from 18 to 24 are the cycle effect bit-patterns) 93 B01000000, // 19 94 B00010000, // 20 95 B00000010, // 21 96 B00000001, // 22 97 B00000100, // 23 98 B00100000, // 24 99}; 100 101// DHT11 temperature and humidity sensor: 102#define DHTPIN 7 // pin the sensor is connected to 103DHT dht (DHTPIN, DHT11); 104byte tempFirstDigit = 0; 105byte tempSecondDigit = 0; 106byte tempThirdDigit = 0; 107byte tempBuffer [4]; // array to hold the temp digits 108byte humidityFirstDigit = 0; 109byte humiditySecondDigit = 0; 110byte humidityBuffer [4]; // array to hold the humidity digits 111float originalTemp = 0; // hold the temperature before compensating for electronics heat 112float compensatedTemp = 0; // hold temperature after compensating for electronics 113const float tempCompensation = 1.80; // degrees in c to compensate for electronics heat 114 115// Dots: 116#define DOTS_PIN A1 117#define DOTS_NUM 2 118Adafruit_NeoPixel dots (DOTS_NUM, DOTS_PIN, NEO_RGB + NEO_KHZ800); 119#define AM_LED 12 120#define PM_LED A2 121 122// WS LEDs: 123#define WS_PIN 2 124#define WS_NUM 4 125Adafruit_NeoPixel ws (WS_NUM, WS_PIN, NEO_RGB + NEO_KHZ800); 126byte wsMode = 1; // variable to hold the WS2911 LEDs mode - default is 1 127byte wsModeNum = 5; // variable to hold the number (sum) of WS2911 LEDs modes 128bool wsTransition = false; // true if mode transition is on, false if not 129#define WSTRANSTIME 1800UL // transition duration in milliseconds 130bool wsOff = false; // true if the WS2911 LEDs are off, false if they are on 131bool wsWasOn = false; // true if the LEDs were on, false if not 132bool rainbowEffectTrigger = false; // flag for triggering the rainbow effect 133bool colorWipeEffectTrigger = false; // flag for triggering the color wipe effect 134bool colorWheelEffectTrigger = false; // flag for triggering the colorWheel effect 135int redLedArray [4] = {0}; // array to hold the values of the red WS2911 LEDs 136int greenLedArray [4] = {0}; // array to hold the values of the green WS2911 LEDs 137int blueLedArray [4] = {0}; // array to hold the values of the blue WS2911 LEDs 138unsigned long tempColorArray [4] = {0}; // array to hold the values of rainbow or wheel colors 139 140// LDR Photoresistor: 141#define LDRPIN A3 // analog pin that the LDR photoresistor is connected on the Arduino 142#define VFD_BRIGHT_MAX 0 // full brightness 143#define VFD_BRIGHT_MIN 250 // fully dimmed 144byte vfdBrightness = 120; // startup brightness of VFDs (half brightness) 145#define WS_BRIGHT_MAX 100 // maximum brightness the LEDs will go depending on room light 146#define WS_BRIGHT_MIN 10 // minimum brightness the LEDs will go depending on room light 147byte wsBrightness = 44; // startup brightness of the WS2811 LEDs (half brightness) 148#define DOTS_BRIGHT_MAX 60 // maximum brightness the dots will go depending on room light 149#define DOTS_BRIGHT_MIN 10 // minimum brightness the dots will go depending on room light 150byte dotsBrightness = 24; // startup brightness of the dots (half brightness) 151 152// Buttons: 153MD_KeySwitch button1 (3, LOW); // set button 1 to pin 3 154MD_KeySwitch button2 (4, LOW); // set button 2 to pin 4 155MD_KeySwitch button3 (5, LOW); // set button 3 to pin 5 156MD_KeySwitch button4 (6, LOW); // set button 4 to pin 6 157bool repeatOn = false; // true if repeat button pressed 158 159// Functions with default values declaration: 160void vfdHandler (bool reset = false); 161void displayTime (bool mode12hours = false); 162void colorWipeEffect (bool resetTrigger = false); 163 164/*-------------------------------------------------- SETUP: --------------------------------------------------*/ 165void setup () 166{ 167 // Debug setup: 168#if DEBUG 169 Serial.begin (9600); 170 PRINTS ("\ 171[VFD Clock]"); 172#endif 173 174 // Set Fast PWM frequency on pin 9 [and 10] (for dimming display): 175 TCCR1B = (TCCR1B & 0b11111000) | 0x1; 176 177 // start SPI: 178 SPI.begin (); 179 180 // VFDs setup: 181 pinMode (strobe, OUTPUT); 182 pinMode (Blank, OUTPUT); 183 analogWrite (Blank, 255); // Set vfd brightness to zero at startup 184 185 // DHT11 temperature and humidity sensor: 186 dht.begin (); 187 188 // Dots setup: 189 dots.begin (); // INITIALIZE NeoPixel strip object (REQUIRED) 190 dots.setBrightness (dotsBrightness); // set default brightness 191 dots.clear (); // set all pixel colors to 'off' 192 dots.show (); // send the updated pixel colors to the hardware 193 194 // WS LEDs setup: 195 ws.begin (); // initialize NeoPixel strip object 196 ws.show (); // turn OFF all pixels ASAP 197 ws.setBrightness (wsBrightness); // Set the brightness 198 wsHandler (); 199 200 // AM-PM LEDs setup: 201 pinMode (AM_LED, OUTPUT); 202 pinMode (PM_LED, OUTPUT); 203 digitalWrite (AM_LED, LOW); 204 digitalWrite (PM_LED, LOW); 205 206 // LDR Photoresistor setup: 207 pinMode (LDRPIN, INPUT); 208 209 // Buttons setup: 210 // Keep in mind library restriction: debounce time < Long Press Time < Repeat time 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 (true); 223 button2.enableRepeat (false); 224 button2.enableRepeatResult (false); 225 button2.setDebounceTime (160); 226 button2.setLongPressTime (2000); // set long press time to 2 seconds 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 (180); 234 button3.setDebounceTime (160); 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 245/*------------------------------------------------- LOOP: ----------------------------------------------------*/ 246void loop () 247{ 248 // Run the handlers: 249 vfdHandler (); 250 buttonsHandler (); 251 photoresistorHandler (); 252 253 // Run the color wipe effect if it is on: 254 if (colorWipeEffectTrigger == true) 255 { 256 colorWipeEffect (); 257 } 258 259 // Run the rainbow effect if it is on: 260 if (rainbowEffectTrigger == true) 261 { 262 rainbowEffect (); 263 } 264 265 // Run the color wheel effect if it is on: 266 if (colorWheelEffectTrigger == true) 267 { 268 colorWheelEffect (); 269 } 270} 271/*---------------------------------------------- END OF LOOP -------------------------------------------------*/ 272 273/*------------------------------------------------------------------------------------------------------------*/ 274/* Function for handling what is displayed in the VFD tubes including timing of events and set time modes. 275 When called with reset = true, variables are reset: 276*/ 277void vfdHandler (bool reset = false) 278{ 279 // Local variables declaration: 280 static unsigned long lastTime = 0; // time keeping for time display 281 static unsigned long lastTimeCyrcleEffect = 0; // time keeping for cycle effect 282 static unsigned long lastTimeDashEffect = 0; // time keeping for dash effect 283 static unsigned long lastTimeDotEffect = 0; // time keeping for dot effect 284 static unsigned long startTime = millis (); // time keeping for blinking digits on set time modes 285 static bool dashEffectFirstRun = true; 286 static bool dotEffectFirstRun = true; 287 static bool tempFirstRun = true; // used to read temperature only once per cycle 288 static bool humidityFirstRun = true; // used to read humidity only once per cycle 289 unsigned long DELAY = 4400; // time that the temp and humidity will be displayed 290 static byte effectCounter = 0; // keep track of the stage of the cycle effect 291 292 // Main code: 293 RTC.readTime (); // get the time from the module 294 295 // Reset variables and exit: 296 if (reset == true) 297 { 298 lastTime = millis (); 299 reset = false; 300 tempFirstRun = true; 301 humidityFirstRun = true; 302 digitalWrite (AM_LED, LOW); 303 digitalWrite (PM_LED, LOW); 304 return; 305 } 306 307 // Execute effects: 308 if (vfdCycleEffectOn == true) // dot effect 309 { 310 if (millis () - lastTimeCyrcleEffect < 60UL) // run for X seconds 311 { 312 effectBuffer [0] = 18 + effectCounter; 313 effectBuffer [1] = 18 + effectCounter; 314 effectBuffer [2] = 18 + effectCounter; 315 effectBuffer [3] = 18 + effectCounter; 316 updateDisplay (effectBuffer); 317 } 318 else 319 { 320 lastTimeCyrcleEffect = millis (); 321 effectCounter++; 322 } 323 if (effectCounter == 7) 324 { 325 effectCounter = 0; 326 vfdCycleEffectOn = false; 327 } 328 return; 329 } 330 else if (vfdDashEffectOn == true) // dash effect, only one effect active simultaneously 331 { 332 if (dashEffectFirstRun == true) 333 { 334 lastTimeDashEffect = millis (); 335 dashEffectFirstRun = false; 336 } 337 if (millis () - lastTimeDashEffect < 1000UL) // run for X seconds 338 { 339 effectBuffer [0] = 17; 340 effectBuffer [1] = 17; 341 effectBuffer [2] = 17; 342 effectBuffer [3] = 17; 343 updateDisplay (effectBuffer); 344 } 345 else 346 { 347 vfdDashEffectOn = false; 348 dashEffectFirstRun = true; 349 } 350 return; 351 } 352 else if (vfdDotEffectOn == true) // dot effect, only one effect active simultaneously 353 { 354 if (dotEffectFirstRun == true) 355 { 356 lastTimeDotEffect = millis (); 357 dotEffectFirstRun = false; 358 } 359 if (millis () - lastTimeDotEffect < 1000UL) // run for X seconds 360 { 361 effectBuffer [0] = 15; 362 effectBuffer [1] = 15; 363 effectBuffer [2] = 15; 364 effectBuffer [3] = 15; 365 updateDisplay (effectBuffer); 366 } 367 else 368 { 369 vfdDotEffectOn = false; 370 dotEffectFirstRun = true; 371 } 372 return; 373 } 374 375 switch (vfdDisplayMode) 376 { 377 378 case 0: // -------------------------------- 24h time display: -------------------------------- 379 if (tempDisplayOn == false) // display only time 380 { 381 displayTime (); 382 } 383 else // display temperature and humidity at DELAY intervals 384 { 385 if (RTC.s > 10 && RTC.s <= 10 + (DELAY / 1000) * 2 || RTC.s > 30 && RTC.s <= 30 + (DELAY / 1000) * 2) 386 { 387 if (millis () - lastTime < DELAY) // run for delay seconds 388 { 389 if (tempFirstRun == true) 390 { 391 tempFirstRun = false; 392 displayTemp (true); 393 vfdCycleEffectOn = true; 394 } 395 else 396 { 397 displayTemp (false); 398 } 399 } 400 else if (millis () - lastTime < DELAY * 2) 401 { 402 if (humidityFirstRun == true) 403 { 404 humidityFirstRun = false; 405 displayHumidity (true); 406 vfdCycleEffectOn = true; 407 } 408 else 409 { 410 displayHumidity (false); 411 } 412 } 413 else 414 { 415 lastTime = millis (); 416 tempFirstRun = true; 417 humidityFirstRun = true; 418 } 419 } 420 else 421 { 422 displayTime (); 423 } 424 } 425 break; 426 427 case 1: // -------------------------------- 12h time display: -------------------------------- 428 if (tempDisplayOn == false) // just display time 429 { 430 displayTime (true); 431 } 432 else // display temperature and humidity at DELAY intervals 433 { 434 if (RTC.s > 10 && RTC.s <= 10 + (DELAY / 1000) * 2 || RTC.s > 40 && RTC.s <= 40 + (DELAY / 1000) * 2) 435 { 436 if (millis () - lastTime < DELAY) // run for DELAY seconds 437 { 438 if (tempFirstRun == true) 439 { 440 tempFirstRun = false; 441 displayTemp (true); 442 vfdCycleEffectOn = true; 443 } 444 else 445 { 446 displayTemp (false); 447 } 448 } 449 else if (millis () - lastTime < DELAY * 2) 450 { 451 if (humidityFirstRun == true) 452 { 453 humidityFirstRun = false; 454 displayHumidity (true); 455 vfdCycleEffectOn = true; 456 } 457 else 458 { 459 displayHumidity (false); 460 } 461 } 462 else 463 { 464 lastTime = millis (); 465 tempFirstRun = true; 466 humidityFirstRun = true; 467 } 468 } 469 else 470 { 471 displayTime (true); 472 } 473 } 474 break; 475 476 case 2: // ---------------------- Temperature and humidity only display mode: ------------------------ 477 if (millis () - lastTime < DELAY) // run for DELAY seconds 478 { 479 if (tempFirstRun == true) 480 { 481 tempFirstRun = false; 482 displayTemp (true); 483 vfdCycleEffectOn = true; 484 } 485 else 486 { 487 displayTemp (false); 488 } 489 } 490 else if (millis () - lastTime < DELAY * 2) 491 { 492 if (humidityFirstRun == true) 493 { 494 humidityFirstRun = false; 495 displayHumidity (true); 496 vfdCycleEffectOn = true; 497 } 498 else 499 { 500 displayHumidity (false); 501 } 502 } 503 else 504 { 505 lastTime = millis (); 506 tempFirstRun = true; 507 humidityFirstRun = true; 508 } 509 break; 510 511 case 3: // ---------------------------- Display temp and humidity once: ---------------------------- 512 if (millis () - lastTime < DELAY + 1000UL) // run for DELAY + 1 seconds 513 { 514 if (tempFirstRun == true) 515 { 516 tempFirstRun = false; 517 displayTemp (true); 518 vfdCycleEffectOn = true; 519 } 520 else 521 { 522 displayTemp (false); 523 } 524 } 525 else if (millis () - lastTime < (DELAY + 1000UL) * 2) 526 { 527 if (humidityFirstRun == true) 528 { 529 humidityFirstRun = false; 530 displayHumidity (true); 531 vfdCycleEffectOn = true; 532 } 533 else 534 { 535 displayHumidity (false); 536 } 537 } 538 else 539 { 540 tempFirstRun = true; 541 humidityFirstRun = true; 542 // to prevent showing temperature two times in a row, skip showing it if it is to close to 543 // previous display: 544 if (RTC.s > 6 && RTC.s <= 12 + ((DELAY + 1000) / 1000) * 2 545 || RTC.s > 36 && RTC.s <= 42 + ((DELAY + 1000) / 1000) * 2) 546 { 547 if (previousDisplayMode == 0) 548 { 549 displayTime (); 550 } 551 else 552 { 553 displayTime (true); 554 } 555 } 556 else 557 { 558 vfdDisplayMode = previousDisplayMode; 559 } 560 } 561 break; 562 case 4: // -------------------------------- 24h set time mode: -------------------------------- 563 if (timeSetModeReset == true) // check if it's the first run of set time 564 { 565 timeSetModeReset = false; 566 for (int i = 0; i < 3; i++) // reset array 567 { 568 setTimeStageArray [i] = false; 569 } 570 tempTimeHolder = RTC.h; // pass current time to temp variable for manipulation with buttons 571 dots.clear (); // set off dots 572 dots.show (); 573 } 574 else if (setTimeStageArray [0] == false) // blink hours except when on repeat 575 { 576 // Hours: 577 if (repeatOn == false) 578 { 579 separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit); 580 if (millis () - startTime < 500UL) 581 { 582 timeBuffer [0] = hoursFirstDigit; 583 timeBuffer [1] = hoursSecondDigit; 584 } 585 else if (millis () - startTime < 1000UL) 586 { 587 timeBuffer [0] = 10; // 10 = blank 588 timeBuffer [1] = 10; // 10 = blank 589 } 590 else 591 { 592 startTime = millis (); 593 } 594 } 595 else // on repeat button press don't blink 596 { 597 separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit); 598 timeBuffer [0] = hoursFirstDigit; 599 timeBuffer [1] = hoursSecondDigit; 600 repeatOn = false; 601 startTime = millis (); 602 } 603 604 // Minutes: 605 separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit); 606 timeBuffer [2] = minutesFirstDigit; 607 timeBuffer [3] = minutesSecondDigit; 608 } 609 else if (setTimeStageArray [1] == false) // if hours set, blink minutes except on repeat 610 { 611 // Hours: 612 separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit); 613 timeBuffer [0] = hoursFirstDigit; 614 timeBuffer [1] = hoursSecondDigit; 615 616 // Minutes: 617 if (repeatOn == false) 618 { 619 separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit); 620 if (millis () - startTime < 500UL) 621 { 622 timeBuffer [2] = minutesFirstDigit; 623 timeBuffer [3] = minutesSecondDigit; 624 } 625 else if (millis () - startTime < 1000UL) 626 { 627 timeBuffer [2] = 10; // 10 = blank 628 timeBuffer [3] = 10; // 10 = blank 629 } 630 else 631 { 632 startTime = millis (); 633 } 634 } 635 else // on repeat button press don't blink 636 { 637 separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit); 638 timeBuffer [2] = minutesFirstDigit; 639 timeBuffer [3] = minutesSecondDigit; 640 repeatOn = false; 641 startTime = millis (); 642 } 643 } 644 updateDisplay (timeBuffer); // update the display 645 break; 646 case 5: // -------------------------------- 12h set time mode: -------------------------------- 647 if (timeSetModeReset == true) // check if it's the first run of set time 648 { 649 timeSetModeReset = false; 650 for (int i = 0; i < 3; i++) // reset array 651 { 652 setTimeStageArray [i] = false; 653 } 654 // Keep the status of the am/pm LEDs for consistency when setting them and translate the 655 // time from 24h to 12h to display correctly: 656 if (RTC.h == 0) 657 { 658 tempTimeHolder = 12; // pass current time to temp variable for manipulation with buttons 659 setTimeAm = true; 660 } 661 else if (RTC.h < 12) 662 { 663 tempTimeHolder = RTC.h; // pass current time to temp variable for manipulation with buttons 664 setTimeAm = true; 665 } 666 else if (RTC.h == 12) 667 { 668 tempTimeHolder = RTC.h; // pass current time to temp variable for manipulation with buttons 669 setTimeAm = false; 670 } 671 else 672 { 673 tempTimeHolder = RTC.h - 12; // pass current time to temp variable for manipulation with buttons 674 setTimeAm = false; 675 } 676 dots.clear (); // turn off dots 677 dots.show (); 678 } 679 else if (setTimeStageArray [0] == false) // blink hours except when on repeat 680 { 681 // Hours: 682 if (repeatOn == false) 683 { 684 separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit); 685 if (millis () - startTime < 500UL) 686 { 687 if (hoursFirstDigit == 0) // don't show zero 688 { 689 timeBuffer [0] = 10; // 10 = blank 690 } 691 else 692 { 693 timeBuffer [0] = hoursFirstDigit; 694 } 695 timeBuffer [1] = hoursSecondDigit; 696 } 697 else if (millis () - startTime < 1000UL) 698 { 699 timeBuffer [0] = 10; // 10 = blank 700 timeBuffer [1] = 10; // 10 = blank 701 } 702 else 703 { 704 startTime = millis (); 705 } 706 } 707 else // on repeat button press don't blink 708 { 709 separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit); 710 if (hoursFirstDigit == 0) // don't show zero 711 { 712 timeBuffer [0] = 10; // 10 = blank 713 } 714 else 715 { 716 timeBuffer [0] = hoursFirstDigit; 717 } 718 timeBuffer [1] = hoursSecondDigit; 719 repeatOn = false; 720 startTime = millis (); 721 } 722 723 // Minutes: 724 separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit); 725 timeBuffer [2] = minutesFirstDigit; 726 timeBuffer [3] = minutesSecondDigit; 727 } 728 else if (setTimeStageArray [1] == false) // if hours set, blink minutes except on repeat 729 { 730 // Hours: 731 if (RTC.h == 0) // convert 24h to 12h for displaying properly 732 { 733 separateDoubleDigits (12, hoursFirstDigit, hoursSecondDigit); 734 } 735 else if (RTC.h > 12) 736 { 737 separateDoubleDigits (RTC.h - 12, hoursFirstDigit, hoursSecondDigit); 738 } 739 else 740 { 741 separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit); 742 } 743 744 if (hoursFirstDigit == 0) // don't show zero 745 { 746 timeBuffer [0] = 10; // 10 = blank 747 } 748 else 749 { 750 timeBuffer [0] = hoursFirstDigit; 751 } 752 timeBuffer [1] = hoursSecondDigit; 753 754 // Minutes: 755 if (repeatOn == false) 756 { 757 separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit); 758 if (millis () - startTime < 500UL) 759 { 760 timeBuffer [2] = minutesFirstDigit; 761 timeBuffer [3] = minutesSecondDigit; 762 } 763 else if (millis () - startTime < 1000UL) 764 { 765 timeBuffer [2] = 10; // 10 = blank 766 timeBuffer [3] = 10; // 10 = blank 767 } 768 else 769 { 770 startTime = millis (); 771 } 772 } 773 else // if on repeat button press don't blink 774 { 775 separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit); 776 timeBuffer [2] = minutesFirstDigit; 777 timeBuffer [3] = minutesSecondDigit; 778 repeatOn = false; 779 startTime = millis (); 780 } 781 } 782 else if (setTimeStageArray [2] == false) // if minutes set, blink AM/PM 783 { 784 // Hours: 785 if (RTC.h == 0) // convert 24h to 12h for displaying properly 786 { 787 separateDoubleDigits (12, hoursFirstDigit, hoursSecondDigit); 788 } 789 else if (RTC.h > 12) 790 { 791 separateDoubleDigits (RTC.h - 12, hoursFirstDigit, hoursSecondDigit); 792 } 793 else 794 { 795 separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit); 796 } 797 798 if (hoursFirstDigit == 0) // don't show zero 799 { 800 timeBuffer [0] = 10; // 10 = blank 801 } 802 else 803 { 804 timeBuffer [0] = hoursFirstDigit; 805 } 806 timeBuffer [1] = hoursSecondDigit; 807 808 // Minutes: 809 separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit); 810 timeBuffer [2] = minutesFirstDigit; 811 timeBuffer [3] = minutesSecondDigit; 812 813 // AM/PM LEDs: 814 if (millis () - startTime < 500UL) 815 { 816 if (setTimeAm == true) 817 { 818 digitalWrite (AM_LED, HIGH); 819 digitalWrite (PM_LED, LOW); 820 } 821 else 822 { 823 digitalWrite (AM_LED, LOW); 824 digitalWrite (PM_LED, HIGH); 825 } 826 } 827 else if (millis () - startTime < 1000UL) 828 { 829 830 digitalWrite (AM_LED, LOW); 831 digitalWrite (PM_LED, LOW); 832 } 833 else 834 { 835 startTime = millis (); 836 } 837 } 838 updateDisplay (timeBuffer); // update the display 839 break; 840 default: 841 break; 842 } 843} 844 845/*------------------------------------------------------------------------------------------------------------*/ 846/* Function for displaing the time on the VFD tubes and blinking the dots. When called with true, the time 847 is displayed with 12 hours: 848*/ 849void displayTime (bool mode12hours = false) 850{ 851 // Local variables declaration: 852 853 // Main code: 854 // Hours: 855 currentHours = RTC.h; 856 if (mode12hours == false) 857 { 858 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 859 timeBuffer [0] = hoursFirstDigit; 860 timeBuffer [1] = hoursSecondDigit; 861 } 862 else 863 { 864 if (currentHours < 12) 865 { 866 switch (currentHours) 867 { 868 case 0: 869 currentHours = 12; 870 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 871 timeBuffer [0] = hoursFirstDigit; 872 timeBuffer [1] = hoursSecondDigit; 873 break; 874 case 1: 875 case 2: 876 case 3: 877 case 4: 878 case 5: 879 case 6: 880 case 7: 881 case 8: 882 case 9: 883 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 884 timeBuffer [0] = 10; // blank 885 timeBuffer [1] = hoursSecondDigit; 886 break; 887 case 10: 888 case 11: 889 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 890 timeBuffer [0] = hoursFirstDigit; 891 timeBuffer [1] = hoursSecondDigit; 892 break; 893 default: 894 break; 895 } 896 digitalWrite (AM_LED, HIGH); 897 digitalWrite (PM_LED, LOW); 898 } 899 else 900 { 901 switch (currentHours) 902 { 903 case 12: 904 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 905 timeBuffer [0] = hoursFirstDigit; 906 timeBuffer [1] = hoursSecondDigit; 907 break; 908 case 13: 909 case 14: 910 case 15: 911 case 16: 912 case 17: 913 case 18: 914 case 19: 915 case 20: 916 case 21: 917 currentHours = currentHours - 12; 918 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 919 timeBuffer [0] = 10; // blank 920 timeBuffer [1] = hoursSecondDigit; 921 break; 922 case 22: 923 case 23: 924 currentHours = currentHours - 12; 925 separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit); 926 timeBuffer [0] = hoursFirstDigit; 927 timeBuffer [1] = hoursSecondDigit; 928 break; 929 default: 930 break; 931 } 932 digitalWrite (AM_LED, LOW); 933 digitalWrite (PM_LED, HIGH); 934 } 935 } 936 937 // Minutes: 938 separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit); 939 timeBuffer [2] = minutesFirstDigit; 940 timeBuffer [3] = minutesSecondDigit; 941 942 // Blinking dots every second: 943 currentSeconds = RTC.s; 944 if (currentSeconds % 2 == 0) // if the seconds are even turn off dots 945 { 946 dots.clear (); // Set all pixel colors to 'off' 947 dots.show (); // Send the updated pixel colors to the hardware 948 } 949 else // if the seconds are even turn on dots 950 { 951 dots.setPixelColor (0, 28, 200, 52); 952 dots.setPixelColor (1, 28, 200, 52); 953 dots.show (); // Send the updated pixel colors to the hardware 954 } 955 updateDisplay (timeBuffer); 956} 957 958/*------------------------------------------------------------------------------------------------------------*/ 959/* Function for displaying the temperature on the VFDs. When called with firstRun true the reading of the 960 temperature and the compensation happens: 961*/ 962void displayTemp (bool firstRun) 963{ 964 // Local variables declaration: 965 int intTemp = 0; 966 static unsigned long lastTime = 0; 967 968 // Main code: 969 if (firstRun == true) // run every DELAY seconds 970 { 971 digitalWrite (AM_LED, LOW); 972 digitalWrite (PM_LED, LOW); 973 originalTemp = dht.readTemperature (); 974 compensatedTemp = originalTemp - tempCompensation; 975 intTemp = compensatedTemp * 10; 976 separateThreeDigits (intTemp, tempFirstDigit, tempSecondDigit, tempThirdDigit); 977 tempBuffer [0] = tempFirstDigit; 978 tempBuffer [1] = tempSecondDigit; 979 tempBuffer [2] = tempThirdDigit; 980 tempBuffer [3] = 11; // c symbol 981 dots.setPixelColor (0, 28, 205, 52); 982 dots.setPixelColor (1, 0, 0, 0); 983 dots.show(); // send the updated pixel colors to the hardware 984 return; // skip first display update for effects to end 985 } 986 updateDisplay (tempBuffer); 987} 988 989/*------------------------------------------------------------------------------------------------------------*/ 990/* Function for displaying on the VFDs. When called with firstRun true the reading of the 991 temperature and the compensation happens: 992*/ 993void displayHumidity (bool firstRun) 994{ 995 // Local variables declaration: 996 static unsigned long lastTime = 0; 997 float dewPointTemp = 0; 998 int originalHumidity = 0; 999 int compensatedHumidity = 0; 1000 1001 // Main code: 1002 if (firstRun == true) // run every seconds 1003 { 1004 digitalWrite (AM_LED, LOW); 1005 digitalWrite (PM_LED, LOW); 1006 originalHumidity = dht.readHumidity (); 1007 dewPointTemp = (originalTemp - (14.55 + 0.114 * originalTemp) * (1 - (0.01 * originalHumidity)) 1008 - pow (((2.5 + 0.007 * originalTemp) * (1 - (0.01 * originalHumidity))), 3) 1009 - (15.9 + 0.117 * originalTemp) * pow ((1 - (0.01 * originalHumidity)), 14)); 1010 compensatedHumidity = 100 * (exp((17.625 * dewPointTemp) / (243.04 + dewPointTemp)) 1011 / exp ((17.625 * compensatedTemp) / (243.04 + compensatedTemp))); 1012 separateDoubleDigits (compensatedHumidity, humidityFirstDigit, humiditySecondDigit); 1013 humidityBuffer [0] = humidityFirstDigit; 1014 humidityBuffer [1] = humiditySecondDigit; 1015 humidityBuffer [2] = 13; // top half on 1016 humidityBuffer [3] = 14; // bottom half on 1017 dots.clear (); 1018 dots.show (); // send the updated pixel colors to the hardware 1019 return; // skip first display update for effects to end 1020 } 1021 updateDisplay (humidityBuffer); 1022} 1023 1024/*------------------------------------------------------------------------------------------------------------*/ 1025/* Function for separating the double digits that hours and minutes come from the RTC module, 1026 to single digits for writing on the VFD tubes: 1027*/ 1028void separateDoubleDigits (byte doubleDigit, byte& firstDigit, byte& secondDigit) 1029{ 1030 firstDigit = doubleDigit / 10; 1031 secondDigit = doubleDigit % 10; 1032} 1033 1034/*------------------------------------------------------------------------------------------------------------*/ 1035/* Function for separating a triple digit to single digits for writing on the VFD tubes: 1036*/ 1037void separateThreeDigits (unsigned int threeDigit, byte& firstDigit, byte& secondDigit, byte& thirdDigit) 1038{ 1039 firstDigit = (threeDigit / 100) % 10; 1040 secondDigit = (threeDigit / 10) % 10; 1041 thirdDigit = threeDigit % 10; 1042} 1043 1044/*------------------------------------------------------------------------------------------------------------*/ 1045/* Function for managing the multiplexing of the grids and displaying the values from the buffers on the VFDs: 1046*/ 1047void updateDisplay (byte inputArray []) 1048{ 1049 static int grid = 0; // hold which grid is to be updated 1050 1051 analogWrite (Blank, 255); // Blank display while updating registers 1052 show (inputArray, grid); 1053 analogWrite (Blank, vfdBrightness); // Set display brightness according to LDR value. 1054 grid++; // Advance to the next grid (ie next tube) next time around. 1055 if (grid > (NUM_DIGITS - 1)) // Reset grid counter after all grids have been updated 1056 { 1057 grid = 0; 1058 } 1059} 1060 1061/*------------------------------------------------------------------------------------------------------------*/ 1062/* Function for actually sending the values of the display buffers to the VFDs chip for displaying using SPI 1063 communication: 1064*/ 1065void show (byte theDisplay [], byte activeGrid) 1066{ 1067 static byte count = 0; 1068 digitalWrite (strobe, LOW); 1069 SPI.transfer (grids [activeGrid]); 1070 SPI.transfer (symbols [theDisplay [count]]); 1071 SPI.transfer (symbols [theDisplay [count + 2]]); 1072 digitalWrite (strobe, HIGH); 1073 count = count + 1; 1074 if (count >= 2) 1075 { 1076 count = 0; 1077 } 1078} 1079 1080/*------------------------------------------------------------------------------------------------------------*/ 1081 1082/*------------------------------------------------------------------------------------------------------------*/ 1083/* Function for managing the WS2811 RGB LEDs color modes: 1084 */ 1085void wsHandler () 1086{ 1087 switch (wsMode) 1088 { 1089 case 1: // red color mode 1090 rainbowEffectTrigger = false; 1091 colorWipeEffectTrigger = true; 1092 colorWheelEffectTrigger = false; 1093 for (int i = 0; i < 4; i++) // populate the arrays with the color red 1094 { 1095 redLedArray [i] = 255; 1096 greenLedArray [i] = 0; 1097 blueLedArray [i] = 0; 1098 } 1099 break; 1100 case 2: // green color mode 1101 rainbowEffectTrigger = false; 1102 colorWipeEffectTrigger = true; 1103 colorWheelEffectTrigger = false; 1104 for (int i = 0; i < 4; i++) // populate the arrays with the color green 1105 { 1106 redLedArray [i] = 0; 1107 greenLedArray [i] = 255; 1108 blueLedArray [i] = 0; 1109 } 1110 break; 1111 case 3: // blue color mode 1112 rainbowEffectTrigger = false; 1113 colorWipeEffectTrigger = true; 1114 colorWheelEffectTrigger = false; 1115 for (int i = 0; i < 4; i++) // populate the arrays with the color blue 1116 { 1117 redLedArray [i] = 0; 1118 greenLedArray [i] = 0; 1119 blueLedArray [i] = 255; 1120 } 1121 break; 1122 case 4: // colorWheel mode 1123 rainbowEffectTrigger = false; 1124 colorWheelEffectTrigger = true; 1125 break; 1126 case 5: // rainbow mode 1127 rainbowEffectTrigger = true; 1128 colorWheelEffectTrigger = false; 1129 break; 1130 default: 1131 return; 1132 } 1133} 1134 1135/*------------------------------------------------------------------------------------------------------------*/ 1136/* Function for running the color wipe effect. When the resetTrigger parameter is set to true, the 1137 * counter starts again from the first (0) LED (used when pressing buttons quickly to ensure that the 1138 * new color is applied to all 4 LEDs every time). Default is false which allows the effect to 1139 * increment from LED to next LED: 1140 */ 1141void colorWipeEffect (bool resetTrigger = false) 1142{ 1143 // Local variables declaration: 1144 static unsigned long lastTime = millis (); 1145 static byte counter = 0; 1146 1147 // Main code: 1148 if (resetTrigger == true) 1149 { 1150 counter = 0; 1151 return; 1152 } 1153 if (millis () - lastTime > (unsigned long) WSTRANSTIME / 18) // time between every step - set it 1154 { // to be always done before 1155 lastTime = millis (); // wsTranstionDisplay is completed 1156 if (counter < 4) // during every step set the color to one RGB LED 1157 { 1158 ws.setPixelColor (counter, ws.Color (redLedArray [counter], greenLedArray [counter], 1159 blueLedArray [counter])); 1160 ws.show(); 1161 counter++; 1162 } 1163 else 1164 { 1165 colorWipeEffectTrigger = false; 1166 counter = 0; 1167 } 1168 } 1169} 1170 1171/*------------------------------------------------------------------------------------------------------*/ 1172/* Function for running the rainbow WS effect (based on code from strandtest neopixel library example - 1173 * adjusted for real time execution): 1174 */ 1175void rainbowEffect () 1176{ 1177 // Local variables declaration: 1178 static unsigned long lastTime = millis (); 1179 static long firstPixelHue = 0; 1180 static int pixelHue = 0; 1181 1182 // Main code: 1183 // Hue of first pixel runs 5 complete loops through the color wheel. 1184 // Color wheel has a range of 65536 but it's OK if we roll over, so 1185 // just count from 0 to 5*65536. Adding 256 to firstPixelHue each time 1186 // means we'll make 5*65536/256 = 1280 passes before starting over: 1187 if (firstPixelHue < 5 * 65536) 1188 { 1189 if (millis () - lastTime > 26UL) // change colors every 26ms 1190 { 1191 lastTime = millis (); 1192 for (int i = 0; i < ws.numPixels (); i++) 1193 { 1194 // For each pixel in strip... 1195 // Offset pixel hue by an amount to make one full revolution of the 1196 // color wheel (range of 65536) along the length of the strip 1197 // (ws.numPixels() steps): 1198 pixelHue = firstPixelHue + (i * 65536L / ws.numPixels()); 1199 // ws.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or 1200 // optionally add saturation and value (brightness) (each 0 to 255). 1201 // Here we're using just the single-argument hue variant. The result 1202 // is passed through ws.gamma32() to provide 'truer' colors 1203 // before assigning to each pixel: 1204 ws.setPixelColor (i, ws.gamma32 (ws.ColorHSV (pixelHue))); 1205 } 1206 ws.show (); // Update strip with new contents 1207 firstPixelHue += 256; 1208 } 1209 } 1210 else 1211 { 1212 firstPixelHue = 0; 1213 } 1214} 1215 1216/*------------------------------------------------------------------------------------------------------------*/ 1217/* Function for running the colorWheel effect (based on code from strandtest_Wheel neopixel library 1218 * example - adjusted for real time execution): 1219 */ 1220void colorWheelEffect () 1221{ 1222 // Local variables declaration: 1223 static unsigned long lastTime = millis (); 1224 static unsigned int counter = 0; 1225 unsigned int i = 0; 1226 1227 // Main code: 1228 if (counter < 256) 1229 { 1230 if (millis () - lastTime > 50UL) // change colors every 50ms 1231 { 1232 lastTime = millis (); 1233 for (i= 0; i < ws.numPixels (); i++) 1234 { 1235 ws.setPixelColor (i, WheelColors ((i+counter) & 255)); 1236 } 1237 ws.show (); 1238 counter++; 1239 } 1240 } 1241 else 1242 { 1243 counter = 0; 1244 } 1245} 1246 1247/*------------------------------------------------------------------------------------------------------------*/ 1248/* Function for calculating and returning the colors to the colorWheelEffect function. Input a value 1249 * 0 to 255 to get a color value. The colors are a transition r - g - b - back to r (code from 1250 * strandtest_Wheel neopixel library example - adjusted for real time execution): 1251 */ 1252unsigned long WheelColors (byte WheelPos) 1253{ 1254 WheelPos = 255 - WheelPos; 1255 if (WheelPos < 85) 1256 { 1257 return ws.Color (255 - WheelPos * 3, 0, WheelPos * 3); 1258 } 1259 if (WheelPos < 170) 1260 { 1261 WheelPos -= 85; 1262 return ws.Color (0, WheelPos * 3, 255 - WheelPos * 3); 1263 } 1264 WheelPos -= 170; 1265 return ws.Color (WheelPos * 3, 255 - WheelPos * 3, 0); 1266} 1267 1268/*------------------------------------------------------------------------------------------------------------*/ 1269 1270/*------------------------------------------------------------------------------------------------------------*/ 1271/* Function for handling the photoresistor - read the light in the room and adjust the WS2811 LEDs 1272 and the VFDs brightness accordingly: 1273*/ 1274void photoresistorHandler () 1275{ 1276 // Local variables declaration: 1277 // WS2811 LEDs brightness part: 1278 static unsigned int count = 0; 1279 static unsigned long lastTime = millis (); 1280 static unsigned int sum = 0; 1281 unsigned int lightMedian = 0; 1282 int countReset = 10; // how many counts (seconds) it takes before changing the brightness 1283 1284 // Main code: 1285 // Check the values of the light in the room once every seconds, count the median light and after 1286 // countReset seconds set the new brightness to VFDs and LEDs: 1287 if (millis () - lastTime > 1000UL) // check the value of the photoresistor every second 1288 { 1289 lastTime = millis (); 1290 count++; 1291 sum = analogRead (LDRPIN) + sum; 1292 lightMedian = sum / count; 1293 } 1294 if (count == countReset) 1295 { 1296 // Set new brightness to backlight LEDs: 1297 wsBrightness = map (lightMedian, 0, 1023, WS_BRIGHT_MIN, WS_BRIGHT_MAX); 1298 ws.setBrightness (wsBrightness); 1299 ws.show (); 1300 // Set new brightness to dot LEDs: 1301 dotsBrightness = map (lightMedian, 0, 1023, DOTS_BRIGHT_MIN, DOTS_BRIGHT_MAX); 1302 dots.setBrightness (dotsBrightness); 1303 dots.show (); 1304 // Set new brightness to VFD tybes part: 1305 vfdBrightness = map (lightMedian, 0, 1023, VFD_BRIGHT_MIN, VFD_BRIGHT_MAX); 1306 count = 0; 1307 sum = 0; 1308 } 1309} 1310/*------------------------------------------------------------------------------------------------------------*/ 1311 1312/*------------------------------------------------------------------------------------------------------------*/ 1313/* Function to handle the button presses: 1314*/ 1315void buttonsHandler () 1316{ 1317 // --------------------------------------------- normal button mode: ---------------------------------------- 1318 if (setTimeModeFlag == false) 1319 { 1320 // Button 1 (normal mode): 1321 if (button1.read () == MD_KeySwitch::KS_PRESS) // switch between 12hour and 24hour modes 1322 { 1323 if (vfdDisplayMode == 2) 1324 { 1325 vfdDisplayMode = previousDisplayMode; // go to mode before entering mode 2 (12h or 24h) 1326 vfdHandler (true); 1327 vfdDashEffectOn = true; 1328 } 1329 else if (vfdDisplayMode == 1) 1330 { 1331 vfdDisplayMode = 0; 1332 vfdHandler (true); 1333 } 1334 else if (vfdDisplayMode == 0) 1335 { 1336 vfdDisplayMode = 1; 1337 vfdHandler (true); 1338 } 1339 PRINTS ("\ 1340Button 1 pressed."); 1341 } 1342 if (button1.read () == MD_KeySwitch::KS_LONGPRESS) // enter set time mode 1343 { 1344 if (vfdDisplayMode == 0) // 24h set time mode 1345 { 1346 vfdDisplayMode = 4; 1347 setTimeModeFlag = true; 1348 } 1349 else if (vfdDisplayMode == 1) // 12h set time mode 1350 { 1351 vfdDisplayMode = 5; 1352 setTimeModeFlag = true; 1353 } 1354 // Disable button 2 long press in order to register repeat presses in set time modes (MD_KeySwitch 1355 // library restriction): 1356 button2.enableLongPress (false); 1357 button2.enableRepeat (true); 1358 button2.enableRepeatResult (true); 1359 button2.setRepeatTime (180); 1360 button2.setLongPressTime (170); // because it needs to be smaller that reapeat time 1361 PRINTS ("\ 1362Button 1 long pressed."); 1363 } 1364 1365 // Button 2 (normal mode): 1366 if (button2.read () == MD_KeySwitch::KS_PRESS) // turn on and off temp & humidity periodic display 1367 { 1368 if (vfdDisplayMode == 2) 1369 { 1370 vfdDisplayMode = previousDisplayMode; // go to mode before entering mode 2 (12h or 24h) 1371 vfdDashEffectOn = true; 1372 return; 1373 } 1374 if (tempDisplayOn == false) 1375 { 1376 tempDisplayOn = true; 1377 vfdHandler (true); 1378 vfdDotEffectOn = true; 1379 previousDisplayMode = vfdDisplayMode; 1380 vfdDisplayMode = 3; 1381 } 1382 else 1383 { 1384 tempDisplayOn = false; 1385 vfdDisplayMode = previousDisplayMode; 1386 vfdDashEffectOn = true; 1387 } 1388 PRINTS ("\ 1389Button 2 pressed."); 1390 } 1391 if (button2.read () == MD_KeySwitch::KS_LONGPRESS) // go to mode 2 (temp & humidity only) on longpress 1392 { 1393 previousDisplayMode = vfdDisplayMode; // keep mode before entering mode 2 (12h or 24h) 1394 vfdDisplayMode = 2; 1395 vfdDotEffectOn = true; 1396 PRINTS ("\ 1397Button 2 long pressed."); 1398 } 1399 1400 // Button 3 (normal mode): 1401 if (button3.read () == MD_KeySwitch::KS_PRESS) // go to next ws LEDs mode 1402 { 1403 if (wsMode < wsModeNum) 1404 { 1405 wsMode++; 1406 } 1407 else if (wsMode == wsModeNum) 1408 { 1409 wsMode = 1; 1410 } 1411 wsTransition = true; 1412 wsHandler (); 1413 if (wsMode != 4 && wsMode != 5) // in modes 4 and 5 wipe effect is off so no reset needed 1414 { 1415 colorWipeEffect (true); // run once to reset the wipe effect 1416 } 1417 PRINTS ("\ 1418Button 3 pressed."); 1419 } 1420 1421 // Button 4 (normal mode): 1422 if (button4.read () == MD_KeySwitch::KS_PRESS) // turn WS LEDs on or off 1423 { 1424 if (wsOff == true) 1425 { 1426 wsOff = false; 1427 if (wsMode != 4 && wsMode != 5) // in modes 4 and 5 wipe effect is off so no reset needed 1428 { 1429 colorWipeEffect (true); // run once to reset the wipe effect 1430 } 1431 wsHandler (); 1432 } 1433 else if (wsOff == false) 1434 { 1435 wsOff = true; 1436 rainbowEffectTrigger = false; 1437 colorWipeEffectTrigger = false; 1438 colorWheelEffectTrigger = false; 1439 ws.clear (); 1440 ws.show (); 1441 } 1442 } 1443 } 1444 else // ------------------------------------- set time button mode: ----------------------------------------- 1445 { 1446 // Button 1 (set time mode): 1447 if (button1.read () == MD_KeySwitch::KS_PRESS) // save temp time variable that was set 1448 { 1449 if (setTimeStageArray [0] == false) 1450 { 1451 if (vfdDisplayMode == 4) // on 24h mode save the time 1452 { 1453 RTC.h = tempTimeHolder; 1454 RTC.writeTime (); // save hours 1455 } 1456 if (vfdDisplayMode == 5) // on 12h mode time needs conversion before saving 1457 { 1458 if (setTimeAm == true) 1459 { 1460 if (tempTimeHolder == 12) 1461 { 1462 RTC.h = 0; // translate to 24h the state of am or pm 1463 } 1464 else 1465 { 1466 RTC.h = tempTimeHolder; 1467 } 1468 } 1469 else 1470 { 1471 if (tempTimeHolder < 12) 1472 { 1473 RTC.h = tempTimeHolder + 12; // translate to 24h the state of am or pm 1474 } 1475 else 1476 { 1477 RTC.h = tempTimeHolder; 1478 } 1479 } 1480 RTC.writeTime (); 1481 } 1482 setTimeStageArray [0] = true; 1483 tempTimeHolder = RTC.m; // pass current minutes to temp time variable for manipulation with buttons 1484 } 1485 else if (setTimeStageArray [1] == false) // save minutes that were set 1486 { 1487 RTC.m = tempTimeHolder; 1488 RTC.s = 0; // seconds always set to 0 when setting minutes 1489 RTC.writeTime (); // save minutes 1490 setTimeStageArray [1] = true; 1491 if (vfdDisplayMode == 4) // exit back to 24h mode 1492 { 1493 vfdDisplayMode = 0; 1494 tempTimeHolder = 0; 1495 setTimeModeFlag = false; 1496 timeSetModeReset = true; 1497 vfdHandler (true); 1498 vfdDotEffectOn = true; 1499 // Enable button 2 long press in order to register long presses in normal modes (MD_KeySwitch 1500 // library restriction): 1501 button2.enableLongPress (true); 1502 button2.enableRepeat (false); 1503 button2.enableRepeatResult (false); 1504 button2.setLongPressTime (2000); 1505 } 1506 } 1507 else if (setTimeStageArray [2] == false) // save AM/PM and exit back to 12h mode 1508 { 1509 if (setTimeAm == true) 1510 { 1511 if (RTC.h == 12) 1512 { 1513 RTC.h = 0; // translate to 24h the state of am or pm 1514 RTC.writeTime (); 1515 } 1516 vfdDisplayMode = 1; 1517 tempTimeHolder = 0; 1518 setTimeModeFlag = false; 1519 timeSetModeReset = true; 1520 vfdHandler (true); 1521 vfdDotEffectOn = true; 1522 } 1523 else 1524 { 1525 if (RTC.h < 12) 1526 { 1527 RTC.h = RTC.h + 12; // translate to 24h the state of am or pm 1528 RTC.writeTime (); 1529 } 1530 vfdDisplayMode = 1; 1531 tempTimeHolder = 0; 1532 setTimeModeFlag = false; 1533 timeSetModeReset = true; 1534 vfdHandler (true); 1535 vfdDotEffectOn = true; 1536 } 1537 // Enable button 2 long press in order to register long presses in normal modes (MD_KeySwitch 1538 // library restriction): 1539 button2.enableLongPress (true); 1540 button2.enableRepeat (false); 1541 button2.enableRepeatResult (false); 1542 button2.setLongPressTime (2000); 1543 } 1544 else 1545 { 1546 return; 1547 } 1548 PRINTS ("\ 1549Button 1 pressed."); 1550 } 1551 1552 // Button 2 (set time mode): 1553 switch (button2.read ()) 1554 { 1555 case MD_KeySwitch::KS_PRESS: // button 2 single press - increase temp time variable 1556 if (setTimeStageArray [0] == false) 1557 { 1558 if (vfdDisplayMode == 4) // 24h mode 1559 { 1560 if (tempTimeHolder >= 0 && tempTimeHolder < 23) // increase hours 1561 { 1562 tempTimeHolder++; 1563 } 1564 else 1565 { 1566 tempTimeHolder = 0; 1567 } 1568 } 1569 if (vfdDisplayMode == 5) // 12h mode 1570 { 1571 if (tempTimeHolder >= 1 && tempTimeHolder < 12) // increase hours 1572 { 1573 tempTimeHolder++; 1574 } 1575 else 1576 { 1577 tempTimeHolder = 1; 1578 } 1579 } 1580 } 1581 else if (setTimeStageArray [1] == false) 1582 { 1583 if (tempTimeHolder >= 0 && tempTimeHolder < 59) // increase minutes 1584 { 1585 tempTimeHolder++; 1586 } 1587 else 1588 { 1589 tempTimeHolder = 0; 1590 } 1591 } 1592 else // set am or pm 1593 { 1594 if (setTimeAm == true) 1595 { 1596 setTimeAm = false; 1597 digitalWrite (AM_LED, LOW); 1598 digitalWrite (PM_LED, HIGH); 1599 } 1600 else 1601 { 1602 setTimeAm = true; 1603 digitalWrite (AM_LED, HIGH); 1604 digitalWrite (PM_LED, LOW); 1605 } 1606 } 1607 PRINTS ("\ 1608Button 2 pressed."); 1609 break; 1610 case MD_KeySwitch::KS_RPTPRESS: // button 2 repeat press - increase temp time variable fast 1611 repeatOn = true; // set to true in order to stop blinking in setTimeMode function 1612 if (setTimeStageArray [0] == false) 1613 { 1614 if (vfdDisplayMode == 4) // 24h mode 1615 { 1616 if (tempTimeHolder >= 0 && tempTimeHolder < 23) // increase hours 1617 { 1618 tempTimeHolder++; 1619 } 1620 else 1621 { 1622 tempTimeHolder = 0; 1623 } 1624 } 1625 if (vfdDisplayMode == 5) // 12h mode 1626 { 1627 if (tempTimeHolder >= 1 && tempTimeHolder < 12) // increase hours 1628 { 1629 tempTimeHolder++; 1630 } 1631 else 1632 { 1633 tempTimeHolder = 1; 1634 } 1635 } 1636 } 1637 else 1638 { 1639 if (tempTimeHolder >= 0 && tempTimeHolder < 59) // increase minutes 1640 { 1641 tempTimeHolder++; 1642 } 1643 else 1644 { 1645 tempTimeHolder = 0; 1646 } 1647 } 1648 PRINTS ("\ 1649Button 2 repeat pressed."); 1650 break; 1651 default: 1652 break; 1653 } 1654 1655 // Button 3 (set time mode): 1656 switch (button3.read ()) 1657 { 1658 case MD_KeySwitch::KS_PRESS: // button 3 single press - decrease temp time variable 1659 if (setTimeStageArray [0] == false) 1660 { 1661 if (vfdDisplayMode == 4) // 24h mode 1662 { 1663 if (tempTimeHolder > 0 && tempTimeHolder <= 23) // decrease hours 1664 { 1665 tempTimeHolder--; 1666 } 1667 else 1668 { 1669 tempTimeHolder = 23; 1670 } 1671 } 1672 if (vfdDisplayMode == 5) // 12h mode 1673 { 1674 if (tempTimeHolder > 1 && tempTimeHolder <= 12) // decrease hours 1675 { 1676 tempTimeHolder--; 1677 } 1678 else 1679 { 1680 tempTimeHolder = 12; 1681 } 1682 } 1683 } 1684 else if (setTimeStageArray [1] == false) 1685 { 1686 if (tempTimeHolder > 0 && tempTimeHolder <= 59) // decrease minutes 1687 { 1688 tempTimeHolder--; 1689 } 1690 else 1691 { 1692 tempTimeHolder = 59; 1693 } 1694 } 1695 else // set am or pm 1696 { 1697 if (setTimeAm == true) 1698 { 1699 setTimeAm = false; 1700 digitalWrite (AM_LED, LOW); 1701 digitalWrite (PM_LED, HIGH); 1702 } 1703 else 1704 { 1705 setTimeAm = true; 1706 digitalWrite (AM_LED, HIGH); 1707 digitalWrite (PM_LED, LOW); 1708 } 1709 } 1710 1711 PRINTS ("\ 1712Button 3 pressed."); 1713 break; 1714 case MD_KeySwitch::KS_RPTPRESS: // button 3 repeat press - decrease temp time variable fast 1715 repeatOn = true; // set to true in order to stop blinking in setTimeMode function 1716 if (setTimeStageArray [0] == false) 1717 { 1718 if (vfdDisplayMode == 4) // 24h mode 1719 { 1720 if (tempTimeHolder > 0 && tempTimeHolder <= 23) // decrease hours 1721 { 1722 tempTimeHolder--; 1723 } 1724 else 1725 { 1726 tempTimeHolder = 23; 1727 } 1728 } 1729 if (vfdDisplayMode == 5) // 12h mode 1730 { 1731 if (tempTimeHolder > 1 && tempTimeHolder <= 12) // decrease hours 1732 { 1733 tempTimeHolder--; 1734 } 1735 else 1736 { 1737 tempTimeHolder = 12; 1738 } 1739 } 1740 } 1741 else 1742 { 1743 if (tempTimeHolder > 0 && tempTimeHolder <= 59) // decrease minutes 1744 { 1745 tempTimeHolder--; 1746 } 1747 else 1748 { 1749 tempTimeHolder = 59; 1750 } 1751 } 1752 PRINTS ("\ 1753Button 3 repeat pressed."); 1754 break; 1755 default: 1756 break; 1757 } 1758 1759 // Button 4 (set time mode): 1760 if (button4.read () == MD_KeySwitch::KS_PRESS) // exit set time mode 1761 { 1762 setTimeModeFlag = false; 1763 timeSetModeReset = true; 1764 if (vfdDisplayMode == 4) // exit back to 24h mode 1765 { 1766 vfdDisplayMode = 0; 1767 } 1768 else if (vfdDisplayMode == 5) // exit back to 12h mode 1769 { 1770 vfdDisplayMode = 1; 1771 } 1772 vfdHandler (true); 1773 if (setTimeStageArray [0] == true) // if even one variable is set, show dot effect 1774 { 1775 vfdDotEffectOn = true; 1776 } 1777 else // if nothing is set, show dash effect 1778 { 1779 vfdDashEffectOn = true; 1780 } 1781 // Enable button 2 long press in order to register long presses in normal modes (MD_KeySwitch 1782 // library restriction): 1783 button2.enableLongPress (true); 1784 button2.enableRepeat (false); 1785 button2.enableRepeatResult (false); 1786 button2.setLongPressTime (2000); 1787 PRINTS ("\ 1788Button 4 pressed."); 1789 } 1790 } 1791} 1792 1793/*************************************************************************************************************** 1794***************************************************************************************************************/ 1795
Downloadable files
Back PCB-Front side
Back PCB-Front side

Front board bill of materials
Components of the front board with the designator that is used in the schematic
Front board bill of materials
Back board bill of materials
Components of the back board with the designator that is used in the schematic
Back board bill of materials
Back board schematic
The schematic of the back board where the power supplies etc. are
Back board schematic
Front board schematic
The schematic of the front board where the IV-22 tubes etc. are
Front board schematic
Button instructions
A document with instructions on how to use the four buttons of the clock
Button instructions
Front PCB-Back side
Front PCB-Back side

Front board bill of materials
Components of the front board with the designator that is used in the schematic
Front board bill of materials
VFD Clock Pin connections
A file with all the pin connections of the clock - what connects to what, what it is named in the Arduino IDE etc.
VFD Clock Pin connections
Front board schematic
The schematic of the front board where the IV-22 tubes etc. are
Front board schematic
Front PCB-Front side
Front PCB-Front side

Back PCB-Back side
Back PCB-Back side

Back PCB-Front side
Back PCB-Front side

Back board bill of materials
Components of the back board with the designator that is used in the schematic
Back board bill of materials
Back board schematic
The schematic of the back board where the power supplies etc. are
Back board schematic
Front PCB-Back side
Front PCB-Back side

VFD Clock Pin connections
A file with all the pin connections of the clock - what connects to what, what it is named in the Arduino IDE etc.
VFD Clock Pin connections
Back PCB-Back side
Back PCB-Back side

Button instructions
A document with instructions on how to use the four buttons of the clock
Button instructions
Comments
Only logged in users can leave comments