Licznik Geigera-Müllera na bazie Arduino (4/4)


Tomasz Bartuś



2018-03-29
Licznik Geigera-Müllera 4/4

W kolejnym, 4-tym odcinku cyklu dotyczącego budowy liczników Geigera-Müllera (G-M), do projektu wykonanego w części 3, dodamy moduł zliczający impulsy i konwertujący tę liczbę na wartość dawki promieniowania pochłoniętego. Układ zrealizujemy na bazie Arduino Nano (Fig. 1). Jako urządzenie wyjściowe zastosujemy popularny wyświetlacz ciekłokrystaliczny z telefonów Nokia 5110. Układ w czasie rzeczywistym będzie obliczał przybliżoną liczbę impulsów na minutę (CPM), a następnie będzie ją przeliczał na wartość dawki promieniowania wyrażoną w μS/h.

Licznik Geigera-Müllera
Fig. 1. Licznik Geigera-Müllera z układem pomiarowym na bazie Arduino Nano

Konwersja CPM na dawkę promieniowania

Formuła, która przelicza CPM na wartość dawki promieniowania wyrażoną w sievertach zależy głównie od zastosowanej tuby Geigera: jej rozmiaru, kształtu, materiału, wrażliwości, czasu martwego, rodzaju mierzonej cząsteczki i innych. Zwykle współczynniki konwersji można uzyskać na podstawie wykresów zamieszczanych w notach katalogowych. Ogólny wzór umożliwiający konwersję wartości CPM na μS/h ma postać:

CPM × współczynnik konwersji = μSv/h (Wz. 1)

Wartości współczynników konwersji dla typowych tub G-M przedstawia Tab. 1.

Tab. 1. Współczynniki konwersji przy przeliczaniu CPM na dawkę promieniowania [μSv/h] dla różnych typów lamp G-M (na podst. Portable Environmental Monitor)
typ lampy G-Mwspółczynnik konwersji
SBM-200,006315
LDN-7120,005940
SI29BG0,010000
SBM190,001500
STS-50,006666
SI22G0,001714
SI3BG:0,631578
SBM210,048000
SBT90,010900
SI1G0,006000

Układ detekcji promieniowania jonizującego, tak jak poprzednio będzie oparty o tubę G-M STS-5 i przetwornicę impulsową podwyższającą napięcie z wejściowego (5-12V) do 400V (DC1; Fig. 2).

Przetwornica impulsowa 5V-12V Step up 300-1200V
Fig. 2. Przetwornica impulsowa 5V-12V Step-up 300-1200V

Zamiast zasilacza płytek prototypowych (5V) wykorzystywanego w częściach 2 i 3, zastosujemy małą impulsową przetwornicę podwyższającą napięcie z dostarczonego przez jedno ogniwo Li-ionowe 18650 około 4V na napięcie 5V (DC2; Fig. 3).

Moduł przetwornicy impulsowej 2-5V Step-up 5V 2A
Fig. 3. Moduł przetwornicy impulsowej 2-5V Step-up 5V 2A

Dodatkowo, w celu umożliwienia ładowania akumulatora, dodano układ ładujący ugniwa Li-jonowe (Fig. 4). Umożliwia on szybkie naładowanie ogniwa z wykorzystaniem dowolnej ładowarki wyposażonej w wyjście usb.

Moduł ładowarki ogniw Li-ion TP4056
Fig. 4. Moduł ładowarki ogniw Li-ion 1A TP4056

Zbudujmy układ wg schematu wykonawczego z Fig. 5. Moduły wraz z elementami elektronicznymi rozmieszczono na dwóch płytkach prototypowych. Schemat wykorzytuje trzy magistrale zasilające. Patrząc od góry występują na nich napięcia: ok. 4,2V; 5V i ok. 400V.

Licznik Geigera-Müllera z mikrokontrolerem Arduino Nano
Fig. 5. Licznik Geigera-Müllera z mikrokontrolerem Arduino Nano

