deathorion
Published © GPL3+

Homemade IV-22 VFD Clock!

Glowing retro tubes made in the Soviet Union? 80's electro-style? Sign me up! (or sign us up comrade?)

IntermediateShowcase (no instructions)2,000
Homemade IV-22 VFD Clock!

Things used in this project

Hardware components

Microchip ATMEGA328P-PU
The microcontroller - you can buy it from ebay with the Arduino UNO bootloader already installed so you can skip installing it yourself
×1
Microchip HV5812P-G
The driver for the VFD tubes
×1
Analog Devices DS3231MZ+
The chip that keeps track of the time
×1
DHT11 Temperature & Humidity Sensor (4 pins)
DHT11 Temperature & Humidity Sensor (4 pins)
×1

Software apps and online services

Arduino IDE
Arduino IDE
The IDE used to program the microcontroller - remember to load the Arduino bootloader to the microcontroller
EasyEDA
Free online or desktop EDA program to design schematics and PCBs

Story

Read more

Schematics

Front board schematic

The schematic of the front board where the IV-22 tubes etc. are

Back board schematic

The schematic of the back board where the power supplies etc. are

Front PCB-Front side

Front PCB-Back side

Back PCB-Front side

Back 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.

Gerber file of the Front board

You can import this file to an EDA program and see or edit the PCB

Gerber file of the Back board

You can import this file to an EDA program and see or edit the PCB

Front board bill of materials

Components of the front board with the designator that is used in the schematic

Back board bill of materials

Components of the back board with the designator that is used in the schematic

Button instructions

A document with instructions on how to use the four buttons of the clock

Code

VFD_Clock-Main_Sketch-0.3.5.ino

C/C++
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.
/***************************************************************************************************************
 ***************************************************************************************************************
   VFD Clock Main Sketch
   Version 0.3.5
   Tested with: Arduino IDE 1.8.16 - Arduino AVR Boards 1.8.4 - MD_DS3231 1.3.1 - Adafruit_NeoPixel 1.7.0 -
   MD_KeySwitch 1.4.2 - DHT sensor library 1.4.3 - ATMega328P-PU with Arduino UNO R3 bootloader
   (for uploading code with the FTDI board select Tools-> Board:-> "Ardruino Uno")
   17-05-2022
   Leon
 **************************************************************************************************************/
// Libraries needed:
#include <MD_DS3231.h> // Pre-existing object named RTC (SCL to pin A5, SDA to pin A4)
#include <Adafruit_NeoPixel.h>
#include <MD_KeySwitch.h>
#include "DHT.h"
#include <SPI.h>

// Turn debugging on and off:
#define DEBUG 1
#if DEBUG
#define PRINTS(s)   { Serial.print (F(s));}                   // Print a string
#define PRINT(s, v) { Serial.print (F(s)); Serial.print (v);} // Print string then value (dec) 
#include <MemoryFree.h> // Library for printing free memory on runtime                                       
#else
#define PRINTS(s)   // Print a string
#define PRINT(s, v) // Print a string followed by a value (decimal)
#endif

// General universal variables:
byte currentHours = 0;       // variable to hold the value of the current hour
byte currentSeconds = 0;     // variable to hold the value of the current seconds

// Variables for holding the individual digits of time:
byte hoursFirstDigit = 0;
byte hoursSecondDigit = 0;
byte minutesFirstDigit = 0;
byte minutesSecondDigit = 0;

// VFD tubes:
#define NUM_DIGITS 2                    // define number of display digits.
const byte Blank = 9;                   // Output to HV5812P-G 'BLANK' input
const byte strobe = 10;                 // Output to HV5812P-G 'STROBE' input
byte timeBuffer [4];                    // array to hold the time digits
byte vfdDisplayMode = 0;                
// mode 0 = 24h time display
// mode 1 = 12h time display
// mode 2 = temperature & humidity only display (without time)
// mode 3 = display temp & humidity once (used when turning tempDisplayOn to true)
// mode 4 = set time in 24h mode
// mode 5 = set time in 12h mode
bool previousDisplayMode = 0;           // variable to hold the previous display mode
bool tempDisplayOn = true;              // show temp and humidity periodically on modes 0 and 1
bool vfdCycleEffectOn = false;          // trigger for vfd cycle effect
bool vfdDashEffectOn = false;           // trigger for vfd dash effect - used to indicate "OFF"
bool vfdDotEffectOn = false;            // trigger for vfd dot effect - used to indicate "ON"
byte effectBuffer [4];                  // array to hold the effects digits
bool setTimeModeFlag = false;           // flag for checking if setTimeMode is running
bool timeSetModeReset = true;           // used to reset variables at the first run of timeSetMode function
byte tempTimeHolder = 0;                // hold the time that is displayed currently on setTimeMode
bool setTimeStageArray [3] = {false};   // array that holds which steps of the time setting are completed
bool setTimeAm = false;                 // if am = true, if pm = false - used in 12h set time  mode

// Array with the bit-pattern for each tube Grid - the grids are MULTIPLEXED: 1 and 3 VFDs are on
// together while 2 and 4 VFDs are off and in reverse:
const byte grids [2] =
{
  B00000101,
  B00001010,
};

// Array with the bit-pattern for each and 7-segment number character:
const byte symbols [25] =
{
  B01110111, // 0
  B00100100, // 1
  B01011101, // 2
  B01101101, // 3
  B00101110, // 4
  B01101011, // 5
  B01111011, // 6
  B00100101, // 7
  B01111111, // 8
  B01101111, // 9
  B00000000, // 10 (Blank)
  B01011000, // 11 (c  celsius)
  B01010011, // 12 (C  Celsius)
  B00001111, // 13 (top half on)
  B01111000, // 14 (bottom half on)
  B10000000, // 15 (. dot - used to signal ON)
  B11111111, // 16 (all segments on)
  B00001000, // 17 (- dash used to signal OFF)
  B00100000, // 18 (from 18 to 24 are the cycle effect bit-patterns)
  B01000000, // 19
  B00010000, // 20
  B00000010, // 21
  B00000001, // 22
  B00000100, // 23
  B00100000, // 24
};

// DHT11 temperature and humidity sensor:
#define DHTPIN 7                     // pin the sensor is connected to
DHT dht (DHTPIN, DHT11);
byte tempFirstDigit = 0;
byte tempSecondDigit = 0;
byte tempThirdDigit = 0;
byte tempBuffer [4];                 // array to hold the temp digits
byte humidityFirstDigit = 0;
byte humiditySecondDigit = 0;
byte humidityBuffer [4];             // array to hold the humidity digits
float originalTemp = 0;              // hold the temperature before compensating for electronics heat
float compensatedTemp = 0;           // hold temperature after compensating for electronics
const float tempCompensation = 1.80; // degrees in c to compensate for electronics heat

// Dots:
#define DOTS_PIN A1
#define DOTS_NUM 2
Adafruit_NeoPixel dots (DOTS_NUM, DOTS_PIN, NEO_RGB + NEO_KHZ800);
#define AM_LED 12
#define PM_LED A2

// WS LEDs:
#define WS_PIN 2
#define WS_NUM 4
Adafruit_NeoPixel ws (WS_NUM, WS_PIN, NEO_RGB + NEO_KHZ800);
byte wsMode = 1;                        // variable to hold the WS2911 LEDs mode - default is 1
byte wsModeNum = 5;                     // variable to hold the number (sum) of WS2911 LEDs modes
bool wsTransition = false;              // true if mode transition is on, false if not
#define WSTRANSTIME 1800UL              // transition duration in milliseconds
bool wsOff = false;                     // true if the WS2911 LEDs are off, false if they are on
bool wsWasOn = false;                   // true if the LEDs were on, false if not
bool rainbowEffectTrigger = false;      // flag for triggering the rainbow effect
bool colorWipeEffectTrigger = false;    // flag for triggering the color wipe effect
bool colorWheelEffectTrigger = false;   // flag for triggering the colorWheel effect
int redLedArray [4] = {0};              // array to hold the values of the red WS2911 LEDs
int greenLedArray [4] = {0};            // array to hold the values of the green WS2911 LEDs
int blueLedArray [4] = {0};             // array to hold the values of the blue WS2911 LEDs
unsigned long tempColorArray [4] = {0}; // array to hold the values of rainbow or wheel colors

