Дозиметр на arduino

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Сообщения: 15
Зарегистрирован: Ср июл 08, 2015 14:08:20

Сообщение lasthope »

Доброго времени суток камрады.
Ввиду планируемого запуска АЭС в Беларуси, озаботился я радиационным фоном. Решил собрать дозиметр и вышел в интернет с этим вопросом. Вторая ссылка в google по запросу «дозиметр на arduino» привела меня на данный сайт, где автор утверждает, что все прекрасно работает и считает. Даже красивый лейбл на дисплей прикрепил. Ну что ж, заказал детали на али, запасся терпением и начал ждать.
Детали пришли. Я все собрал и запустил. Да, все работает, только не считает датчик ионы. Мне стало грустно и начал искать в интернете правильную схему включения датчика. Попробовав каждую что нашел, почитав комментарии что все они полная ерунда, решил собрать схему, что нашел на хабре .
Осциллограф показывает, что импульсы идут, а это хороший знак – я в процессе опытов не спалил датчик СТС-5. Дальше подключаю buzzer, который начинает пищать от 5В, и о чудо, он пикает. Начинаем усложнять схему подключения и подключаю все это дело через Arduino. Опять все работает.
Воодушевленный я начал писать свой код работы, т.к. код автора, по чьей схеме я первоначально хотел собирать мне жутко не понравился (имхо, отдельную библиотеку для обработки кнопки — это дикость…). Ну да ладно, о вкусах не спорят.
Углубился в теорию. Самое сложное это было понять, как связать пик-пик buzzer-а, с уровнем радиации. Полазив в интернете я нашел статью на англоязычном форуме, где автор показатель CPM (количество импульсов в минуту) умножает на загадочный коэффициент и переводит все это дело в микро зиверты в час. Изучив данную тему (в коде есть ссылка на неё), я нашел коэффициент для своего датчика, ну и решил: почему бы не использовать их всех. Пускай схема идет в массы, пользователь сам решил какой датчик использовать.
Через некоторое время я дописал код, прошелся напильником и готов представить предрелизную версию (в релизной кроме использования китайского модуля DC-DC up на 400В, можно будет включить генерацию ШИМ с Arduino и намотать/найти где то повышающий трансформатор.
Логика работы программы следующая: после включения выводится таймер на 60 секунд (именно столько времени должен идти отсчет для подсчета импульсов), после выводится текущий фон в мкЗв/ч, CPM и сколько импульсов получается в течении минуты. Обработка полученного сигнала делал через прерывания. Все просто.
Представляю Вашему внимание мой код и схему.
p.s. берегите глаза.
СпойлерИзображение
Спойлер

Код: Выделить всё

#define schet 2 //желательно не менять. Если очень надо, то https://alexgyver.ru/lessons/interrupts/
#define buzz 9
#define batIn A1
#define detectorName 4 // 1-SBM20, 2-SI29BG, 3-SBM19, 4-STS5, 5-SI22G, 6-SI3BG, 7-SBM21, 8-LND712, 9-SBT9, 10-SI1G.
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 7, 6, 5, 4, 3); // (RS, E, DB4, DB5, DB6, DB7)
int flag = 0,  temp = 0, tikTak = 0, batLvl = 0;
int temp1 = -1, tikTak1 = -1, batLvl1 = -1, SPM1 = -1; //чтобы экран часто не обновлять
volatile int SPM = 0;
float type = 0, mkSv = 0, mkSv1 = -1;
unsigned long previousMillis = 0;
const long interval = 60000; //SPM 60 sec
unsigned long previousMillis1 = 0;
const long interval1 = 100; //power on buzzer 0.2 sec
unsigned long previousMillis2 = 0;
const long interval2 = 1000; //отсчет до вывода инфы
boolean calculation = false, timer = true;