Tuba G-M, poprzez rezystor R1 (6,8MΩ 0,25W) będzie zasilana napięciem 400V generowanym w przetwornicy DC1. Impuls wyładowania lawinowego poprzez kondensator C1 (15pF) będzie przekazywany do układu wzmacniającego. Zastosowano wzmacniacz zbudowany w oparciu o dwa tranzystory BC-547 pracujące w układzie Darlingtona. W celu przyspieszenia przełączania układu (zwłaszcz przy przechodzeniu do stanu zatkania) pomiędzy bazę i emiter tranzystora T2 podłączono rezystor R3 (3,3kΩ). Na wyjściu wzmacniacza zastosowano zieloną diodę świecącą (LED1), która będzie reagowała na analogowe sygnały z tuby. Do wyjścia wzmacniacza podłączono ją poprzez rezystor R8 (150Ω). Sygnał jest dalej przekazywany do układu pomiarowego opartego o mikrokontroler Arduino Nano. Sygnał poprowadzono do pinu cyfrowego D8. Do układu mikrokontrolera podłączono trzy urządzenia wyjściowe: buzzer (SG1), wyświetlacz ciekłokrystaliczny Nokia 5110 oraz czerwoną diodę świecącą (LED2), której zadaniem będzie sygnalizowanie alarmów. Buzzer poprzez mikroprzełącznik oraz rezystor ograniczający prąd R10 (100Ω) podłączono do pinu cyfrowego D9. Wyświetlacz ciekłokrystaliczny poprzez rezystory ograniczające prąd R3-R7 (10kΩ) podłączono do pinów cyfrowych Arduino D3-D7. Układ wyświetlacza, zgodnie z zaleceniami producenta zasilany jest napięciem 3,3V pochodzącym z układu Arduino. Czerwoną diodę świecącą (LED2) oprzez rezystor R9 (130Ω) podłączono do pinu cyfrowego D11. W celu kontroli stanu naładowania akumulatora, napięcie z jego zacisków podłączono do pinu analogowego A0 układu Arduino.

Lista części

  1. GM-1 - tuba Geigera-Müllera, tu STS-5,
  2. zaciski bezpiecznikowe do osadzenia tuby G-M (2 szt.),
  3. DC1 - przetwornica impulsowa 5V-12V Step-up 300-1200V,
  4. DC2 - przetwornica impulsowa 2-5V Step-up 5V, 2A,
  5. SG1 - buzzer 5V HCM12-X,
  6. Arduino Nano,
  7. T1, T2 - BC547,
  8. R1 - 6,8MΩ 0,25W,
  9. R2 - 3,3kΩ,
  10. R3-R7 - 10kΩ,
  11. R8 - 150Ω,
  12. R9 - 130Ω,
  13. R10 - 100Ω,
  14. C1 - 15pF 1kV,
  15. LED1 - zielona,
  16. LED2 - czerwona,
  17. wyświetlacz Nokia 5110,
  18. ogniwo Li-ionowe 18650 wraz z koszykiem,
  19. moduł ładowania ogniw Li-jon 18650,
  20. płytka prototypowa (2 szt.),
  21. mikroprzełączniki 2-stanowe (2 szt.),
  22. przewody.

Działanie układu

Układ mikrokontrolera dokonuje ciągłej kontroli stanu pinu cyfrowego D8, stanowiącego wejście sygnału pomiarowego. Gdy Arduino zarejestruje impuls, obliczany jest czas jaki upłynął od poprzedniego impulsu. Obliczona różnica stanowi podstawę do obliczenia częstotliwości pojawienia się impulsów w okresie jednej minuty (CPM). Pojawienie się cząsteczki promieniowania jonizującego jest sygnalizowane akustycznie przez buzzer oraz optycznie za pomocą diody LED2. Obliczona wartość CPM jest następnie przeliczana na szacunkową wartość dawki promieniwania wyrażoną w μSv/h (Wz. 1). Dwa alarmy: 1000 i 5000 μSv

Kod

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

