2011 m. rugpjūčio 22 d., pirmadienis

Added 3LED indicator function (software ammended)



http://www.youtube.com/watch?v=bDFuHII-ahM

I have amended the default software to control the 3 LED indicator.
This indicator works as follows: on boot shows that it is alive (working)
then if radiation dose rate exceeds 0.5uSv/h then yellow LED is lit. If dose rate exceeds 1uSv/h yellow and orange LEDs are lit and if dose rate is over 1.2uSv/h then all three LEDs yellow, orange and red are lit. As you can see this change works together with LCD and serial connection. So if you just need to have  a rather simple Geiger counter (without LCD) you can do it with three leds: yellow - just warning of some radiative anomaly, orange - informing that a person should not be in that place more than several hours and red - advising to hide or leave instantly.

the connection of LEDs which is supposed by software is in the picture below

The software sketch for SMB-20 and is below:



/* Geiger Counter Kit - Default Sketch (v5b.1)                         bHogan 7/29/11
 * Ammended with 3 LED threshold indicator by       impexeris on ebay.com on 08/22/11
 *                                               
 * if you use si29BG (СИ29БГ) I would suggest the ratio of 102 or 101.5
 Counts events/min. and outputs CPM & ~uSv/hr to LCD display and also to serial port.
 * Sample period shortens with increase in counts. Bar graph on LCD 
 * One of 2 conversion ratios can be selected via jumper. ACCURACY NOT VERIFIED
 * v4 adds check for voltage at the uC to indicate a low battery voltage
 * v5 add seperate counterfor serial - set at 1 min to give CPM without rounding
 *
 * SETUP: (Any 2x16 Hitachi HD44780 compatible LCD)
 * +5V LCD Vdd pin 2             >>>     Gnd LCD Vss pin 1, and R/W pin 5
 * LCD RS pin 4 to D3            >>>     LCD Enable pin 6 to D4
 * LCD D4 pin 11 to D5           >>>     LCD D5 pin 12 to D6
 * LCD D6 pin 13 to D7           >>>     LCD D7 pin 14 to D8
 * LCD LEDA pin 15 to ~1K to +5  >>>     LCD LEDK pin 16 to GND
 * 10K pot: - ends to +5V and Gnd, wiper to LCD VO pin (pin 3)
 * *INT from Geiger circuit is connected to PIN 2 and triggered as FALLING.
 * PIN 9 - jumper to GND if secondary conversion ratio is desired
 *
 * This program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2.1 of the License, or any later version.
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 * 
 * THIS PROGRAM AND IT'S MEASUREMENTS IS NOT INTENDED TO GUIDE ACTIONS TO TAKE, OR NOT
 * TO TAKE REGARDING EXPOSURE TO RADIATION. ALWAYS FOLLOW THE INSTRUCTIONS GIVEN BY
 * THE CIVIL AUTHORITIES. DO NOT RELY ON THIS PROGRAM!
 */

#include <LiquidCrystal.h>              // HD44780 compatible LCDs work with this lib
#define LED_PIN          13             // for debug only - flashes 5X at startup
#define LED_PIN_Y        12             // yellow led - over 0.5 mSv/H
#define LED_PIN_O        11             // orange led - over 1   mSv/H
#define LED_PIN_R        10             // orange led - over 1.2 mSv/H
#define TUBE_SEL          9             // jumper to select alt conversion to uSv

// HOW MANY CPM =1 uSV? Two commonly used sets of ratios for the SBM-20 & LND712 are defined:
// libelium now uses: 175.43 for SBM-20 and 100.00 for LND712
// www.utsunomia.com/y.utsunomia/Kansan.html use: 150.51 for SBM-20 and 123.14 for LND712
#define PRI_RATIO        175.43        // no TUBE_SEL jumper - SET FOR SBM-20
#define SEC_RATIO        100.00         // TUBE_SEL jumper to GND - SET FOR LND712
// use 102 or 101.5 for si29BG (СИ29БГ)

// mS between writes to serial - counts also accumulate seperately for this period
#define LOGGING_PEROID 60000            // best set for at least 1 min (60000 mS) unless testing

