IN-9 VU Meter

My wife bought several IN-9 nixie tubes as an anniversary present, so this is a quick project to display sound levels on one of them. Quick to put together, but a lot of research on exactly how to do it.

The IN-9 is a very simple tube. Just a single long cathode. As you increase the current (up to about 10mA) more of the cathode lights up, so it is essentially a bargraph. To control the current we attach the collector of a MJE340 transistor to the cathode, the emitter to ground via a variable resistor and then control the voltage on the base. Then we connect the anode to 150V. We could go higher, and adjust the resistor on the cathode to a higher value to keep the tube operating over its full range. I used one of my own adjustable nixie power supplies for this, but there are several supplies available commercially, such as the Taylor Edge power supply and the Omnixie power supply.

I used a Wemos D1 mini pro to control the base, because I happen to have several I’m not using. Because it doesn’t have a DAC we have to fabricate one with a resistor and capacitor and then feed it a PWM signal. So we end up with this:

IN-9 VU Meter Circuit

So now we need to get some sound in to it. I wanted this to be free-standing, so I wanted a microphone of some sort. Eventually I settled on this module from Adafruit. It has auto-gain control and produces a peak-to-peak output that matches well with the 3.3V inputs of the Wemos, and of course Adafruit have code samples for it. In particular a simple sound-level sketch for arduino.

Everything worked great, except for one thing: The glow kept detaching from the bottom of the tube. The IN-9 is well known for this. Most people recommend you use IN-13 instead, but that’s not what I had. Eventually I discovered this article about an IN-9 thermometer. The authors reasoned that the tube was originally meant to be driven via AC, so if they turned the tube off periodically it should work, and it did. They used a hardware solution, but I used a software solution, I just interleaved a PWM signal with the analog output, so it turned off completely every so often. This is the whole code:

#include "Arduino.h"

 * Sometimes you just want to do things according
 * to a duty cycle other than toggle some GPIO.
 * Sometimes you want to run multiple
 * duty cycles on one output pin? You could use several
 * of these to figure out when to turn it off and when
 * to turn it on.
struct SoftPWM {
	byte quantum = 1;
	byte onPercent = 100;
	int count = 0;

	SoftPWM(byte onPercent) {

	SoftPWM(byte onPercent, byte quantum) {
		this->quantum = quantum;

	bool off() {
		count = (count + quantum) % 100;
		return count >= onPercent;

	void reset(byte onPercent) {
		this->onPercent = onPercent;
		count = 0;

// ESP8266 pins
const byte CTRLpin = 5;
const byte INpin = A0;

void setup()
	pinMode(CTRLpin, OUTPUT);
	// Freq and Range are ESP8266-specific calls.
	analogWrite(CTRLpin, 75);

SoftPWM oscillator(90);	// A 90% duty cycle for turning the tube off. Pick something that works.

const int sampleWindow = 50; // Sample window width in mS (50 mS = 20Hz)
unsigned int sample;
unsigned long startMillis = 0;
unsigned int peakToPeak = 0;   // peak-to-peak level
unsigned int signalMax = 0;
unsigned int signalMin = 1024;

void loop()
	// collect data for 50 mS - code based on
	// but this code externalizes the loop, because we don't want
	// to hold the whole ESP8266 up
	if (millis() - startMillis < sampleWindow) {
		// Set the min and max levels over a 50ms period.
		sample = analogRead(INpin);
		if (sample < 1024)  // toss out spurious readings
			if (sample > signalMax) {
				signalMax = sample;  // save just the max levels
			} else if (sample < signalMin) {
				signalMin = sample;  // save just the min levels
	} else {
		// Done sampling, calculate the peak-to-peak level in the last 50ms.
		startMillis = millis();
		peakToPeak = signalMax - signalMin;  // max - min = peak-peak amplitude
		signalMax = 0;
		signalMin = 1024;

	if ( {
		// Keep the glow stuck to the bottom by turning the tube off occasionally
		analogWrite(CTRLpin, 0);
	} else {
		// Output the sound level
		analogWrite(CTRLpin, map(peakToPeak, 0, 1024, 0, 100));

Here’s a video of it in action. The quality (of the video) isn’t great:

I’ve got a few more of these tubes, so now I have to decide if I want to make stereo VU meter or a spectrum analyzer. I think I would prefer to make a multi-purpose bar-graph display like this one from Nuvitron.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.