#define GeigerCounter 8             // geiger counter pin
#define Buzzer 9                    // buzzer pin
#define LED_Alarm 11                // LED_Alarm pin
#define numReadings 30              // raise this number to increase data smoothing (mean CPM value)

const float factor = 0.006666;      // define constans factor CPM to uS/h
const int alarm1 = 850;             // 5,70 ?Sv/h (max day dose calculated as a part of the max permissible annual radiation dose in USA (50 000 ?Sv)
const int alarm2 = 1700;
int noCounts = 0;                   // Variable: no of counts

const unsigned char myBitmap [] PROGMEM = {
  // logo, 80x46px
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff,
  0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xc1, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xf0, 0x1f,
  0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00,
  0x7f, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xe0, 0x03, 0xff, 0xff,
  0xff, 0xe0, 0x3b, 0xfc, 0xe1, 0xf0, 0x03, 0xff, 0x80, 0x7f, 0xff, 0xc0, 0x1b, 0xfc, 0xe1, 0xc0,
  0x63, 0xff, 0x80, 0x3f, 0xff, 0x87, 0x13, 0x80, 0x37, 0x83, 0xe3, 0x80, 0x8e, 0x1f, 0xff, 0x0f,
  0xe3, 0x00, 0x37, 0x8f, 0x03, 0x80, 0x0f, 0x1f, 0xff, 0x1f, 0xe3, 0xf8, 0x3f, 0x8f, 0x03, 0xfc,
  0x0e, 0x1f, 0xff, 0x1c, 0x23, 0xf8, 0x3f, 0x8d, 0xe3, 0xfc, 0x40, 0x3f, 0xff, 0x18, 0x23, 0xf8,
  0x3f, 0x8f, 0xe3, 0xfc, 0x40, 0x7f, 0xff, 0x1c, 0x23, 0x00, 0x3b, 0x8d, 0xe3, 0x80, 0x40, 0x7f,
  0xff, 0x0f, 0x23, 0x00, 0x3f, 0x8e, 0xe3, 0x80, 0x6c, 0x3f, 0xff, 0x87, 0x23, 0x80, 0x37, 0xfb,
  0x63, 0xc0, 0x6e, 0x3f, 0xff, 0xc0, 0x63, 0xfc, 0xf2, 0x3c, 0x63, 0xfe, 0x6f, 0x1f, 0xff, 0xe0,
  0x03, 0xfc, 0xe2, 0x0e, 0x43, 0xfc, 0x6f, 0x0f, 0xff, 0xff, 0x80, 0x00, 0x18, 0x01, 0x80, 0x00,
  0x1f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x18, 0x01, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x03,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf3, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xf8, 0x01, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xe0, 0x78, 0xe0, 0xef, 0xe0, 0x70, 0x38, 0x8f,
  0xff, 0x80, 0xc0, 0x38, 0xe8, 0xff, 0xe0, 0x60, 0x18, 0x0f, 0xff, 0x1e, 0x86, 0x38, 0xf8, 0xe3,
  0xf1, 0xe7, 0x98, 0x0f, 0xff, 0x1f, 0x8f, 0x18, 0xf8, 0xe3, 0xf1, 0xc0, 0x18, 0xff, 0xff, 0x1f,
  0x8f, 0x18, 0xd8, 0xe3, 0xb1, 0xc0, 0x18, 0xff, 0xff, 0x1f, 0x8f, 0x18, 0xd8, 0xe3, 0xb1, 0xc7,
  0xf8, 0xff, 0xff, 0x0e, 0xc6, 0x38, 0xb8, 0xe3, 0x91, 0xe3, 0xd8, 0xff, 0xff, 0x80, 0xc0, 0x38,
  0x78, 0xe3, 0x90, 0x60, 0x18, 0xff, 0xff, 0xc1, 0xe0, 0xfc, 0xd8, 0xe3, 0x88, 0x78, 0x1c, 0xff,
  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00,
  0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xfc, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff
};