void setup() {
  pinMode(schet, INPUT);
  digitalWrite(schet, INPUT_PULLUP);
  pinMode(buzz, OUTPUT);
  digitalWrite(buzz, LOW);
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(schet), trigger, FALLING);
  switch (detectorName) {//https://www.uradmonitor.com/topic/hardware-conversion-factor/
    case 1:
      type = 0.006315;
      break;
    case 2:
      type = 0.010000;
      break;
    case 3:
      type = 0.001500;
      break;
    case 4:
      type = 0.006666;
      break;
    case 5:
      type = 0.001714;
      break;
    case 6:
      type = 0.631578;
      break;
    case 7:
      type = 0.048000;
      break;
    case 8:
      type = 0.005940;
      break;
    case 9:
      type = 0.010900;
      break;
    case 10:
      type = 0.006000;
      break;
  }
  lcd.begin(16, 2);
  tikTak = interval / 1000;
  // pesent=
  checkBat();
}
void trigger() { // считаем количество срабатываний датчика
  flag = 1;
  SPM++; //считаем количество импульсов в минуту
  digitalWrite(buzz, HIGH);
  previousMillis1 = millis();
}
void loop() {

  unsigned long currentMillis = millis();
  if ((currentMillis - previousMillis1 >= interval1) && (flag == 1)) { //раз в интервал выключаем пищалку
    digitalWrite(buzz, LOW);
    flag = 0;
  }
  if (currentMillis - previousMillis >= interval) { //раз в интервал обнуляем SPM
    previousMillis = currentMillis;
    temp = SPM;
    SPM = 0;
    calculation = true;
    checkBat();
  }
  if ((tikTak > 0) && ((currentMillis - previousMillis2) >= interval2)) {
    previousMillis2 = currentMillis;
    tikTak--;
  }
  if (tikTak == 0) {
    timer = false;
  }
  if (calculation == true) {
    mkSv = temp * type;
    calculation = false;
  }
  if ((SPM1 != SPM) || ( tikTak1 != tikTak) || (temp1 != temp) || (batLvl1 != batLvl) || (mkSv1 != mkSv)) {
    lsdOut();
  }
}
int checkBat() {
  batLvl = (analogRead(batIn) * 5.0 / 1024.0 - 2.8) * 100 / 1.4;
  if (batLvl > 99) batLvl = 99;
  if (batLvl < 0) batLvl = 0;
}
void lsdOut() {
  lcd.clear();
  lcd.setCursor(0, 0);
  if (timer) {
    lcd.print("Wait");
    lcd.setCursor(5, 0);
    if (tikTak >= 10) {
      lcd.print(tikTak);
    } else {
      lcd.print("0");
      lcd.print(tikTak);
    }
    lcd.print("s");
  } else {
    lcd.print("SPM");
    lcd.setCursor(4, 0);
    lcd.print(temp);
  }
  lcd.setCursor(9, 0);
  lcd.print("bat");
  lcd.setCursor(13, 0);
  lcd.print(batLvl);
  lcd.setCursor(15, 0);
  lcd.print("%");
  lcd.setCursor(0, 1);
  lcd.print(mkSv);
  lcd.setCursor(5, 1);
  lcd.print("mkSv/h");
  lcd.setCursor(13, 1);
  lcd.print(SPM);
  {
    tikTak1 = tikTak;
    temp1 = temp;
    batLvl1 = batLvl;
    mkSv1 = mkSv;
    SPM1 = SPM;
  }
}
Спойлер
Прошу сильно не пинать, решил впервые выложить свой шедевр. Пробовал на профильный сайтах, но там не дошло подтверждение о успешной регистрации.
Всем спасибо за внимание
Вложения
схема.JPG
Схема
(247.35 КБ) 630 скачиваний
Последний раз редактировалось lasthope Пн июл 13, 2020 14:04:01, всего редактировалось 1 раз.
Реклама
sio
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Сб мар 14, 2015 14:16:25

Сообщение sio »

А главное ни слова про доброго человека, который подсказал что импульсы надо ловить не кнопкой, а прерыванием :)
Реклама
Друг Кота
Аватара пользователя
Сообщения: 3385
Зарегистрирован: Пн окт 11, 2010 19:00:08

Сообщение Мурик »