// mS between writes to display - counts/period are averaged to CPM < 60000 less accurate
// LOGGING_PERIOD shuld be a multiple of these periods
#define LONG_PERIOD      10000          // mS sample & display below 100 CPM
#define SHORT_PERIOD     5000           // mS sample & display above 100 CPM

#define FULL_SCALE       1000           // max CPM for 8 bars & overflow warning
#define LOW_VCC          4200 //mV      // if Vcc < LOW_VCC give low voltage warning

// instantiate the library and pass pins for (RS, Enable, D4, D5, D6, D7)
LiquidCrystal lcd(3, 4, 5, 6, 7, 8);    // default layout for the Geiger board 

volatile boolean newEvent = false;      // true when new event was caught by ISR
boolean lowVcc = false;                 // true when Vcc < LOW_VCC
unsigned long dispPeriodStart, dispPeriod, dispCnt, dispCPM; // counters for the display period
unsigned long logPeriodStart, logCnt, logCPM;                // counters for the logging period
unsigned long checkVccTime;
float uSv = 0.0;                        // display CPM converted to "unofficial" uSv
float uSvLogged = 0.0;                  // logging CPM converted to "unofficial" uSv
float uSvRate;                          // holds the rate selected by jumper
int Vcc_mV;                             // mV of Vcc from last check 

//Custom characters used for bar graph
byte bar_0[8] = {0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00}; //blank
byte bar_1[8] = {0x10, 0x10, 0x18, 0x18, 0x18, 0x10, 0x10, 0x00}; //1 bar
byte bar_2[8] = {0x18, 0x18, 0x1c, 0x1c, 0x1c, 0x18, 0x18, 0x00}; //2 bars
byte bar_3[8] = {0x1C, 0x1C, 0x1e, 0x1e, 0x1e, 0x1C, 0x1C, 0x00}; //3 bars
byte bar_4[8] = {0x1E, 0x1E, 0x1f, 0x1f, 0x1f, 0x1E, 0x1E, 0x00}; //4 bars
byte bar_5[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00}; //5 bars
byte bar_6[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00}; //6 bars (same)

void setup(){
  Serial.begin(9600);                   // comspec 96,N,8,1
  attachInterrupt(0,GetEvent,FALLING);  // Geiger event on pin 2 triggers interrupt
  pinMode(LED_PIN,OUTPUT);              // setup LED pin 13
  pinMode(LED_PIN_Y,OUTPUT);            // setup LED pin 12
  pinMode(LED_PIN_O,OUTPUT);            // setup LED pin 11
  pinMode(LED_PIN_R,OUTPUT);            // setup LED pin 10
  pinMode(TUBE_SEL,INPUT);              // setup tube select jumper pin
  digitalWrite(TUBE_SEL, HIGH);         // set 20K pullup on jumper pin(low active)
  dispPeriod = LONG_PERIOD;             // start with long display period
  Blink(LED_PIN,5);                     // show it's alive
  Blink_fast(LED_PIN_R,1);              // show it's alive
  Blink_fast(LED_PIN_O,1);              // show it's alive
  Blink_fast(LED_PIN_Y,1);              // show it's alive
  Blink_fast(LED_PIN_O,1);              // show it's alive
  Blink_fast(LED_PIN_R,1);              // show it's alive
  Blink_fast(LED_PIN_O,1);              // show it's alive
  Blink_fast(LED_PIN_Y,1);              // show it's alive
  lcd.begin(16,2);                      // cols, rows of display (8x2, 16x2, etc.)
  lcd.createChar(0, bar_0);             // load 7 custom characters in the LCD
  lcd.createChar(1, bar_1);
  lcd.createChar(2, bar_2);
  lcd.createChar(3, bar_3);
  lcd.createChar(4, bar_4);
  lcd.createChar(5, bar_5);
  lcd.createChar(6, bar_6);
  lcd.setCursor(0,0);

  lcd.clear();                          // clear the screen
  lcd.print(" GEIGER COUNTER ");           // display a simple banner
  delay (2000);                         // leave the banner up 2 sec.
  lcd.clear();                          // clear the screen
  if(digitalRead(TUBE_SEL)){            // read jumper to select conversion ratio
    uSvRate = PRI_RATIO;                // use the primary ratio defined
  }
  else{                                 // jumper is set to GND . . .
    uSvRate = SEC_RATIO;                // use the secondary ratio defined
  }
  lcd.print(uSvRate,0);                 // display conversion ratio in use 
  lcd.print(" CPM to uSv");
  lcd.setCursor(0,1);                   // set cursor on line 2
  Vcc_mV = readVcc();                   // read Vcc voltage
  lcd.print("Running at ");             // display it
  lcd.print(Vcc_mV/1000. ,2);           // display as volts with 2 dec. places
  lcd.print("V");
  delay (5000);                         // leave info up for 5 sec.
  lcd.clear();                          // clear the screen

  lcd.print("CPM ");                    // display static "CPM"
  lcd.setCursor(0,1);
  lcd.print("uSv/hr ");                 // display static "uSv/hr"
  Serial.println("CPM \t uSv \t Vcc");  // print header for log
  dispPeriodStart = millis();           // start timing display CPM
  logPeriodStart = dispPeriodStart;     // start logging timer
  checkVccTime = dispPeriodStart;       // start Vcc timer
}


