Hardware components | ||||||
![]() |
| × | 1 | |||
Software apps and online services | ||||||
![]() |
| |||||
Hand tools and fabrication machines | ||||||
![]() |
|
I'm pretty new to Arduino and electronics in general. Browsing around I soon noticed these orange glowing tube projects that a lot of people made. Came to find out that they are called nixie tubes and are vintage electronics used in the 60s and 70s for displaying numbers and symbols. Plus, they are not made anymore (with one exception) and those tubes that people used are from old stocks or gutted from old equipment. Can this get any cooler I thought? Then I learned that to light up they need about 180 Volts... That scared me enough to put my plans on the self until I had a little more experience with electronics.
Two projects later (a three wheel robot and a 1280 LED scrolling text display) I felt ready to get my hands on those dusty old tubes and treat myself and my living room to a great looking nixie clock.
So, here we are.
The clock has the following features implemented:
- Time display of course (only in 24 hour format since I prefer that), with blinking colons
- Accurate time keeping and battery to keep the time when the power is off
- RGB LED backlight on the digits and the semicolons, with eight different color effects
- Light sensor and automatic dimming of the LEDs depending on the light in the room
- Test mode which circles through every digit and LED color plus display of the light sensor reading
- Four buttons which can control the following:
- - set the time
- - circle through the LED color effects
- - turn the LEDs on and off
- - enter and control test mode
- Anti-Cathode-Poison (ACP) routines to keep the tubes in healthy condition
- Routine that turns the tubes and LEDs off at night when there is no light in the room to save power and increase their lifetime
- easy access for repairs
- On-off power switch
- Fuse for safety
So, the thinking behind the design was to make it as simple as possible so all the components could be placed on one perfboard neatly. The perfboard had to look presentable since the cover was going to be see-through. I did not use multiplexing because to do so I would have to include extra circuitry to make each nixie turn on and off individually and since those soviet nixie chips (K155ID1) are cheap enough, it was easier to use six of them. I also had a lot of space on the bottom floor for an Arduino mega, so the many pins needed for each chip (4 per chip) would not be a problem. The IDC ribbon cable helped a lot making all those pins easy to connect. Again, simplicity was the goal and this was the simplest way considering my skills and understanding.
For the backlighting I used the WS2811 addressable RGB LEDs which do not need much extra circuitry and can be easily controlled individually to create some cool effects.
The clock gets its power from a simple 12Volt wall power supply I had laying around. For powering the tubes I chose a high voltage nixie power supply (12V to 174V) and a step down - buck - converter (12V to 5V) for powering the LEDs. The Arduino Mega is powered straight from the 12Volts of the wall power supply. Current consumption of the finished clock is at about 250mA.
Finnaly, for the time keeping part I choose a cheap ebay RTC module based on the DS3231 chip. It communicates with the arduino using the I2C protocol and is powered straight from the arduino 5V pin.
Since finding out how a nixie tube works, how to light it up and that kind of stuff is pretty easy online thanks to the articles that many folks have written on the topic, I decided that it would be more useful to talk about the things I learned making the project which I wish somebody had told me before starting. So, here we go:
- There are many nixie tube power supplies available on e-bay from chinese sellers that are pretty cheap. I bought some of them and they all worked, but not on the advertised capacities. What I came to find out is that this power supplies are copies of designs available online and are advertised as having the same capabilities with the originals. The problem is that since they use cheaper components than the originals, they can't really perform as advertised. In my case, the knock-off power supplies could not output enough current for all the six nixies and the colon lamps, so the nixies would fade when the colon were on and some numbers (number 2 mostly) would not light up fully. With another design, the flicker would go away but the power supply would get extremely hot. So, I ended up getting an original power supply that worked great and as advertised.
- You can get wires that are rapped in silicon rubber which, unlike PVC, does not melt with a soldering iron. This is really, really helpful when you are trying to solder many wires on a perfboard.
- Before connecting your nixie tubes, clean their pins with steel wool or something like that. Since they were made decades before, the metal pins can get oxidized. Cleaning them will save you from a lot of headaches and connection issues.
- Plugging and unplugging the tubes is hard because their pins bend easily. Especially on the IN-16 (small ones for displaying the seconds). If I did it all over again, I would prefer to use some tube sockets, connect the tubes on them and then (the sockets) on the clock pins - something like an in-between. This way I could plug and unplug the the sockets as many times as I wanted, easily and without risking damage on the tube pins. On ebay you can buy sockets like these. Or you can create your own ether on perfboard or PCB.
- Plan your algorithm before you start writing code. Making things as you go along works with small projects but as soon as things get a little more complex, spaghetti code is waiting around the corner. What I mean is that you need to plan the flow of information (variable values etc.) between the various parts (e.g. functions) of the algorithm, otherwise - when things get more complex - you end up with making one change and having five things broken! For example, you will often hear that using global variables is bad practice. Well, as soon as you get tangled into the spaghetti code, you'll understand why. Having a general plan of how information will flow helps a lot.
- 4pcs IN-14 Nixie tubes
- 2pcs IN-16 Nixie tubes
- 2pcs Glass Columns with 2 NE-2H Neon Lamps + Holders
- Prototyping perfboard 120x180mm double-sided
- Arduino Mega 2560 R3 without headers
- DS3231 AT24C32 I2C Precision RTC Module
- 6pcs K155ID1 nixie Driver ICs
- 2pcs MPSA42 A42 0.5A/300V NPN TO-92 DIP transistors
- 8pcs WS2811 RGB LEDs 5mm through hole
- Photo Resistor LDR 5mm
- NCH6300HV DC-DC power supply - Original from omnixie
- 3A mini DC-DC Step-down converter 5V fixed-output
- 20 resistors 1/4 Watt 5%, various values
- 14pcs ceramic capacitors 100nF
- Electrolytic capacitor 100µF 16V
- Electrolytic capacitor 1000µF 16V
- 7pcs 5.08mm 2Pin terminals
- IDC Connector 2x13 Pins male
- IDC Connector 2x13 Pins male angled
- IDC Ribbon Cable 2x13 Pins
- 6pcs DIP Sockets - 16Pins
- 4pcs mini push button switches
- Fuse holder THT mount 5x20mm
- Glass fuse 5x20mm 500mA
- Rocker Switch ON-OFF Red
- 5.5x2.1mm DC power plug jack square connector
- 56cm2 plexiglass, 4mm thickness
Perfboard schematic
_schematic_v7kjspq5c5_HnQjxycEuw.png)
Perfboard components placement schematic
_pcb_3ob1oaoeuo_U9JLLts4dh.png)
Bottom layer components schematic