lasthope писал(а):Воодушевленный я начал писать свой код работы, т.к. код автора, по чьей схеме я первоначально хотел собирать мне жутко не понравился (имхо, отдельную библиотеку для обработки кнопки — это дикость…).
Код автора из статьи не смог оценить - это же надо было додуматься дать ссылку на закрытую страницу вконтакте!
lasthope писал(а):Прошу сильно не пинать, решил впервые выложить свой шедевр.
Я все же по критикую. Это поможет вам в дальнейшем писать более оптимальный код.
Зачем столько глобальных переменных если данные можно передавать через аргументы функций?
Зачем завышать тип переменных? Не забывайте что в ардуине устаревший простейший 8-ми битный МК. Для него все что больше байта - программная эмуляция. И всякие int, long и тем более float без веской причины нежелательны т. к. тормоза и раздутый код! Не забывайте ваша конструкция на примитивнейшем МК (по современным меркам).
Собутыльник Кота
Сообщения: 2905
Зарегистрирован: Ср ноя 29, 2017 06:58:50

Сообщение BlackKilkennyCat »

Код: Выделить всё

switch (detectorName) {//https://www.uradmonitor.com/topic/hardware-conversion-factor/
    case 1:
      type = 0.006315;
      break;
    case 2:
      type = 0.010000;
      break;
    case 3:
      type = 0.001500;
      break;
    case 4:
      type = 0.006666;
      break;
    case 5:
      type = 0.001714;
      break;
    case 6:
      type = 0.631578;
      break;
    case 7:
      type = 0.048000;
      break;
    case 8:
      type = 0.005940;
      break;
    case 9:
      type = 0.010900;
      break;
    case 10:
      type = 0.006000;
      break;
  }
Здесь напрашивается обычный массив, индекс элемента которого был detectorName. Не видеть этого как минимум странно.
Если глянуть выше, то внезапно обнаруживается, что detectorName - дефайн.
То есть, всё это дерево условий совершенно бесполезно, ибо всегда выдаст один результат.
Надо было просто написать десяток закомментированных дефайнов #type с описанием какой почему и раскомментировать нужный.
Реклама
Эиком - электронные компоненты и радиодетали
Родился
Сообщения: 15
Зарегистрирован: Ср июл 08, 2015 14:08:20

Сообщение lasthope »

[uquote="Мурик",url="/forum/viewtopic.php?p=3866455#p3866455"]Я все же по критикую. Это поможет вам в дальнейшем писать более оптимальный код.
Зачем столько глобальных переменных если данные можно передавать через аргументы функций?
Зачем завышать тип переменных? Не забывайте что в ардуине устаревший простейший 8-ми битный МК. Для него все что больше байта - программная эмуляция. И всякие int, long и тем более float без веской причины нежелательны т. к. тормоза и раздутый код! Не забывайте ваша конструкция на примитивнейшем МК (по современным меркам).[/uquote]
Тут осталась дурная привычка, которая появилась из за того, что с МК я познакомился именно в виде Ардуино подобных плат и среда программирования Ардуино иде. "Если стабильно что то работает, то не нужно это ковырять." Пока нету необходимости черезчур оптимизировать. Я не спорю, для человека который по хардкору учился с бейсика или Паскаля и все выше и выше, коды написанные в иде будут вырвиглазными, но это единственное, что начало популизировать МК среди населения. Счас уйду в полемику: почему ардуино это хорошо.
Главное чтобы ты сам понимал что ты на кодил. Имхо.
[uquote="BlackKilkennyCat",url="/forum/viewtopic.php?p=3866474#p3866474"]Здесь напрашивается обычный массив, индекс элемента которого был detectorName. Не видеть этого как минимум странно.
Если глянуть выше, то внезапно обнаруживается, что detectorName - дефайн.
То есть, всё это дерево условий совершенно бесполезно, ибо всегда выдаст один результат.
Надо было просто написать десяток закомментированных дефайнов #type с описанием какой почему и раскомментировать нужный.[/uquote]
Спасибо за ваше замечание, но данный свич писался только для того, чтобы человек, который слабо во всем разбирается, решит повторить данное дело, просто поставит цифру своего датчика и не будет долго думать какой дефайн за что отвечает. Оптимизировал как мог) а свич легко гуглится и не нужно будет долго разбираться что он делает. Ну и мне просто понравилось решение первоисточника, с этими коэффициентами.
Реклама
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

