Introduction: LED Arduino Nixie Clock: Crafting a Futuristic Glow for the New Year!

🎉 New Year’s is just around the corner – why not celebrate with a custom-built Nixie Tube Clock?

I’ll guide you step-by-step through building your own futuristic Arduino Nixie Clock, broken down into 5 easy-to-follow sections:

1️⃣ The Box – Crafting the base to hold everything together

2️⃣ The Electronics – Assembling the brain of the clock

3️⃣ The LED Array – Adding the mesmerizing glow

4️⃣ The Numbers – Bringing the display to life

5️⃣ Uploading the Code – Making it all work seamlessly


Link to the CAD and code files


Supplies

Step 1: Build the Box

Laser Cut the Box:

  1. Load your CAD files into the laser cutter.
  2. Set the laser cutter to 100% power at 30mm/s and cut the 3mm wood panels.

Assemble with Hot Glue:

  1. Apply hot glue along the edges and press the panels together.

Sand Off Black Marks:

  1. Sand any black marks left from the laser cutting.


Step 2: The Electronics

Connect the Buttons:

  1. Push the buttons into place.
  2. Solder the common ground (one pin of each button) to the GND pin on the Arduino.
  3. Connect four separate wires from the other pins of the buttons to pins 2, 3, 4, and 5 on the Arduino.

Connect the DS1302 Time Module:

  1. 5V to the 5V pin on the Arduino.
  2. GND to the GND pin on the Arduino.
  3. IO pin to pin 9 on the Arduino.
  4. SCLK pin to pin 10 on the Arduino.
  5. RESET pin to pin 8 on the Arduino.

Connect the WS2812B LED Strip:

  1. 5V to the 5V pin on the Arduino.
  2. GND to the GND pin on the Arduino.
  3. Data pin to pin 6 on the Arduino.


Step 3: LED Strip

Cut the LED Strips:

  1. Carefully cut the WS2812B LED strip into segments of 10 LEDs each (following the cut lines on the strip).
  2. Use sharp scissors or a utility knife to make clean cuts.

Arrange the LEDs:

  1. Arrange the 10-LED segments according to the LED layout diagram. Ensure the orientation of the LEDs matches the diagram for proper wiring.

Solder the Strips Together:

  1. Use thin wire for connecting the strips, as illustrated by the green wires in your diagram.
  2. Apply plenty of flux to the connection points before soldering. This helps to avoid cold solder joints and makes the process smoother.
  3. Solder the data, 5V, and GND lines between the strips as required.
  4. Ensure you’re soldering the correct leads for each connection and maintain a clean, solid connection.



Step 4: Acrylic Numbers

Cut the Numbers from the 2mm Acrylic Panels:

  1. Use your laser cutter with the settings:
  2. Engraving: 8% power at 100mm/s.
  3. Cutting: 100% power at 30mm/s.
  4. Adjust these settings if necessary, depending on your laser cutter.

Peel Off the Protective Adhesive:

  1. Carefully peel off the protective adhesive from the numbers once they’re cut.

Insert the Numbers into the Wooden Slots:

  1. Gently insert the acrylic numbers into the corresponding wooden slots.
  2. Be careful not to touch the numbers with your fingers to avoid leaving fingerprints or smudges.



Step 5: Upload the Code!

Plug the Arduino into Your Computer:

  1. Connect your Arduino to your computer using the USB cable.

2. Open the Arduino IDE:

  1. Launch the Arduino IDE on your computer.

3. Install the Libraries:

  1. Adafruit NeoPixel Library (for controlling WS2812B LEDs)
  2. RtcDS1302 Library (for interfacing with the DS1302 RTC module)

Here’s how to install them:

Install the Adafruit NeoPixel Library:

  1. In the Arduino IDE, go to the "Sketch" menu and select "Include Library" > "Manage Libraries...".
  2. In the Library Manager, type "Adafruit NeoPixel" in the search bar.
  3. Find "Adafruit NeoPixel" by Adafruit in the list.
  4. Click the "Install" button next to the library name.
  5. Wait for the installation to finish.

Install the RtcDS1302 Library:

  1. In the Arduino IDE, go to the "Sketch" menu and select "Include Library" > "Manage Libraries...".
  2. In the Library Manager, type "RtcDS1302" in the search bar.
  3. Find "RtcDS1302" by Matthias Hertel in the list.
  4. Click the "Install" button next to the library name.
  5. Wait for the installation to finish.


Here’s a summary of the final notes on the clock’s operation:

1. Initial Upload:

  1. On the first upload, the clock will sync with your computer’s time automatically.

2. Manually Change the Time:

  1. To manually change the time, press and hold the two outside buttons (buttons 1 and 4).
  2. The display will turn red, indicating that the clock is in time-changing mode.
  3. After changing the time, press and hold the two outer buttons again to resume normal operation.