// LDR Photoresistor:
#define LDRPIN A3                // analog pin that the LDR photoresistor is connected on the Arduino
#define VFD_BRIGHT_MAX 0         // full brightness                
#define VFD_BRIGHT_MIN 250       // fully dimmed
byte vfdBrightness = 120;        // startup brightness of VFDs (half brightness)
#define WS_BRIGHT_MAX 100         // maximum brightness the LEDs will go depending on room light
#define WS_BRIGHT_MIN 10         // minimum brightness the LEDs will go depending on room light
byte wsBrightness = 44;          // startup brightness of the WS2811 LEDs (half brightness)
#define DOTS_BRIGHT_MAX 60       // maximum brightness the dots will go depending on room light
#define DOTS_BRIGHT_MIN 10       // minimum brightness the dots will go depending on room light
byte dotsBrightness = 24;        // startup brightness of the dots (half brightness)

// Buttons:
MD_KeySwitch button1 (3, LOW); // set button 1 to pin 3
MD_KeySwitch button2 (4, LOW); // set button 2 to pin 4
MD_KeySwitch button3 (5, LOW); // set button 3 to pin 5
MD_KeySwitch button4 (6, LOW); // set button 4 to pin 6
bool repeatOn = false;         // true if repeat button pressed

// Functions with default values declaration:
void vfdHandler (bool reset = false);
void displayTime (bool mode12hours = false);
void colorWipeEffect (bool resetTrigger = false);

/*-------------------------------------------------- SETUP: --------------------------------------------------*/
void setup ()
{
  // Debug setup:
#if DEBUG
  Serial.begin (9600);
  PRINTS ("\n[VFD Clock]");
#endif

  // Set Fast PWM frequency on pin 9 [and 10] (for dimming display):
  TCCR1B = (TCCR1B & 0b11111000) | 0x1;

  // start SPI:
  SPI.begin ();

  // VFDs setup:
  pinMode (strobe, OUTPUT);
  pinMode (Blank, OUTPUT);
  analogWrite (Blank, 255);  // Set vfd brightness to zero at startup

  // DHT11 temperature and humidity sensor:
  dht.begin ();

  // Dots setup:
  dots.begin ();                        // INITIALIZE NeoPixel strip object (REQUIRED)
  dots.setBrightness (dotsBrightness);  // set default brightness
  dots.clear ();                        // set all pixel colors to 'off'
  dots.show ();                         // send the updated pixel colors to the hardware

  // WS LEDs setup:
  ws.begin ();                     // initialize NeoPixel strip object
  ws.show ();                      // turn OFF all pixels ASAP
  ws.setBrightness (wsBrightness); // Set the brightness
  wsHandler (); 

  // AM-PM LEDs setup:
  pinMode (AM_LED, OUTPUT);
  pinMode (PM_LED, OUTPUT);
  digitalWrite (AM_LED, LOW);
  digitalWrite (PM_LED, LOW);

  // LDR Photoresistor setup:
  pinMode (LDRPIN, INPUT);

  // Buttons setup:
  // Keep in mind library restriction: debounce time < Long Press Time < Repeat time
  // Button 1:
  button1.begin();
  button1.enableDoublePress (false);
  button1.enableLongPress (true);
  button1.enableRepeat (false);
  button1.enableRepeatResult (false);
  button1.setDebounceTime (160);
  button1.setLongPressTime (2000); // set long press time to 2 seconds
  // Button 2:
  button2.begin();
  button2.enableDoublePress (false);
  button2.enableLongPress (true);
  button2.enableRepeat (false);
  button2.enableRepeatResult (false);
  button2.setDebounceTime (160);
  button2.setLongPressTime (2000); // set long press time to 2 seconds
  // Button 3:
  button3.begin();
  button3.enableDoublePress (false);
  button3.enableLongPress (false);
  button3.enableRepeat (true);
  button3.enableRepeatResult (true);
  button3.setRepeatTime (180);
  button3.setDebounceTime (160);
  // Button 4:
  button4.begin();
  button4.enableDoublePress (false);
  button4.enableLongPress (true);
  button4.enableRepeat (false);
  button4.enableRepeatResult (false);
  button4.setDebounceTime (160);
  button4.setLongPressTime (2000); // set long press time to 2 seconds
}