long cancelTime = 0;                    // time after which, when radiation is detected, the buzzer is switched off
long lastEventTime = 0;                 // variable used to calculate the time between radiation detections
int CPM = 0;                            // variable: counts per 1 minute
boolean canceled = true;                // logical variable for activation of the buzzer
float uSperH;                           // dose of radiation in uS/h
float uSperHmax = 0.0;                  // max value of the dose of radiation in uS/h

int readings[numReadings];              // the readings from the analog input
int index = 0;                          // the index of the current reading
int total = 0;                          // the running total
int meanCPM = 0;                        // final average of the probe reading

// DNokia 5110 display pins:
// pin 7 - Serial clock out (SCLK)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Command select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)
//Adafruit_PCD8544 display = Adafruit_PCD8544(SCLK, DIN, D/C, CS, RST);
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);

void setup() {
  Serial.begin(9600);
  pinMode(GeigerCounter, INPUT);
  pinMode(Buzzer, OUTPUT);
  pinMode(LED_Alarm, OUTPUT);
  pinMode(A0, INPUT);

  display.begin();                                    // start display
  display.setContrast(40);                            // contrast settings
  display.clearDisplay();                             // clear display buffer
  display.drawBitmap(2, 1, myBitmap, 80, 46, BLACK);  // draw bitmap myBitmap
  display.display();                                  // display bitmap
  delay(3000);                                        // stop for 3 sec.

  display.clearDisplay();                             // clear display buffer
  display.drawRect(0, 0, 83, 47, BLACK);              // draw a rectangle from (x1,y1) to (x2,y2)
  display.setTextSize(1);                             // font size settings
  display.setTextColor(BLACK);                        // font color settings
  display.setCursor(26, 5);                           // set cursor on position X, y
  display.print("Geiger");                            // print txt
  display.setCursor(23, 15);                          // set cursor on position X, y
  display.print("counter");                           // print txt
  display.setCursor(3, 25);                           // set cursor on position X, y
  display.print("Tomasz Bartus");                     // print txt
  display.setCursor(32, 35);                          // set cursor on position X, y
  display.print("2018");                              // print txt
  display.display();                                  // display buffer
  delay(1000);                                        // stop for 2 sec.
  tone(Buzzer, 500);
  delay(200);
  tone(Buzzer, 1000);
  delay(200);
  tone(Buzzer, 1500);
  delay(200);
  noTone(Buzzer);
  display.clearDisplay();                             // clear the screen and buffer

  for (int i = 0; i < numReadings; i++) {
    readings[i] = 0;                                  // initialize all the readings to 0
  }
}

void loop() {
  if (digitalRead(GeigerCounter)) {
    long eventTime = millis();
    analogWrite(Buzzer, 127);
    canceled = false;
    cancelTime = eventTime + 10;

    long elapsed = eventTime - lastEventTime;
    int CPM = 60000 / elapsed;
    uSperH = CPM * factor;                    // convertion of the CPM value to the radiation dose value
    if (uSperH > uSperHmax) {                 // if the current dose measurement is greather than the max dose measurement
      uSperHmax = uSperH;                     // assign the current dose measurement as the max measurement
    }

    lastEventTime = eventTime;
    delay(100);
    noCounts++;                               // increment no of counts

    total -= readings[index];                 // subtract the last reading
    readings[index] = CPM;                    // read from the sensor
    total += readings[index];                 // add the reading to the total
    index = (index + 1);                      // advance to the next index

    if (index >= numReadings)                 // if we're at the end of the array...
      index = 0;                              // ...wrap around to the beginning

    meanCPM = total / numReadings;            // calculate the average

   // float power = analogRead(A0) / 1024.00 * 5;         // power in volts
    float power = (analogRead(A0) * 5) / 1023.00;         // power in volts

    display.clearDisplay();

    display.setCursor(2, 0);                   // set cursor on position x, y
    display.print(power);                      // print power voltage
    display.setCursor(26, 0);                  // set cursor on position x, y
    display.print("V");                        // print txt

    display.setCursor(2, 9);                   // set cursor on position x, y
    display.print("CPM: ");                    // print txt
    display.print(CPM);                        // print the CPM value

    display.setCursor(2, 17);                  // set cursor on position x, y
    display.print((char)229);                  // print the mi char
    display.print("S/h: ");                    // print txt
    display.print(uSperH);                     // print the dose value

    display.setCursor(2, 25);                  // set cursor on position x, y
    display.print("counts: ");                 // print txt
    display.print(noCounts);                   // print the no of counts value

    display.setCursor(2, 33);                  // set cursor on position x, y
    display.print("max: ");                    // print txt
    display.print(uSperHmax);                  // print the max dose value
    display.setCursor(57, 33);                 // set cursor on position x, y
    display.print((char)229);                  // print the mi char
    display.print("S/h");                      // print txt

    display.setCursor(2, 41);                  // set cursor on position x, y
    display.print("mean CPM: ");
    if (noCounts < numReadings) {
      display.print("...");
    } else {
      display.print(meanCPM);                  // print the average CPM value (from the numReadings table of readings)
    }
    display.display();                         // display buffer

    if (CPM >= alarm1) {
      digitalWrite(LED_Alarm, HIGH);           // turn the LED on
      tone(Buzzer, 500);
      delay(300);
      tone(Buzzer, 1500);
      delay(300);
      tone(Buzzer, 500);
      delay(300);
      tone(Buzzer, 1500);
      delay(300);
      tone(Buzzer, 500);
      delay(300);
      tone(Buzzer, 1500);
      delay(300);
      noTone(Buzzer);
      digitalWrite(LED_Alarm, LOW);            // turn the LED on
    }

  } else if (! canceled && millis() > cancelTime) {
    analogWrite(Buzzer, 0);
    cancelTime = millis();
    canceled = true;
  }
}

Działanie skryptu

Na wstępie deklarowane są biblioteki obsługujące komunikację układu Arduino z wyświetlaczem Nokia 5110 oraz obsługujące ten wyświetlacz. Następnie deklarowane są zmienne definiujące numery pinów, do których podłączono tubę G-M oraz urządzenia wyjściowe - buzzer i czerwoną diodę LED służącą do optycznej sygnalizacji alarmu w przypadku przekroczenia dopuszczalnego poziomu promieniowania. Warto zwrócić uwagę, że buzzer podłączono do pinu 9 umożliwiającego modulację szerokości impulsu czyli PWM.

Deklarowana jest też zmienna numReadings definiująca liczbę elementów tablicy readings, w której będą deponowane kolejne pomierzone wartości CPM. Gromadzone dane będą potrzebne do wyznaczania przeciętnej liczby CPM.

W kolejnych wierszach definiowane są:

  • wspólczynnik konwersji z wartości CPM na wartości dawki pochłoniętej wyrażone w μS/h oraz
  • dwa rodzaje alarmów - miękki i twardy. W dalszym ciągu skryptu będzie wykorzystywana wyłącznie wartość alarmu miękkiego. Poziom alarmu miękkiego został ustawiony na 850 zliczeń na minutę (czyli 5,70 μSv/h). Jest to maksymalna godzinna dawka, która została obliczona na podstawie maksymalnej dopuszczalnej rocznej dawki promieniowania w USA (50 000 μSv).

Definiowana jest także zmienna noCounts przechowująca całkowitą zarejestrowaną liczbę cząstek promieniowania.

W kolejnej linii skryptu deklarowana tablica przechowująca bitmapę, która będzie wyświetlana na ekranie wyświetlacza w chwili włączenia urządzenia. Można ją automatycznie wygenerować w odpowiednich programach (np. LCDAssistant lub też za pomocą aplikacji dostępnych online), na podstawie przygotowanych wcześniej plików bmp o wielkości obrazka nie przekraczającej liczby punktów wyświetlacza Nokia 5110, czyli 84 ∗ 48 pikseli. W praktyce dobrze jest zrobić taki obrazek nieco mniejszy np. 80 ∗ 46 pikseli.