void loop(){
  if (millis() >= checkVccTime + 2000){  // timer for check battery
    checkVccTime = millis();            // reset timer
    Vcc_mV = readVcc();
    if (Vcc_mV <= LOW_VCC) lowVcc = true; // check if Vcc is low 
    else lowVcc = false;
  }
  if (millis() >= dispPeriodStart + dispPeriod) ProcCounts(); // period is over
  if (newEvent){                        // add to current count
    dispCnt++;
    logCnt++;
    newEvent = false;
  }
  logCount();                           // check if it's time to log & if so log
  //uncomment 2 lines below for self check (1/166ms X 60 = 360 CPM
  //newEvent = true;                      // simulate an interrupt
  //delay(167);                           // 167 mS ~= 6 Hz    
}


void ProcCounts(){ // aggregate totals and reset counters for each period
  // These are calcs for display - less accurate
  dispCPM = (dispCnt * 60) /(dispPeriod / 1000); // calc CPM for the period
  uSv = dispCPM / uSvRate;                       // make uSV conversion
  if (dispCPM > 99)dispPeriod = SHORT_PERIOD;    // shorten sample period if CPM > 100  
  else dispPeriod = LONG_PERIOD;  
  LEDIndicate(uSv);
  displayCount();
  dispCnt = 0;                                   // reset display event counter
  dispPeriodStart = millis();                    // reset display time
}


void LEDIndicate(float uSv){
  if (uSv > 0.5)
    digitalWrite(LED_PIN_Y,HIGH);
    else digitalWrite(LED_PIN_Y,LOW);
  if (uSv > 1)
    digitalWrite(LED_PIN_O,HIGH);
    else digitalWrite(LED_PIN_O,LOW);
  if (uSv > 1.2)
    digitalWrite(LED_PIN_R,HIGH);
    else digitalWrite(LED_PIN_R,LOW);    
}

void displayCount(){
  lcd.setCursor(4, 0);                  // set cursor after "CPM "
  lcd.print("      ");                  // clear area
  lcd.setCursor(4, 0);                  // set cursor after "CPM" again
  lcd.print(dispCPM);                   // display CPM on line 1
  lcd.setCursor(7, 1);                  // as above for line 2
  lcd.print("          ");
  lcd.setCursor(7, 1);
  lcd.print(uSv,4);                     // display uSv/hr on line 2
  lcd.setCursor(9,0);                   // move cursor to 9th col, 1st line for lcd bar
  if (dispCPM <= FULL_SCALE) lcdBar(dispCPM);   // display bargraph on line 2
  else {                                // put warning on line 2 if > full scale
    lcd.setCursor(10,0);                // move cursor to 10th col, 1st line for lcd bar
    lcd.print("        ");
    lcd.setCursor(10,0);
    lcd.print(">");                     // show what full scale on bars is set at
    lcd.print(FULL_SCALE);
  }
  if (lowVcc) {                         // overwrite display with battery voltage if low
    lcd.print("        ");
    lcd.setCursor(9,0);
    lcd.print("Vcc=");
    lcd.print(Vcc_mV/1000. ,2);         // display as volts with 2 dec. places
  }
}


