Счётчик Гейгера и Народный мониторинг
Иногда хочется знать не только температуру или влажность на улице, но и измерять уровень радиации. Для этого можно использовать счётчик Гейгера. В этой статье я опубликовал код для отправки данных на Народный мониторинг.

Для этого одним из пользователей Narodmon был куплен кит для сборки счётчика Гейгера и отдельно трубка СБМ-20. Ссылка на магазин: Geiger Counter Radiation Detector DIY Kit Arduino Compatible ver. 3.00 w/o GM Tube. Фото с того же сайта:

И мной уже была написана прошивка к Arduino для работы с данным устройством. На самом деле работает всё довольно просто. Трубка периодически пробивается при пролёте ионизирующей частицы через объём газа. И тем чаще, чем выше уровень излучения. Схема воспринимает эти разряды как импульсы, которые отправляются на ардуину. В коде происходит подсчёт количества импульсов за определённое время, высчитывается количество импульсов за минуту. И полученное число умножается на константу, зависящую от типа трубки (для СБМ-20 = 0,57). В результате получаем уровень излучения в мкР/ч.

Если найдутся тестеры, то объединю этот код с кодом метеостанции.
// Скетч для Arduino для отправки данных о радиационном фоне на Народный мониторинг // Версия 1.0 (15.02.2016) // // Автор: Гладышев Дмитрий (2016) // // Часть кода взята здесь: // http://www.rhelectronics.net/store/radiation-detector-geiger-counter-diy-kit-second-edition.html // /* 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. */ #include <SPI.h> #include <Ethernet.h> bool Debug = false; //режим отладки //******************************************************************************************** byte mac[] = { 0xDE, 0xAD, 0xBE, 0x00, 0x00, 0x00 }; //MAC-адрес Arduino #define GEIGER_PIN 2 // пин для подключения счётчика Гейгера #define GEIGER_INT 0 // прерывание для счётчика Гейгера #define postingInterval 600000 // интервал между отправками данных в миллисекундах (10 минут) #define LOG_PERIOD 15000 //Logging period in milliseconds, recommended value 15000-60000. //******************************************************************************************** #define MAX_PERIOD 60000 //Maximum logging period IPAddress server(94,19,113,221); // IP сервера народного мониторинга char macbuf[13]; EthernetClient client; unsigned long lastConnectionTime = 0; // время последней передачи данных boolean lastConnected = false; // состояние подключения int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract; char replyBuffer[160]; // буфер для отправки volatile unsigned long counts; //variable for GM Tube events unsigned long cpm; //variable for CPM unsigned long mkrh; unsigned int multiplier; //variable for calculation CPM in this sketch unsigned long previousMillis; //variable for time measurement void tube_impulse(){ //procedure for capturing events from Geiger Kit counts++; } void setup() { if (Debug) { Serial.begin(9600); } // Пробуем подключиться по Ethernet до тех пор пока это не удастся do { delay(1000); } while (Ethernet.begin(mac) == 0); lastConnectionTime = millis()-postingInterval+15000; //первое соединение через 15 секунд после запуска counts = 0; cpm = 0; multiplier = MAX_PERIOD / LOG_PERIOD; //calculating multiplier, depend on your log period pinMode(GEIGER_PIN, INPUT); // set pin INT0 input for capturing GM Tube events digitalWrite(GEIGER_PIN, HIGH); // turn on internal pullup resistors, solder C-INT on the PCB } void loop() { //Если вдруг нам случайно приходят откуда-то какие-то данные, //то просто читаем их и игнорируем, чтобы очистить буфер if (client.available()) { client.read(); } if (!client.connected() && lastConnected) { if (Debug) { Serial.println(); Serial.println("disconnecting."); } client.stop(); } //если не подключены и прошло определённое время, то делаем замер, //переподключаемся и отправляем данные if (!client.connected() && (millis() - lastConnectionTime > postingInterval)) { //формирование HTTP-запроса memset(replyBuffer, 0, sizeof(replyBuffer)); strcpy(replyBuffer,"ID="); memset(macbuf, 0, sizeof(macbuf)); //Конвертируем MAC-адрес for (int k=0; k<6; k++) { int b1=mac[k]/16; int b2=mac[k]%16; char c1[2],c2[2]; if (b1>9) c1[0]=(char)(b1-10)+'A'; else c1[0] = (char)(b1) + '0'; if (b2>9) c2[0]=(char)(b2-10)+'A'; else c2[0] = (char)(b2) + '0'; c1[1]='\0'; c2[1]='\0'; strcat(macbuf,c1); strcat(macbuf,c2); } strcat(replyBuffer, macbuf); unsigned long currentMillis = millis(); counts = 0; attachInterrupt(GEIGER_INT, tube_impulse, FALLING); //define external interrupts while (millis()-currentMillis < LOG_PERIOD) { } detachInterrupt(GEIGER_INT); cpm = counts * multiplier; mkrh = round((float)cpm*0.57); // CPM --> мкР/ч char temp[8]; itoa(mkrh, temp); strcat(replyBuffer, "&"); strcat(replyBuffer, "R1="); strcat(replyBuffer, temp); strcat(replyBuffer,'\0'); if (Debug) { Serial.println(replyBuffer); Serial.print("Content-Length: "); Serial.println(len(replyBuffer)); } //отправляем запрос httpRequest(); } //храним последнее состояние подключения lastConnected = client.connected(); } //Функция отправки данных void httpRequest() { if (client.connect(server, 80)) { if (Debug) { Serial.println("connecting..."); } // отправляем HTTP POST запрос: client.println("POST http://narodmon.ru/post.php HTTP/1.0"); client.println("Host: narodmon.ru"); client.println("Content-Type: application/x-www-form-urlencoded"); client.print("Content-Length: "); client.println(len(replyBuffer)); client.println(); client.println(replyBuffer); client.println(); lastConnectionTime = millis(); } else { if (Debug) { Serial.println("connection failed"); Serial.println("disconnecting."); } client.stop(); } } //Функция определения длины строки int len(char *buf) { int i=0; do { i++; } while (buf[i]!='\0'); return i; } //Функция переворота строки void reverse(char s[]) { int i, j; char c; for (i = 0, j = strlen(s)-1; i<j; i++, j--) { c = s[i]; s[i] = s[j]; s[j] = c; } } //Функция конвертирования числа в символьный массив void itoa(int n, char s[]) { int i, sign; if ((sign = n) < 0) /* записываем знак */ n = -n; /* делаем n положительным числом */ i = 0; do { /* генерируем цифры в обратном порядке */ s[i++] = n % 10 + '0'; /* берем следующую цифру */ } while ((n /= 10) > 0); /* удаляем */ if (sign < 0) s[i++] = '-'; s[i] = '\0'; reverse(s); }
В строках 21-25:
mac — MAC-адрес Arduino. Это ваш уникальный идентификатор на сайте народного мониторинга. Поэтому для защиты от совпадений рекомендую использовать MAC-адрес вашего компьютера/роутера/телефона с изменённым последним байтом (чтобы не было коллизии внутри локальной сети).
GEIGER_PIN — пин подключения счётчика. Не изменяйте, если не знаете что делаете.
GEIGER_INT — номер прерывания. Не изменяйте, если не знаете что делаете.
postingInterval — интервал отправки данных в миллисекундах.
LOG_PERIOD — время замера в миллисекундах. Максимум 60000 мс.
