## Introduction: VIRTUAL NIXIE CLOCK ON LED MATRIX 64X64

Today, I'd like to share how to build a Virtual Nixie Tube Clock on RGB led matrix 64x64. The virtual nixie digits are simulated from nixie tube's images.

Before getting started, let's see my videos below.

Update May 15, 2020 - Virtual Nixie Clock with some animations.

## Step 1: PARTS LIST

Main parts are listed as below:

## Step 2: LED MATRIX ASSEMBLY

I reused hardware from the previous INTERACTIVE INTERNET CLOCK project and we can see the details as topic below:

https://www.instructables.com/id/INTERACTIVE-INTER...

For wiring diagram between ESP32 (NODEMCU-32S) and RGB led matrix 64x64, you can refer to PxMatrix Library by Dominic Buchstaller (2dom).

• Control board for led matrix 64x64.

• RGB led matrix picture after finishing assembly work.

## Step 3: IMAGE CONVERTER

There are many Image Converter Tools on the internet for supporting programming images in led matrix, such as:

• ImageConverter (UTFT): which be used to convert images into hexadecimal code for programming.

http://www.rinkydinkelectronics.com/t_imageconvert...

• ezGIF: The online GIF maker and image editor, which is helpful for processing the *.GIF images.

I tried to look for nixie tube images that clearly and beautifully displayed the numbers inside nixie tube. And luckily I found them from a Japanese guy. He also did a virtual nixie tube clock project with M5Stick C and it looks very cool:

https://macsbug.wordpress.com/2019/06/06/m5stickc...

I only used his nixie tube images, resized and converted to HEX code by ImageConverter (UTFT) to make a virtual nixie clock on led matrix 64x64 by my way.

• NIXIE NUMBER SIZE 20x31

• NIXIE NUMBER SIZE 32x61

Example: HEX code for NIXIE NUMBER "0" - SIZE 20x31 is as follow:

