Introduction: Arduino Nixie Clock & Weather Station
I wanted to build a Nixie clock driven by an Arduino and found a few places on the internet, but none were 100% complete to get it working from the beginning to end. I either found bad wiring diagrams, bad code in programs or bad supporting literature that really slowed down my progress, so I gutted it out, figured it out and came up with the following. Maybe someone can say well, you missed this or that... Hopefully i haven't and I have given you enough here to let you find the mistakes. Anyway... this is my Nixie clock / Weather station. I used a Syncroscope from a Nuclear power plant for the case. The clock displays the time from the top of the minute to 15 sec in, and then displays the temperature (F), then back to time until the bottom of the minute (30 sec.), then it displays atmospheric pressure (mm Hg), then back to time until 45 sec into the minute and displays relative humidity. Upon reaching 60 sec. it increments the time and repeats the cycle. The BMP280 has a very poor temperature sensing capability and is not nearly as accurate as a DS18B20 Waterproof Temperature Sensor that I used in another project of mine. I may just swap this out. Also I had a nice mesh cage around the sensors to protect them from damage and this too led to inaccurate results so I modified that as well. The indicator arrow is scaled for the low and highest pressures found in my state. the indicator arrow does a good job of showing changes in the pressure when a storm or clear skies are developing.
Arduino Mega - For the Output count.
Real Time Clock Module - DS3231 AT24C32 IIC precision Real time clock RTC memory module
Pushbutton Board -
Micro Servo -SG90 Mini Micro Servo
DHT22 humidity Sensor
BME 280 Temperature / Pressure sensor.
IN-12A Nixie Tubes
K155ID1 ( = SN 74141) IC Driver for Nixie tubes
DC 10V-18V to 130-200V Voltage Power Supply Module
Surplus wall wart 120 VAC to 5 vdc power supply
Neon 120 VAC bulbs w/ resistors
Assorted Blue and UV LEDs
Be sure to check the code carefully for exact wiring points to the IO points wired. I must have changed code and wires several times to get things to work. Double and triple check your code to the wiring as it is soooo easy to mess it up. I believe my wiring diagram is accurate except note the 8 pushbuttons are into separate inputs not numbered.
Step 1: Explaining the Code ...
I tried to annotate the code as best as I could. I discovered that in learning Arduino and C++ programming (former Fortran guy here), it takes a lot of self teaching moments and it isn't always that obvious to follow someone else's code (at least for beginners). So go to the link and reference the LINE #'s to what I describe as the critical things to consider, below:
LINES 2-3 - These bring tin the supporting library code to get your clock module to work and define the clock module you are using.
DS3231 rtc(SDA, SCL);
LINES 6 - 27: To keep the code straight I assigned each tube from left to right as you look at them N1, N2, N3, and N4. Then I have to group the 4 control wires (ABCD) that will drive each tube's chip to these respective tubes.
#define N1C 28 //C <<<--- N1 is the Hour tens digit Nixie Tube so repeat these 4 lines for each tube!
#define N1B 26 //B
#define N1D 24 //D
#define N1A 22 //A <<<----- This is the line that assigns the output of pin 22 to be the wire to the chip for the leftmost Nixie Tube. It is plugged into output pin 22 and soldered to the "A" lead of the chip. By the truth table, the "A" lead is the least significant digit and the D Lead is the Most significant digit. So I bet you're wondering why the pin assignments are not in sequence to ABCD alphabetically... That is because the chip has them from top to bottom ADBC and I wanted the wires to not have a cross twist when soldering. It was easier to keep them straight (so I thought). But any trick for consistency is good to have to prevent wiring errors. You can always change the program to match but the troubleshooting is where the time is lost.
LINE 49 - byte dig1, dig2, dig3, dig4; Each tube must display a given digit whether it is a digit for time or temp, whatever... The program takes the digit and uses a byte to hold onto the number as stripped off the register later on in the program, but it is defined here.
LINE 53 - 60 This is the canned code for a DHT22 from the examples taken from several sources from the internet. Found lots of places. Note I cut out the code for other models of sensors (DHT11) as I want a lean program.
LINES 64-77 just code to set up the BME Sensor and Servo for Library support. Line 77 assigns the servo control to that pin 61.
LINES 79 - 104 This assigns all of the pins for the 4 BINARY control wires ABCD for each of the 4 N1 - N4 Nixie tubes to be outputs. Note I am trying to show in the comments that the "A" output is the 2**0 (least sig. bit), "B" is 2**1, "C" is 2**2, and finally and "D" is 2**2 or the Most significant bit. So, what does this mean? Look at the Truth table for the chip in the attached photos. If I want the number "6" to light up on the nixie tube, I need to send a binary bit pattern over ABCD wires to turn on the pin 6 of the chip. Or A is off, B is on, C is on, and D is off. The chip only looks at the ABCD wires if they are on and sums them up to turn on the respective output. 2**1 = 2, and 2**2 = 4, so 0+2+4 +0 = 6. Now, if I solder a wire from pin 6 of the chip to the terminal pin of the Tube for #6 wire to energize, It will complete the circuit from the 170VDC from the anode and light up.
LINES 106-113 Defines the pins of the Mega to be inputs for the button panel.
LINES 122-128 Sets up the initial Time and date of the RTC module. On first scan it will load the module with the values you actually have on this line of code. You will then change the time with the button panel once the Arduino is running your total code.
LINES 129 - 234 BME280 standard set up code. Just use these parameters and lines of code, no issues here. I wish I had more time to truly learn if the BMP280 can be calibrated by the last few lines but I really did not get a good reference for this code. My BMP is not accurate to actual temperature and had to force a calibration by subtracting a whole number from that measured later in the program. See if you can find it!
LINES 237 - 240 - DHT sensor set up. No worries here.
LINES 246-253 state that if a pushbutton is being pressed set that variable name "butXstate" to HIGH status.
LINES 262 - 300 and 392-409 - THESE ARE CRITICAL for troubleshooting your project if the nixies are not displaying correctly. The lines use the serial port to let you know what is INSIDE the memory registers of temp, time, etc. data... This is where you see that. Then debug from there to get it out on your tubes. The serial port does not lie what is in these registers, and at times I was wondering if I had a slow SDA/SCL comm. issue. Nope - bad wiring!
LINES 302 -304 - This calls up DISPLAYWHAT(). to see if there is a request for a certain parameter (button being pushed). Then it goes to DriveTubes(), to actually write a ABCD control pattern to each of the 4 tubes based on what is being asked under "DisplayWhat().
LINES 307 - 390 Is the sequencing of the scrolling feature of the clock to display the time, temp, time, pressure, time, humidity, time cycle. It uses the "freq = t.sec" to see the total value of seconds that has elapsed and displays whatever quadrant of a "minute" it is in. The IF statements are saying if seconds elapsed in in this range of time and there is NOT a pushbutton being pressed, then go get the number from the registers, then drive the tubes accordingly for that number. Also light the green LED to let the person know what the number represents.
LINES 412 - 424 These just get the humidity refreshed from the sensor to the register for use.
LINES 427 - 454 DisplayWhat() this just checks to see IF a button is pushed and if so, which one. Then go do what that button is calling for. If button 0,1,2,or 3 is pressed then go to Change Time since the person is wanting to change the clock time. If button 4 then go get the temp and display it, Button 5 - go get the pressure and display it, Button 6 go get the humidity and display it. If button 7, then flush all the tubes with a sequence to help prevent cathode poisoning of the tube.
LINES 456 - 473 DisplayTime() grabs the time in hours and minutes from the RTC and convrts it from Military time to 12 hour basic time (line 462-3). Then whether for minutes or hours, it strips off the first digit by dividing by ten and then grabs the second digit by taking that remainder of that division. To turn off the first Nixie tube if the hour is less than "10", I drive the chip to full value of 16 so all the ABCD turn on and the truth table shuts off all outputs of the chip so no digit will light. This is the only value that strips the numbers this way.
LINES 474 - 512 ChangeTime() Is called up if one is pressing any of the first 4 pushbuttons. The variable name of newhour etc is incremented or decremented by the pushbutton being pressed each time (same for minutes) and then on line 510 the new values are written to the RTC memory and the clock takes in the new time setting.
LINES 513 - 594 DisplayTemp(), or DisplayPress() or DisplayHumid() all function the same way. The weather variable is defined as a floating point number and then read from the sensor. This number is then broken up into 4 digits and individually stripped off one by one as the number is divided by 10 then subtracted off to get to the next digit. That is multiplied by 10 and indexed over for the digit to be driven to that tube and repeated for the remaining tubes. Example: Temp = 71.25 then temp becomes 7.125, and dig1 = 7. Temp is still 7.125 - 7 = 0.125 then * 10 = 1.25 which is now set to Dig2 and so forth.
LINES 598 - 822 RunPoission() drives the four nixie tubes to scroll through the numbers 0 thru 9 at 0.1sec durations for each number. We write a low or high to the respective control wires at their respective pins to get the correct BINARY pattern to turn on the right output on the chip to light up the correct wire inside the tube.
//3 - To display the number 3 for example on Nixie tube N1....
digitalWrite(N1D, LOW); //D1 this is 2**3, so we don't need an 8 so "write" the pin N1D off or LOW.
digitalWrite(N1C, LOW); //C1 this is 2**2, so we don't need an 4 so "write" the pin N1D off or LOW.
digitalWrite(N1B, HIGH); //B1 this is 2**1, so we DO need an 2 so "write" the pin N1D on or HIGH.
digitalWrite(N1A, HIGH); //A1 this is 2**0, so we DO need a 1 so "write" the pin N1D on or HIGH.
2+1 is three and the chip drives the output 3 to ON, thus passing the 170VDC to the wire in the tube.
delay(10); delay for 0.010 seconds and continue to scan and display a "4" then a "5" etc.
LINES 828 - 1119 DriveTubes() work analogous to RunPoission() by checking if the values of Dig1, Dig2, Dig3, and Dig 4 are equal to and then if true for that condition, it falls through and drives the control wire pattern to the corresponding write pattern.
Step 2: Clean Up the Case
I knew the Syncroscope was not large enough to hold all of the power supplies needed for the project much less the Arduino Mega, chips, and wiring. So I built an acrylic box to give it an exploded type look to the case.
I gutted the scope internals to make way for the rest of the parts of the clock. I knew it would be tight. I only saved the panel and indicator for the Atmospheric indication. Assembling the Acrylic case was a bit tricky to NOT HAVE THE GLUE SLOP ALL AROUND. A little goes a long way. This definitely takes practice and I used painter's tape to keep glue from contacting areas I did not want to be ruined. SUGGESTION: Learn how to sand and polish the edges with buffing wheels or with a propane tank flame. Both methods work great but require patience and practice.
I tried to minimize the access panels to this case and discovered I made it incredibly hard to assemble the complete working structure. I tried to maintain the internal supports from the original meter to hold it all together and that proved to be very challenging to say the least. Note that there is only one side to access the clear box and I had to use long articulated needle nose pliers to get the far rods in place and tighten those nuts. The entire assembly pulls together as a clamp type design. In other words... do something much less complicated and this will go together easier and trouble shooting will be easier as well. It got so bad to trouble shoot it, I pulled it all apart and remounted all the components on a scrap board to get everything to work, THEN reassembled the clock in the final case. I did this twice!!!
Step 3: CUtting the Face Panel
Since I only had one shot at cutting the aluminum face panel, I was very careful to lay it out graphically first and took measurements carefully. Measure twice cut once. I even photocopied the face as a guide for cutting the plexiglass face panel as reassurance it was correct. I then buffed / polished the edges in my drill press.
Step 4: Build the Circuit...
I have three transformers in the clock that I put into the rear round section of the case:
1. 120 VAC to 5 VDC to power the Arduino and sensors.
2. A 120 VAC to 12 VDC to power the high voltage converter.
3. a 12 VDC to 200 VDC transformer - to power the Nixie tubes.
A toggle powers them up and I use two 120 VAC neon bulbs to indicated 120 VAC is switched on.
I then followed the wiring diagram shown, having to test each soldering connection several times to ensure a good connection. Follow the wiring from the Arduino outputs to the 4 Chip drivers Carefully. Be sure to have the IO numbers match up consistently to ABCD of the chips for all 4 chips. Then ensure the chips to the SOCKETS are wired consistently to match up the Chip output to the right number to be displayed. Note that the IN12 pin numbers ARE NOT the numbers for the digits that light up. It is easy to forget this so check and check again.
Step 5: Soldering the Circuits...
Soldering the chips needs a pencil point iron, generous use of flux and technique to ensure no two pins get shorted. I used a circuit board to keep everything neat and tidy and also used Arduino pins for plug ins. Be super conservative in stripping these fine wires as the heat will cause much of the insulation to pull or shrink back. Solder the ABCD wires into groups of 4 onto the pins then plug the 4 ganged pins into the female block as soldered to the chips.
To hold the pins into place, I hot melted the sides of the pins to the sides of the female blocks. The hot melt is removable with an Xacto knife if you have to do rework. Just take your time. But the glue holds everything together and avoids loose connections.
I kept a good color scheme of wires to keep things straight....
Yellow - 170 VDC for the nixie
Red- 5 vdc
Black - Ground
White / Black 120 VAC
Purple 12 VDC
Orange Browns, etc... Specific leads for Servo, Nixie numbers, etc.
Step 6: Setting the Clock
The Pushbutton Board... (See Wiring Diagram). The buttons are used for setting the hours and minutes up / down, and calling up the Temp, Humidity, and Atmospheric pressure on demand. The last button runs an anti-poisoning routine to wash the tubes.
Be sure to use the 8K Ohm resistor (6K - 10K works fine) to pull the input to ground when the pushbutton is not pressed. This prevents troublesome stray voltage turning on the inputs. Some examples elsewhere about these panels do not use this method and they short cut it with programming, but it is NOT reliable. Just do it the right way. See the wiring diagram and follow the correct scheme for trouble free working buttons.
I extended the pushbuttons through the case via soldering on a small brass washer on the bottom of brass pins which were cut and sanded from rod stock. The rods then cannot fall out if turned upside down. This also allows for a clean appearance of not having a huge cut out for the buttons through the sidewall, and a clean appearance.
Step 7: Assembly
Assembly will depend on your Clock design and case. These pictures show a number of assembly stages that frankly some did not work out well, and then I re-did the construction. If you look closely at the pictures here and the finished project you will see many of the changes I made. Most notably is the nixie sockets were soldered back all the way to the Chip Driver pins as mounted onto the circuit board. Then the ABCD control wires were pins from the chip to pins into the Arduino.
I used plenty of masking tape to prevent scratching of the acrylic. Lots of wire ties to train the wires and not break off at their respective solder joints, and plenty of hot melt glue to insulate the wires were they were stripped.
Step 8: Final Assembly & Trouble Shooting
I alternated between building the clock, writing the program, and trouble shooting it. I basically built up small pieces of code to get one thing working, then added code for another feature. If something didn't work then... I knew it was the new feature added and that it was upsetting the scan or had bad flow structure.
I had the far digit to the right not displaying all the numbers correctly and I wasn't sure if it was code or a bad wiring job / cross short, or a bad nixie tube. So I swapped tubes... all tubes functioned the same way so it wasn't the tubes. Then I hunted down the wiring and discover two wires were crossed as wired to the socket (the numbers threw me off from the digits to be displayed). This only happened once, but I still wasn't out of the woods. I was ALMOST there but getting crazy numbers, and finally discovered I had a typo in driving the number "2". AAAARGH! Finding this was a needle in the haystack and once found of course it make perfect sense. This was days to get this one digit to work.
Runner Up in the