/*------------------------------------------------- LOOP: ----------------------------------------------------*/
void loop ()
{
  // Run the handlers:
  vfdHandler ();
  buttonsHandler ();
  photoresistorHandler ();

  // Run the color wipe effect if it is on:
  if (colorWipeEffectTrigger == true)
  {
    colorWipeEffect ();
  }

  // Run the rainbow effect if it is on:
  if (rainbowEffectTrigger == true)
  {
    rainbowEffect ();
  }

  // Run the color wheel effect if it is on:
  if (colorWheelEffectTrigger == true)
  {
    colorWheelEffect ();
  }
}
/*---------------------------------------------- END OF LOOP -------------------------------------------------*/

/*------------------------------------------------------------------------------------------------------------*/
/* Function for handling what is displayed in the VFD tubes including timing of events and set time modes.
   When called with reset = true, variables are reset:
*/
void vfdHandler (bool reset = false)
{
  // Local variables declaration:
  static unsigned long lastTime = 0;             // time keeping for time display
  static unsigned long lastTimeCyrcleEffect = 0; // time keeping for cycle effect
  static unsigned long lastTimeDashEffect = 0;   // time keeping for dash effect
  static unsigned long lastTimeDotEffect = 0; // time keeping for dot effect
  static unsigned long  startTime = millis (); // time keeping for blinking digits on set time modes
  static bool dashEffectFirstRun = true;
  static bool dotEffectFirstRun = true;
  static bool tempFirstRun = true;     // used to read temperature only once per cycle
  static bool humidityFirstRun = true; // used to read humidity only once per cycle
  unsigned long DELAY = 4400;          // time that the temp and humidity will be displayed
  static byte effectCounter = 0;       // keep track of the stage of the cycle effect

  // Main code:
  RTC.readTime (); // get the time from the module

  // Reset variables and exit:
  if (reset == true)
  {
    lastTime = millis ();
    reset = false;
    tempFirstRun = true;
    humidityFirstRun = true;
    digitalWrite (AM_LED, LOW);
    digitalWrite (PM_LED, LOW);
    return;
  }

  // Execute effects:
  if (vfdCycleEffectOn == true) // dot effect
  {
    if (millis () - lastTimeCyrcleEffect < 60UL) // run for X seconds
    {
      effectBuffer [0] = 18 + effectCounter;
      effectBuffer [1] = 18 + effectCounter;
      effectBuffer [2] = 18 + effectCounter;
      effectBuffer [3] = 18 + effectCounter;
      updateDisplay (effectBuffer);
    }
    else
    {
      lastTimeCyrcleEffect = millis ();
      effectCounter++;
    }
    if (effectCounter == 7)
    {
      effectCounter = 0;
      vfdCycleEffectOn = false;
    }
    return;
  }
  else if (vfdDashEffectOn == true) // dash effect, only one effect active simultaneously
  {
    if (dashEffectFirstRun == true)
    {
      lastTimeDashEffect = millis ();
      dashEffectFirstRun = false;
    }
    if (millis () - lastTimeDashEffect < 1000UL) // run for X seconds
    {
      effectBuffer [0] = 17;
      effectBuffer [1] = 17;
      effectBuffer [2] = 17;
      effectBuffer [3] = 17;
      updateDisplay (effectBuffer);
    }
    else
    {
      vfdDashEffectOn = false;
      dashEffectFirstRun = true;
    }
    return;
  }
  else if (vfdDotEffectOn == true) // dot effect, only one effect active simultaneously
  {
    if (dotEffectFirstRun == true)
    {
      lastTimeDotEffect = millis ();
      dotEffectFirstRun = false;
    }
    if (millis () - lastTimeDotEffect < 1000UL) // run for X seconds
    {
      effectBuffer [0] = 15;
      effectBuffer [1] = 15;
      effectBuffer [2] = 15;
      effectBuffer [3] = 15;
      updateDisplay (effectBuffer);
    }
    else
    {
      vfdDotEffectOn = false;
      dotEffectFirstRun = true;
    }
    return;
  }

  switch (vfdDisplayMode)
  {

    case 0: // --------------------------------   24h time display:   --------------------------------
      if (tempDisplayOn == false) // display only time
      {
        displayTime ();
      }
      else // display temperature and humidity at DELAY intervals
      {
        if (RTC.s > 10 && RTC.s <= 10 + (DELAY / 1000) * 2 || RTC.s > 30 && RTC.s <= 30 + (DELAY / 1000) * 2)
        {
          if (millis () - lastTime < DELAY) // run for delay seconds
          {
            if (tempFirstRun == true)
            {
              tempFirstRun = false;
              displayTemp (true);
              vfdCycleEffectOn = true;
            }
            else
            {
              displayTemp (false);
            }
          }
          else if (millis () - lastTime < DELAY * 2)
          {
            if (humidityFirstRun == true)
            {
              humidityFirstRun = false;
              displayHumidity (true);
              vfdCycleEffectOn = true;
            }
            else
            {
              displayHumidity (false);
            }
          }
          else
          {
            lastTime = millis ();
            tempFirstRun = true;
            humidityFirstRun = true;
          }
        }
        else
        {
          displayTime ();
        }
      }
      break;

    case 1: // --------------------------------  12h time display:   --------------------------------
      if (tempDisplayOn == false) // just display time
      {
        displayTime (true);
      }
      else // display temperature and humidity at DELAY intervals
      {
        if (RTC.s > 10 && RTC.s <= 10 + (DELAY / 1000) * 2 || RTC.s > 40 && RTC.s <= 40 + (DELAY / 1000) * 2)
        {
          if (millis () - lastTime < DELAY) // run for DELAY seconds
          {
            if (tempFirstRun == true)
            {
              tempFirstRun = false;
              displayTemp (true);
              vfdCycleEffectOn = true;
            }
            else
            {
              displayTemp (false);
            }
          }
          else if (millis () - lastTime < DELAY * 2)
          {
            if (humidityFirstRun == true)
            {
              humidityFirstRun = false;
              displayHumidity (true);
              vfdCycleEffectOn = true;
            }
            else
            {
              displayHumidity (false);
            }
          }
          else
          {
            lastTime = millis ();
            tempFirstRun = true;
            humidityFirstRun = true;
          }
        }
        else
        {
          displayTime (true);
        }
      }
      break;

    case 2: // ----------------------  Temperature and humidity only display mode:   ------------------------
      if (millis () - lastTime < DELAY) // run for DELAY seconds
      {
        if (tempFirstRun == true)
        {
          tempFirstRun = false;
          displayTemp (true);
          vfdCycleEffectOn = true;
        }
        else
        {
          displayTemp (false);
        }
      }
      else if (millis () - lastTime < DELAY * 2)
      {
        if (humidityFirstRun == true)
        {
          humidityFirstRun = false;
          displayHumidity (true);
          vfdCycleEffectOn = true;
        }
        else
        {
          displayHumidity (false);
        }
      }
      else
      {
        lastTime = millis ();
        tempFirstRun = true;
        humidityFirstRun = true;
      }
      break;

    case 3: // ----------------------------   Display temp and humidity once:   ----------------------------
      if (millis () - lastTime < DELAY + 1000UL) // run for DELAY + 1 seconds
      {
        if (tempFirstRun == true)
        {
          tempFirstRun = false;
          displayTemp (true);
          vfdCycleEffectOn = true;
        }
        else
        {
          displayTemp (false);
        }
      }
      else if (millis () - lastTime < (DELAY + 1000UL) * 2)
      {
        if (humidityFirstRun == true)
        {
          humidityFirstRun = false;
          displayHumidity (true);
          vfdCycleEffectOn = true;
        }
        else
        {
          displayHumidity (false);
        }
      }
      else
      {
        tempFirstRun = true;
        humidityFirstRun = true;
        // to prevent showing temperature two times in a row, skip showing it if it is to close to
        // previous display:
        if (RTC.s > 6 && RTC.s <= 12 + ((DELAY + 1000) / 1000) * 2
            || RTC.s > 36 && RTC.s <= 42 + ((DELAY + 1000) / 1000) * 2)
        {
          if (previousDisplayMode == 0)
          {
            displayTime ();
          }
          else
          {
            displayTime (true);
          }
        }
        else
        {
          vfdDisplayMode = previousDisplayMode;
        }
      }
      break;
    case 4: // --------------------------------   24h set time mode:   --------------------------------
      if (timeSetModeReset == true) // check if it's the first run of set time
      {
        timeSetModeReset = false;
        for (int i = 0; i < 3; i++) // reset array
        {
          setTimeStageArray [i] = false;
        }
        tempTimeHolder = RTC.h; // pass current time to temp variable for manipulation with buttons
        dots.clear ();  // set off dots
        dots.show ();   
      }
      else if (setTimeStageArray [0] == false) // blink hours except when on repeat
      {
        // Hours:
        if (repeatOn == false)
        {
          separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit);
          if (millis () - startTime < 500UL)
          {
            timeBuffer [0] = hoursFirstDigit;
            timeBuffer [1] = hoursSecondDigit;
          }
          else if (millis () - startTime < 1000UL)
          {
            timeBuffer [0] = 10; // 10 = blank
            timeBuffer [1] = 10; // 10 = blank
          }
          else
          {
            startTime = millis ();
          }
        }
        else // on repeat button press don't blink
        {
          separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit);
          timeBuffer [0] = hoursFirstDigit;
          timeBuffer [1] = hoursSecondDigit;
          repeatOn = false;
          startTime = millis ();
        }

        // Minutes:
        separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit);
        timeBuffer [2] = minutesFirstDigit;
        timeBuffer [3] = minutesSecondDigit;
      }
      else if (setTimeStageArray [1] == false) // if hours set, blink minutes except on repeat
      {
        // Hours:
        separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit);
        timeBuffer [0] = hoursFirstDigit;
        timeBuffer [1] = hoursSecondDigit;

        // Minutes:
        if (repeatOn == false)
        {
          separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit);
          if (millis () - startTime < 500UL)
          {
            timeBuffer [2] = minutesFirstDigit;
            timeBuffer [3] = minutesSecondDigit;
          }
          else if (millis () - startTime < 1000UL)
          {
            timeBuffer [2] = 10; // 10 = blank
            timeBuffer [3] = 10; // 10 = blank
          }
          else
          {
            startTime = millis ();
          }
        }
        else // on repeat button press don't blink
        {
          separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit);
          timeBuffer [2] = minutesFirstDigit;
          timeBuffer [3] = minutesSecondDigit;
          repeatOn = false;
          startTime = millis ();
        }
      }
      updateDisplay (timeBuffer); // update the display
      break;
    case 5: // --------------------------------   12h set time mode:   --------------------------------
      if (timeSetModeReset == true) // check if it's the first run of set time
      {
        timeSetModeReset = false;
        for (int i = 0; i < 3; i++) // reset array
        {
          setTimeStageArray [i] = false;
        }
        // Keep the status of the am/pm LEDs for consistency when setting them and translate the
        // time from 24h to 12h to display correctly:
        if (RTC.h == 0)
        {
          tempTimeHolder = 12; // pass current time to temp variable for manipulation with buttons
          setTimeAm = true;
        }
        else if (RTC.h < 12)
        {
          tempTimeHolder = RTC.h; // pass current time to temp variable for manipulation with buttons
          setTimeAm = true;
        }
        else if (RTC.h == 12)
        {
          tempTimeHolder = RTC.h; // pass current time to temp variable for manipulation with buttons
          setTimeAm = false;
        }
        else
        {
          tempTimeHolder = RTC.h - 12; // pass current time to temp variable for manipulation with buttons
          setTimeAm = false;
        }
        dots.clear ();  // turn off dots
        dots.show ();
      }
      else if (setTimeStageArray [0] == false) // blink hours except when on repeat
      {
        // Hours:
        if (repeatOn == false)
        {
          separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit);
          if (millis () - startTime < 500UL)
          {
            if (hoursFirstDigit == 0) // don't show zero
            {
              timeBuffer [0] = 10; // 10 = blank
            }
            else
            {
              timeBuffer [0] = hoursFirstDigit;
            }
            timeBuffer [1] = hoursSecondDigit;
          }
          else if (millis () - startTime < 1000UL)
          {
            timeBuffer [0] = 10; // 10 = blank
            timeBuffer [1] = 10; // 10 = blank
          }
          else
          {
            startTime = millis ();
          }
        }
        else // on repeat button press don't blink
        {
          separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit);
          if (hoursFirstDigit == 0) // don't show zero
          {
            timeBuffer [0] = 10; // 10 = blank
          }
          else
          {
            timeBuffer [0] = hoursFirstDigit;
          }
          timeBuffer [1] = hoursSecondDigit;
          repeatOn = false;
          startTime = millis ();
        }

        // Minutes:
        separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit);
        timeBuffer [2] = minutesFirstDigit;
        timeBuffer [3] = minutesSecondDigit;
      }
      else if (setTimeStageArray [1] == false) // if hours set, blink minutes except on repeat
      {
        // Hours:
        if (RTC.h == 0) // convert 24h to 12h for displaying properly
        {
          separateDoubleDigits (12, hoursFirstDigit, hoursSecondDigit);
        }
        else if (RTC.h > 12)
        {
          separateDoubleDigits (RTC.h - 12, hoursFirstDigit, hoursSecondDigit);
        }
        else
        {
          separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit);
        }
        
        if (hoursFirstDigit == 0) // don't show zero
        {
          timeBuffer [0] = 10; // 10 = blank
        }
        else
        {
          timeBuffer [0] = hoursFirstDigit;
        }
        timeBuffer [1] = hoursSecondDigit;

        // Minutes:
        if (repeatOn == false)
        {
          separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit);
          if (millis () - startTime < 500UL)
          {
            timeBuffer [2] = minutesFirstDigit;
            timeBuffer [3] = minutesSecondDigit;
          }
          else if (millis () - startTime < 1000UL)
          {
            timeBuffer [2] = 10; // 10 = blank
            timeBuffer [3] = 10; // 10 = blank
          }
          else
          {
            startTime = millis ();
          }
        }
        else // if on repeat button press don't blink
        {
          separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit);
          timeBuffer [2] = minutesFirstDigit;
          timeBuffer [3] = minutesSecondDigit;
          repeatOn = false;
          startTime = millis ();
        }
      }
      else if (setTimeStageArray [2] == false) // if minutes set, blink AM/PM
      {
        // Hours:
        if (RTC.h == 0) // convert 24h to 12h for displaying properly
        {
          separateDoubleDigits (12, hoursFirstDigit, hoursSecondDigit);
        }
        else if (RTC.h > 12)
        {
          separateDoubleDigits (RTC.h - 12, hoursFirstDigit, hoursSecondDigit);
        }
        else
        {
          separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit);
        }
        
        if (hoursFirstDigit == 0) // don't show zero
        {
          timeBuffer [0] = 10; // 10 = blank
        }
        else
        {
          timeBuffer [0] = hoursFirstDigit;
        }
        timeBuffer [1] = hoursSecondDigit;

        // Minutes:
        separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit);
        timeBuffer [2] = minutesFirstDigit;
        timeBuffer [3] = minutesSecondDigit;

        // AM/PM LEDs:
        if (millis () - startTime < 500UL)
        {
          if (setTimeAm == true)
          {
            digitalWrite (AM_LED, HIGH);
            digitalWrite (PM_LED, LOW);
          }
          else
          {
            digitalWrite (AM_LED, LOW);
            digitalWrite (PM_LED, HIGH);
          }
        }
        else if (millis () - startTime < 1000UL)
        {

          digitalWrite (AM_LED, LOW);
          digitalWrite (PM_LED, LOW);
        }
        else
        {
          startTime = millis ();
        }
      }
      updateDisplay (timeBuffer); // update the display
      break;
    default:
      break;
  }
}