```// Generated by   : ImageConverter 565 Online// Generated from : Nixie_20x31_0.png
// Time generated : Mon, 11 May 20 17:48:20 +0200  (Server timezone: CET)
// Image Size     : 20x31 pixels
// Memory usage   : 1240 bytesstatic const uint16_t Nixie_20x31_0[620] PROGMEM={
0x0000, 0x0020, 0x2944, 0x3986, 0x5A89, 0x7287, 0x82A5, 0x7224, 0x51A3, 0x7A04, 0x59C4, 0x59C4, 0x5A04, 0x59E4, 0x3922, 0x3102,   // 0x0010 (16) pixels
0x18A1, 0x1881, 0x20E3, 0x2924, 0x0020, 0x52AB, 0x3165, 0x30A0, 0x61C2, 0x7202, 0x59A2, 0x4962, 0x4142, 0x18A1, 0x28C2, 0x51A3,   // 0x0020 (32) pixels
0x7224, 0x7244, 0x7245, 0x8AC5, 0x7A45, 0x18A2, 0x20C2, 0x2903, 0x2965, 0x5206, 0x3901, 0xBCEA, 0xABA6, 0x7244, 0x8AC5, 0x59A3,   // 0x0030 (48) pixels
0x3902, 0x28C2, 0x20C2, 0x28E2, 0x59C4, 0x92C6, 0x92E6, 0x9B27, 0x82C6, 0xCC49, 0x4163, 0x3944, 0x4A49, 0x0000, 0x3103, 0xE5AA,   // 0x0040 (64) pixels
0x30C1, 0x59C4, 0x3103, 0x18A2, 0x20C2, 0x8262, 0xB302, 0x59C2, 0x20C2, 0x3943, 0x6204, 0x7245, 0x5983, 0xC447, 0x1082, 0x0841,   // 0x0050 (80) pixels
0x4A28, 0x0041, 0x3942, 0x40E0, 0x1060, 0x1860, 0x1040, 0x0840, 0x0000, 0x2060, 0x5120, 0x2040, 0x0000, 0x1060, 0x28A1, 0x30E2,   // 0x0060 (96) pixels
0x3922, 0x7A04, 0x0062, 0x1081, 0x4A48, 0x0841, 0x3942, 0x69A2, 0x20A1, 0x28A1, 0x18A2, 0x1001, 0xB3A1, 0xA2C0, 0xA201, 0xBB40,   // 0x0070 (112) pixels
0x9B01, 0x1001, 0x30E2, 0x4962, 0x59C4, 0xA284, 0x0061, 0x1081, 0x4228, 0x0041, 0x3122, 0x71C2, 0x1040, 0x1860, 0x3062, 0xFD20,   // 0x0080 (128) pixels
0x89C0, 0x2001, 0x4020, 0x2000, 0x9A00, 0xF4E0, 0x3883, 0x30E1, 0x51A3, 0x9223, 0x0062, 0x1061, 0x4228, 0x0041, 0x3142, 0x81E2,   // 0x0090 (144) pixels
0x1860, 0x1022, 0xFD00, 0x2841, 0x0000, 0x2860, 0x2880, 0x2860, 0x0800, 0x3861, 0xFD80, 0x3084, 0x4142, 0x9A03, 0x0062, 0x1041,   // 0x00A0 (160) pixels
0x4208, 0x0841, 0x2901, 0x79C2, 0x1881, 0xBAE2, 0x8181, 0x0821, 0x1860, 0x2060, 0x28A1, 0x2040, 0x1860, 0x0000, 0x9A42, 0xB402,   // 0x00B0 (176) pixels
0x30C2, 0xA203, 0x0021, 0x1041, 0x4208, 0x0841, 0x2101, 0x8202, 0x38A2, 0xFCC1, 0x0001, 0x1040, 0x1861, 0x1840, 0x30C1, 0x2060,   // 0x00C0 (192) pixels
0x1040, 0x2081, 0x1802, 0xF462, 0x30E3, 0xAA23, 0x0062, 0x1061, 0x4208, 0x0841, 0x20E1, 0x7182, 0xC342, 0x8221, 0x1841, 0x1840,   // 0x00D0 (208) pixels
0x1040, 0x1840, 0x20A1, 0x1840, 0x1860, 0x1881, 0x2081, 0x92A3, 0x8241, 0xB203, 0x0041, 0x1041, 0x3A08, 0x0841, 0x18E1, 0x78E2,   // 0x00E0 (224) pixels
0xE501, 0x5122, 0x1020, 0x1861, 0x0820, 0x1040, 0x2081, 0x1840, 0x1861, 0x1020, 0x28A1, 0x8A84, 0xE420, 0x9122, 0x0041, 0x1041,   // 0x00F0 (240) pixels
0x3A07, 0x0041, 0x18C1, 0xA1E1, 0xD461, 0x2842, 0x1881, 0x1040, 0x0820, 0x1040, 0x2081, 0x2081, 0x1020, 0x0820, 0x3902, 0x40A3,   // 0x0100 (256) pixels
0xD401, 0x9962, 0x0041, 0x1061, 0x4208, 0x0041, 0x18A1, 0xCA61, 0xB2C2, 0x2041, 0x28C2, 0x1020, 0x1040, 0x1861, 0x28C2, 0x1860,   // 0x0110 (272) pixels
0x1020, 0x1040, 0x4143, 0x3081, 0xA222, 0xAA03, 0x0001, 0x1081, 0x39E7, 0x0041, 0x10C1, 0xF2C0, 0x8281, 0x2881, 0x28A1, 0x20A2,   // 0x0120 (288) pixels
0x1881, 0x1881, 0x1881, 0x1881, 0x1881, 0x20A1, 0x30C1, 0x2861, 0xDBE2, 0xC201, 0x0000, 0x1061, 0x39E7, 0x0041, 0x0881, 0xFB00,   // 0x0130 (304) pixels
0x6141, 0x4122, 0x1861, 0x1061, 0x1060, 0x1861, 0x1881, 0x1860, 0x1040, 0x20A1, 0x30E2, 0x40E2, 0x9AE1, 0xC200, 0x0000, 0x1061,   // 0x0140 (320) pixels
0x39C7, 0x0041, 0x08A1, 0xFAC1, 0x79E2, 0x30E1, 0x1861, 0x1040, 0x0820, 0x1040, 0x1861, 0x1840, 0x1040, 0x20A1, 0x38E2, 0x28E3,   // 0x0150 (336) pixels
0xCBA1, 0xC1E0, 0x0000, 0x1061, 0x39C7, 0x0021, 0x1081, 0xF2C1, 0x79E1, 0x30C1, 0x1860, 0x1861, 0x1060, 0x1861, 0x1861, 0x1860,   // 0x0160 (352) pixels
0x1860, 0x1881, 0x2081, 0x3861, 0xDBA0, 0xB9E0, 0x0000, 0x1061, 0x31A7, 0x0020, 0x18A1, 0xAA02, 0x6161, 0x28A1, 0x1060, 0x1861,   // 0x0170 (368) pixels
0x1061, 0x1060, 0x1861, 0x1860, 0x1881, 0x1040, 0x2081, 0x30C1, 0x7101, 0x9140, 0x0000, 0x1061, 0x31A6, 0x0020, 0x20A1, 0x79E2,   // 0x0180 (384) pixels
0xB2C1, 0x2041, 0x2081, 0x1861, 0x1061, 0x1860, 0x1861, 0x1860, 0x1881, 0x1861, 0x30C1, 0x3861, 0xB280, 0x5061, 0x0020, 0x1061,   // 0x0190 (400) pixels
0x3186, 0x0020, 0x28C1, 0x5102, 0xD360, 0x2021, 0x1860, 0x1040, 0x1040, 0x1840, 0x1860, 0x1860, 0x1880, 0x1040, 0x28A1, 0x5961,   // 0x01A0 (416) pixels
0xCB00, 0x3860, 0x0020, 0x1061, 0x3186, 0x0020, 0x20C1, 0x30A1, 0xD420, 0x5101, 0x1040, 0x1040, 0x1040, 0x1860, 0x1860, 0x2081,   // 0x01B0 (432) pixels
0x1840, 0x1840, 0x2881, 0x9A40, 0x4900, 0x58C1, 0x0000, 0x1061, 0x2965, 0x0000, 0x20A1, 0x5121, 0x50E0, 0xC2A0, 0x0000, 0x1860,   // 0x01C0 (448) pixels
0x1040, 0x1860, 0x1860, 0x2081, 0x1040, 0x2080, 0x0001, 0xF3C0, 0x0821, 0x58E0, 0x0000, 0x1061, 0x2945, 0x0000, 0x20A0, 0x5101,   // 0x01D0 (464) pixels
0x1841, 0xFC80, 0x0000, 0x1840, 0x1840, 0x1840, 0x2060, 0x2061, 0x1860, 0x1021, 0x8A20, 0x8220, 0x0001, 0x48E0, 0x0000, 0x1061,   // 0x01E0 (480) pixels
0x2124, 0x0000, 0x2080, 0x40E0, 0x1860, 0x48C1, 0xF4A0, 0x0001, 0x1840, 0x2060, 0x2060, 0x2060, 0x1021, 0x5121, 0xFC20, 0x0001,   // 0x01F0 (496) pixels
0x0820, 0x40E0, 0x0020, 0x1041, 0x2104, 0x0000, 0x1860, 0x38C0, 0x1840, 0x1040, 0x8180, 0xC2C0, 0x1040, 0x2000, 0x2040, 0x1800,   // 0x0200 (512) pixels
0x7140, 0xCAC0, 0x1001, 0x1040, 0x0000, 0x38C0, 0x0020, 0x1041, 0x18E3, 0x0000, 0x1860, 0x30C0, 0x1040, 0x2060, 0x0000, 0x51A0,   // 0x0210 (528) pixels
0xB2A0, 0x7160, 0x38A0, 0xB1E0, 0x79E0, 0x1021, 0x0820, 0x1040, 0x0820, 0x30C0, 0x0020, 0x1061, 0x10C2, 0x0000, 0x1860, 0x2880,   // 0x0220 (544) pixels
0x0820, 0x1020, 0x0000, 0x0000, 0x0000, 0x5100, 0x7A00, 0x30C0, 0x0000, 0x0800, 0x0000, 0x0000, 0x0000, 0x30A0, 0x0000, 0x0841,   // 0x0230 (560) pixels
0x10A2, 0x0000, 0x0000, 0x18A2, 0x2902, 0x3943, 0x20C2, 0x20E3, 0x18A2, 0x3922, 0x3901, 0x3962, 0x3943, 0x4184, 0x3984, 0x3164,   // 0x0240 (576) pixels
0x3123, 0x2924, 0x0000, 0x1041, 0x0881, 0x0000, 0x0800, 0x9344, 0x4142, 0x1060, 0x0840, 0x1861, 0x1040, 0x0020, 0x1040, 0x0820,   // 0x0250 (592) pixels
0x1061, 0x1061, 0x1881, 0x28C1, 0x18A1, 0x8A64, 0x18A1, 0x18A2, 0x0861, 0x0000, 0x0000, 0x51E2, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0260 (608) pixels
};```

