2012 m. kovo 24 d., šeštadienis

inside si29bg ( СИ29БГ )

I had one faulty geiger tube which I decided to open to see what's in there.
Internal surface of anode (the rod in the center) and cathode (the external shell) looks covered with some kind of powder. The construction looks extremely sturdy in comparison to what I have seen inside other tubes.





2012 m. kovo 13 d., antradienis

The Arduino sketch (for Arduino IDE v1.0) use board setting in IDE -> arduino uno

/* Geiger Counter Kit - Default Sketch (v5b.2)                         bHogan 7/29/11
 * Ammended with 3 LED threshold indicator by       impexeris on ebay.com on 08/22/11
 * Adjusted to work with Arduino IDE v1.0           impexeris on ebay.com on 15/01/12
 *
 * 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        102        // no TUBE_SEL jumper - SET FOR si29bg
#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.write(5);                  // print full blocks
  }
  lcd.write(prtlBlock);            // 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;
}