Pod tablicą bitmapy deklarowane są zmienne pomocnicze wykorzystywane w skrypcie:

  • cancelTime - definiujący czas, po którym, po wykryciu promieniowania przez rurkę G-M, wyłączany jest buzzer,
  • lastEventTime - czas ostatniej rejestracji cząstki promieniowania,
  • CPM - początkową wartość zliczeń cząstek na minutę (CPM),
  • canceled - zmienna logiczna służąca aktywacji buzzera w momencie wykrycia cząstki promieniowania jonizującego, jej wartość początkowa ustawiana jest na "true" - czyli wyłączony,
  • uSperH - zmienna przechowująca wartość dawki promieniowania jonizującego wyrażoną w μS/h,
  • uSperHmax - wartość początkowa maksymalnej rejestrowanej dawki promieniowania.

Po deklaracji wyżej wymienionyh zmiennych, tworzona jest numReadings - elementowa tablica readings, przechowująca czasy rejestracji cząstek promieniowania jonizującego.

Następnie deklarowane są jeszcze trzy zmienne:

  • index - zmienna przechowująca indeks z tablicy readings aktualnie rejestrowanej cząski,
  • total - zmienna wyrażająca sumaryczną wartość wszystkich pomiarów CPM przechowywanych w tablicy readings,
  • meanCPM - wartość początkowa średniej wartości CPM.

W kolejnej linii skryptu deklarowane są piny, do których podłączono wyświetlacz Nokia 5110.

Po tych wstępnych deklaracjach następuje część setup, w której

  • inicjowane jest połączenie z portem szeregowym oraz
  • deklarowane są rodzaje podłączenia do układu Arduino urządzeń wejściowych i wyjściowych.

W kolejnych liniach skryptu:

  • inicjowany jest wyświetlacz,
  • ustawiany jest jego kontrast
  • czyszczony jest ekran.

Następnie na ekran wyświetlacza wysyłany jest obraz zadeklarowanej tablicy z bitmapą. Będzie on wyświetlany przez 3000ms czyli 3 sekundy.

  • Po ich upłynięciu ekran wyświetlacza zostanie wyczyszczony,
  • zostanie wyświetlony prostokąt,
  • a w jego wnętrzu pojawia się napis: "Geiger counter Tomasz Bartuś 2018".

Po jego wyświetleniu i 1-sekundowej pauzie, buzer wygeneruje kolejno dźwięki o częstotliwościach kolejno: 500, 1000 i 1500 Hz.

W ostatnich liniach części setup wszystkie elementy tablicy readings zostaną wypełnione wartościami "0".

W pętli loop, na wstępie sprawdzana jest aktywność na pinie cyfrowym 8, do którego podłączona jest tuba G-M. Jeśli mikrokontroler wykryje wyładowanie lawinowe, do zmiennej eventTime zapisywany jest czas pojawienia się cząstki promieniowania jonizującego.

  • Do buzera wysyłany jest sygnał PWM o wartości 127. PWM w Arduino Nano jest 8 bitowa, co znaczy, że można do niego wprowadzić wartości z zakresu od 0-255. 127 to połowa z 255, co z kolei oznacza, że sygnał będzie posiadał wypełnienienie 50%.
  • Gdy licznik wykryje przejście przez tubę cząstki promieniowania jonizującego wartość zmiennej canceled zostaje zmieniona z "true" na "false".
  • Czas wygaszenia sygnału zostaje ustawiony na 10ms.

Teraz następuje część skryptu odpowiedzialna za oszacowanie poziomu liczby cząstek promieniowania na minutę (CPM) oraz jej konwersję na wartość dawki pochłoniętej.

  • Liczony jest czas jaki upłynął od ostatniego wyładowania lawinowego, po czym
  • jest on przeliczany na liczbę impulsów na minutę (czyli CPM),
  • wartość CPM jest konwertowana na wartość dawki pochłoniętej wyrażoną w μS/h, a następnie,
  • sprawdzane jest czy obliczona dawka jest mniejsza czy większa od największej wartości dawki rejestrowanej podczas sesji pomiarowej.