3. Adjusting Brightness:

  1. The right-most buttons are used to increase or decrease the brightness of the LEDs.

4. Change Colour Modes and Speeds:

  1. The left buttons are used to change between color modes and adjust the speed of the color changes.


Below is the code, or see attached file.



// Nixie LED Clock
// By: Newson's Electronics
// Date: Dec 29,2024


// used two libraries
#include <Adafruit_NeoPixel.h>
#include <RtcDS1302.h>

// Define debounce delay (in milliseconds)
#define DEBOUNCE_DELAY 200


unsigned long lastDebounceTime = 0; // Last time a button was pressed
bool button1State = false; // State of button 1
bool button4State = false; // State of button 4

ThreeWire myWire(9, 10, 8); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);


#define LED_PIN 6
// How many NeoPixels are attached to the Arduino?
#define LED_COUNT 130

int h1, h2 = 0; // h1= hour ones, h2= hour tens (digits)
int m1, m2 = 0; // m1= minutes ones, m2=minutes tens
int s = 0; // seconds
int dots = 0;
int year, month, day, hours, minutes, seconds = 0;
int brightness = 125;
int fadeSpeed = 256;
bool changeTime = 0;
bool fadeColour = 0;
uint16_t hue = 10; // Hue value for color cycling (0-65535)
uint8_t red = 255; // Maximum value for uint8_t
uint8_t green = 0; // Minimum value
uint8_t blue = 128; // Mid-range value


//Setup the neopixel
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

uint32_t color = strip.Color(255, 255, 255); // Initialize white color
uint32_t color2 = strip.Color(255, 255, 255); // Initialize temp color variable



// used to test the leds to see if they all turn on
void test() {
for (int i = 0; i <= 130; i++) {

strip.setPixelColor(i, strip.Color(255, 255, 255));
strip.show();
delay(100); // Off
}
}

void clearDisplay() {
for (int i = 0; i <= 130; i++) {
strip.setPixelColor(i, strip.Color(0, 0, 0)); // Off
}
}


void displayTime(int h2, int h1, int m2, int m1) {
clearDisplay();

// M1 Digits
strip.setPixelColor(0 + m1, color);
strip.setPixelColor(19 - m1, color);
strip.setPixelColor(20 + m1, color);
// M2 Digits
strip.setPixelColor(39 - m2, color);
strip.setPixelColor(40 + m2, color);
strip.setPixelColor(59 - m2, color);
// Centre dots

// moving down the centre line
//s=seconds%10;
//strip.setPixelColor(60+s, strip.Color(255, 255, 255));




// centre led
strip.setPixelColor(64, color);

// Flashing Centre led
/*
if (s % 2 == 0) {
strip.setPixelColor(64, color);
}

if (s % 2 > 0) {
strip.setPixelColor(64, strip.Color(0, 0, 0));
}
*/

// H1 Digits
strip.setPixelColor(79 - h1, color);
strip.setPixelColor(80 + h1, color);
strip.setPixelColor(99 - h1, color);

// H2 Digits
if (h2!=0||changeTime==1) // don't display 0 in front
{
strip.setPixelColor(100 + h2, color);
strip.setPixelColor(119 - h2, color);
strip.setPixelColor(120 + h2, color);
}

strip.show();
}



void setup() {
Serial.begin(9600);

//Clock setup
Serial.print("compiled: ");
Serial.print(__DATE__);
Serial.println(__TIME__);

Rtc.Begin();

if (!Rtc.IsDateTimeValid()) {
Serial.println("RTC lost power, setting the time!");
Rtc.SetIsRunning(true);
Rtc.SetIsWriteProtected(false);
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
Rtc.SetDateTime(compiled); // Set RTC to compile time
} else {
// RTC is valid, no need to set time
Serial.println("RTC time is valid.");
}


// Get the compile time


// Check if the RTC time is valid


// Check the battery status


// RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
// printDateTime(compiled);
// Serial.println();
// Rtc.SetIsRunning(true);
// Rtc.SetIsWriteProtected(false);
//Rtc.SetDateTime(compiled);


//clock setup done





strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)

clearDisplay();
delay(1000);


strip.setBrightness(brightness); // Set BRIGHTNESS to about 1/5 (max = 255)
//LED_COUNT= 10;
//strip.begin();

//setup the buttons ()
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
}


// loop() function -- runs repeatedly as long as board is on ---------------


void debounceButtons() {
// Check for both buttons pressed
if (digitalRead(2) == LOW && digitalRead(5) == LOW) {
// If debounce delay has passed
if (millis() - lastDebounceTime > DEBOUNCE_DELAY) {
changeTime = !changeTime; // Toggle the changeTime state

// Save the current color before changing
color2 = color;

if (changeTime == 1) {
color = strip.Color(255, 0, 0); // Change to red for time setting mode
Rtc.SetIsWriteProtected(false);
Rtc.SetIsRunning(false);
}

if (changeTime == 0) {
color = strip.Color(255, 255, 255); // Change back to white
Rtc.SetIsWriteProtected(true);
Rtc.SetIsRunning(true);
}

// Update the display
displayTime(h2, h1, m2, m1);
strip.show();

// Save the current time of the debounce to avoid multiple triggers
lastDebounceTime = millis();
}
}
}


