Geigerduino - Arduino Geiger Counter

Hello i'm feeling stuck and hope I can find some ideas,

I am reading the value from Analog PIN A0 and I would like to create a tally/total everytime Analog pin A0 makes a reading of 10 or above. Something like:

/--analog count sketch 2015 --/

int analogPin = 0;
int val = 0;
int tcount = (not sure what goes here?)

void setup()
{
  Serial.begin(9600);    //  setup serial
}

void loop()
{
val = analogRead(analogPin);    // read the input pin
if val < 10 (tcount = val+1) /--stuck here as I don't know if this would record a running tally/total or how yikes!--/ 
SerialPrint ("total count:" tcount);
}

Should I be using '++' somewhere? As in to +1 to the count?

My brain is fizzing and confused now, so I thought i would reach out for help.

Many thanks in advance for advice and corrections. :o

So thinking about it would this work??

/--analog count sketch 2015 --/

int analogPin = 0; // set input pin
int val = 0;
int tcount = 0;

void setup()
{
  Serial.begin(9600);    //  setup serial
}

void loop()
{

val = analogRead(analogPin);    // read the input pin

if val < 10 (tcount++);            //--better??--/ 

SerialPrint ("total count:" tcount);
}

You said to add to the tally when you get a reading of 10 or greater.
So I have set it up to trigger the counter when it is greater than 9.

int analogPin = 0; // set input pin
int val = 0;
int tcount = 0;

void setup(){
  Serial.begin(9600);    //  setup serial
}

void loop(){

 val = analogRead(analogPin);    // read the input pin

 if (val > 9){
  tcount++;
 }

Serial.print("Total Count:");
Serial.println(tcount);

}

Ahh-haaaa! That helps a lot thanks. I guess I need to understand if statements better (and my < and > wink) :slight_smile:

Just wondering also if it is possible to collect number of counts in a minute? Is it possible to do without using an RTC, or would it be better/more accurate to perform using an RTC module?

I can't really see a way to use millis() to collect counts in a minute.

ty

I won't give everything away - but this might get you on the right track.

unsigned long previousMillis = 0;
int secondsElapsed=0;

void setup() {
  Serial.begin(9600);
  previousMillis = millis();
}

void loop() {
  if((millis()-previousMillis)>1000){
    secondsElapsed++;
    Serial.println(secondsElapsed);
    previousMillis=millis();
  }
}

Benduino:
I can't really see a way to use millis() to collect counts in a minute.

Have a look at the way millis() is used in several things at a time.

Save the value of mllis() and the value of the count at the start of your minute then

unsigned long millisInMinute = 60UL * 60 * 1000;

if (millis() - startMillis >= millisInMinute) {
   lastCount = newCount;  // save the previous value
   newCount = count;
   startMillis += millisInMinute;  // reset for next minute
}

Then the difference between lastCount and newCount will be number in a minute

All the variables associated with millis() should be unsigned long

...R

So it is possible using millis()?

I'm currently reading this topic: Count number of times pin goes high per minute
I will read Robin2's post also: Demonstration code for several things at the same time

@ScottC

Seconds elapsed:

int analogPin = 0; // set input pin
int val = 0;
int tcount = 0;
unsigned long previousMillis = 0;
int secondsElapsed=0;

void setup(){
  Serial.begin(9600);    //  setup serial
  previousMillis = millis();
}

void loop(){
  
  if((millis()-previousMillis)>1000){
    secondsElapsed++;
    previousMillis=millis();
  }
 val = analogRead(analogPin);    // read the input pin

 if (val > 1){
  tcount++;
 }

Serial.print("Total Count:");
Serial.print(tcount);
Serial.print("  Secs:");
Serial.println(secondsElapsed);

}

So, to get the count number within a duration of 60 (secondsElapsed) the sketch will include:

{
if (secondsElapsed = 60);
Serial.print (tcount);
}

But then reset 'secondsElapsed' to (0)?

Ahh wait.

So I have:

secondsElapsed / 60 = mins
tcount / mins
= Counts per minute

You could calculate it every second or every minute.
If you want it to update every minute - you could do it this way:

unsigned long previousMillis = 0;
int minutesElapsed = 0;
int analogPin = 0; // set input pin
int val = 0;
int tcount = 0;
unsigned long tcountRate=0;