Jeżeli aktualny pomiar jest wyższy od najwyższego dotychczas zarejestrowanego, jego wartość jest podmieniana wartością aktualnego pomiaru.

  • Zmienna przechowująca czas ostatniego wyładowania lawinowego lastEventTime zostaje podmieniona wartością obecnego wyładowania.
  • działanie skryptu zostaje zatrzymane na 10 ms, a następnie,
  • zmienna noCounts oznaczająca liczbę zarejestrowanych cząstek zostaje inkrementowana o "1".
  • od sumarycznej wartość wszystkich pomiarów CPM przechowywanych w zmiennej total odejmowana jest stara wartość czasu rejestracji cząstki promieniowania o indeksie bieżącego pomiaru,
  • Aktualna wartość CMP jest zapisywana do elementu tablicy readings o indeksie index.
  • do sumarycznej wartość wszystkich pomiarów CPM przechowywanych w tablicy readings dodawana jest bieżąca watość CPM,
  • zmienna index określająca element tablicy readings jest powiększana o "1".

Jeżeli bieżąca wartość indeksu jest większa bądź równa liczbie elementów tablicy numReadings,

  • wartość indeksu jest zerowana.
  • Na podstawie sumarycznej liczby CPM wszystkich pomiarów w tablicy, obliczana jest średnia wartość CPM. Będzie ona wyświetlana na wyświetlaczu dopiero po wykonaniu numReadings pomiarów.
  • W kolejnej części skryptu, obliczane jest napięcie na okładkach akumulatora. Gdyby to napięcie wynosiło 5V, to 10-bitowy przetwornik analogowo-cyfrowy (ADC) wykazałby je jako wartość 1023. Stąd z proporcji:

analogRead(A0) - power [V]
1023.00 - 5 [V]

power = (analogRead(A0) * 5) / 1023.00

Po wykonaniu niezbędnych obliczeń następuje część skryptu odpowiedzialna za wyświetlanie danych na wyświetlaczu. Na wstępie czyszczony jest bufor wyświetlacza, po czym wyświetlane są następujące parametry:

  • napięcie na zaciskach akumulatora,
  • bieżąca liczba zliczeń cząstek promieniowania jonizującego na minutę (CPM),
  • wartość dawki pochłoniętej w μS/h,
  • całkowita liczba zliczonych cząstek od momentu włączenia urządzenia - noCounts,
  • maksymalna rejestrowana podczas sesji dawka promieniowania pochłoniętego w μS/h oraz
  • średnia wartość CPM obliczona na podstawie numReadings pomiarów. Jak widać ta zmienna jest wyświetlana dopiero po zarejestrowaniu w tablicy numReadings pomiarów.

W końcowej części skryptu włączono obsługę miękkiego alarmu alarm1. Jeżeli bieżąca wartość CPM jest większa od 850 zliczeń na minutę, sytuacja ta jest sygnalizowana akustycznie i za pomocą czerwonej diody LED.

Skrypt zamyka kontynuacja instrukcji warunkowej z początku skryptu. Jeżeli zmienna logiczna canceled, po zarejestrowaniu cząstki promieniowania jonizującego, ma wartość "false" - czyli przeciwną do ustawionej na początku skryptu wartości początkowej, oraz czas, który upłynął od jej zarejestrowania jest większy od 10ms, to:

  • buzer ma zostać wyłączony,
  • zmiennej cancelTime przypisywana jest wartość aktualnego czasu oraz
  • wartość zmiennej canceled ponownie zmieniana jest na "true".

Układ przechodzi w tryb oczekiwania na rejestrację kolejnej cząstki promieniowania.

Szkodliwość dawki promieniowania

(na podst. Libelium Team, 2011)