void updateTime() {
// Create a new RtcDateTime object with updated minutes
RtcDateTime updatedTime(
year, month, day,
hours, minutes, seconds);

// Set the updated time back to the RTC
Rtc.SetIsWriteProtected(false);
Rtc.SetDateTime(updatedTime);
delay(200);
Rtc.SetIsWriteProtected(true);
}


void loop() {

RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
Serial.println();
//int minutes=dt.Second();


// Buttons 1 and 4 press both at same time to enter time setting mode (RED mode)
int button1 = digitalRead(2); // brightness increase
int button2 = digitalRead(3); // brightness decrease
int button3 = digitalRead(4); // fadeColour speed increase
int button4 = digitalRead(5); // fadeColour speed decrease


// print out the value of buttons note 1 == not pressed:
Serial.print(button1);
Serial.print(button2);
Serial.print(button3);
Serial.print(button4);
Serial.print(": ");

Serial.println(color);

//ChangeTime setting mode
if (button1 == 0 && button4 == 0) {


//if (millis() - lastDebounceTime > DEBOUNCE_DELAY) {
changeTime = !changeTime; // Toggle the changeTime state
//}



// changeTime = !changeTime;
//delay(200);

// save the current colour
color2 = color;

if (changeTime == 1)
{color = strip.Color(255, 0, 0); // turn the lights to red change time.
displayTime(h2, h1, m2, m1);
Rtc.SetIsWriteProtected(false);
Rtc.SetIsRunning(false);

}
if (changeTime == 0)
{
//color = color2; // update to the previous colour
color = strip.Color(255, 255, 255);
Rtc.SetIsWriteProtected(true);
Rtc.SetIsRunning(true);
button1 = 1;
button2 = 1;
button3 = 1;
button4 = 1;
//delay(1000);
}
displayTime(h2, h1, m2, m1);
strip.show();


while (button1 == 0 && button4 == 0) {
button1 = digitalRead(2);
button4 = digitalRead(5);
}
// avoid button debounce


delay(500);
button1 = 1;
button2 = 1;
button3 = 1;
button4 = 1;
}



// update time
if (changeTime == 1) {


if (button1 == 0) {
m1 += 1;
if (m1 == 10) {
m1 = 0;
}
minutes = m2 * 10 + m1;
updateTime();
}

if (button2 == 0) {
m2 += 1;
if (m2 == 6) {
m2 = 0;
}
minutes = m2 * 10 + m1;
updateTime();
}


if (button3 == 0) {
h1 += 1;
if (h1 == 10 || h1 > 3 && h2 == 2) {
if (h2 != 0) h1 = 0;
if (h2 == 0) h1 = 1;
}
hours = h2 * 10 + h1;
updateTime();
}
if (button4 == 0) {
h2 += 1;
if (h2 == 3) {
if (h1 != 0) h2 = 0;
if (h1 == 0) h2 = 1;
}
hours = h2 * 10 + h1;
updateTime();
}
}







if (changeTime == 0) {

if (button1 == 0 && brightness < 250) {
brightness += 5;
strip.setBrightness(brightness);
Serial.println(brightness);
}

if (button2 == 0 && brightness > 5) {
brightness -= 5;
strip.setBrightness(brightness);
Serial.println(brightness);
}



if (fadeColour == 1) {

hue += fadeSpeed; // Increment hue to cycle colors

if (hue > 65535) hue = 0; // Wrap around hue value
if (hue < 0) hue = 65535;
color = strip.ColorHSV(hue); // Get RGB from HSV
}

if (button3 == 0) {

//
fadeSpeed += 10;
fadeColour = 1;
}

if (button4 == 0) {

fadeSpeed -= 50;
fadeColour = 1;
if (fadeSpeed < 0) fadeSpeed = 0;

}
}

m1 = minutes % 10;
m2 = minutes / 10;
h1 = hours % 10;
h2 = hours / 10;
s = seconds % 10;



displayTime(h2, h1, m2, m1);
}

#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime& dt) {
char datestring[26];
month = dt.Month();
year = dt.Year();
day = dt.Day();
hours = dt.Hour();
minutes = dt.Minute();
seconds = dt.Second();

snprintf_P(datestring,
countof(datestring),
PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
dt.Month(),
dt.Day(),
dt.Year(),
dt.Hour(),
dt.Minute(),
dt.Second());
Serial.print(datestring);
}

// Function to read a register
// Function to read a register from DS1302