Welcome to Laser Pointer Forums - discuss green laser pointers, blue laser pointers, and all types of lasers

Buy Site Supporter Role (remove some ads) | LPF Donations

Links below open in new window

FrozenGate by Avery

Arduino based Pulse Counter

Joined
Dec 11, 2011
Messages
4,364
Points
83
I decided to work on an old pancake geiger counter I picked up a few years back. I did the circuitry repairs years ago but I never got around to making a computer interface for pulse counting/scaling. Today I rectified that.

I'm posting it here because it may be of use for our members for other applications. The program simply looks for >2.3V to 5V pulses on Arduino's Pin3 and flashes the built in led (and drives Pin13 HIGH for 33mS) every time there is a pulse. The program then tallies up all the pulses observed over the time period indicated in the SamplePeriod variable (which is in mS, so it is set by default to 60,000, or 1 minute) and displays this count via the built in Serial Monitor on the Arduino IDE program. If you adjust the SamplePeriod variable it will automatically correct for the time period and update the serial monitor display to display the correct time period. You'll have to push the code to the arduino any time yoiu make changes though, I didn't do live serial two way communication.

Sample applications would be RPM counter, Frequency Counter (set SamplePeriod to 1000), item counter, etc.

UPDATE: New version of counter program optimized for general pulse counting use with dead time compensation to prevent retriggering on a single pulse. Requires the user to input the expected pulse length in uS.

Code:
// Arduino Pulse Counter
// Written by Matt "Sigurthr" Giordano 7/17/14
// email me at Sigurthr@SigurthrEnterprises.com
// TTL input on Pin 3
// Indicator LED on Pin 13 (continuous above 30cps)
// Writes counts per SamplePeriod to Serial Monitor
// once every sample period.
// Set PulseDuration variable to incoming pulse length in uS.
// This code is released for free use and sharing.
// Please just cite the author (me!) upon reuse/republishing!

void setup(){
 Serial.begin(9600);
 Serial.println("Arduino Pulse Counter");
 pinMode(3, INPUT);
 pinMode(13, OUTPUT);
}

 unsigned long X = 0;
 unsigned long SamplePeriod = 60000; // in mS
 unsigned long currentMillis = 0;
 unsigned long previousMillis = 0;
 unsigned long LEDmillis = 0;
 int timeperiod = (SamplePeriod / 1000); // converts mS to S
 int PulseDuration = 100; // Pulse Duration in uS
 boolean LEDstate = false;

void loop(){
  currentMillis = millis();
  if (digitalRead(3) == HIGH){
    X = X + 1;
    LEDstate = true;
    LEDmillis = currentMillis;
    delayMicroseconds(PulseDuration);  // prevents multiple triggering on a single pulse
  }
  if (currentMillis - LEDmillis >= 33){  //keeps indicator LED on for 33mS
    LEDstate = false;
    digitalWrite(13,LOW);
  }
  switch (LEDstate){
    case true:
      digitalWrite(13,HIGH);
      break;
    case false:
      digitalWrite(13,LOW);
      break;
  }
  if (currentMillis - previousMillis >= SamplePeriod) {
    previousMillis = currentMillis;
    Serial.print("Counts per ");
    Serial.print(timeperiod);
    Serial.print(" seconds: ");
    Serial.println(X);
    X = 0;
  }    
}

Also, here is a Geiger Counter Friendly version, which includes dosimetry data output and a cleaned up serial interface. Again, requires expected pulse length in uS and also requires CPM per uR/hr sensitivity for the GM tube used if accurate dosimetry data is to be expected.

Code:
// Arduino Geiger Counter Scaler
// Written by Matt "Sigurthr" Giordano 7/17/14
// email me at Sigurthr@SigurthrEnterprises.com
// TTL input on Pin 3
// Indicator LED on Pin 13 (continuous above 30cps)
// Writes counts per SamplePeriod to Serial Monitor
// once every sample period.
// Set PulseDuration variable to incoming pulse length in uS.
// This code is released for free use and sharing.
// Please just cite the author (me!) upon reuse/republishing!

void setup(){
 Serial.begin(9600);
 Serial.println("Arduino Geiger Counter Scaler"); // Header for Serial Text
 pinMode(3, INPUT); // Pin 3 TTL input
 pinMode(13, OUTPUT); // Pin13 LED indicator output
}

//User Serviceable Variables
unsigned long SamplePeriod = 60000; // Sample Period in mS
int PulseDuration = 100; // Pulse Duration in uS
float GMsensitivity = 3; // GM Tube cpm per uR/hr

//Non-Serviceable Variables
unsigned long X = 0;
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
unsigned long LEDmillis = 0;
int timeperiod = (SamplePeriod / 1000); // converts mS to S
boolean LEDstate = false;
float uRem;


void loop(){
  currentMillis = millis();
  if (digitalRead(3) == HIGH){
    X = X + 1;
    LEDstate = true;
    LEDmillis = currentMillis;
    delayMicroseconds(PulseDuration);  // prevents multiple triggering on a single pulse
  }
  if (currentMillis - LEDmillis >= 33){  //keeps indicator LED on for 33mS
    LEDstate = false;
    digitalWrite(13,LOW);
  }
  switch (LEDstate){
    case true:
      digitalWrite(13,HIGH);
      break;
    case false:
      digitalWrite(13,LOW);
      break;
  }
  if (currentMillis - previousMillis >= SamplePeriod) {
    previousMillis = currentMillis;
    uRem = (float)X / (float)GMsensitivity;
    Serial.print(X);
    Serial.print("CPM, ");
    Serial.print(uRem);
    Serial.println("uR/hr");
    X = 0;
  }    
}
 