nixie_clock_main_sketch_0_9_ino.c
C/C++/*********************************************************************************************************
*********************************************************************************************************
* Nixie Clock Main Sketch
* Version 0.9
* Tested with: Arduino IDE 1.8.13 - Arduino AVR Boards 1.8.3 - MD_DS3231 1.3.1 -
* Adafruit_NeoPixel 1.7.0 - MD_KeySwitch 1.4.2 - Arduino Mega 2560 R3
* 30-04-2021
* Leon
********************************************************************************************************/
// Libraries needed:
#include <MD_DS3231.h> // Pre-existing object named RTC (SCL to pin 21, SDA to pin 20)
#include <Adafruit_NeoPixel.h>
#include <MD_KeySwitch.h>
// Turn debugging on and off:
#define DEBUG 0
#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:
bool secondPassFlag = false; // flag for checking if a second has passed
byte currentSeconds = 0; // variable to hold the value of the current seconds
byte currentHours = 0; // variable to hold the value of the current hour
byte previousHours = 0; // variable to hold the value of the previous hour
bool acpMinRoutineFlag = false; // flag for checking if the acpMinRoutine function is running
#define ACPNIGHTHOUR 2 // hour that the acp night routine runs (different from night pause)
#define NIGHTPAUSESTART 3 // start time of the night pause (must be after midnight)
#define NIGHTPAUSEEND 7 // end time of the night pause (must be after midnight and start time)
bool setTimeModeFlag = false; // flag for checking if setTimeMode is running
bool testModeFlag = false; // flag for checking if test mode is running
bool testPhotoresistorFlag = false; // flag for checking if photoresistor part of test mode is running
bool acpNightRoutineFlag = false; // flag for checking if the acpNightRoutine function is running
bool acpNightRoutineOn = false; // flag that's true when the routine is actually displayed
bool nightLightTrigger = false; // flag for checking if the light in the room is low enough
bool nightEndTrigger = false; // flag for checking if a night mode end event happened
bool nightPauseRoutineFlag = false; // flag for checking if the nigthPauseRoutine function runs
bool nightPauseRoutineOn = false; // flag that's true when the tubes are actually paused
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 witch steps of the time setting are completed
// Variables for holding the individual digits of time:
byte hoursFirstDigit = 0;
byte hoursSecondDigit = 0;
byte minutesFirstDigit = 0;
byte minutesSecondDigit = 0;
byte secondsFirstDigit = 0;
byte secondsSecondDigit = 0;
// Nixie1:
// Use pins 36, 32, 30 & 34 of Arduino to connect to pins A, B, C & D of the Nixie1 driver chip
#define N1A 36
#define N1B 32
#define N1C 30
#define N1D 34
// Nixie2:
// Use pins 35, 31, 29 & 33 of Arduino to connect to pins A, B, C & D of the Nixie2 driver chip
#define N2A 35
#define N2B 31
#define N2C 29
#define N2D 33
// Nixie3:
// Use pins 44, 40, 38 & 42 of Arduino to connect to pins A, B, C & D of the Nixie3 driver chip
#define N3A 44
#define N3B 40
#define N3C 38
#define N3D 42
// Nixie4:
// Use pins 43, 39, 37 & 41 of Arduino to connect to pins A, B, C & D of the Nixie4 driver chip
#define N4A 43
#define N4B 39
#define N4C 37
#define N4D 41
// Nixie5:
// Use pins 52, 48, 46 & 50 of Arduino to connect to pins A, B, C & D of the Nixie5 driver chip
#define N5A 52
#define N5B 48
#define N5C 46
#define N5D 50
// Nixie6:
// Use pins 51, 47, 45 & 49 of Arduino to connect to pins A, B, C & D of the Nixie4 driver chip
#define N6A 51
#define N6B 47
#define N6C 45
#define N6D 49
// Dots:
// Use transistor 1 to control dots 1 & 2 and transistor 2 to control dots 2 & 3
#define TRAN1 28
#define TRAN2 53
// WS2811 THT RGB LEDs:
#define WSPIN 23 // Arduino pin for controlling the WS2811 LEDs
#define WSCOUNT 8 // number of WS2911 LEDs connected together
Adafruit_NeoPixel wsStrip (WSCOUNT, WSPIN, NEO_RGB + NEO_KHZ800); // create neopixel object
byte wsMode = 1; // variable to hold the WS2911 LEDs mode - default is 1
byte wsModeNum = 8; // variable to hold the number (sum) of WS2911 LEDs modes
bool wsTransition = false; // true if mode transition is on, false if not
#define WSTRANSTIME 1400UL // 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 [8] = {0}; // array to hold the values of the red WS2911 LEDs
int greenLedArray [8] = {0}; // array to hold the values of the green WS2911 LEDs
int blueLedArray [8] = {0}; // array to hold the values of the blue WS2911 LEDs
unsigned long tempColorArray [8] = {0}; // array to hold the values of rainbow or wheel colors
// LDR Photoresistor:
#define LDRPIN A0 // analog pin that the LDR photoresistor is connected on the Arduino
unsigned int wsBrightness = 50; // startup brightness of the WS2811 LEDs from 0 to 255
#define BRIGHTNESSMAX 80 // maximum brightness the LEDs will go depending on room light
#define BRIGHTNESSMIN 5 // minimum brightness the LEDs will go depending on room light
// Buttons:
MD_KeySwitch button1 (24, HIGH); // set button 1 to pin 24
MD_KeySwitch button2 (25, HIGH); // set button 2 to pin 25
MD_KeySwitch button3 (26, HIGH); // set button 3 to pin 26
MD_KeySwitch button4 (27, HIGH); // set button 4 to pin 27
bool repeatOn = false; // true if repeat button pressed
// High voltage power supply:
#define HVPSUPIN 22
// Functions with default values declaration:
void wsModeHandler (bool shuffleTrigger = false);
void colorWipeEffect (bool resetTrigger = false);
void testMode (bool resetTrigger = false);
bool psuState (byte order = 2);
/*----------------------------------------------- SETUP: -----------------------------------------------*/
void setup ()
{
// Debug setup:
#if DEBUG
Serial.begin (9600);
PRINTS ("\n[Nixie Clock]");
#endif
// Setup the pins that communicate with the nixie chips (K144ID1) us outputs
// and write on all the tubes the number 0:
// Nixie1:
pinMode (N1A, OUTPUT);
pinMode (N1B, OUTPUT);
pinMode (N1C, OUTPUT);
pinMode (N1D, OUTPUT);
writeOnNixieX (1, 0);
// Nixie2:
pinMode (N2A, OUTPUT);
pinMode (N2B, OUTPUT);
pinMode (N2C, OUTPUT);
pinMode (N2D, OUTPUT);
writeOnNixieX (2, 0);
// Nixie3:
pinMode (N3A, OUTPUT);
pinMode (N3B, OUTPUT);
pinMode (N3C, OUTPUT);
pinMode (N3D, OUTPUT);
writeOnNixieX (3, 0);
// Nixie4:
pinMode (N4A, OUTPUT);
pinMode (N4B, OUTPUT);
pinMode (N4C, OUTPUT);
pinMode (N4D, OUTPUT);
writeOnNixieX (4, 0);
// Nixie5:
pinMode (N5A, OUTPUT);
pinMode (N5B, OUTPUT);
pinMode (N5C, OUTPUT);
pinMode (N5D, OUTPUT);
writeOnNixieX (5, 0);
// Nixie6:
pinMode (N6A, OUTPUT);
pinMode (N6B, OUTPUT);
pinMode (N6C, OUTPUT);
pinMode (N6D, OUTPUT);
writeOnNixieX (6, 0);
// Dots:
pinMode (TRAN1, OUTPUT);
pinMode (TRAN2, OUTPUT);
// WS2811 LEDs setup:
wsStrip.begin (); // initialize NeoPixel strip object
wsStrip.show (); // turn OFF all pixels ASAP
wsStrip.setBrightness (wsBrightness); // Set the brightness
wsModeHandler (true);
// LDR Photoresistor:
pinMode (LDRPIN, INPUT);
// Buttons setup:
// 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 (false);
button2.enableRepeat (true);
button2.enableRepeatResult (true);
button2.setRepeatTime (120);
button2.setDebounceTime (140);
// Button 3:
button3.begin();
button3.enableDoublePress (false);
button3.enableLongPress (false);
button3.enableRepeat (true);
button3.enableRepeatResult (true);
button3.setRepeatTime (120);
button3.setDebounceTime (140);
// 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
// High Voltage power supply:
pinMode (HVPSUPIN, OUTPUT);
psuState (HIGH); // turn on HV psu
// Command so that the "L" onboard LED of the Arduino MEGA (connected to pin 13) stays off:
pinMode (13, OUTPUT);
}
/*---------------------------------------------- LOOP: -------------------------------------------------*/
void loop ()
{
// Run the mode that is currently on or if no specific mode is on, run the default - displayTime:
if (setTimeModeFlag == true)
{
setTimeMode ();
}
else if (testModeFlag == true)
{
testMode ();
}
else if (wsTransition == true)
{
wsTransitionDisplay ();
}
else if (acpMinRoutineFlag == true)
{
acpMinRoutine ();
}
else if (acpNightRoutineFlag == true)
{
acpNightRoutine ();
}
else if (nightPauseRoutineFlag == true)
{
nightPauseRoutine ();
}
else
{
displayTime ();
}
// Run the rainbow effect if it is on:
if (rainbowEffectTrigger == true)
{
rainbowEffect ();
}
// Run the color wipe effect if it is on:
if (colorWipeEffectTrigger == true)
{
colorWipeEffect ();
}
// Run the color wipe effect if it is on:
if (colorWheelEffectTrigger == true)
{
colorWheelEffect ();
}
// Run the function that handles button presses:
buttonsHandler ();
// Run the function that handles the photoresistor:
photoresistorHandler ();
}
/*------------------------------------------- END OF LOOP ----------------------------------------------*/
/*********************************************************************************************************
* Functions for managing the RTC time aspects of the clock:
********************************************************************************************************/
/*------------------------------------------------------------------------------------------------------*/
/* Function for doing the necessary steps for displaying the time on the nixie tubes. Also, it manages
* various timing events of the clock (dots blinking every second, night modes etc) using the time read
* from the DS3231 RTC clock:
*/
void displayTime ()
{
RTC.readTime (); // get the time from the module
// Hours:
currentHours = RTC.h;
separateDoubleDigits (currentHours, hoursFirstDigit, hoursSecondDigit);
if (currentHours == ACPNIGHTHOUR) // check if it is acp night hour and turn it's flag on
{
acpNightRoutineFlag = true;
}
else // turn the acp night flag off if not it's hour
{
acpNightRoutineFlag = false;
}
if (currentHours >= NIGHTPAUSESTART && currentHours < NIGHTPAUSEEND) // check if it's night pause hours and
{ // turn it's flag on
nightPauseRoutineFlag = true;
}
else // turn the night pause flag off if not it's hours
{
nightPauseRoutineFlag = false;
}
if (acpMinRoutineFlag == false)
{
writeOnNixieX (1, hoursFirstDigit);
writeOnNixieX (2, hoursSecondDigit);
previousHours = currentHours;
}
// Minutes:
separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit);
if (acpMinRoutineFlag == false)
{
writeOnNixieX (3, minutesFirstDigit);
writeOnNixieX (4, minutesSecondDigit);
}
// Seconds:
currentSeconds = RTC.s;
// Blinking dots every second:
if (currentSeconds % 2 == 0) // if the seconds are even turn off dots
{
dotsOn (false);
}
else // if the seconds are even turn on dots
{
dotsOn (true);
}
separateDoubleDigits (currentSeconds, secondsFirstDigit, secondsSecondDigit);
// Acp routine trigger at the 00 seconds and change random LED color if on mode 1:
if (secondsFirstDigit == 0 && secondsSecondDigit == 0)
{
acpMinRoutineFlag = true;
if (wsMode == 1 && wsOff == false)
{
colorWipeEffect (true); // reset color wipe effect to make sure it starts from first LED
wsModeHandler (true); // trigger color change if on random mode
}
}
else
{
writeOnNixieX (5, secondsFirstDigit);
writeOnNixieX (6, secondsSecondDigit);
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for writing the digits on a specific (x) nixie tube - it gets me nixie number and the value
* (one digit) that is going to be written:
*/
void writeOnNixieX (byte nixieNum, byte value)
{
switch (nixieNum)
{
case 1:
sentToNixie (N1A, N1B, N1C, N1D, value);
break;
case 2:
sentToNixie (N2A, N2B, N2C, N2D, value);
break;
case 3:
sentToNixie (N3A, N3B, N3C, N3D, value);
break;
case 4:
sentToNixie (N4A, N4B, N4C, N4D, value);
break;
case 5:
sentToNixie (N5A, N5B, N5C, N5D, value);
break;
case 6:
sentToNixie (N6A, N6B, N6C, N6D, value);
break;
default:
return;
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for running the anti-cathode-poisoning routine for keeping the nixie tubes in good condition
* - it cycles through the digits, about 100ms each digit - 1 second total:
*/
void acpMinRoutine ()
{
// Local variables declaration:
static unsigned long lastTime = 0; // millis() memory
static byte counter = 0;
static byte nixie1_Order [10]; // Arrays for holding the order of the digits based on what
static byte nixie2_Order [10]; // is currently on display and the physical order of the digits
static byte nixie3_Order [10]; // in the tubes
static byte nixie4_Order [10];
byte nixie5_Order [10] = { 5, 6, 1, 0, 7, 9, 3, 8, 4, 2 }; // Since the starting seconds are always
byte nixie6_Order [10] = { 9, 3, 8, 4, 2, 5, 6, 1, 0, 7 }; // the same (00) there arrays are fixed
static bool firstRunFlag = true;
// Main code:
if (firstRunFlag == true) // check if it is the first run of each routine so to populate the arrays
{
getOrderIn14 (nixie1_Order, hoursFirstDigit);
getOrderIn14 (nixie2_Order, hoursSecondDigit);
getOrderIn14 (nixie3_Order, minutesFirstDigit);
getOrderIn14 (nixie4_Order, minutesSecondDigit);
firstRunFlag = false;
}
switch (counter)
{
case 0:
if (millis () - lastTime < 120UL) // more than 100ms to make sure that a second passes in total
{
writeOnNixieX (1, nixie1_Order [0]);
writeOnNixieX (2, nixie2_Order [0]);
writeOnNixieX (3, nixie3_Order [0]);
writeOnNixieX (4, nixie4_Order [0]);
writeOnNixieX (5, nixie5_Order [0]);
writeOnNixieX (6, nixie6_Order [0]);
}
else
{
counter++;
lastTime = millis ();
}
break;
case 1:
if (millis () - lastTime < 120UL)
{
writeOnNixieX (1, nixie1_Order [1]);
writeOnNixieX (2, nixie2_Order [1]);
writeOnNixieX (3, nixie3_Order [1]);
writeOnNixieX (4, nixie4_Order [1]);
writeOnNixieX (5, nixie5_Order [1]);
writeOnNixieX (6, nixie6_Order [1]);
}
else
{
counter++;
lastTime = millis ();
}
break;
case 2:
if (millis () - lastTime < 120UL)
{
writeOnNixieX (1, nixie1_Order [2]);
writeOnNixieX (2, nixie2_Order [2]);
writeOnNixieX (3, nixie3_Order [2]);
writeOnNixieX (4, nixie4_Order [2]);
writeOnNixieX (5, nixie5_Order [2]);
writeOnNixieX (6, nixie6_Order [2]);
}
else
{
counter++;
lastTime = millis ();
}
break;
case 3:
if (millis () - lastTime < 120UL)
{
writeOnNixieX (1, nixie1_Order [3]);
writeOnNixieX (2, nixie2_Order [3]);
writeOnNixieX (3, nixie3_Order [3]);
writeOnNixieX (4, nixie4_Order [3]);
writeOnNixieX (5, nixie5_Order [3]);
writeOnNixieX (6, nixie6_Order [3]);
}
else
{
counter++;
lastTime = millis ();
}
break;
case 4:
if (millis () - lastTime < 120UL)
{
writeOnNixieX (1, nixie1_Order [4]);
writeOnNixieX (2, nixie2_Order [4]);
writeOnNixieX (3, nixie3_Order [4]);
writeOnNixieX (4, nixie4_Order [4]);
writeOnNixieX (5, nixie5_Order [4]);
writeOnNixieX (6, nixie6_Order [4]);
}
else
{
counter++;
lastTime = millis ();
}
break;
case 5:
if (millis () - lastTime < 120UL)
{
writeOnNixieX (1, nixie1_Order [5]);
writeOnNixieX (2, nixie2_Order [5]);
writeOnNixieX (3, nixie3_Order [5]);
writeOnNixieX (4, nixie4_Order [5]);
writeOnNixieX (5, nixie5_Order [5]);
writeOnNixieX (6, nixie6_Order [5]);
}
else
{
counter++;
lastTime = millis ();
}
break;
case 6:
if (millis () - lastTime < 120UL)
{
writeOnNixieX (1, nixie1_Order [6]);
writeOnNixieX (2, nixie2_Order [6]);
writeOnNixieX (3, nixie3_Order [6]);
writeOnNixieX (4, nixie4_Order [6]);
writeOnNixieX (5, nixie5_Order [6]);
writeOnNixieX (6, nixie6_Order [6]);
}
else
{
counter++;
lastTime = millis ();
}
break;
case 7:
if (millis () - lastTime < 120UL)
{
writeOnNixieX (1, nixie1_Order [7]);
writeOnNixieX (2, nixie2_Order [7]);
writeOnNixieX (3, nixie3_Order [7]);
writeOnNixieX (4, nixie4_Order [7]);
writeOnNixieX (5, nixie5_Order [7]);
writeOnNixieX (6, nixie6_Order [7]);
}
else
{
counter++;
lastTime = millis ();
}
break;
case 8:
if (millis () - lastTime < 120UL)
{
writeOnNixieX (1, nixie1_Order [8]);
writeOnNixieX (2, nixie2_Order [8]);
writeOnNixieX (3, nixie3_Order [8]);
writeOnNixieX (4, nixie4_Order [8]);
writeOnNixieX (5, nixie5_Order [8]);
writeOnNixieX (6, nixie6_Order [8]);
}
else
{
counter++;
lastTime = millis ();
}
break;
case 9:
if (millis () - lastTime < 120UL)
{
writeOnNixieX (1, nixie1_Order [9]);
writeOnNixieX (2, nixie2_Order [9]);
writeOnNixieX (3, nixie3_Order [9]);
writeOnNixieX (4, nixie4_Order [9]);
writeOnNixieX (5, nixie5_Order [9]);
writeOnNixieX (6, nixie6_Order [9]);
}
else
{
counter = 0;
lastTime = millis ();
firstRunFlag = true;
acpMinRoutineFlag = false;
}
break;
default:
break;
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for running the anti-cathode-poisoning night routine for keeping the nixie tubes in good
* condition - it runs for and hour and cycles between all the numbers for 6 minutes each. It starts
* from 9 in order to give the bigger numbers better chance of running because they are usually not
* used. Also, the LEDs are turned off for long life and energy savings:
*/
void acpNightRoutine ()
{
// Local variables declaration:
static unsigned long lastTime = 0; // millis() memory
static bool firstRunFlag = true;
static byte currentDay = 0;
static bool dailyRunArray [10] = {false};
// Main code:
if (firstRunFlag == true) // check if it is the first run for the day and reset the run array
{
firstRunFlag = false;
currentDay = RTC.dd;
for (int i = 0; i < 10; i++)
{
dailyRunArray [i] = false;
}
}
if (currentDay != RTC.dd) // if the day has changed, reset the first run and night end trigger flags
{
firstRunFlag = true;
nightEndTrigger = false;
}
if (nightLightTrigger == true && nightEndTrigger == false)
{
acpNightRoutineOn = true;
dotsOn (false);
if (wsOff == false) // check if the LEDs were on and turn them off
{
wsWasOn = true;
wsOff = true;
rainbowEffectTrigger = false;
colorWipeEffectTrigger = false;
colorWheelEffectTrigger = false;
wsStrip.clear ();
wsStrip.show ();
}
if (dailyRunArray [9] == false)
{
if (millis () - lastTime < 340000UL) // run for about six minutes
{
writeOnNixieX (1, 9);
writeOnNixieX (2, 9);
writeOnNixieX (3, 9);
writeOnNixieX (4, 9);
writeOnNixieX (5, 9);
writeOnNixieX (6, 9);
}
else
{
lastTime = millis ();
dailyRunArray [9] = true;
}
}
else if (dailyRunArray [8] == false)
{
if (millis () - lastTime < 340000UL) // run for about six minutes
{
writeOnNixieX (1, 8);
writeOnNixieX (2, 8);
writeOnNixieX (3, 8);
writeOnNixieX (4, 8);
writeOnNixieX (5, 8);
writeOnNixieX (6, 8);
}
else
{
lastTime = millis ();
dailyRunArray [8] = true;
}
}
else if (dailyRunArray [7] == false)
{
if (millis () - lastTime < 340000UL) // run for about six minutes
{
writeOnNixieX (1, 7);
writeOnNixieX (2, 7);
writeOnNixieX (3, 7);
writeOnNixieX (4, 7);
writeOnNixieX (5, 7);
writeOnNixieX (6, 7);
}
else
{
lastTime = millis ();
dailyRunArray [7] = true;
}
}
else if (dailyRunArray [6] == false)
{
if (millis () - lastTime < 340000UL) // run for about six minutes
{
writeOnNixieX (1, 6);
writeOnNixieX (2, 6);
writeOnNixieX (3, 6);
writeOnNixieX (4, 6);
writeOnNixieX (5, 6);
writeOnNixieX (6, 6);
}
else
{
lastTime = millis ();
dailyRunArray [6] = true;
}
}
else if (dailyRunArray [5] == false)
{
if (millis () - lastTime < 340000UL) // run for about six minutes
{
writeOnNixieX (1, 5);
writeOnNixieX (2, 5);
writeOnNixieX (3, 5);
writeOnNixieX (4, 5);
writeOnNixieX (5, 5);
writeOnNixieX (6, 5);
}
else
{
lastTime = millis ();
dailyRunArray [5] = true;
}
}
else if (dailyRunArray [4] == false)
{
if (millis () - lastTime < 340000UL) // run for about six minutes
{
writeOnNixieX (1, 4);
writeOnNixieX (2, 4);
writeOnNixieX (3, 4);
writeOnNixieX (4, 4);
writeOnNixieX (5, 4);
writeOnNixieX (6, 4);
}
else
{
lastTime = millis ();
dailyRunArray [4] = true;
}
}
else if (dailyRunArray [3] == false)
{
if (millis () - lastTime < 340000UL) // run for about six minutes
{
writeOnNixieX (1, 3);
writeOnNixieX (2, 3);
writeOnNixieX (3, 3);
writeOnNixieX (4, 3);
writeOnNixieX (5, 3);
writeOnNixieX (6, 3);
}
else
{
lastTime = millis ();
dailyRunArray [3] = true;
}
}
else if (dailyRunArray [2] == false)
{
if (millis () - lastTime < 340000UL) // run for about six minutes
{
writeOnNixieX (1, 2);
writeOnNixieX (2, 2);
writeOnNixieX (3, 2);
writeOnNixieX (4, 2);
writeOnNixieX (5, 2);
writeOnNixieX (6, 2);
}
else
{
lastTime = millis ();
dailyRunArray [2] = true;
}
}
else if (dailyRunArray [1] == false)
{
if (millis () - lastTime < 340000UL) // run for about six minutes
{
writeOnNixieX (1, 1);
writeOnNixieX (2, 1);
writeOnNixieX (3, 1);
writeOnNixieX (4, 1);
writeOnNixieX (5, 1);
writeOnNixieX (6, 1);
}
else
{
lastTime = millis ();
dailyRunArray [1] = true;
}
}
else if (dailyRunArray [0] == false)
{
if (millis () - lastTime < 340000UL) // run for about six minutes
{
writeOnNixieX (1, 0);
writeOnNixieX (2, 0);
writeOnNixieX (3, 0);
writeOnNixieX (4, 0);
writeOnNixieX (5, 0);
writeOnNixieX (6, 0);
}
else
{
lastTime = millis ();
dailyRunArray [0] = true;
}
}
else // if the daily run is completed, start again for the remaining time
{
for (int i = 0; i < 10; i++)
{
dailyRunArray [i] = false;
}
}
}
else // if the conditions are not right, display the time as usual
{
if (wsWasOn == true) // turn the LEDs back on, if they were previously on
{
wsOff = false;
wsModeHandler ();
}
acpNightRoutineOn = false;
displayTime ();
}
// Make sure that if the acp night hour ends, we go to night pause routine:
if (RTC.h == NIGHTPAUSESTART)
{
acpNightRoutineFlag = false;
nightPauseRoutineFlag = true;
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for running the night pause routine which turns off the nixie tubes at the night when the
* light is low in order to make them last longer. The tubes are turned off by setting the high voltage
* power supply pin to low. Also, the WS2811 LEDs are turned off for power saving and long life:
*/
void nightPauseRoutine ()
{
if (nightLightTrigger == true && nightEndTrigger == false)
{
nightPauseRoutineOn = true;
if (wsOff == false)
{
wsOff = true;
wsWasOn = true;
rainbowEffectTrigger = false;
colorWipeEffectTrigger = false;
colorWheelEffectTrigger = false;
wsStrip.clear ();
wsStrip.show ();
}
dotsOn (false);
psuState (LOW); // turn off HV psu
}
else
{
nightPauseRoutineOn = false;
psuState (HIGH); // turn on HV psu
if (wsWasOn == true)
{
wsOff = false;
wsModeHandler ();
}
displayTime ();
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for separating the double digits that hours, minutes and seconds come from the RTC module,
* to single digits for writing on the nixie tubes:
*/
void separateDoubleDigits (byte doubleDigit, byte& firstDigit, byte& secondDigit)
{
firstDigit = doubleDigit / 10;
secondDigit = doubleDigit % 10;
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for separating a triple digit to single digits for writing on the nixie tubes:
*/
void separateThreeDigits (unsigned int threeDigit, byte& firstDigit, byte& secondDigit, byte& thirdDigit)
{
firstDigit = (threeDigit / 100) % 10;
secondDigit = (threeDigit / 10) % 10;
thirdDigit = threeDigit % 10;
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for separating a quadruple digit to single digits for writing on the nixie tubes:
*/
void separateFourDigits (unsigned int fourDigit, byte& firstDigit, byte& secondDigit, byte& thirdDigit,
byte& fourthDigit)
{
firstDigit = (fourDigit / 1000) % 10;
secondDigit = (fourDigit / 100) % 10;
thirdDigit = (fourDigit / 10) % 10;
fourthDigit = fourDigit % 10;
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for finally sending the value to be displayed to the nixie chips - it gets the numbers of
* the four Arduino pins that communicate with the nixie chip and the value to be sent (one digit or for
* blanking the number 10):
*/
void sentToNixie (byte a, byte b, byte c, byte d, byte value)
{
//D is most significant bit
//A is least significant bit
digitalWrite (d, (value & 0x08) >> 3);
digitalWrite (c, (value & 0x04) >> 2);
digitalWrite (b, (value & 0x02) >> 1);
digitalWrite (a, value & 0x01);
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for turning the dots on (true) or off (false):
*/
void dotsOn (bool onState)
{
if (onState == true)
{
digitalWrite (TRAN1, HIGH);
digitalWrite (TRAN2, HIGH);
}
else
{
digitalWrite (TRAN1, LOW);
digitalWrite (TRAN2, LOW);
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for turning the nixie PSU on (true - 1 - HIGH) or off (false - 0 - LOW) or just getting back
* the state that it is currently (2, which is the default):
*/
bool psuState (byte order = 2)
{
static bool psuStatus = false;
if (order == 0)
{
digitalWrite (HVPSUPIN, LOW); // turn off HV psu
psuStatus = false;
return psuStatus;
}
else if (order == 1)
{
digitalWrite (HVPSUPIN, HIGH); // turn on HV psu
psuStatus = true;
return psuStatus;
}
else
{
return psuStatus;
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function that populates the IN-14 nixie order arrays with the physical order based on the currently
* displayed digit (startValue):
*/
void getOrderIn14 (byte *nixieXArrayPosition, byte startValue)
{
// Local variables declaration:
byte rowArray [ ] = { 1, 0, 2, 9, 3, 8, 4, 7, 5, 6 }; // physical order of the digits in the tubes
// Main code:
switch (startValue)
{
case 0:
for (int i = 0; i < 10; i++)
{
if (i < 9)
{
nixieXArrayPosition [i] = rowArray [i + 1];
}
else if (i >= 9)
{
nixieXArrayPosition [i] = rowArray [i - 9];
}
}
return;
case 1:
for (int i = 0; i < 10; i++)
{
nixieXArrayPosition [i] = rowArray [i];
}
return;
case 2:
for (int i = 0; i < 10; i++)
{
if (i < 8)
{
nixieXArrayPosition [i] = rowArray [i + 2];
}
else if (i >= 8)
{
nixieXArrayPosition [i] = rowArray [i - 8];
}
}
return;
case 3:
for (int i = 0; i < 10; i++)
{
if (i < 6)
{
nixieXArrayPosition [i] = rowArray [i + 4];
}
else if (i >= 6)
{
nixieXArrayPosition [i] = rowArray [i - 6];
}
}
return;
case 4:
for (int i = 0; i < 10; i++)
{
if (i < 4)
{
nixieXArrayPosition [i] = rowArray [i + 6];
}
else if (i >= 4)
{
nixieXArrayPosition [i] = rowArray [i - 4];
}
}
return;
case 5:
for (int i = 0; i < 10; i++)
{
if (i < 2)
{
nixieXArrayPosition [i] = rowArray [i + 8];
}
else if (i >= 2)
{
nixieXArrayPosition [i] = rowArray [i - 2];
}
}
return;
case 6:
for (int i = 0; i < 10; i++)
{
if (i < 1)
{
nixieXArrayPosition [i] = rowArray [i + 9];
}
else if (i >= 1)
{
nixieXArrayPosition [i] = rowArray [i - 1];
}
}
return;
case 7:
for (int i = 0; i < 10; i++)
{
if (i < 3)
{
nixieXArrayPosition [i] = rowArray [i + 7];
}
else if (i >= 3)
{
nixieXArrayPosition [i] = rowArray [i - 3];
}
}
return;
case 8:
for (int i = 0; i < 10; i++)
{
if (i < 5)
{
nixieXArrayPosition [i] = rowArray [i + 5];
}
else if (i >= 5)
{
nixieXArrayPosition [i] = rowArray [i - 5];
}
}
return;
case 9:
for (int i = 0; i < 10; i++)
{
if (i < 7)
{
nixieXArrayPosition [i] = rowArray [i + 3];
}
else if (i >= 7)
{
nixieXArrayPosition [i] = rowArray [i - 7];
}
}
return;
default:
return;
}
}
/*------------------------------------------------------------------------------------------------------*/
/*********************************************************************************************************
* Functions for managing the WS2811 RGB LEDs aspects of the clock:
********************************************************************************************************/
/*------------------------------------------------------------------------------------------------------*/
/* Function for managing the WS2811 RGB LEDs color modes - if the shuffleTrigger parameter is set to
* true the random mode generates a new random color, else it displays the previous random color (used
* with button4 to turn the RGBs on to the previous color for consistency):
*/
void wsModeHandler (bool shuffleTrigger = false)
{
switch (wsMode)
{
case 1: // random color mode
rainbowEffectTrigger = false;
colorWheelEffectTrigger = false;
if (shuffleTrigger == true)
{
// Feed the random seed for better randomness:
randomSeed (analogRead (A1));
int redValue = random (6, 255); // starting from 6 to prevent off state
int greenValue = random (6, 255);
int blueValue = random (6, 255);
for (int i = 0; i < 8; i++) // populate the arrays with the random values
{
redLedArray [i] = redValue;
greenLedArray [i] = greenValue;
blueLedArray [i] = blueValue;
}
colorWipeEffectTrigger = true;
}
else
{
colorWipeEffectTrigger = true;
}
break;
case 2: // red color mode
rainbowEffectTrigger = false;
colorWipeEffectTrigger = true;
colorWheelEffectTrigger = false;
for (int i = 0; i < 8; i++) // populate the arrays with the color red
{
redLedArray [i] = 255;
greenLedArray [i] = 0;
blueLedArray [i] = 0;
}
break;
case 3: // green color mode
rainbowEffectTrigger = false;
colorWipeEffectTrigger = true;
colorWheelEffectTrigger = false;
for (int i = 0; i < 8; i++) // populate the arrays with the color green
{
redLedArray [i] = 0;
greenLedArray [i] = 255;
blueLedArray [i] = 0;
}
break;
case 4: // blue color mode
rainbowEffectTrigger = false;
colorWipeEffectTrigger = true;
colorWheelEffectTrigger = false;
for (int i = 0; i < 8; i++) // populate the arrays with the color blue
{
redLedArray [i] = 0;
greenLedArray [i] = 0;
blueLedArray [i] = 255;
}
break;
case 5: // white color mode
rainbowEffectTrigger = false;
colorWipeEffectTrigger = true;
colorWheelEffectTrigger = false;
for (int i = 0; i < 8; i++) // populate the arrays with the color white
{
redLedArray [i] = 255;
greenLedArray [i] = 255;
blueLedArray [i] = 255;
}
break;
case 6: // multi color mode
rainbowEffectTrigger = false;
colorWipeEffectTrigger = true;
colorWheelEffectTrigger = false;
// Hours LEDs set to red:
redLedArray [0] = 255;
greenLedArray [0] = 0;
blueLedArray [0] = 0;
redLedArray [1] = 255;
greenLedArray [1] = 0;
blueLedArray [1] = 0;
// Dots 1 LEDs set to white:
redLedArray [2] = 255;
greenLedArray [2] = 255;
blueLedArray [2] = 255;
// Minutes LEDs set to green:
redLedArray [3] = 0;
greenLedArray [3] = 255;
blueLedArray [3] = 0;
redLedArray [4] = 0;
greenLedArray [4] = 255;
blueLedArray [4] = 0;
// Dots 2 LEDs set to white:
redLedArray [5] = 255;
greenLedArray [5] = 255;
blueLedArray [5] = 255;
// Minutes LEDs set to blue:
redLedArray [6] = 0;
greenLedArray [6] = 0;
blueLedArray [6] = 255;
redLedArray [7] = 0;
greenLedArray [7] = 0;
blueLedArray [7] = 255;
break;
case 7: // colorWheel mode
rainbowEffectTrigger = false;
colorWheelEffectTrigger = true;
break;
case 8: // rainbow mode
rainbowEffectTrigger = true;
colorWheelEffectTrigger = false;
break;
default:
return;
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for managing the transition effect between WS2811 RGB LEDs modes - it displays on the middle
* nixies the number of the mode that is on:
*/
void wsTransitionDisplay ()
{
// Local variables declaration:
static unsigned long startTime = 0; // millis() memory
byte firstDigit = 0;
byte secondDigit = 0;
static byte wsModeHolder = 0;
// Main code:
if (wsModeHolder != wsMode)
{
wsModeHolder = wsMode;
startTime = millis ();
}
if (wsModeHolder <= 9)
{
firstDigit = 10;
secondDigit = wsMode;
}
else
{
separateDoubleDigits (wsModeHolder, firstDigit, secondDigit);
}
if (millis () - startTime < WSTRANSTIME)
{
writeOnNixieX (1, 10);
writeOnNixieX (2, 10);
writeOnNixieX (3, firstDigit);
writeOnNixieX (4, secondDigit);
writeOnNixieX (5, 10);
writeOnNixieX (6, 10);
dotsOn (false);
}
else
{
wsTransition = false;
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for running the rainbow WS effect (based on code from strandtest neopixel library example -
* adjusted for real time execution):
*/
void rainbowEffect ()
{
// Local variables declaration:
static unsigned long lastTime = millis ();
static long firstPixelHue = 0;
static int pixelHue = 0;
// Main code:
// Hue of first pixel runs 5 complete loops through the color wheel.
// Color wheel has a range of 65536 but it's OK if we roll over, so
// just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
// means we'll make 5*65536/256 = 1280 passes before starting over:
if (firstPixelHue < 5 * 65536)
{
if (millis () - lastTime > 26UL) // change colors every 26ms
{
lastTime = millis ();
for (int i = 0; i < wsStrip.numPixels (); i++)
{
// For each pixel in strip...
// Offset pixel hue by an amount to make one full revolution of the
// color wheel (range of 65536) along the length of the strip
// (wsStrip.numPixels() steps):
pixelHue = firstPixelHue + (i * 65536L / wsStrip.numPixels());
// wsStrip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
// optionally add saturation and value (brightness) (each 0 to 255).
// Here we're using just the single-argument hue variant. The result
// is passed through wsStrip.gamma32() to provide 'truer' colors
// before assigning to each pixel:
wsStrip.setPixelColor (i, wsStrip.gamma32 (wsStrip.ColorHSV (pixelHue)));
}
wsStrip.show (); // Update strip with new contents
firstPixelHue += 256;
}
}
else
{
firstPixelHue = 0;
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for running the color wipe effect. When the resetTrigger parameter is set to true, the
* counter starts again from the first (0) LED (used when pressing buttons quickly to ensure that the
* new color is applied to all 8 LEDs every time). Default is false which allows the effect to
* increment from LED to next LED:
*/
void colorWipeEffect (bool resetTrigger = false)
{
// Local variables declaration:
static unsigned long lastTime = millis ();
static byte counter = 0;
// Main code:
if (resetTrigger == true)
{
counter = 0;
return;
}
if (millis () - lastTime > (unsigned long) WSTRANSTIME / 18) // time between every step - set it
{ // to be always done before
lastTime = millis (); // wsTranstionDisplay is completed
if (counter < 8) // during every step set the color to one RGB LED
{
wsStrip.setPixelColor (counter, wsStrip.Color (redLedArray [counter], greenLedArray [counter],
blueLedArray [counter]));
wsStrip.show();
counter++;
}
else
{
colorWipeEffectTrigger = false;
counter = 0;
}
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for running the colorWheel effect (based on code from strandtest_Wheel neopixel library
* example - adjusted for real time execution):
*/
void colorWheelEffect ()
{
// Local variables declaration:
static unsigned long lastTime = millis ();
static unsigned int counter = 0;
unsigned int i = 0;
// Main code:
if (counter < 256)
{
if (millis () - lastTime > 50UL) // change colors every 50ms
{
lastTime = millis ();
for (i= 0; i < wsStrip.numPixels (); i++)
{
wsStrip.setPixelColor (i, WheelColors ((i+counter) & 255));
}
wsStrip.show ();
counter++;
}
}
else
{
counter = 0;
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for calculating and returning the colors to the colorWheelEffect function. Input a value
* 0 to 255 to get a color value. The colors are a transition r - g - b - back to r (code from
* strandtest_Wheel neopixel library example - adjusted for real time execution):
*/
unsigned long WheelColors (byte WheelPos)
{
WheelPos = 255 - WheelPos;
if (WheelPos < 85)
{
return wsStrip.Color (255 - WheelPos * 3, 0, WheelPos * 3);
}
if (WheelPos < 170)
{
WheelPos -= 85;
return wsStrip.Color (0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return wsStrip.Color (WheelPos * 3, 255 - WheelPos * 3, 0);
}
/*------------------------------------------------------------------------------------------------------*/
/*********************************************************************************************************
* Functions for managing the buttons and the photoresistor of the clock:
********************************************************************************************************/
/*------------------------------------------------------------------------------------------------------*/
/* Function to handle the button presses:
*/
void buttonsHandler ()
{
// ------------------------------------------ normal button mode: -------------------------------------
if (setTimeModeFlag == false && testModeFlag == false)
{
// Button 1 (normal mode):
if (button1.read () == MD_KeySwitch::KS_PRESS)
{
// if button is pressed while night modes are on (displayed), set the night end trigger to true:
if (acpNightRoutineOn == true || nightPauseRoutineOn == true)
{
nightEndTrigger = true;
if (psuState () == LOW)
{
psuState (HIGH); // turn on HV psu
}
}
PRINTS ("\nButton 1 pressed.");
}
if (button1.read () == MD_KeySwitch::KS_LONGPRESS) // enter setTimeMode
{
setTimeModeFlag = true;
// turn off the WS LEDs effects on set time mode:
if (rainbowEffectTrigger == true)
{
rainbowEffectTrigger = false;
}
if (colorWipeEffectTrigger == true)
{
colorWipeEffectTrigger = false;
}
if (colorWheelEffectTrigger == true)
{
colorWheelEffectTrigger = false;
}
// Light up only the hours WS LEDs if the LEDs were on, if they were off leave them off:
if (wsOff == false)
{
if (wsMode == 7 || wsMode == 8) // if rainbow or colorWheel mode is on, pass the current color
{ // to the rainbow array so we can use them in the setTimeMode
for (int i = 0; i < 8; i++)
{
tempColorArray [i] = wsStrip.getPixelColor (i);
}
wsStrip.setPixelColor (0, tempColorArray [0]);
wsStrip.setPixelColor (1, tempColorArray [1]);
}
else // if not rainbow or wheel mode, the color values are already available in there arrays
{
wsStrip.setPixelColor (0, wsStrip.Color (redLedArray [0], greenLedArray [0],
blueLedArray [0]));
wsStrip.setPixelColor (1, wsStrip.Color (redLedArray [1], greenLedArray [1],
blueLedArray [1]));
}
wsStrip.setPixelColor (2, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (3, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (4, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (5, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (6, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (7, wsStrip.Color (0, 0, 0));
wsStrip.show();
}
PRINTS ("\nButton 1 long pressed.");
}
// Button 2 (normal mode):
if (button2.read () == MD_KeySwitch::KS_PRESS) // go to next ws LEDs mode
{
if (wsMode < wsModeNum)
{
wsMode++;
}
else if (wsMode == wsModeNum)
{
wsMode = 1;
}
wsTransition = true;
wsModeHandler (true);
if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed
{
colorWipeEffect (true); // run once to reset the wipe effect
}
// if button is pressed while night modes are on (displayed), set the night end trigger to true:
if (acpNightRoutineOn == true || nightPauseRoutineOn == true)
{
nightEndTrigger = true;
if (psuState () == LOW)
{
psuState (HIGH); // turn on HV psu
}
}
PRINTS ("\nButton 2 pressed.");
}
// Button 3 (normal mode):
if (button3.read () == MD_KeySwitch::KS_PRESS) // go to previous WS LEDs mode
{
if (wsMode > 1)
{
wsMode--;
}
else if (wsMode == 1)
{
wsMode = wsModeNum;
}
wsTransition = true;
wsModeHandler (true);
if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed
{
colorWipeEffect (true); // run once to reset the wipe effect
}
// if button is pressed while night modes are on (displayed), set the night end trigger to true:
if (acpNightRoutineOn == true || nightPauseRoutineOn == true)
{
nightEndTrigger = true;
if (psuState () == LOW)
{
psuState (HIGH); // turn on HV psu
}
}
PRINTS ("\nButton 3 pressed.");
}
// Button 4 (normal mode):
if (button4.read () == MD_KeySwitch::KS_PRESS) // turn WS LEDs on or off
{
if (wsOff == true)
{
wsOff = false;
if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed
{
colorWipeEffect (true); // run once to reset the wipe effect
}
wsModeHandler ();
}
else if (wsOff == false)
{
wsOff = true;
rainbowEffectTrigger = false;
colorWipeEffectTrigger = false;
colorWheelEffectTrigger = false;
wsStrip.clear ();
wsStrip.show ();
}
// if button is pressed while night modes are on (displayed), set the night end trigger to true:
if (acpNightRoutineOn == true || nightPauseRoutineOn == true)
{
nightEndTrigger = true;
if (psuState () == LOW)
{
psuState (HIGH); // turn on HV psu
}
}
PRINTS ("\nButton 4 pressed.");
}
if (button4.read () == MD_KeySwitch::KS_LONGPRESS) // enter test mode
{
testModeFlag = true;
PRINTS ("\nButton 4 long pressed.");
}
}
else if (testModeFlag == false) // ---------------- set time button mode: ----------------------------
{
// Button 1 (set time mode):
if (button1.read () == MD_KeySwitch::KS_PRESS) // save temp time variable set
{
if (setTimeStageArray [0] == false)
{
RTC.h = tempTimeHolder;
RTC.writeTime (); // save hours
setTimeStageArray [0] = true;
tempTimeHolder = RTC.m; // pass current minutes to temp time variable for manipulation with buttons
// Light up only the minutes WS LEDs if the LEDs were on, if they were off leave them off:
if (wsOff == false)
{
wsStrip.setPixelColor (0, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (1, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (2, wsStrip.Color (0, 0, 0));
if (wsMode == 7 || wsMode == 8) // if rainbow or color wheel was on, use tempColorArray to
{ // retrieve the colors
wsStrip.setPixelColor (3, tempColorArray [3]);
wsStrip.setPixelColor (4, tempColorArray [4]);
}
else // if not rainbow or wheel mode, use the individual color arrays to retrieve the colors
{
wsStrip.setPixelColor (3, wsStrip.Color (redLedArray [3], greenLedArray [3],
blueLedArray [3]));
wsStrip.setPixelColor (4, wsStrip.Color (redLedArray [4], greenLedArray [4],
blueLedArray [4]));
}
wsStrip.setPixelColor (5, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (6, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (7, wsStrip.Color (0, 0, 0));
wsStrip.show();
}
}
else if (setTimeStageArray [1] == false)
{
RTC.m = tempTimeHolder;
RTC.writeTime (); // save minutes
setTimeStageArray [1] = true;
tempTimeHolder = RTC.s; // pass current seconds to temp time variable for manipulation with buttons
// Light up only the seconds WS LEDs if the LEDs were on, if they were off leave them off:
if (wsOff == false)
{
wsStrip.setPixelColor (0, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (1, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (2, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (3, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (4, wsStrip.Color (0, 0, 0));
wsStrip.setPixelColor (5, wsStrip.Color (0, 0, 0));
if (wsMode == 7 || wsMode == 8) // if rainbow or color wheel was on, use tempColorArray to
{ // retrieve the colors
wsStrip.setPixelColor (6, tempColorArray [6]);
wsStrip.setPixelColor (7, tempColorArray [7]);
}
else // if not rainbow mode, use the individual color arrays to retrieve the colors
{
wsStrip.setPixelColor (6, wsStrip.Color (redLedArray [6], greenLedArray [6],
blueLedArray [6]));
wsStrip.setPixelColor (7, wsStrip.Color (redLedArray [7], greenLedArray [7],
blueLedArray [7]));
}
wsStrip.show();
}
}
else if (setTimeStageArray [2] == false)
{
RTC.s = tempTimeHolder;
RTC.writeTime (); // save seconds
setTimeStageArray [2] = true;
tempTimeHolder = 0;
setTimeModeFlag = false;
timeSetModeReset = true;
if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed
{
colorWipeEffect (true); // run once to reset the wipe effect
}
if (wsOff == false)
{
wsModeHandler ();
}
}
else
{
return;
}
PRINTS ("\nButton 1 pressed.");
}
// Button 2 (set time mode):
switch (button2.read ())
{
case MD_KeySwitch::KS_PRESS: // button 2 single press - increase temp time variable
if (setTimeStageArray [0] == false)
{
if (tempTimeHolder >= 0 && tempTimeHolder < 23) // increase hours
{
tempTimeHolder++;
}
else
{
tempTimeHolder = 0;
}
}
else
{
if (tempTimeHolder >= 0 && tempTimeHolder < 59) // increase minutes and seconds
{
tempTimeHolder++;
}
else
{
tempTimeHolder = 0;
}
}
PRINTS ("\nButton 2 pressed.");
break;
case MD_KeySwitch::KS_RPTPRESS: // button 2 repeat press - increase temp time variable fast
repeatOn = true; // set to true in order to stop blinking in setTimeMode function
if (setTimeStageArray [0] == false)
{
if (tempTimeHolder >= 0 && tempTimeHolder < 23) // increase hours
{
tempTimeHolder++;
}
else
{
tempTimeHolder = 0;
}
}
else
{
if (tempTimeHolder >= 0 && tempTimeHolder < 59) // increase minutes and seconds
{
tempTimeHolder++;
}
else
{
tempTimeHolder = 0;
}
}
PRINTS ("\nButton 2 repeat pressed.");
break;
default:
break;
}
// Button 3 (set time mode):
switch (button3.read ())
{
case MD_KeySwitch::KS_PRESS: // button 3 single press - decrease temp time variable
if (setTimeStageArray [0] == false)
{
if (tempTimeHolder > 0 && tempTimeHolder <= 23) // decrease hours
{
tempTimeHolder--;
}
else
{
tempTimeHolder = 23;
}
}
else
{
if (tempTimeHolder > 0 && tempTimeHolder <= 59) // decrease minutes and seconds
{
tempTimeHolder--;
}
else
{
tempTimeHolder = 59;
}
}
PRINTS ("\nButton 3 pressed.");
break;
case MD_KeySwitch::KS_RPTPRESS: // button 3 repeat press - decrease temp time variable fast
repeatOn = true; // set to true in order to stop blinking in setTimeMode function
if (setTimeStageArray [0] == false)
{
if (tempTimeHolder > 0 && tempTimeHolder <= 23) // decrease hours
{
tempTimeHolder--;
}
else
{
tempTimeHolder = 23;
}
}
else
{
if (tempTimeHolder > 0 && tempTimeHolder <= 59) // decrease minutes and seconds
{
tempTimeHolder--;
}
else
{
tempTimeHolder = 59;
}
}
PRINTS ("\nButton 3 repeat pressed.");
break;
default:
break;
}
// Button 4 (set time mode):
if (button4.read () == MD_KeySwitch::KS_PRESS) // exit set time mode
{
setTimeModeFlag = false;
timeSetModeReset = true;
if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed
{
colorWipeEffect (true); // run once to reset the wipe effect
}
if (wsOff == false)
{
wsModeHandler ();
}
PRINTS ("\nButton 4 pressed.");
}
}
else // ----------------------------------------- test mode: -----------------------------------------
{
// Button 1 (test mode):
if (button1.read () == MD_KeySwitch::KS_PRESS) // switch photoresistor test on and off
{
if (testPhotoresistorFlag == false)
{
testPhotoresistorFlag = true;
if (psuState () == LOW)
{
psuState (HIGH); // turn on HV psu
}
}
else
{
testPhotoresistorFlag = false;
}
PRINTS ("\nButton 1 pressed.");
}
// Button 4 (test mode):
if (button4.read () == MD_KeySwitch::KS_PRESS) // exit test mode
{
testModeFlag = false;
testPhotoresistorFlag = false;
testMode (true); // reset test mode
if (psuState () == LOW)
{
psuState (HIGH); // turn on HV psu
}
if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed
{
colorWipeEffect (true); // run once to reset the wipe effect
}
if (wsOff == false)
{
wsModeHandler ();
}
PRINTS ("\nButton 4 pressed.");
}
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for handling the set time mode:
*/
void setTimeMode ()
{
// Local variables declaration:
static unsigned long startTime = millis (); // millis() memory
// Main code:
RTC.readTime (); // get the time from the module
if (timeSetModeReset == true) // check if it's the first run of function
{
dotsOn (false); // turn off dots
timeSetModeReset = false;
for (int i = 0; i < 3; i++) // reset array
{
setTimeStageArray [i] = false;
}
// Hours:
tempTimeHolder = RTC.h; // pass current time to temp variable for manipulation with buttons
separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit);
writeOnNixieX (1, hoursFirstDigit);
writeOnNixieX (2, hoursSecondDigit);
// Minutes:
separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit);
writeOnNixieX (3, minutesFirstDigit);
writeOnNixieX (4, minutesSecondDigit);
// Seconds:
separateDoubleDigits (RTC.s, secondsFirstDigit, secondsSecondDigit);
// Acp routine trigger at the 00 seconds and change random LED color if on mode 1:
writeOnNixieX (5, secondsFirstDigit);
writeOnNixieX (6, secondsSecondDigit);
}
else if (setTimeStageArray [0] == false) // blink hours except when on repeat
{
// Hours:
if (repeatOn == false)
{
separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit);
if (millis () - startTime < 500UL)
{
writeOnNixieX (1, hoursFirstDigit);
writeOnNixieX (2, hoursSecondDigit);
}
else if (millis () - startTime < 1000UL)
{
writeOnNixieX (1, 10);
writeOnNixieX (2, 10);
}
else
{
startTime = millis ();
}
}
else // if on repeat button press don't blink
{
separateDoubleDigits (tempTimeHolder, hoursFirstDigit, hoursSecondDigit);
writeOnNixieX (1, hoursFirstDigit);
writeOnNixieX (2, hoursSecondDigit);
repeatOn = false;
startTime = millis ();
}
// Minutes:
separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit);
writeOnNixieX (3, minutesFirstDigit);
writeOnNixieX (4, minutesSecondDigit);
// Seconds:
separateDoubleDigits (RTC.s, secondsFirstDigit, secondsSecondDigit);
// Acp routine trigger at the 00 seconds and change random LED color if on mode 1:
writeOnNixieX (5, secondsFirstDigit);
writeOnNixieX (6, secondsSecondDigit);
}
else if (setTimeStageArray [1] == false) // if hours set, blink minutes except on repeat
{
// Hours:
separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit);
writeOnNixieX (1, hoursFirstDigit);
writeOnNixieX (2, hoursSecondDigit);
// Minutes:
if (repeatOn == false)
{
separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit);
if (millis () - startTime < 500UL)
{
writeOnNixieX (3, minutesFirstDigit);
writeOnNixieX (4, minutesSecondDigit);
}
else if (millis () - startTime < 1000UL)
{
writeOnNixieX (3, 10);
writeOnNixieX (4, 10);
}
else
{
startTime = millis ();
}
}
else // if on repeat button press don't blink
{
separateDoubleDigits (tempTimeHolder, minutesFirstDigit, minutesSecondDigit);
writeOnNixieX (3, minutesFirstDigit);
writeOnNixieX (4, minutesSecondDigit);
repeatOn = false;
startTime = millis ();
}
// Seconds:
separateDoubleDigits (RTC.s, secondsFirstDigit, secondsSecondDigit);
// Acp routine trigger at the 00 seconds and change random LED color if on mode 1:
writeOnNixieX (5, secondsFirstDigit);
writeOnNixieX (6, secondsSecondDigit);
}
else if (setTimeStageArray [2] == false) // if hours and minutes set, blink seconds except on repeat
{
// Hours:
separateDoubleDigits (RTC.h, hoursFirstDigit, hoursSecondDigit);
writeOnNixieX (1, hoursFirstDigit);
writeOnNixieX (2, hoursSecondDigit);
// Minutes:
separateDoubleDigits (RTC.m, minutesFirstDigit, minutesSecondDigit);
writeOnNixieX (3, minutesFirstDigit);
writeOnNixieX (4, minutesSecondDigit);
// Seconds:
if (repeatOn == false)
{
separateDoubleDigits (tempTimeHolder, secondsFirstDigit, secondsSecondDigit);
if (millis () - startTime < 500UL)
{
writeOnNixieX (5, secondsFirstDigit);
writeOnNixieX (6, secondsSecondDigit);
}
else if (millis () - startTime < 1000UL)
{
writeOnNixieX (5, 10);
writeOnNixieX (6, 10);
}
else
{
startTime = millis ();
}
}
else // if on repeat button press don't blink
{
separateDoubleDigits (tempTimeHolder, secondsFirstDigit, secondsSecondDigit);
writeOnNixieX (5, secondsFirstDigit);
writeOnNixieX (6, secondsSecondDigit);
repeatOn = false;
startTime = millis ();
}
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for running test mode - it first tunrs off the HV power supply then it runs throught all
* the numbers once, blinks the dots and sets the WS2811 LEDs to green then red and finally blue color.
* When button 1 is pressed, it displays the value of the photoresistor readings. If resetTrigger is set
* to true, it resets the function variables to be ready for the next run.:
*/
void testMode (bool resetTrigger = false)
{
// Local variables declaration:
static unsigned long lastTime = 0; // millis() memory
static unsigned long lastTimeLight = millis (); // millis() memory for the light part
static byte counter = 0;
unsigned long onTime = 2200; // time in ms that each number stays on
static bool firstRunFlag = true; // flag to check if it's the first run of every instance
unsigned int lightValue = 0;
byte lightValueDigits = 0;
byte lightFirstDigit = 0;
byte lightSecondDigit = 0;
byte lightThirdDigit = 0;
byte lightFourthDigit = 0;
// Main code:
if (resetTrigger == true) // reset variables
{
counter = 0;
firstRunFlag = true;
return;
}
if (firstRunFlag == true) // check if it is the first run of each routine
{
rainbowEffectTrigger = false;
colorWipeEffectTrigger = false;
colorWheelEffectTrigger = false;
for (int i = 0; i < 8; i++)
{
wsStrip.setPixelColor (i, wsStrip.Color (255, 0, 0));
}
wsStrip.show ();
lastTime = millis ();
dotsOn (false);
firstRunFlag = false;
}
if (testPhotoresistorFlag == false) // normal test part
{
switch (counter)
{
case 0:
if (millis () - lastTime < onTime) // run for "onTime" duration
{
psuState (LOW); // turn off HV psu
}
else
{
counter++;
lastTime = millis ();
dotsOn (true);
psuState (HIGH); // turn on HV psu
}
break;
case 1:
if (millis () - lastTime < onTime) // run for "onTime" duration
{
for (int i = 0; i < 8; i++)
{
writeOnNixieX (i, 0);
}
}
else
{
counter++;
lastTime = millis ();
dotsOn (false);
}
break;
case 2:
if (millis () - lastTime < onTime) // run for "onTime" duration
{
for (int i = 0; i < 8; i++)
{
writeOnNixieX (i, 1);
}
}
else
{
counter++;
lastTime = millis ();
dotsOn (true);
}
break;
case 3:
if (millis () - lastTime < onTime) // run for "onTime" duration
{
for (int i = 0; i < 8; i++)
{
writeOnNixieX (i, 2);
}
}
else
{
counter++;
lastTime = millis ();
dotsOn (false);
for (int i = 0; i < 8; i++)
{
wsStrip.setPixelColor (i, wsStrip.Color (0, 255, 0));
}
wsStrip.show ();
}
break;
case 4:
if (millis () - lastTime < onTime) // run for "onTime" duration
{
for (int i = 0; i < 8; i++)
{
writeOnNixieX (i, 3);
}
}
else
{
counter++;
lastTime = millis ();
dotsOn (true);
}
break;
case 5:
if (millis () - lastTime < onTime) // run for "onTime" duration
{
for (int i = 0; i < 8; i++)
{
writeOnNixieX (i, 4);
}
}
else
{
counter++;
lastTime = millis ();
dotsOn (false);
}
break;
case 6:
if (millis () - lastTime < onTime) // run for "onTime" duration
{
for (int i = 0; i < 8; i++)
{
writeOnNixieX (i, 5);
}
}
else
{
counter++;
lastTime = millis ();
dotsOn (true);
}
break;
case 7:
if (millis () - lastTime < onTime) // run for "onTime" duration
{
for (int i = 0; i < 8; i++)
{
writeOnNixieX (i, 6);
}
}
else
{
counter++;
lastTime = millis ();
dotsOn (false);
for (int i = 0; i < 8; i++)
{
wsStrip.setPixelColor (i, wsStrip.Color (0, 0, 255));
}
wsStrip.show ();
}
break;
case 8:
if (millis () - lastTime < onTime) // run for "onTime" duration
{
for (int i = 0; i < 8; i++)
{
writeOnNixieX (i, 7);
}
}
else
{
counter++;
lastTime = millis ();
dotsOn (true);
}
break;
case 9:
if (millis () - lastTime < onTime) // run for "onTime" duration
{
for (int i = 0; i < 8; i++)
{
writeOnNixieX (i, 8);
}
}
else
{
counter++;
lastTime = millis ();
dotsOn (false);
}
break;
case 10:
if (millis () - lastTime < onTime) // run for "onTime" duration
{
for (int i = 0; i < 8; i++)
{
writeOnNixieX (i, 9);
}
}
else
{
counter = 0;
testModeFlag = false;
firstRunFlag = true;
if (wsMode != 7 && wsMode != 8) // in modes 7 and 8 wipe effect is off so no reset needed
{
colorWipeEffect (true); // run once to reset the wipe effect
}
if (wsOff == false)
{
wsModeHandler ();
}
}
break;
default:
break;
}
}
else // photoresistor test part
{
dotsOn (false);
if (millis () - lastTimeLight > 500UL) // run every half second
{
lastTimeLight = millis ();
lightValue = analogRead (LDRPIN);
lightValueDigits = numberOfDigits (lightValue);
switch (lightValueDigits)
{
case 1:
writeOnNixieX (1, 0);
writeOnNixieX (2, 0);
writeOnNixieX (3, 0);
writeOnNixieX (4, lightValue);
writeOnNixieX (5, 10);
writeOnNixieX (6, 10);
break;
case 2:
separateDoubleDigits (lightValue, lightFirstDigit, lightSecondDigit);
writeOnNixieX (1, 0);
writeOnNixieX (2, 0);
writeOnNixieX (3, lightFirstDigit);
writeOnNixieX (4, lightSecondDigit);
writeOnNixieX (5, 10);
writeOnNixieX (6, 10);
break;
case 3:
separateThreeDigits (lightValue, lightFirstDigit, lightSecondDigit, lightThirdDigit);
writeOnNixieX (1, 0);
writeOnNixieX (2, lightFirstDigit);
writeOnNixieX (3, lightSecondDigit);
writeOnNixieX (4, lightThirdDigit);
writeOnNixieX (5, 10);
writeOnNixieX (6, 10);
break;
case 4:
separateFourDigits (lightValue, lightFirstDigit, lightSecondDigit, lightThirdDigit,
lightFourthDigit);
writeOnNixieX (1, lightFirstDigit);
writeOnNixieX (2, lightSecondDigit);
writeOnNixieX (3, lightThirdDigit);
writeOnNixieX (4, lightFourthDigit);
writeOnNixieX (5, 10);
writeOnNixieX (6, 10);
break;
default:
break;
}
}
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for handling the photoresistor - read the light in the room and adjust the WS2811 LEDs
* brightness accordingly:
*/
void photoresistorHandler ()
{
// Local variables declaration:
// WS2811 LEDs brightness part:
static unsigned int count = 0;
static unsigned long lastTime = millis ();
static unsigned int sum = 0;
unsigned int lightMedian = 0;
int countReset = 10; // how many counts (seconds) it takes before changing the brightness
// Night mode part:
static unsigned long nightCount = 0;
static unsigned long lastTimeNightMode = millis ();
static bool nightEnd = false; // check if the night modes time has ended
// Main code:
// WS2811 LEDs brightness part:
if (wsOff == false) // run only if the LEDs are on
{
if (millis () - lastTime > 1000UL) // check the value of the photoresistor every second
{
lastTime = millis ();
count++;
sum = analogRead (LDRPIN) + sum;
lightMedian = sum / count;
}
if (count == countReset)
{
wsBrightness = map (lightMedian, 0, 1023, BRIGHTNESSMIN, BRIGHTNESSMAX);
wsStrip.setBrightness (wsBrightness);
PRINT ("\nBrightness set to: ", wsBrightness)
if (setTimeModeFlag == false && testModeFlag == false)
{
wsModeHandler ();
}
count = 0;
sum = 0;
}
}
// Night mode part:
RTC.readTime (); // get the time from the module - also populate rtc variables at every run
// so that other functions can have updated values without having to read
// the module again and again
// Start checking for the light in the room only at the acp night hour or the night pause time:
if (RTC.h == ACPNIGHTHOUR || (RTC.h >= NIGHTPAUSESTART && RTC.h < NIGHTPAUSEEND))
{
if (millis () - lastTimeNightMode > 2000UL) // check the value of the photoresistor every 2 seconds
{
PRINT ("\nLDR: ", analogRead (LDRPIN))
lastTimeNightMode = millis ();
if (analogRead (LDRPIN) < 100) // check if the light in the room is low enough for the night acp
{ // and the pause routines to trigger, if not reset
nightCount++;
}
else
{
nightCount = 0;
}
}
if (nightCount >= 15) // if the light is low for many readings (30 seconds) start night mode
{
nightLightTrigger = true;
}
else // but if it gets brighter, end it immediately
{
nightLightTrigger = false;
}
nightEnd = false;
}
else if (RTC.h == NIGHTPAUSEEND) // make sure that the night light and end triggers
{ // are false when night time ends
if (nightEnd == false) // a check used for running once
{
nightEnd = true;
nightLightTrigger = false;
nightEndTrigger = false;
if (wsWasOn == true)
{
wsOff = false;
wsModeHandler ();
}
wsWasOn = false;
if (psuState () == LOW)
{
psuState (HIGH); // turn on HV psu
}
}
}
}
/*------------------------------------------------------------------------------------------------------*/
/* Function for counting the number of digits of the photoresistor value - it gets the reading and
* returns the number of the digits:
*/
byte numberOfDigits (unsigned int number)
{
byte digits = 0;
if (number == 0)
{
return 1;
}
while (number != 0)
{
number = number / 10;
digits++;
}
return digits;
}
/*********************************************************************************************************
*********************************************************************************************************/
Comments
Please log in or sign up to comment.