Traditionally, a Geiger counter like the CDV-700 series is a completely analog device--the device output is driven entirely by the analog electronics. Electrical pulses passing through the Geiger-Müller tube during ionizing events are run through a speaker cone, generating the characteristic clicks of a Geiger counter. That voltage is also directed into an electromechanical meter that displays the average clicks over a given amount of time. For Project Pripyat, I wanted to have the option to drive several different kinds of output with minimal rewiring and I want to be able to save data gathered and send it to a computer. The easiest way to accomplish all of these objectives was to pipe the GM tube output into an Arduino, and I just so happened to have a bunch of Nanos in my parts bin!
Arduino code for a Geiger counter
The Nano has a pretty low tolerance for excessive voltage on its digital pins, so I had to incorporate a pretty hefty voltage divider into my circuit design (from 400V down to <5V) to prevent frying the thing. The code itself was a work of trial and error, mostly playing around with various ways to drive the analog meter. Since the Arduino does not have true analog output (only pulse-width modulation), I decided to let digital pulses "kick" the needle into the appropriate position on the meter. The more frequent the pulses, the more the needle will be displaced. It's basically PWM, but there's no averaging being done in software. The v1.0 code, therefore, is rock-basic simple. It is almost entirely pin definitions, based on the "Blink" example sketch, but it's snappy and serves its purpose as a "minimum viable" solution.
const byte interruptPin = 2;
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, LOW);
In the sketch, we define several pins on the Arduino and how they'll be used. Pin 2 is going to serve as an interrupt and is attached to the pulse generator in the circuit. In my Geiger counter circuit, the pulse generator is actually reverse-biased to become an interrupt generator. Every ionizing event detected by the GM tube causes the 2N2222 transistor to ground the signal line connected to the Arduino which will be picked up as the interrupt signal. Upon detecting the interrupt, the Arduino will jump to the blink
interrupt service routine which changes quickly changes pin states for the LED, meter, and piezo buzzer. The counter sketch has a resolution of about 3 milliseconds which is significantly lower than the theoretical dead time on the SBM-20 tube, but this project is more of a concept demonstration and exploratory toy than anything else, so I'm not worried about it.
One other item to note: When simply given a high/low signal on one pin, the piezo buzzer's clicks are extremely soft. Connecting the ground terminal of the buzzer to another digital pin held low and swapping the high/low pins during the ISR effectively doubles the deflection of the buzzer and results in a much more satisfying click!
/* Project Pripyat v1.0 * by Matthew Eargle https://airbornesurfer.com * for element14 Presents * CC-BY-SA 2018 AirborneSurfer */ const byte ledPin = 13; const byte interruptPin = 2; const byte speakerPin = 5; volatile byte state = LOW; volatile byte speaker = LOW; void setup() { pinMode(ledPin, OUTPUT); pinMode(speakerPin, OUTPUT); pinMode(interruptPin, INPUT); pinMode(6, OUTPUT); pinMode(12, OUTPUT); pinMode(9, OUTPUT); attachInterrupt(digitalPinToInterrupt(interruptPin), blink, LOW); } void loop() { digitalWrite(ledPin, LOW); digitalWrite(speakerPin, LOW); digitalWrite(6, HIGH); digitalWrite(12, LOW); delay(3); } void blink() { digitalWrite(ledPin, HIGH); digitalWrite(speakerPin, HIGH); digitalWrite(6, LOW); digitalWrite(12, HIGH); }