No dobrze, mamy urządzenie, potrafimy w przybliżeniu określić dawkę przyjętego promieniowania. Pora na ocenę, czy otrzymywane dawki są bezpieczne. Niebezpieczeństwo związane z ekspozycją na źródło promieniowania jonizującego zależy głównie od trzech czynników:

  • rodzaju promieniowania (α, β czy γ; zob. 1/4),
  • poziomu promieniowania [μSv],
  • okresu oddziaływania.
Podczas ekspozycji trudno rozdzielić poszczególne rodzaje promieniowania, dlatego normy definiują łączną, maksymalną dawkę możliwą do zaabsorbowania przez cały rok. Norma ta dla Polski wynosi 1000 μSv/rok promieniowania pochodzących od źródeł sztucznych (poza medycznymi). W USA norma dopuszczalnej rocznej dawki całkowitego promieniowania możliwego do zaabsorbowania wynosi 50 000 μSv/rok. To duża dawka promieniowania. W normalnych warunkach nawet po upływie roku nie mamy szans na jej przyjęcie. Typowy poziom promieniowania tła (promieniowanie kosmiczne, skały, materiały budowlane itp.) wynosi ok. 0,081 μSv/h, a więc w przeciągu roku otrzymujemy dawkę ok. 3650 μSv. Nawet jeśli otrzymamy dodatkowe dawki promieniowania podczas zdjęć rentgenowskich (mammogram - 3 000 μSv; prześwietlenie klatki piersiowej - 20 μSv), nadal nie mamy szansy przekroczenia wspomnianej normy.

Możliwość pomiaru dawek promieniowania powyżej 0,1μSv/h może dostarczyć nam cennych informacji o anormalnych źródłach skażeń promieniotwórczych. Dzieląc maksymalną roczną dawkę promieniowania przez liczbę godzin w roku otrzymamy maksymalną dawkę promieniowania na godzinę.

(50 000 μSv) / (24 × 365) = 5,70 μSv/h

Dla porównania, średnia godzinna dawka promieniowania na jaką ludzie byli narażenii podczas katastrofy elektrowni jądrowej w Fukushimie 21 marca wynosiła około 7,47μSv/h. Niektóre inne poziomy odniesienia (tylko wartość nominalna, a nie czas ekspozycji!):

  • 10 μSv - średnia dzienna dawka promieniowania tła,
  • 40 μSv - dawka promieniowanie otrzymywana podczas lotów na wysokościachprzelotowych,
  • 100 μSv - dawka promieniowania, na którą jesteśmy narażeni podczas prześwietlenia stomatologicznego,
  • 800 μSv - całkowita dawka promieniowania w wyniku incydentu w elektrowni jądrowej na wyspie Three-Mile (28.03.1979),
  • 3 000 μSv - dawka promieniowania w wyniku badania mammogrficznego,
  • 3 600 μSv - średnia roczna dawka promieniowania tła,
  • 50 000 μSv - maksymalna dopuszczalna roczna dawka promieniowania (USA),
  • 100 000 μSv - najniższa roczna dawka, która może się wiązać z podwyższonym ryzykiem zachorowania na raka,
  • 2 000 000 μSv - ciężka choroba popromienna (czasami śmiertelna),
  • 3 500 000 μSv - dawka LD-50 (lethal dose 50 proc.) t.j. dawka, po otrzymaniu której połowa populacji umiera po miesiącu (przy braku leczenia).

Film



Wykorzystane materiały

Kurzela M, 2015. Kurs elektroniki II - #4 - układ Darlingtona
Libelium Team, 2011. Geiger Counter - Radiation Sensor Board for Arduino and Raspberry Pi
Mirley, 2013. Kieszonkowy Licznik Geigera
Nota katalogowa tuby STS-5
Monk S., 2015. Arduino. 36 projektów dla pasjonatów elektroniki. Helion, Gliwice.
 
 

Doktorat

Spis treści
Rozdzialy
Abstrakt [pl]
Abstract [eng]