void setup() {
  Serial.begin(9600);
  previousMillis = millis();
}

void loop() {
  val = analogRead(analogPin); 
  if(val>9){
    tcount++;
  }
  
  if((millis()-previousMillis)>60000){
    minutesElapsed++;
    previousMillis=millis();
    tcountRate = (tcount / minutesElapsed);
    Serial.print("Rate:");
    Serial.print(tcountRate);
    Serial.println(" counts / minute");
  }
}

If you want to calculate it every second : you would change 60000 to 1000 (like my previous example).
But you would have to multiply the result by 60.

For example 1 count per second = 60 counts per minute.

To count the number of times the value goes above 10 per minute (or any time interval) only has meaning if you measure the value at a fixed time interval or also count the number of times you measured that value in a minute.
For example if your measuring a signal that is constantly above 10 for the entire minute at 1 sample per second the count would be 60 but if you measured the same signal every 10 milliseconds then the result would be 6000. Vastly different results and both meaningless unless you take into account the number of sample times as the true answer should be 1 (the value was constantly above 10 for the entire minute).

Interesting.

I have this for 'Counts per minute'. It seems to update the CPM value after every 60 seconds:

int analogPin = 0; // set input pin
int val = 0;
int tcount = 0;
unsigned long previousMillis = 0;
int secondsElapsed=0;
int mins = 0;
int CPM = 0;

void setup(){
  Serial.begin(9600);    //  setup serial
  previousMillis = millis();
}

void loop(){
  
  if((millis()-previousMillis)>1000){
    secondsElapsed++;
    previousMillis=millis();
  }
 val = analogRead(analogPin);    // read the input pin
 if (val > 1){
  tcount++;
 }
 
 mins = (secondsElapsed/60);
 CPM = (tcount/mins);
 
Serial.print("Total Count:");
Serial.print(tcount);
Serial.print("  Secs:");
Serial.print(secondsElapsed);
Serial.print("  CPM:");
Serial.println(CPM);
}

Testing your code:

unsigned long previousMillis = 0;
int minutesElapsed = 0;
int analogPin = 0; // set input pin
int val = 0;
int tcount = 0;
unsigned long tcountRate=0;

void setup() {
  Serial.begin(9600);
  previousMillis = millis();
}

void loop() {
  val = analogRead(analogPin); 
  if(val>9){
    tcount++;
  }
  
  if((millis()-previousMillis)>60000){
    minutesElapsed++;
    previousMillis=millis();
    tcountRate = (tcount / minutesElapsed);
    Serial.print("Rate:");
    Serial.print(tcountRate);
    Serial.println(" counts / minute");
  }
}

I get a value every 60 seconds.

Changing to:

unsigned long previousMillis = 0;
int minutesElapsed = 0;
int analogPin = 0; // set input pin
int val = 0;
int tcount = 0;
unsigned long tcountRate=0;

void setup() {
  Serial.begin(9600);
  previousMillis = millis();
}

void loop() {
  val = analogRead(analogPin); 
  if(val>9){
    tcount++;
  }
  
  if((millis()-previousMillis)>1000){
    minutesElapsed++;
    previousMillis=millis();
    tcountRate = (tcount / minutesElapsed);
    Serial.print("Rate:");
    Serial.print(tcountRate);
    Serial.println(" counts / minute");
  }
}

Gives me an update every second.

It also depends whether you want to refresh the rate every minute or not.
For example:

1st minute: 200 counts
2nd minute: 300 counts

You can either get it to display:
Rate: 200 counts / minute : which is 200 counts divided by 1 minute
Rate: 300 counts / minute : which is 300 counts divided by 1 minute

Each time the rate is refreshed.

Or the other alternative, you can get it to keep an overall tally.
Rate: 200 counts/minute : which is 200 counts divided by 1 minute
Rate: 250 counts/minute : which is 200+300 = 500 counts divided by 2 minutes

So it depends on how you want to record the data.
My last example was using the 2nd alternative

I hope that made sense ??? :o

You need to decide how often you want it to update - every second or every minute.
And then make the necessary calculations to suit.

if((millis()-previousMillis)>1000) : This will calculate how many seconds have elapsed, not minutes