Last edited:





You could probably get even better timing if you used interrupts. You used pin 3 for input, which on the Duemilanove/nano/168/328 based boards are connected to interrupt 1, so you wouldn't even have to modify your hardware :)
 
Last edited:
Yeah, I'm still quite a novice when it comes to programming. I'm a hardware guy (EE, not SE). It took me about five hours to research, write, and debug this code. I haven't learned interrupts yet, and as it is this is my first program using switch...case.
 
Fair enough :D Programming sucks, avoid at all costs :D

Doesn't make a huge difference, but C* has a way of handling x = x +/- 1 in a neater way, you can just use x++; or x--; :)

You can also make if statements a bit neater if you're only dealing with logical values.

Code:
if (x == 1){

Can also just be
Code:
if (x){

or

Code:
if (~x){

x could either be a boolean or an integer that's either 0 or 1.

You can even omit brackets entirely if you only have 1 thing you need to execute:

Code:
if (x)
  Serial.println('Yes it is!');
rest_of_code();
 
Last edited:
Fair enough :D Programming sucks, avoid at all costs :D

Doesn't make a huge difference, but C* has a way of handling x = x +/- 1 in a neater way, you can just use x++; or x--; :)

Haha, I agree. Yeah I know about the ++ and -- operators but I wasn't sure if I could just do X++; as a sole line of code so I went the old school route to prevent further debugging.

Interestingly; I got the actual counter code to work first try without any issue. Getting the damn LED's ONTIME pulse width to not be tied to the incoming pulse's pulse width took me hours. I was trying to hook it into the primary timer used in the counter, I didn't realize I had to write an entirely separate timer routine for it. I was originally using two If conditionals instead of the switch...case but for some reason I couldn't get reliable state toggling. That and nested debugging drives me insane.
 
Yeah, those are the fun program problems you run into. The issue with things like Arduino is that unless you need to use them, you don't really understand what the underlying code is actually doing since you don't have to touch it usually.

For example one project I was working on involved driving some self-clocked addressable LED strip from a serial input. When I was sending it serial data, occasionally a few bytes would go missing, just like that, they wouldn't even make it to the serial buffer. Upon reading into it, the Arduino serial buffer is interrupt driven. However, to get the timing perfect for the LED strips, it's library was disabling interrupts while it was pushing data to it. So for the time it was outputting data to the strips, any serial data you send to it was just completely lost. Had me scratching my head for half the day, trying a few different microcontrollers and USB-serial converters etc till I finally figured it out. Of course if I had've written that library from scratch I would have been well aware of that issue from the start, but it was worth the convenience I guess :)
 
Last edited:
Updated the OP to reflect new program version and new program fork. I refined the pulse counter a bit and worked out some inaccuracy bugs (pulse retriggering), as well as added a Geiger Counter friendly version with included dosimetry.
 
Cool!! I just got a hold of some GM tubes ( in Canada (I'm still in S.Korea), My bro found them at a speciality shop near Kelowna (desert country). Apparently he's got LND 7312, LND 712, and LND 7311's for sale.
Going to put together a Hand held probe and a portable digital Geiger counter. Good post.

If you can please post a pic of the old Geiger counter... is it a CDV700 ?
Got me thinking about Geiger mods :)

btw, somewhat related to your post....
Last night for fun I decided to take Theremino for a test drive with Cs137.WAV file from
a Gamma Spectacular1100A. I set up the program to record line in at 129Khz @ 16bit.
The spectrum was visible in under 30 seconds.
 

Attachments

  • Cs137 spectra.png
    Cs137 spectra.png
    140.7 KB · Views: 688
Last edited:
Very cool S_L.

The GC I used for testing was a Black Cat Systems GM-45. They use a russian pancake similar to the LND712 I think.

I also have a SBM-20 from a DSRB-70 (I think it was 70), the entire circuit is intact and working fine but the housing is totally broken. One day I'll rebuild it into a nice housing.

I also have a Universal Atomics CDV-700 that I refurbished years ago. Works a treat.

If you go onto the Black Cat systems website and find their Rad Map you can see live data from the GM-45 unit. I'm the only station in Michigan.
 
Very cool S_L.

The GC I used for testing was a Black Cat Systems GM-45. They use a russian pancake similar to the LND712 I think.

I also have a SBM-20 from a DSRB-70 (I think it was 70), the entire circuit is intact and working fine but the housing is totally broken. One day I'll rebuild it into a nice housing.

I also have a Universal Atomics CDV-700 that I refurbished years ago. Works a treat.

If you go onto the Black Cat systems website and find their Rad Map you can see live data from the GM-45 unit. I'm the only station in Michigan.

That Blackcat systems model 45 is an LND7312 based unit. ~3500CPM:1mR/hr
Those tubes have gone up in price since the 2011 Great Eastern Japan quake

You're using it as a monitoring station...Cool.
Really itching to get into Gamma Spectroscopy. Would like to get my hands on a Gamma Spectacular (new model with upgraded PSU and noise filtering) and a DSO nano loaded with the new GG2014 firmware. :). I have even heard a rumour floating around that it might be ported to run the faster ARM8 or ARM9 processor boards. A fast ADC (16bit or better) would be needed to run the GG to get higher res. Currently the GG only runs on a ARM Cortex M3 with a 10bit ADC... :\ while this works, it would be nicer to use modern ARM architecture.
 





Back
Top