/*------------------------------------------------------------------------------------------------------------*/
/* Function for displaing the time on the VFD tubes and blinking the dots. When called with true, the time
    is displayed with 12 hours:
*/
void displayTime (bool mode12hours = false)
{
  // Local variables declaration:

  // Main code:
  // Hours:
  currentHours = RTC.h;
  if (mode12hours == false)
  {
    separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit);
    timeBuffer [0] = hoursFirstDigit;
    timeBuffer [1] = hoursSecondDigit;
  }
  else
  {
    if (currentHours < 12)
    {
      switch (currentHours)
      {
        case 0:
          currentHours = 12;
          separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit);
          timeBuffer [0] = hoursFirstDigit;
          timeBuffer [1] = hoursSecondDigit;
          break;
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
          separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit);
          timeBuffer [0] = 10; // blank
          timeBuffer [1] = hoursSecondDigit;
          break;
        case 10:
        case 11:
          separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit);
          timeBuffer [0] = hoursFirstDigit;
          timeBuffer [1] = hoursSecondDigit;
          break;
        default:
          break;
      }
      digitalWrite (AM_LED, HIGH);
      digitalWrite (PM_LED, LOW);
    }
    else
    {
      switch (currentHours)
      {
        case 12:
          separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit);
          timeBuffer [0] = hoursFirstDigit;
          timeBuffer [1] = hoursSecondDigit;
          break;
        case 13:
        case 14:
        case 15:
        case 16:
        case 17:
        case 18:
        case 19:
        case 20:
        case 21:
          currentHours = currentHours - 12;
          separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit);
          timeBuffer [0] = 10; // blank
          timeBuffer [1] = hoursSecondDigit;
          break;
        case 22:
        case 23:
          currentHours = currentHours - 12;
          separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit);
          timeBuffer [0] = hoursFirstDigit;
          timeBuffer [1] = hoursSecondDigit;
          break;
        default:
          break;
      }
      digitalWrite (AM_LED, LOW);
      digitalWrite (PM_LED, HIGH);
    }
  }

  // Minutes:
  separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit);
  timeBuffer [2] = minutesFirstDigit;
  timeBuffer [3] = minutesSecondDigit;

  // Blinking dots every second:
  currentSeconds = RTC.s;
  if (currentSeconds % 2  == 0) // if the seconds are even turn off dots
  {
    dots.clear ();  // Set all pixel colors to 'off'
    dots.show ();   // Send the updated pixel colors to the hardware
  }
  else                          // if the seconds are even turn on dots
  {
    dots.setPixelColor (0, 28, 200, 52);
    dots.setPixelColor (1, 28, 200, 52);
    dots.show ();   // Send the updated pixel colors to the hardware
  }
  updateDisplay (timeBuffer);
}