if((millis()-previousMillis)>60000) : This will calculate how many minutes have elapsed.

I think I should explain the purpose of the code:

I have an old Geiger counter in a drawer that has no readout. It makes a 'click' everytime a particle of radioactive material touches the sensor/element.

I decided I could try to get a serial/LCD reading by connecting my Arduino nano to the 'click' speaker (positive to A0, & GND to GND). It seems to work reasonably well.

But I think the Arduino misses some clicks (perhaps 10-20%?) perhaps due to it's ability to run the sketch loop at a given speed, it seems to miss more 'clicks' as the code becomes more complex? I haven't investigated this possibility, but just observing so far over the last hour.

Here is a photo of the device connected to arduino just now:

here is the photo of the resulting serial monitor values using ScottC code:

here is the photo of the resulting serial monitor values using Benduino adaptation:

I think that was the fastest geiger-counter hack ever :slight_smile: :slight_smile: :slight_smile:

@Riva is correct.

For example: If the sensor reading goes from 0 to 20 in the first second, but then stays at a value of 20 for the rest of the minute. My previous code will produce the wrong result.

The following code should accommodate Riva's comment (I hope) :slight_smile:

unsigned long previousMillis = 0;
int minutesElapsed = 0;
int analogPin = 0; // set input pin
int val = 0;
int tcount = 0;
unsigned long tcountRate=0;
boolean isLow = false;

void setup() {
  Serial.begin(9600);
  previousMillis = millis();
  isLow = true;
}

void loop() {
  val = analogRead(analogPin); 
  if(val>9 && isLow){
    tcount++;
    isLow=false;
  }
  
  if(val<10){
    isLow=true;
  }
  
  if((millis()-previousMillis)>60000){
    minutesElapsed++;
    previousMillis=millis();
    tcountRate = (tcount / minutesElapsed);
    Serial.print("Rate:");
    Serial.print(tcountRate);
    Serial.println(" counts / minute");
  }
}

As you are trying to catch every click - you would be better off using Serial.print sparingly.
Maybe print every 10 seconds or every minute. This will reduce the number of missed readings.

The only way to get meaningful results would be to make the count loop very fast with little latency (no serial printing while counting) or a another method might be to process the speaker signal a bit to clean it up and adjust the level so you could use a digital interrupt to count with.

If you stick to the current method then the code will need tweaking so the value has to go high (above 10) and back low to count as 1 pulse else you could be counting a single high multiple times giving false counts.

Ok I will try reducing the serial.print time and examine this effect on the result.

The geiger sensor at rest is always zero(0), and I observed that when a 'click' is made the value is different each time; but always above ten(10), so I figure this is a good place to choose, maybe even just one(1) is satisfactory too.

I feel I must take a short break now to review, and stop my brain from fizzing. Now that 'counts-per-minute is obtained, there is no reason why microseiverts can't be calculated too using this blog post conversion:
"The standard unit of radiation dosing in an area is the micro-Sievert/hour (uSv/hr). For this tube, multiply its CPM by 0.0057 to get the equivalent uSv/hr radiation level."

Ok - now that I know what you are trying to do.
I would only update the display when you identify a click.
With the attempt to reduce the number of missed clicks.

This is the updated code:

unsigned long startMillis = 0;
float secondsElapsed = 0;
int analogPin = 0; // set input pin
unsigned long val = 0;
unsigned long tcount = 0;
float tcountRate=0;
boolean isLow = false;
float microSievert = 0;

void setup() {
  Serial.begin(9600);
  startMillis = millis();
  isLow = true;
}

void loop() {
  val = analogRead(analogPin); 
  if(val>9 && isLow){
    tcount++;
    secondsElapsed = (float) (millis()-startMillis)/1000;
    tcountRate = (float) 60.0 * (tcount / secondsElapsed);
    microSievert = (float) tcountRate * 0.0057;
    Serial.print("tCount:");
    Serial.print(tcount);
    Serial.print(" , Seconds:");
    Serial.print(secondsElapsed);
    Serial.print(" , Rate:");
    Serial.print(tcountRate);
    Serial.print(" CPM,   ");
    Serial.print(microSievert);
    Serial.println(" uSv/hr");
    
    isLow=false;    
  }
  
  if(val<10){
    isLow=true;
  } 
}