I converted all nixie number images into a HEX codes for next programming step.

## Step 4: PROGRAMING

The project code for VIRTUAL NIXIE CLOCK ON LED MATRIX 64X64 is available at my GitHub.

My program is explained as follows:

• Nixie Number Image: There are 2 sets of Nixie number libraries with different sizes, named SMALL and BIG size number:

- Nixie_20x31.h

- Nixie_32x61.h

• Internet Clock:

- Time is updated via internet by NODEMCU-32S and hour/ minute/ second digits are displayed by corresponding nixie number pictures. The tens and units digit of time will be lookup in to picture arrays as below:

```/* Small Nixie Number*/
const uint16_t *Numbers_S[10] =
{
Nixie_20x31_0,
Nixie_20x31_1,
Nixie_20x31_2,
Nixie_20x31_3,
Nixie_20x31_4,
Nixie_20x31_5,
Nixie_20x31_6,
Nixie_20x31_7,
Nixie_20x31_8,
Nixie_20x31_9,
};

/* Big Nixie Number*/
const uint16_t *Numbers_B[10] =
{
Nixie_32x61_0,
Nixie_32x61_1,
Nixie_32x61_2,
Nixie_32x61_3,
Nixie_32x61_4,
Nixie_32x61_5,
Nixie_32x61_6,
Nixie_32x61_7,
Nixie_32x61_8,
Nixie_32x61_9,
};```

