Home    Gallery    Archive    Links    About    

Monday, February 25, 2019

Easy-peasy "Geiger" Counter
(technically it's a scinitllation counter)

The Radiation-Watch gamma ray sensor kit is made in Japan for people who live near the Fukushima reactor melt down site, to monitor their local radiation. The sensor attaches to a phone, or can be used with a microcontroller, such as Arduino. This gamma ray detector uses the innovative X-100 photodiode from First Sensor. It's a scintillation device - any gamma ray impinging on the 1 square centimeter active surface of the chip will output a pulse. The Radiation Watch device sends a pulse on the signal output line when a gamma ray is detected. The board includes a noise output, which goes high whenever the device experiences physical shock. I don't use this feature in my device.

Sparkfun sells the Radiaton Watch type 5 (made for Arduino) kit. This is what you get for sixty seventy bucks:

To use the sensor, I built a minimalist counter.

My counter is compact, accurate and reliable. Plus it's cool looking. I used the 14 pin AT Tiny 84 as the microcontroller - its the smallest avr chip that has the resources needed for this device. It has a high speed 8 bit parallel port to connect to the seven segment LED display, an input pin that uses the microcontroller's external interrupt to read the pulses, a digital output pin capable of supplying 30 milliamps for short periods, and a second input pin to which a switch is attached. The sensor connects to the counter with a 1/8 inch connector, which is included in the kit.

There are several controls. A power switch turns it on and off. A reset button starts a measurement over. A mode switch can be set to counts per minute, or counts per second. And a silence switch turns off the clicking sound. The outputs are a bright green LED that is flashed on gamma ray detection, an active buzzer that clicks, and a seven segment red LED numeric display with a decimal point. Power is provided by 3 aaa cells, which snap into cell holders. The entire device is on a single circuit board, and has no case.

Radioactive decay happens randomly because it comes from a non-deterministic quantum process. When counts are calculated as a frequency, decay data has one significant figure of precision at best. So a single digit numeric display is really all that's needed. A flashing decimal point shows the order of magnitude, giving a range of 0 to 1000. This can handle most radiological situations you'd be likely to encounter.

The data is shown logarithmically on the single digit LED numeric display:

  • 0-9 with no decimal is zero to nine,
  • 10-90 is the number plus a decimal point,
  • 100-900 is the number plus a blinking decimal point,
  • greater than 1000 just shows a blinking decimal point.
  • Just like a geiger counter, this device has a bright green flash, and a click for every count. You can judge a radioactive source's activity by it's sound and sight. You don't need to interpret the numeric display to sense the radiation level. If it sounds hot, it's hot!

    The display has two modes: counts per minute for background radiation, and counts per second for radioactive items. If counts per minute is too high to read, switch to counts per second mode. If it still reads over a thousand counts per second, move away from the source (probably a good idea anyway), and multiply the reading by the square of the increase in distance. To determine dose, divide the counts per minute by 53 to get uSv/hr, the sensor has been calibrated for cesium 137.

    If the counter is in background radiation mode, the average counts are calculated as counts per minute, and the average is displayed every second. It takes a few seconds for the counts per minute value to stabilize. Display of counts per second is in real time-l IF the clicking is bothersome, it can be turned off, but the green LED will always flash once per gamma ray.

    The Arduino code reads the pulses and outputs to the 7 segment numeral very fast. It can handle even the highest measurable pulse count without skipping pulses. If two or more pulses are encountered simultaneously, the device beeps instead of clicking. To accomplish this, the 7 segment display chip is wired directly to the 8 bits of port A on the Tiny84 (each LED with an appropriate resistor), so an entire number can be written with a single 'PORTA = n' instruction. The sensor sends 50 μs pulses directly to the hardware interrupt pin of the microcontroller. The interrupt code just sets a flag, true or false, indicating whether the signal is high or low. The loop code determines if the pulse has begun or ended, turns on or off both the LED and the buzzer - the short duration of the pulse is what gives it a sharp click. The number of finished pulses are added up, and the seven segment display is updated every second.




    /* pocketGeiger100318.ino
       ATTiny 84 (http://www.microchip.com/wwwproducts/en/attiny84) pinout:
         (page numbers in parenthesis refer to the 2010 ATTiny84 datasheet)
                    __   __                     ___________
               Vcc =| \_/ |= GND   7 segment: F|           |A
        XTAL1  PB0 =|10  0|= PA0              G|   _a__    |B
        XTAL2_ PB1 =|9   1|= PA1             nc| f|    |b  |GND
             RESET =|    2|= PA2            GND|  |_g__|   |nc
          PB2 INT0 =|8   3|= PA3             nc| e|    |c  |nc
               PA7 =|7   4|= PA4 SCK          E|  |_d__|dp |DP
          MOSI PA6 =|6___5|= PA5 MISO         D|___________|E
          (connect segments A thru DP to PA0 thru PA7 via 220Ω resistor)
        X100 signal on pin 8 (https://www.sparkfun.com/products/14209)
        very bright LED (https://www.sparkfun.com/products/8285) via BC547B transistor
          and a buzzer (https://adafruit.com/product/1536) on pin 9 via SPST switch
        generic common cathode seven segemt display (above)
        mode switch (SPST) on pin 10 to ground
        Runs on 3 aaa batteries, lithium preferred for max lifespan
        Version History:
        040218  884/15 uno with buzzer and LED
        042018 1894/43 use porta to write LED digit
        100118 1748/39 use ISR(INT0_vect) instead of attachInterrupt
        ***This is the program on the chip in the device***
    #include <avr/interrupt.h>
    #include <avr/io.h>
    // pin (0 - 6) --> 220 ohm resistor --> LED segment (A - G) --> common gnd
    const byte pointPin = 7;  // --> 220R --> decimal point LED --> common gnd
    const byte inputPin = 8;  // <-- (pullup) X100 gamma sensor
    const byte outputPin = 9;  // --> transistor (vcc --> led + buzzer) --> gnd
    const byte modePin = 10;  // <-- (pullup) switch --> gnd
    unsigned long counts = 0UL;
    long seconds = 0L;
    unsigned long lastDisplayMillis;
    const long displayMillis = 1000L; // one second
    unsigned long lastBlinkMillis;
    const long blinkMillis = 125UL;
    boolean point = false;
    boolean blinking = false;
    volatile boolean inputState = false;
    boolean lastInputState = false;
    void setup() {
      DDRA = 0b11111111;  // pins 0 - 7 all OUTPUT (p56)
      pinMode(outputPin, OUTPUT);
      pinMode(inputPin, INPUT_PULLUP);
      pinMode(modePin, INPUT_PULLUP);
      // was: attachInterrupt(0, setInputState, CHANGE); (p51)
      MCUCR |= (1<<ISC00);   //   set bit ISC00 set CHANGE mode in MCU Control Register
      MCUCR &= ~(1<<ISC01);  // clear bit ISC01 "    "     "   "   "    "       "
      GIMSK |= (1<<INT0);    // enable INT0 in General Interrupt (control register) MaSK
      sei();                 // ... did I mention I HATE Atmel's acronyms?
      // start up the display timer
      lastDisplayMillis = millis();
    // was: void setInputState() { inputState = digitalRead(inputPin); }
    ISR(INT0_vect) {   // isr on INT0 (p48-52)
      inputState = PINB & 0b0100;  // (p56-58)
    void loop() {
      // do this every time through the lizard
      if (inputState != lastInputState) {  // if there's a change
        if (lastInputState) counts++;  // add to count when pulse is done
        digitalWrite(outputPin, lastInputState);  // clickety click - LED and piezo
        lastInputState = inputState;
      // update the display every 'displayMillis'
      if (millis() - lastDisplayMillis >= displayMillis) {
        lastDisplayMillis += displayMillis;
        seconds++;  // keep track of sample time for CPM
        blinking = false;  // set true when needed
        if (digitalRead(modePin)) {  // show counts per second : CPS
          showValue(counts);  // refresh every second
          counts = 0;
          seconds = 0;
        } else {        // show time averaged counts per minute: CPM
          showValue((60 * counts) / seconds);  // sV can set blinking true 
      // flash the dp on and off if needed (ie. blinking = true)
      if ((millis() - lastBlinkMillis >= blinkMillis) and blinking) {
        lastBlinkMillis += blinkMillis;
        point = !point;
        digitalWrite(pointPin, point);
    // show numbers 0 - 1000 with one digit and a decimal point
    void showValue(int n) {
      // 0 - 9, show numeral + (no decimal)
      if (n < 10) {
        digitalWrite(pointPin, LOW);
      // 10 - 99, show numeral + decimal point
      if ((n > 9) and (n < 100)) {
        showNumeral(n / 10);
        digitalWrite(pointPin, HIGH);
      // 100 - 999, show numeral + blinking decimal point
      if ((n > 99) and (n < 1000)) {
        showNumeral(n / 100);
        blinking = true;
      // over 1000, (no numeral) + blinking decimal point
      if (n > 1000) {
        blinking = true;
    /* show a numeral on a  generic
       single digit 7 segment LED display
       wired to pins 0-7 of ATTiny84 */
    const byte numerals[] = {
      0b00111111, //   0    --- a ---
      0b00000110, //   1   |         |    a = pin PA0
      0b01011011, //   2   f         b    b = pin PA1
      0b01001111, //   3   |         |    c = pin PA2
      0b01100110, //   4   |--- g ---|    d = pin PA3
      0b01101101, //   5   |         |    e = pin PA4
      0b01111101, //   6   e         c    f = pin PA5
      0b00000111, //   7   |         |    g = pin PA6
      0b01111111, //   8    --- d ---  p  p = pin PA7
      0b01100111, //   9
    void showNumeral (byte n) {
      PORTA = numerals[n];  // (p55, 67)
    void blankNumeral () {
      PORTA = 0;

    Wednesday, February 20, 2019
    101-365   is a blog of truth and beauty, art and science, new and old, what have you.

    After nearly ten years, this blog returns.


    February 2019
    Sun Mon Tue Wed Thu Fri Sat
              1 2
    3 4 5 6 7 8 9
    10 11 12 13 14 15 16
    17 18 19 20 21 22 23
    24 25 26 27 28    
    Jan   Mar
    © copyright, Chris101, 2019