"Если стабильно что то работает, то не нужно это ковырять." Пока нету необходимости черезчур оптимизировать.
Так можете никогда и не научиться писать нормальный код. А когда застрянете на проблеме - вряд ли кто будет помогать, потому что:
чтобы ты сам понимал что ты на кодил.
вот кроме вас никто и не захочет разбираться.
Почему бы не потренироваться в написании нормального кода, путем оптимизации текущего? Вам нормальные советы дали, если будет время - воспользуйтесь ими и перепишите с их учетом код - прибавится знаний и следующий код уже сразу будете писать лучше, с учетом накопленного опыта.
Реклама
Родился
Сообщения: 15
Зарегистрирован: Ср июл 08, 2015 14:08:20

Сообщение lasthope »

[uquote="NStorm",url="/forum/viewtopic.php?p=3866586#p3866586"]вот кроме вас никто и не захочет разбираться.
Почему бы не потренироваться в написании нормального кода, путем оптимизации текущего? Вам нормальные советы дали, если будет время - воспользуйтесь ими и перепишите с их учетом код - прибавится знаний и следующий код уже сразу будете писать лучше, с учетом накопленного опыта.[/uquote]
К сожалению, так и есть, по этому самому приходится разбираться почему не работает или работает не так как надо. Я же не отрицаю что я не умею писать. "В пианиста не стрелять, играет как умеет". Вы ещё мои первые потуги не видели, когда писал код для конкретной задачи. Все приходит с опытом, вы правы. Но его можно получить только имея практику. А на практике набираем шишки.
Спасибо за критику. Учту в дальнейшем. Я же для этого и выложил на серьезном форуме, а не пытался продолжать зарегистрироваться на Ардуино подобных, где люди не могут даже в блинк.
Собутыльник Кота
Сообщения: 2905
Зарегистрирован: Ср ноя 29, 2017 06:58:50

Сообщение BlackKilkennyCat »

[uquote="lasthope",url="/forum/viewtopic.php?p=3866581#p3866581"]данный свич писался только для того, чтобы человек, который слабо во всем разбирается, решит повторить данное дело, просто поставит цифру своего датчика и не будет долго думать какой дефайн за что отвечает. Оптимизировал как мог) а свич легко гуглится и не нужно будет долго разбираться что он делает. Ну и мне просто понравилось решение первоисточника, с этими коэффициентами.[/uquote]
а) код ничего не делает по сути;
б) код только запутает человека, слабо разбирающегося;
в) нет никакой разницы между "думать какой дефайн раскомментировать" и "думать какую цифру поставить";
г) следуя Вашей логике надо избавиться вообще от элементарного, переходить на с++ сразу, и всё реализовать классово-оопно-интерфейсно, а человек погуглит.
Что касается коэффициентов первоисточника, то я не предлагал их выкинуть. Если это решение в первоисточнике, то забудьте такой первоисточник, это источник г.

И еще, насчёт слаборазбирающихся:

Код: Выделить всё

int checkBat() {
  batLvl = (analogRead(batIn) * 5.0 / 1024.0 - 2.8) * 100 / 1.4;
  if (batLvl > 99) batLvl = 99;
  if (batLvl < 0) batLvl = 0;
}
что возвращает эта функция, что должна возвращать, где используется результат? Вы осознаете, что некоторые компиляторы подобную небрежность вообще посчитают за фатальную ошибку?
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

BlackKilkennyCat писал(а):что возвращает эта функция, что должна возвращать, где используется результат?
Конкретнее вопрос человеку задавайте.

Код: Выделить всё

int checkBat() {
  batLvl = (analogRead(batIn) * 5.0 / 1024.0 - 2.8) * 100 / 1.4;
  if (batLvl > 99) batLvl = 99;
  if (batLvl < 0) batLvl = 0;
}
функция используется без оператора return
BlackKilkennyCat писал(а):некоторые компиляторы подобную небрежность вообще посчитают за фатальную ошибку?
sio
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Сб мар 14, 2015 14:16:25

Сообщение sio »

Зачем тебе эта Ардуина, ай да на Паскале кодить! Там точно ни кто не поймет :)))
Родился
Сообщения: 15
Зарегистрирован: Ср июл 08, 2015 14:08:20

Сообщение lasthope »

[uquote="BlackKilkennyCat",url="/forum/viewtopic.php?p=3866660#p3866660"]а) код ничего не делает по сути;
б) код только запутает человека, слабо разбирающегося;
в) нет никакой разницы между "думать какой дефайн раскомментировать" и "думать какую цифру поставить";
г) следуя Вашей логике надо избавиться вообще от элементарного, переходить на с++ сразу, и всё реализовать классово-оопно-интерфейсно, а человек погуглит.[/uquote]
а) код расположенный в setup выполняется только один раз при включении. и он задает коэффициент.
б) для этого и нужны комментарии... Если Вы их не используете, значит у Вас феноменальная память и Вы можете разобраться в коде, который писали 1-2 года назад.
в) разницы нету, согласен. по этому я выбрал такой способ.
г) Вы не поверите. Я всю информацию нахожу в гугле. Особенно обидно когда переходишь по ссылке на форум, где должно быть решение, а там отправляют туда, от куда пришел. Очень весело %)
[uquote="BlackKilkennyCat",url="/forum/viewtopic.php?p=3866660#p3866660"]Что касается коэффициентов первоисточника, то я не предлагал их выкинуть. Если это решение в первоисточнике, то забудьте такой первоисточник, это источник г.[/uquote]
Предложите свое решение :) А лучше релизуйте ;)
[uquote="BlackKilkennyCat",url="/forum/viewtopic.php?p=3866660#p3866660"]И еще, насчёт слаборазбирающихся:
что возвращает эта функция, что должна возвращать, где используется результат? Вы осознаете, что некоторые компиляторы подобную небрежность вообще посчитают за фатальную ошибку?[/uquote]
хм... Странно что вы не заметили что переменная "batLvl" объявленная как глобальная... По этому я не писал функцию return.
Собутыльник Кота
Сообщения: 2905
Зарегистрирован: Ср ноя 29, 2017 06:58:50

Сообщение BlackKilkennyCat »

Понятно. Ну, что я могу сказать... Наплевать на общепринятые правила, логику и здравый смысл в программировании - это Ваше право.

P.S.
Я заметил глобальные переменные. К своему ужасу.
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

Да глобальные переменные не страшны. Только если у функции нет возвращаемого значения, то так и надо писать - void checkBat().
Последний раз редактировалось NStorm Чт июл 16, 2020 20:53:36, всего редактировалось 1 раз.
Собутыльник Кота
Сообщения: 2905
Зарегистрирован: Ср ноя 29, 2017 06:58:50

Сообщение BlackKilkennyCat »

Использование глобальных переменных должно быть оправданно. В неумелых руках они страшны.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Стоило бы начать с этого
Спецификатор типа функции задает тип возвращаемого значения. Функция возвращает значение если ее выполнение заканчивается оператором return. Если оператор return не содержит выражения или выполнение функции завершается после выполнения последнего ее оператора (без выполнения оператора return), то возвращаемое значение не определено.
Для функций, не использующих возвращаемое значение, должен быть использован тип void, указывающий на отсутствие возвращаемого значения.
Родился
Сообщения: 15
Зарегистрирован: Ср июл 08, 2015 14:08:20

Сообщение lasthope »

[uquote="BlackKilkennyCat",url="/forum/viewtopic.php?p=3867758#p3867758"]Понятно. Ну, что я могу сказать... Наплевать на общепринятые правила, логику и здравый смысл в программировании - это Ваше право.

