A while ago I found a Burroughs B-5853 Nixie tube kicking around in the lab and decided that I should put it to good use. Since I only had one of this size, I wanted to make a single-digit display out of it. After I saw Jason Harper's Nixie clock gallery, I decided that one digit really could make a cool clock.
To add to the excitement, I wanted to be able to PWM the display, allowing smooth fading and ultra sexiness (you know, for the ladies :-P) and allow for further expansion, perhaps via a computer interface. For these reasons, I chose the Microchip PIC16F628 microcontroller, which has an on-board USART and does hardware PWM on one pin. Moreover, I'm already quite experienced making crap with the 16F628, including another clock, and I've got a metric assload of them lying around.
To drive the Nixie, I'm lucky enough to have a stash of 74141 BCD-to-decimal decoder / gas discharge tube driver ICs. These are somewhat hard to find, although you should still be able to get your hands on some from Mouser or EBay. The outputs are open-collector, so you just hook the Nixie anode to rectified mains via a 20ish kOhm resistor, connect the appropriate outputs on the 74141, and you're all set.
Unfortunately, the 74141 is damn expensive (I just checked---it's $7 from Mouser); fortunately, it's not the only game in town. It turns out that you can drop some voltage across the Nixie without lighting it up. That means you can drive the Nixie from an IC that can't tolerate the full 170 Volt rail by protecting the output with a Zener diode. The ULN2003 is an open-collector transistor array that can withstand 50 Volts at the collector terminals. Along with a 47 Volt Zener this makes a perfectly reasonable driver (except that you'll need two of them to cover all the outputs). Depending on your Nixie, 47 Volts might not be enough to turn off the filaments completely. In this case, you could use the ULN2023 (and an appropriately-chosen Zener) instead, as it's capable of withstanding 100 Volts. An example of how you'd use the ULN20x3 is shown to the right.
Another option is to use high voltage discrete transistors to drive the Nixies. This can take up a lot of board area (and assembly time, especially if you're not going to have the board fabbed, for example by---shameless plug coming up---Advanced Circuits). On the upside, it's virtually guaranteed to work and more or less foolproof. Jason Harper has written an excellent paper, Driving Nixies with Discrete Transistors, on just this subject. I recommend you give it a read. Another good resource is How to Drive Nixies over at Onno's Electronics Page.
In a perfect world, everyone would run everything on the other side of an isolation transformer, no one would worry about ground loops, and everything would be hunky-dory.
This ain't no perfect world.
As you can see from the picture, my clock only has one transformer, and I'll tell you a secret: it's just a 6.3 Volt RMS secondary running into a rectifier to provide the low voltage rail for the 74141 and the 16F628. The Nixie supply is rectified mains, and as a result it's potentially (heh, so punny) very dangerous. If you go building one, don't zap yourself. In fact, to be safe, put a 1:1 isolation transformer between the wall and the circuit.
The power supply doesn't have to be all that beefy. In my case, I use a bridge rectifier on the mains and another on the transformer output. Throw caps on the rectifiers (check the voltage ratings!) and put an LM7805 and a cap on the low voltage one. "Bam," as the man says.
Since the whole thing runs pretty slowly and oscillator timing isn't critical, I didn't worry about using a nice accurate 20 MHz crystal. Instead, I rely on the internal 4 MHz oscillator in the 16F628. This frees up pins A6 and A7, which we will use to drive the decimal points.
For a time reference, I use 60 Hertz off the mains, since it's guaranteed to be very precise (at least over several days/weeks). To get it into the PIC, I just put it through a large (470 kOhm) limiting resistor with clipping diodes to the 5 Volt rail and ground. This is better than dividing down the sine, since you don't have to worry about offset when you clip the sine wave. I put the resultant 60 Hertz square wave into A4, the external timer input pin, so that I can use the PIC's tmr0 interrupt to keep track of the time.
The 74141 has a simple BCD interface which I tie to A3-A0, allowing me to write a number to port A to display it on the Nixie. The 74141 has another feature I find useful: an invalid (>10) input causes the 74141 to blank the display. This is cool because it lets me do PWM easily using the 16F628's hardware PWM output. Even though there's only one output pin, as long as I can use that pin to force an invalid input, I'm golden. To do this, I employ a simple wired-OR with the two most significant bits of the 74141 (since 8 + 4 > 10, I only need the two high bits to guarantee an invalid input).
It's a little more easily said than done, however, since I need a low impedance between the data drivers (A3-A2) and the MSBs of the 74141 in order to sink the maximum output current in the low state (a whopping 3.2 mA at .6 Volts!), yet I need to be able to drive both of the inputs high with the PWM output. To the left is the circuit I ended up using. Yup, those are the right resistor values---B3 needs to supply about 22 mA (remember, .6 Volt diode drop) in the worst case! (Don't worry, the PIC is rated for 25 mA per output up to a total of 200 mA into or out of A and B combined; we're not even close to that.) Perhaps better than my rambling is the image to the left, which illustrates the wired-OR circuit. Note the diodes, which isolate A3 from A2 when B3 is pulled low (i.e. when not blanking).
As I promised earlier, A6 and A7 drive transistors for the decimal points (since the 74141 doesn't do decimals, only the 10 digits). I had BF859s lying around from my plasma tweeter project (description forthcoming, I promise), so I used them (even though they're a bit overkill with their 300 Volt collector voltage rating). 1 kOhm resistors on the bases and we're all set.
I mentioned earlier that I wanted to allow room for a possible computer interface. Though I haven't implemented it, B2 and B1 are unused, so I could pop in a little code and use the 16F628's USART to talk RS232. Or maybe you could, if you're motivated. A friend of mine suggested using it as a load average indicator on my office computer. Sounds like a plan to me.
The PIC is configured to use its internal 4 MHz oscillator; the tmr0 interrupt, PWM hardware, and weak port B pullups are enabled.
The code that drives the clock is more or less just an interrupt handler. Every clock transition on the 60 Hertz input causes a tmr0 interrupt during which, as they say, shit happens.
First, I check B7 and B4, the buttons for advancing the hours and minutes. Since the switches bounce like bastards, I debounce them in software by requiring the switch to be depressed for four successive 60 Hertz periods.
The next step is to increment the counter. I actually use four separate registers to hold the time data as sixtieths, seconds, minutes, and hours. A little bit of overflow checking at this point saves a lot of time in displaying the data later.
To do the display, I use a lookup table to convert the counts to BCD (so 10 becomes 0x10, 24 becomes 0x24, &c). The lookup table is placed in the data EEPROM (we have 128 bytes total), since it's slightly faster (three cycles versus four) to load it from the data EEPROM than to use a jump table.
Finally, the PWM value is placed in the appropriate register. Again, I use a lookup table to translate the sixtieth of the second we're currently in into a PWM value, and once again this table resides in the data EEPROM.
If you download the code (see below), let the Makefile be your guide; I've written a couple Perl scripts to generate the appropriate EEPROM entries. These may or may not work with programs other than picprog.
After making the circuit, I mounted the whole thing on a piece of HDPE. It's ghetto, but it works.
Of course, I would be remiss if I didn't provide a schematic (pdf or postscript) of the whole thing (updated 02/20/2005 to fix a couple errors in the schematic), and the code (nominally in JAL, though almost all of it is just assembler). If you don't care to compile the code yourself, you can instead download either the 60Hz hex file or the 50Hz hex file (or 50Hz with 24-hour format). All are precompiled with a sinusoidal fade pattern.
After giving the original Nixie-1 to my younger sister, I decided I wanted another one for my desk at work, so I invested the time to make a board in Eagle and sent it off to Advanced Circuits. This clock uses a B-5440, since that's what I had lying around, and I added a DB9 with appropriate connections for when I finally get around to coding up something useful for the serial interface.
If you're interested in making one of these, you can download a zipfile of the layout ready to be uploaded to 4pcb.com. The parts (other than the 74141 and the Nixie) are available from Digi-Key. The only ones that aren't completely standard are
The diodes not marked as 1N4148s are 1N4004s or the like.
Note: although it's not in the schematic, you're going to want a .1uF ceramic capacitor across D12 to prevent spurious clock transitions. In addition, R2 is probably too large by a factor of 10 or so; a 47kOhm is probably perfect.
In the process of making this board, I discovered some extremely useful things which you might find interesting.
Here's what it looks like stuffed: