Вступ
- Активний стан – логічна одиниця
- Реєстратор імпульсів і Трубка Гейгера-Мюллера
- Форма імпульсів з реєстратора GGreg20_V1 з трубкою СБМ-20
- Висновок
- Перерахунок імпульсів у потужність випромінювання
- Післямова
Публікація розглядає аспекти розробки спеціалізованого ISR (interrupt service routine, interrupt handler) – опрацьовувач переривань являє собою функцію зворотного виклику (callback function) в середовищі NodeMCU/Lua, як реакцію на зміну зовнішнього по відношенню до порту вводу/виводу контролера ESP8266 стану. У тіло функції зворотного виклику розміщується код, котрий необхідно виконати у процесі опрацювання зміни стану GPIO, щойно така зміна виникла.
Оскільки будь-який контролер очікує на вході якісний сигнал квадратної форми, а трубка Гейгера-Мюллера видає на вихід сигнал сформований розрядом, виникає задача правильного програмного підрахунку імпульсів, що є основою для розрахунку потужності іонізуючого випромінювання.
Далі у статті докладно розглянемо шляхи подолання цієї та інших супутніх проблем.
Розглядати часткові випадки і наводити приклади будемо у середовищі Lua, спираючись на наш комерційний програмний модуль radCounter.
Активний стан – логічна одиниця
У сучасній міжнародній літературі активний стан прийнято позначати як active-high або active-low.
active-high означає, що логічна одиниця за задумом розробника/виробника виникає на дискретному вході чи виході тоді, коли значення рівня фізичної величини, котра використовується для кодування дискретних станів, стає вищим встановленого порога.
active-low – аналогічно, але навпаки: стан дискретного рівня вважається активним (тотожним логічній одиниці), якщо значення рівня кодуючої фізичної величини стає меншим встановленого абсолютного порога.
Наприклад,
Припустимо, що у нас є пристрій з виходом INT і контролер з входом GPIO. Ці два порти з’єднано сигнальним провідником.
Найчастіше, кодуючою фізичною величиною виступає напруга.
У документації виробник вказує характеристики спеціального фізичного виходу переривання (INT):
- Напруга живлення Vdd = 3.3V;
- за еквівалентний рівень логічної одиниці приймаємо аналоговий рівень > 0.7 * Vdd, V;
- за еквівалентний рівень логічного нуля приймаємо аналоговий рівень < 0.3 * Vdd, V;
- дискретна логіка є наступною: active-low.
Це означає, що:
- пристрій, котрий “генерує” переривання, подасть на певний час на свій вихід INT рівень напруги 0.7 вольт, що є відповідно до документації нижче порога 0.3 * 3.3 = 0.99 вольт;
- цей рівень (0.7V) у себе на вхідному GPIO зареєструє контролер і оцінить його як “низький”, бо відповідно до його специфікації, цей рівень напруги теж сприймається як “низький”;
- в залежності від налаштованої дискретної логіки (а ми налаштували active-low) на порту GPIO, контролер запустить обробник переривання, так як “низький” – є активним – тобто рівнем TRUE, тобто потрібно обробляти переривання. 🙂
Зазвичай, у мікроелектроніці загальноприйнятим активним рівнем є “низький”. Але бувають виключення з цього правила, як з точки зору апаратного дизайну, так і з точки зору задачі, що необхідно вирішити. А тому, виробники мікроконтролерної техніки передбачають щонайменше декілька різних активних станів на вхідних портах, що необхідно налаштувати.
Ще раз: підпорядковані пристрої можуть генерувати активний рівень по-різному. Тому контролери повинні вміти обробляти активний рівень на вході різними методами.
Контролер ESP8266 на рівні Lua, підтримує чотири типи обробки переривань:
- зростаючий фронт;
- спадаючий фронт;
- низький рівень;
- високий рівень.
Рис.1 Типи режимів роботи опрацьовувача переривань NodeMCU/ESP8266
Примітка: за обробку переривань в NodeMCU відповідає метод gpio.trig(). Документацію можливо знайти тут: gpio.trig()
В залежності від апаратної та програмної архітектури контролера, а також від реалізації виробником механізмів обробки на низькому рівні, апаратний watchdog переривань може по-різному обробляти одну і ту ж прикладну зміну стану на вході.
Наведемо приклад. Для прикладу використаємо кнопку D3 Flash, що є на платі NodeMCU.
Для того, щоб підключити опрацьовувач переривань, напишемо простий код.
1 2 |
gpio.mode(3,gpio.INT) gpio.trig(3, "down", function(level, timestamp, eventcount) print (level, timestamp, eventcount) end) |
Натиснемо Flash, декілька разів (ми натиснули 4 рази), щоб перевірити, як працює наш скрипт:
1 2 3 4 |
0 346760375 1 0 348436970 1 0 349609274 1 0 350638530 1 |
Як можна бачити, кнопка D3 в натиснутому стані дає level == 0; eventcount == 1. Тобто логіка кнопки працює в режимі active-low, брязкіт відсутній, адже апаратний API дає нам eventcount 1 для кожного натискання.
Що буде, якщо ми натиснемо кнопку і не будемо її відпускати?
0 654602962 1
— з’явилася лише ще одна подія обробника. При відпусканні події немає.
Тепер дещо змінимо наш тестовий код:
1 2 |
gpio.mode(3,gpio.INT) gpio.trig(3, "low", function(level, timestamp, eventcount) print (level, timestamp, eventcount) end) |
і натиснемо на кнопку знову декілька разів:
1 2 3 4 5 6 7 |
0 807547542 1 0 807553539 1 0 807558445 1 … вирізано .. 0 810737476 1 0 810742657 1 0 810747555 1 |
такий код нам дав 121 подію при всього чотирьох натисканнях на кнопку.
Що ж буде, коли ми натиснемо кнопку і будемо її тримати?
Аналогічна історія – події генеруються зі швидкістю, котру тільки вміє розвивати апаратний обробник на порту. У нас вийшло близько 5000 мікросекунд == 5 мілісекунд між подіями, а це аналогічно частоті 200 гц.
Зауважимо, що якщо розігнати центральний процесор ESP8266 з 80МГЦ до 160МГЦ командою node.setcpufreq(node.CPU160MHZ)
:
1 2 3 4 5 6 7 8 9 10 |
0 381403844 1 0 381406468 1 0 381409092 1 0 381411715 1 0 381414340 1 0 381416966 1 0 381419809 1 0 381422684 1 0 381425313 1 0 381427937 1 |
то обробка переривань на порту в такому режимі відбувається в середньому кожні 2.6 мілісекунди, що дорівнює частоті 384.6 ГЦ.
Таким чином, у цьому прикладі ми побачили, що одне й те ж натискання кнопки, або інший аналогічний інформаційний сигнал, може оброблятися на порту GPIO по різному, відповідно до встановлених параметрів. Тому у даній статті ми будемо розглядати лише ті режими роботи, котрі нам підходять для реєстрації імпульсів з трубки Гейгера-Мюллера, а саме “up” та “down” що принято в прошивці NodeMCU для переднього та заднього фронтів відповідно. Цим типам обробки відповідають діаграми Рис.1 Type A і Рис.1 Type B.
З теоретичною частиною розібралися і навіть провели необхідні експерименти. Переходимо до імпульсів з реєстратора імпульсів з встановленою трубкою Гейгера-Мюллера.
Реєстратор імпульсів і Трубка Гейгера-Мюллера
Для вимірювання еквівалентної потужності іонізуючого випромінювання ми застосовуємо апаратний модуль українського виробника GGreg20_V1. Серед інших, ми знайшли на сайті комплект №1, котрий вже включає до складу трубку СБМ-20. Що дуже зручно, адже ця трубка є однією з найпопулярніших.
Таку популярність СБМ-20 отримала не кількістю, а своїми зручними для побутового застосування технічними характеристиками. Наведемо лише деякі з них, котрі нам важливо розглянути і цій статті:
- швидкість рахунку при потужності 4 мкР ∙ с-1 від джерела 137Cs від 240 імп ∙ с-1 до 280 імп ∙ с-1;
- чутливість – від 60 імп / мкР до 75 імп / мкР;
- діапазон відхилення чутливості – не більше ± 20%;
- рівень натурального фону (Nф) – 60 імп / хв.;
- мінімальний мертвий час при 400 В – 190 мкс
Реєстратор імпульсів GGreg20_V1 забезпечує необхідний режим живлення для трубки СБМ-20 і формує на вихід узгоджені за напругою та тривалістю імпульси, котрі ми подаємо на порт GPIO контролера ESP8266 (підійде як модуль ESP8266-12 з платою-програматором, так і плата NodeMCU з модулем ESP8266-12E/F) і обробляємо переривання, що виникають за умови надходження імпульсів.
Форма імпульсів з реєстратора GGreg20_V1 з трубкою СБМ-20
Схематично, імпульси, що приходять на порт GPIO можемо зобразити так, як це показано на Рис.2.
З урахуванням викладеного раніше, у розробника є щонайменше два варіанти, коли саме опрацьовувати вхідний імпульс – по передньому фронту, або ж по задньому фронту. Якщо виходити з дискретної логіки пристрою GGreg20_V1, котрим ми послуговуємося, нам необхідно було використовувати саме передній фронт імпульса, адже логіка виходу реєстратора active-low та в стані спокою на вході контролера формується високий рівень, тобто для програмного коду – активний рівень має бути низький.
Рис.2 Схематична форма імпульсів від реєстратора на базі трубки Гейгера-Мюллера
Так і вчинимо – налаштуємо метод gpio.trig()
на обробку переривання з параметром “down”. Далі наводимо журнал роботи обробника переривань нашого програмного продукту radCounter
з розширеними даними налагодження.
Примітка: з описом продукту
radCounter
можливо ознайомитися у магазині за посиланням: Модуль лічильника імпульсів
Для виводу журналу обробки окремих імпульсів у консоль, запустимо модуль radCounter наступним чином:
спершу зареєструємо у системному оточенні NodeMCU новий модуль radCounter
:
1 |
radCounter = require("radCounter") |
а далі, відповідно до синтаксису:
1 |
radCounter.init(pin, dir, time_out, lo_flt, hi_flt, dbg) |
де
pin | номер піну контролера для отримання імпульсів |
dir | фронт спрацювання ( 1 – передній, 0 – задній ) |
time_out | час одиничного циклу вимірювання, мілісекунд (для трубки СБМ-20 рекомендуємо 60) |
lo_flt | низькорівневий фільтр ( ‘ON’ – вмикання, ‘OFF’ – вимикання ) |
hi_flt | високорівневий фільтр ( ‘ON’ – вмикання, ‘OFF’ – вимикання ) |
dbg | вивод у консоль розширених даних діагностики ( 1 – вмикання, 0 – вимикання ) |
запустимо публічний метод ініціалізації/налаштування модуля radCounter:
1 |
radCounter.init(4, 0, 60000, 'OFF', 'OFF', 1) |
з такими параметрами radCounter
буде опрацьовувати переривання на вході D4, дискретна логіка буде active-low (задній фронт), цикл вимірювання мікрозівертів на годину буде відбуватися протягом однієї хвилини, всі наявні фільтри вимкнено, режим діагностики активовано.
В консолі спостерігаємо наступне:
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 29 30 31 32 33 34 35 36 37 38 39 |
radCounter module v2020.07.08 (c) 2020 alterstrategy.com dbg: Start with params: 4 0 60000 OFF OFF 1 > lvl: 0 ts: 1371667714 evcnt: 1 true count: 1 lvl: 1 ts: 1371667924 evcnt: 1 true count: 2 lvl: 0 ts: 1373526862 evcnt: 1 true count: 3 lvl: 1 ts: 1373527070 evcnt: 1 true count: 4 lvl: 0 ts: 1374856267 evcnt: 1 true count: 5 lvl: 0 ts: 1386905557 evcnt: 1 true count: 6 lvl: 1 ts: 1386905765 evcnt: 1 true count: 7 lvl: 0 ts: 1389551712 evcnt: 1 true count: 8 lvl: 1 ts: 1389551907 evcnt: 1 true count: 9 lvl: 0 ts: 1395902115 evcnt: 1 true count: 10 lvl: 0 ts: 1402508670 evcnt: 1 true count: 11 lvl: 1 ts: 1402508877 evcnt: 1 true count: 12 lvl: 0 ts: 1409378421 evcnt: 1 true count: 13 lvl: 0 ts: 1409904781 evcnt: 1 true count: 14 lvl: 0 ts: 1413892480 evcnt: 1 true count: 15 lvl: 1 ts: 1413892689 evcnt: 1 true count: 16 lvl: 0 ts: 1414315133 evcnt: 1 true count: 17 lvl: 1 ts: 1414315334 evcnt: 1 true count: 18 lvl: 0 ts: 1414623598 evcnt: 1 true count: 19 lvl: 1 ts: 1414623806 evcnt: 1 true count: 20 lvl: 0 ts: 1414867162 evcnt: 1 true count: 21 lvl: 1 ts: 1414867365 evcnt: 1 true count: 22 lvl: 0 ts: 1416314466 evcnt: 1 true count: 23 lvl: 1 ts: 1416314674 evcnt: 1 true count: 24 lvl: 0 ts: 1417745734 evcnt: 1 true count: 25 lvl: 0 ts: 1418471960 evcnt: 1 true count: 26 lvl: 0 ts: 1419041699 evcnt: 1 true count: 27 lvl: 0 ts: 1421301877 evcnt: 1 true count: 28 lvl: 0 ts: 1422197387 evcnt: 1 true count: 29 lvl: 1 ts: 1422197593 evcnt: 1 true count: 30 lvl: 0 ts: 1423913098 evcnt: 1 true count: 31 lvl: 0 ts: 1431417625 evcnt: 1 true count: 32 lvl: 1 ts: 1431417832 evcnt: 1 true count: 33 1 60.002 sec Imps: 33 Rad_lvl: 0.1881 uSv/h 18.81 uR/h avgLvl: 0.1881 min: 0.1881 max: 0.1881 dose: 0.003135 imps: 33 mins: 1 State: Ok. Normal Radiation level |
де
lvl | рівень GPIO, з котрим відбулося спрацювання і запуск функції опрацювання переривання | |
ts | відмітка системного часу | |
evcnt | кількість спрацювань на апаратному рівні, якщо це число не дорівнює 1, то ймовірно присутній брязкіт | |
true count | накопичувальний лічильник врахованих у даному циклі вимірювання імпульсів |
через 60 секунд, по завершенню циклу вимірювання відбувається розрахунок результатів першої хвилини роботи, де:
avgLvl | ковзне середнє з п’яти хвилинних циклів вимірювання, мікрозівертів на годину | ||
min | мінімальне зареєстроване значення, мікрозівертів на годину | ||
max | максимальне зареєстроване значення, мікрозівертів на годину | ||
dose | накопичена доза від початку роботи, мікрозівертів | ||
imps | накопичена кількість імпульсів від початку роботи | ||
mins | накопичена кількість хвилин (тобто циклів вимірювання), що пройшло від початку роботи |
Уважний читач неодмінно звернув увагу, що в наведеному журналі вимірювання, параметр lvl
іноді приймає дивні значення, а саме “1”. І це при тому, що ми налаштували дискретну логіку як active-low, і в такому разі спрацювання мало б відбуватися лише з lvl
“0”.
Ми маємо припущення, що проблема криється у наступному:
Оскільки вихідний тракт реєстратора імпульсів GGreg20_V1 ніяк не втручається і не спотворює форму сигналів з трубки СБМ-20, а це потрібно для того, щоб розробник був впевненим у своїх розрахунках, ми бачимо в журналі спрацювань radCounter
нерівності у формі розрядів, що відбуваються в трубці. І таким чином контролер ESP8266, маючи порти з високою швидкодією на рівні заліза, встигає зареєструвати перехідні процеси і рахує їх як окремі імпульси – хибні-позитивні (false-positive) спрацювання.
А тепер запустимо radCounter у іншому режимі:
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 29 |
radCounter module v2020.07.08 (c) 2020 alterstrategy.com dbg: Start with params: 4 1 60000 OFF OFF 1 > lvl: 1 ts: 11439740 evcnt: 1 true count: 1 lvl: 1 ts: 14959483 evcnt: 1 true count: 2 lvl: 1 ts: 16421494 evcnt: 1 true count: 3 lvl: 1 ts: 16781022 evcnt: 1 true count: 4 lvl: 1 ts: 18793071 evcnt: 1 true count: 5 lvl: 1 ts: 25570253 evcnt: 1 true count: 6 lvl: 1 ts: 26515806 evcnt: 1 true count: 7 lvl: 1 ts: 28904293 evcnt: 1 true count: 8 lvl: 1 ts: 29914574 evcnt: 1 true count: 9 lvl: 1 ts: 32936558 evcnt: 1 true count: 10 lvl: 1 ts: 40517233 evcnt: 1 true count: 11 lvl: 1 ts: 41251024 evcnt: 1 true count: 12 lvl: 1 ts: 42573048 evcnt: 1 true count: 13 lvl: 1 ts: 42679125 evcnt: 1 true count: 14 lvl: 1 ts: 45698644 evcnt: 1 true count: 15 lvl: 1 ts: 46744691 evcnt: 1 true count: 16 lvl: 1 ts: 48376232 evcnt: 1 true count: 17 lvl: 1 ts: 52011833 evcnt: 1 true count: 18 lvl: 1 ts: 57779112 evcnt: 1 true count: 19 lvl: 1 ts: 60389127 evcnt: 1 true count: 20 lvl: 1 ts: 64292991 evcnt: 1 true count: 21 lvl: 1 ts: 66022148 evcnt: 1 true count: 22 lvl: 1 ts: 70556121 evcnt: 1 true count: 23 1 60.000664 sec Imps: 23 Rad_lvl: 0.1311 uSv/h 13.11 uR/h avgLvl: 0.1311 min: 0.1311 max: 0.1311 dose: 0.002185 imps: 23 mins: 1 State: Ok. Normal Radiation level |
Як видно, маємо зовсім іншу картину. Немає хибних спрацювань. Рівень потужності іонізуючого випромінювання в межах притаманного для Києва, де ми і проводимо вимірювання.
Примітка: всі вимірювання в статті порівнювалися із вимірами другого, сертифікованого, професійного дозиметра.
Висновок
Хоча апаратний реєстратор імпульсів розроблено для active-low логіки, ми успішно і якісно застосували програмний модуль radCounter
в логіці active-high.
Перерахунок імпульсів у потужність випромінювання
Перерахунок виконується відповідно до документації виробника на трубку Гейгера-Мюллера. Трубка СБМ-20, яки зазначили раніше, має наступні характеристики швидкості підрахунку імпульсів:
при потужності 4 мкР/с від джерела 137Cs від 240 імп/с до 280 імп/с. (а)
також, виробник наводить коефіцієнт:
рівень натурального фону (Nф) – 60 імп / хв (б)
Спробуємо виконати розрахунки з першим виразом, що позначено (а). Для того щоб перейти до практичних розрахунків у програмному забезпеченні, спочатку виконуємо математичні перетворення:
- візьмемо середнє з (а) => Імп = (240 + 280) / 2 = 260
- 4 мкР/с = 260 імп/c => 1 мкР/с = 65 імп/с
- від мкР/с перейдемо до мР/с => 1 мР/с = 65000 імп/с
- від мР/с перейдемо до мР/год, для цього поділимо 65000 поділимо на 3600:
- 1 мР/год = ~ 18 імп/с
- від імп/с перейдемо до імп/хв => 1 мР/год = 1080 імп/хв
- від мР/год перейдемо до мкЗв/год => 1 мкЗв/год = 108 імп/хв
- розрахуємо значення одного імпульсу на хвилину у мкЗв/год:
- коефіцієнт перетворення 1 імп/хв = 0.0092 мкЗв/год (в)
Алгоритм застосування формули (в) наступний:
Щоб отримати значення еквівалентної потужності іонізуючого випромінювання, потрібно кількість імпульсів, що отримано протягом шестидесяти секундного циклу вимірювання, необхідно помножити на коефіцієнт перетворення:
мкЗв/год = імп/хв * 0.0092 (г)
Перевіримо отриманий результат за допомогою виразу (б)
60 * 0.0092 = 0.552 мкЗв/год
Як можна бачити, 0.552 мкЗв/год значно перевищує прийняту зараз норму потужності фонового випромінювання у 0.3 мкЗв/год, що свідчить або про неточності у документації з минулого століття, або про різночитання у означенні що таке натуральний фон (Nф), або ж про відхилення цивільного застосування від цілового призначення трубки, для якого і було розроблено документацію.
Зауважте, що для трубки Гейгера-Мюллера відмінної від СБМ-20, необхідно виконувати індивідуальний розрахунок відповідно до технічних характеристик заявлених виробником. Отриманий коефіцієнт перерахунку (г) підходить лише для СБМ-20 і відповідає наявній документації.
Фільтри – low-pass та high-pass
Ми не змогли під час підготовки матеріалів для статті відтворити на практиці випадки, коли потрібно застосовувати фільтри передбачені у radCounter – і це добре, бо це означає, що залізо працює як треба і в нашому тестовому стенді брязкоту немає. А тому, ми наведемо теоретичні відомості про ці фільтри, без скріншотів чи журналів.
Фільтри виникли під час процесу налагодження кількох стендових комплексів вимірювання радіації з іншими трубками в тому числі.
lo_flt
– це фільтр, котрий працює на низькому рівні API, і дозволяє відкинути хиби за яких evcnt (дивись вище) має значення більше одиниці. Тобто є брязкіт на GPIO.
hi_flt
– це фільтр, котрий на високому рівні (тобто на рівні скриптових алгоритмів) відкидає імпульси, що прийшли через час, що є меншим за час нечутливості (deadtime) трубки. Трубка СБМ-20 просто не взмозі, відповідно до настанов виробника, надсилати імпульси протягом 190 мікросекунд від попереднього імпульса.
Післямова
Ми розглянули процес розробки опрацьовувача переривань, навели приклади і звернули увагу на виклики що постали свого часу перед нами, провели практичні досліди, розглянули наш підхід у комерційних продуктах, надали підказки із розв’язування проблем, зробили прив’язку матеріалів до характеристик і особливостей трубки Гейгера-Мюллера.
Сподіваємося, що цей матеріал допоможе вам у програмуванні власного програмного коду вимірювача потужності іонізуючого випромінювання.
Якщо ж вас зацікавив наш комерційний програмний модуль radCounter
, будь-ласка, замовляйте!
Купуте українське, друзі!