P.S.
Я заметил глобальные переменные. К своему ужасу.[/uquote]
[uquote="BlackKilkennyCat",url="/forum/viewtopic.php?p=3867769#p3867769"]Использование глобальных переменных должно быть оправданно. В неумелых руках они страшны.[/uquote]
а чем они плохи, в данном случае?
[uquote="NStorm",url="/forum/viewtopic.php?p=3867766#p3867766"]Да глобальные переменные не страшны. Только если у функции нет возвращаемого значения, то так и надо писать - void checkBat().[/uquote]
забыл поправить, спасибо. когда буду добавлять генератор и видоизменять схему под не заказную повышайку, то поправляю.
Собутыльник Кота
Сообщения: 2905
Зарегистрирован: Ср ноя 29, 2017 06:58:50

Сообщение BlackKilkennyCat »

lasthope, они плохи не в данном случае единичном, а в общей практике. Например, завтра Вы используете свою функцию в другом проекте, и внезапно оказывается, что там уже есть переменная с таким же именем. И возникает следующий неприятный вариант: Вы это не заметили, а программа не выдает фатальной ошибки (типы переменных совпали). Но выдает непонятный результат-с...
Или мы вместе работаем над проектом - опять придется договариваться о глобальности. Это притом, что в громадном большинстве случаях такие переменные не нужны - результат прекрасно возвращает функция, более того, проверка результата функции более информативна.
Это не означает, что нужно маниакально шарахаться от них, вовсе нет. Просто применять там, где это оправдано.

И однократные вызовы функции - это тоже, такая ещё штука... с одной стороны, удобно и стильно. С другой стороны - около 4 байт лишних сожрется каждый вызов (в зависимости от архитектуры).

И оптимальность алгоритма - надо минимизировать всякие условия-ветвления, если их можно минимизировать.
например: if ((SPM1 != SPM) || ( tikTak1 != tikTak) || (temp1 != temp) || (batLvl1 != batLvl) || (mkSv1 != mkSv)) {
lsdOut();
}
если посмотреть lsdOut() то обнаруживается, что независимо от того, что привело к срабатыванию условия, выводится вся информация.
Так может тогда проще каждые 0.2 секунды просто вызывать lsdOut()? тогда сразу выкидывается половина переменных, а если сделать корректной функцию checkBat(), то lcd.print(batLvl); будет выглядеть как lcd.print(checkBat()); и выкинется еще одна переменная, более того, выкинется пара вызовов checkBat() из других функций... ну и т. д.
Родился
Сообщения: 15
Зарегистрирован: Ср июл 08, 2015 14:08:20

Сообщение lasthope »

BlackKilkennyCat,
спасибо. Это очень ценное конструктивное замечание, которое пилась с целью объяснить, а не "азазазаза я пишу по другому, делай как я".
Как Вы заметили в коде, переменные обзывались по принципу: что там будет. Тут нет переменный в имени которых нету описания хранимой информации (a,b, abc, 1srffdshrej3 - для примера). Они сами по себе комментарий. И да. если делать проект с кем то, то тогда такой индусский код и решения вызовут различные вопросы и проблемы.
По поводу оптимизации алгоритма. Данное условие было написано вовремя проверки в устройстве, т.к. постоянно выводилась информация на экран и он мерцал. Оно в своем роде костыль. Который обновляет информацию только тогда, когда есть изменения, перед этим его очистив. Я не спорю, это некрасивое решение, в дальнейшем я его перепишу. Разберусь как очищать не весь экран, а только определенную часть.
по поводу функции checkBat(); она вызывается только два раза, в момент запуска устройства (когда выполняется код в setup(); и раз в минуту (когда выводится показатель CPM). На всякий случай даже пересмотрел код....
Последний раз редактировалось lasthope Сб июл 18, 2020 17:29:48, всего редактировалось 1 раз.
Друг Кота
Аватара пользователя
Сообщения: 6322
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Сообщение Jack_A »

lasthope Я, конечно, не модератор, но советую вкурить понятие "оверквотинг" и не допускать его. В былые времена я за 3 строчки цитаты огрёб неделю RO ("нужно было 2 строчки оставить"). Наверно, времена изменились и на это махнули лапой.
Изображение
Ответить

Вернуться в «AVR»