/*------------------------------------------------------------------------------------------------------------*/
/* Function for displaying the temperature on the VFDs. When called  with firstRun true the reading of the 
   temperature and the compensation happens:
*/
void displayTemp (bool firstRun)
{
  // Local variables declaration:
  int intTemp = 0;
  static unsigned long lastTime = 0;

  // Main code:
  if (firstRun == true) // run every DELAY seconds
  {
    digitalWrite (AM_LED, LOW);
    digitalWrite (PM_LED, LOW);
    originalTemp = dht.readTemperature ();
    compensatedTemp = originalTemp - tempCompensation;
    intTemp = compensatedTemp * 10;
    separateThreeDigits (intTemp, tempFirstDigit, tempSecondDigit, tempThirdDigit);
    tempBuffer [0] = tempFirstDigit;
    tempBuffer [1] = tempSecondDigit;
    tempBuffer [2] = tempThirdDigit;
    tempBuffer [3] = 11; // c symbol
    dots.setPixelColor (0, 28, 205, 52);
    dots.setPixelColor (1, 0, 0, 0);
    dots.show();   // send the updated pixel colors to the hardware
    return;        // skip first display update for effects to end
  }
  updateDisplay (tempBuffer);
}

/*------------------------------------------------------------------------------------------------------------*/
/* Function for displaying on the VFDs. When called  with firstRun true the reading of the
   temperature and the compensation happens:
*/
void displayHumidity (bool firstRun)
{
  // Local variables declaration:
  static unsigned long lastTime = 0;
  float dewPointTemp = 0;
  int originalHumidity = 0;
  int compensatedHumidity = 0;

  // Main code:
...

This file has been truncated, please download it to see its full contents.

Credits

deathorion

deathorion

3 projects • 3 followers

Comments