- When the seconds in range 0 to 30, led matrix 64x64 display all digits of hour, minute and second in SMALL nixie numbers. The seconds from 31 to 59 will be displayed in BIG nixie numbers. At this time, led matrix 64x64 only show the tens and units digit of second.

```if (seconds>=0 && seconds<=30) // Show all digits when seconds is from 0 ~ 30 in Small Nixie Number.<br>    {
if (seconds==0)
{
NixieNumbers.clearNumber(0, 0, NUMBER_WIDTH_B, NUMBER_HEIGHT_B);    // Clear Big Nixie Number
NixieNumbers.clearNumber(32, 0, NUMBER_WIDTH_B, NUMBER_HEIGHT_B);   // Clear Big Nixie Number
}
Nixie_S0();
Nixie_S1();
Nixie_M0();
Nixie_M1();
Nixie_H0();
Nixie_H1();
}
else   // Show only second from 31 ~ 59 in Big Nixie Number.
{
if (seconds==31)
{
NixieNumbers.clearNumber(0, 0, NUMBER_WIDTH_S, NUMBER_HEIGHT_S);    // Clear Small Nixie Number
NixieNumbers.clearNumber(0, 33, NUMBER_WIDTH_S, NUMBER_HEIGHT_S);   // Clear Small Nixie Number
NixieNumbers.clearNumber(22, 0, NUMBER_WIDTH_S, NUMBER_HEIGHT_S);   // Clear Small Nixie Number
NixieNumbers.clearNumber(22, 33, NUMBER_WIDTH_S, NUMBER_HEIGHT_S);  // Clear Small Nixie Number
NixieNumbers.clearNumber(44, 0, NUMBER_WIDTH_S, NUMBER_HEIGHT_S);   // Clear Small Nixie Number
NixieNumbers.clearNumber(44, 33, NUMBER_WIDTH_S, NUMBER_HEIGHT_S);  // Clear Small Nixie Number
}
Nixie_S0_B();
Nixie_S1_B();
}```

- At the units and tens digit of hour, minute and second, before showing the newly updated time, we have to erase the time that was shown previously. For example:

```void Nixie_S0()
{
if ((unsigned long) (micros() - samplingtimes0) > 99)
{
if (s0 != prves0)
{
NixieNumbers.clearNumber(44, 33, NUMBER_WIDTH_S, NUMBER_HEIGHT_S);
NixieNumbers.drawNumber(44, 33, Numbers_S[s0], NUMBER_WIDTH_S, NUMBER_HEIGHT_S);
prves0 = s0;
}
else
{
NixieNumbers.drawNumber(44, 33, Numbers_S[prves0], NUMBER_WIDTH_S, NUMBER_HEIGHT_S);
}
samplingtimes0 = micros();
}
}```

Here below is my result picture.

## Step 5: DONE

It looks more beautiful when we see it in real life and stand far from the led screen. The flickers you see on videos is due to CAMERA, human eyes can't see these flickers.

If we have a led screen with big size and high resolution, this nixie clock will looks even better.

Participated in the
Arduino Contest 2020