void lcdBar(int counts){  // displays CPM as bargraph on 2nd line
  // Adapted from DeFex http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1264215873/0
  int scaler = FULL_SCALE / 47;         // 8 char=47 "bars", scaler = counts/bar
  int cntPerBar = (counts / scaler);    // amount of bars needed to display the count
  int fullBlock = (cntPerBar / 6);      // divide for full "blocks" of 6 bars 
  int prtlBlock = (cntPerBar % 6 );     // calc the remainder of bars
  for (int i=0; i<fullBlock; i++){
    lcd.print(5,BYTE);                  // print full blocks
  }
  lcd.print(prtlBlock,BYTE);            // print remaining bars with custom char
  for (int i=(fullBlock + 1); i<8; i++){
    lcd.print(" ");                     // blank spaces to clean up leftover
  }  
}


void logCount(){ // unlike logging sketch, just outputs to serial
  if (millis() < logPeriodStart + LOGGING_PEROID) return; // period not over
  logCPM = float(logCnt) / (float(LOGGING_PEROID) / 60000);
  uSvLogged = logCPM / uSvRate;         // make uSV conversion
  

  // Print to serial in a format that might be used by Excel
  Serial.print("  ");    
  Serial.print(logCPM,DEC);
  Serial.print(",\t");    
  Serial.print(uSvLogged,4);
  Serial.print(",\t"); // comma delimited
  Serial.print(Vcc_mV/1000. ,2);        // print as volts with 2 dec. places
  Serial.print("V");
  Serial.println(",");    
  Blink(LED_PIN,2);                     // show it logged
  logCnt = 0;                           // reset log event counter
  logPeriodStart = millis();            // reset log time
  dispCnt = 0;                          // reset display event counter
  dispPeriodStart = millis();           // reset display time
}


void Blink(byte led, byte times){ // just to flash the LED
  for (byte i=0; i< times; i++){
    digitalWrite(led,HIGH);
    delay (150);
    digitalWrite(led,LOW);
    delay (100);
  }
  
}

void Blink_fast(byte led, byte times){ // just to flash the LED
  for (byte i=0; i< times; i++){
    digitalWrite(led,HIGH);
    delay (60);
    digitalWrite(led,LOW);
    delay (50);
  }

}

long readVcc() { // SecretVoltmeter from TinkerIt
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result; // Back-calculate AVcc in mV
  return result;
}


void GetEvent(){   // ISR triggered for each new event (count)
  newEvent = true;
}






Arduino Geiger counter with LCD and si29bg GM tube




2011 m. liepos 28 d., ketvirtadienis


http://www.youtube.com/watch?v=EzXb-15rzK8

This is a working arduino geiger counter assembled from the exact set of parts which I have photographed in previous posts. Here it is working connected to computer. This is to demonstrate how the detector part works togeather with the Arduino part. In addition to flashing the LED and sounding the buzzer when Ionizing nuclear radiation particle is detected by the geiger tube SI29-BG, it also runs a counting program on the atmega328p processor and sends data through serial port to computer.

http://www.youtube.com/watch?v=vbDveyMODus
This is a working arduino geiger counter assembled from the exact set of parts which I have photographed in previous posts. Here it is working not connected to computer. This is to demonstrate how the detector part works (flashes LED and sounds the buzzer when Ionizing nuclear radiation particle is detected by the geiger tube SI29-BG)

2011 m. liepos 27 d., trečiadienis

Arduino set of components including Geiger–Müller tube


A set of electronic components including Geiger–Müller tube, which can be used to build an Arduino Geiger ionizing radiation counter.

Arduino set of components


A set of electronic components which can be used to build an Arduino Geiger ionizing radiation counter.

Simple set of components


Set of electronic components which can be used to make a simple electronic circuit for the Geiger ionizing radiation detector.

2011 m. birželio 22 d., trečiadienis

Board pictures and description


This is a factory manufacturedand tested PCB for DIY Arduino Geiger Radiation Counter developed and presented by brohogan  according to his kit schematic and assembly instructions
As I needed only a few of these boards but had to order more from the factory I can sell the rest.
If interested please send your inquires by this address arturas456@gmail.com