Делаем дозиметр!

Muxi
Offline
Зарегистрирован: 22.01.2019

tekagi пишет:
Muxi, подключён акк верно? Ардуина какая? Фото и файл печатки? Кнопки по плате как разведены? Подтяжки стоят?

Не знаю, как можно не правильно подключить акб, уже цеплял непосредственно к ардуино. Ардуино про мини

фотку сейчас не закину :( Кнопки без подтяжек, мне не кажется, что дело в кнопках, т.к. будь это наводка, то клики бы продолжались и внутри меню, а так по меню я спокойно передвигаюсь, меняю значения и тд

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Ну, в тему заглядывали уникумы, подключавшие на Vin вместо Vcc, и даже цеплявшие акк через повышайку.
Вход в меню должен происходить только по кнопкам. Подтяжки по 10к я бы всё же советовал поставить, ближе к входам ардуины.
Длинные и проложенные рядом с импульсными цепями проводники прекрасно могут собирать наводки.

Muxi
Offline
Зарегистрирован: 22.01.2019

tekagi, очередной респект! подтяжка в 10к сработала. Скажите еще, можно как-то проверить блок с буззером без трубки?

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Обычно для срабатывания достаточно коснуться пинцетом или отвёрткой точки подсоединения катода счётчика (R42 или R1, в зависимости от схемы), или непосредственно базы транзистора детектора. Если индикация частиц в меню включена - должен пикнуть и моргнуть светодиодом.

Arezus
Arezus аватар
Offline
Зарегистрирован: 26.06.2013

Я для визуализации режимов индикации в каждый вариант добавил по пару строк соответствующего режима, то есть при выборе в меню «Свет+Звук» сразу идут периодические щелчки и моргания, на вибре — сразу ж-ж-ж идет, при переходе к следующему пункту меню останавливаются. Правда есть странный косяк, при этом набрасывает лишние показания в текущее среднее, потом стабилизируется в норму. Не разбирался откуда такой глюк, все равно режим не так часто переключается. Но строки при выборе пункта меню только задают выходные сигналы, ровно как и при регистрации частиц.

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Arezus, делали через while или for, или же неблокирующим кодом? Если первое - то возможная проблема описана здесь.

Arezus
Arezus аватар
Offline
Зарегистрирован: 26.06.2013

Да нет, напрямую, как при обычной индикации.

  case 3:
    myGLCD.print(utf8rus("ЗВУК+СВЕТ"), RIGHT, 30); //индикация звуком и светом
    if (n_menu == 5)
     {
      #ifdef buzzer_active //если задефайнен активный бузер
       {
        PORTB |= (1 << 5); //включаем светодиод
        PORTD |= (1 << 6); //включаем писк
        delay(del_BUZZ); // пауза писка
        PORTD &= ~(1 << 6); //выключаем бузер 
        PORTB &= ~(1 << 5); //выключаем светодиод
       }
       #else //пассивный бузер
        {
         PORTB |= (1 << 5); //включаем светодиод
         tone (6,2730,5); // щелчек
         delay(del_BUZZ);// пауза между щелчками
         PORTB &= ~(1 << 5);//выключаем светодиод
        }
      #endif
     } 
    break; 

 

MarkDV
Offline
Зарегистрирован: 24.11.2018

Привет ребят! А как вы замеряете напряжение на трубке ( 400 V) ?

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Не на самой трубке, а на выходе преобразователя. Высокоомным делителем, являющимся частью схемы. По этой же цепи работает стабилизация высокого.
Arezus, в каком месте эта конструкция стоит? Целиком скетч.

Arezus
Arezus аватар
Offline
Зарегистрирован: 26.06.2013

Tekagi, в void lcd_menu(), не хотел простыней флудить.

/* ArDOs   v1.08
***Дозиметр на Ардуино
***IDE Arduino 1.8.8
  ветка форума arduino.ru/forum/proekty/delaem-dozimetr
  сайт srukami.inf.ua/ardos.html
*/

#include <util/delay.h> //уже есть
#include <EEPROM.h>//уже есть
#include <LCD5110_Graph.h>//нужно установить

//настройки /////////////начало
LCD5110 myGLCD(A1, A0, 12, 10, 11); //подключение дисплея
#define contrast 70 //контрастность дисплея
//#define buzzer_active //если используется активный бузер (со встроенным генератором), управляемый транзистором с выхода 6, то раскомментировать эту строчку, если пассивный (с усилителем или без) - оставить закомментированой.
//#define UNO_DIP // если используется ArduinoUNO или плата на голой атмеге328 в корпусе DIP - раскомментируйте данную строчку. Это переключит чтение напряжения с делителя с ноги A6 на ногу A5.
#define first_alarm_duration 7000 //длительность сигнала тревоги при превышении первого аварийного порога в миллисекундах
byte treviga_1 = 40; //первая ступень тревоги
byte treviga_2 = 60; //вторая ступень тревоги
byte del_BUZZ = 7;//длительность одиночного сигнала
#define  ADC_value 203  // 163 значение АЦП при котором 400В с учетом вашего делителя напряжения (0..255). Для значений делителя с сайта srukami 163. alexadresat 185. (Тестовая версия tekagi  67)
#define k_delitel 455 // 576 коефициент делителя напряжения, зависит от вашего делителя. Для значений делителя с сайта srukami k_delitel 576. alexadresat 500 (Тестовая версия tekagi  1395)
byte puls = 2; //тонкая настройка длинны импульса высоковольтного транса
byte scrin_GRAF = 1; //скорость построения графика в секундах
bool podsvetka = 1; //подсветка
uint8_t graph_type = 1; //тип графика
bool alarm_sound = 0; //флаг индикации превышения порога звуком
float opornoe = 1.10; //делить на opornoe/10
#define save_DOZ 20 //как часто сохранять накопленную дозу например каждые 20мкР
#define geiger_counter_seconds 40 // число секунд для замера, соответствующее характеристикам счётчика. Для СБМ-20 равно 40.
byte beta_time = 5; //время замера бета излучения
//настройки //////////////конец
//служебные переменные
extern uint8_t SmallFontRus[], MediumNumbers[], TinyFontRus[];
volatile uint8_t timer_seconds = 0; // для отсчёта секундных интервалов в прерывании
uint8_t beta_seconds = 0;
uint8_t count_and_dose_seconds = 0;
#define maxString 21 // для работы функции преобразования кодировки utf8us
char target[maxString + 1] = ""; // для работы функции преобразования кодировки utf8us
extern uint8_t logo_bat[], logo_rag[], logo_tr[], beta_prev_1[], beta_prev_2[];
volatile int shet = 0;
int8_t ind_ON = 1;  //0 - индикация выключена, 1 - включён бузер, 2 - светодиод, 3 - и бузер, и светодиод
uint8_t first_alarm_type = 1;  //1-3, 1 - только бузер, 2 - только вибро, 3 - и бузер, и вибро
byte periodical_alarm_variable = 0; // переменная для периодически повторяющейся тревожной сигнализации
unsigned long gr_milis = 0, lcd_milis = 0;
unsigned long alarm_milis = 0; //для отсчёта длительности сигнала тревоги по превышению порога
unsigned long spNAK_milis = 0, time_doza = 0, bat_mill = 0;
uint16_t hv_adc, hv_400, shet_n = 0, shet_s = 0;
uint16_t fon = 0, fon_254 = 0;
int speed_nakT = 0, speed_nak = 0, result;
byte MIN, DAY, HOUR, MONTH; //для учёта времени дозы
uint16_t doza_vr = 0, fon_vr254 = 0, fon_vr_poisk = 0;
byte mass_p[84]; // массив для графика
byte m = 0, n_menu = 0, sys_menu = 0;
byte  mass_poisk[255]; // основной рабочий массив
byte val_kl = 0, val_ok = 0, menu = 0, zam_poisk_counter = 0;
byte sek = 0, minute = 0, bet_z = 0, gotovo = 0;
int  bet_z0 = 0, bet_z1 = 0, bet_r = 0;
float VCC = 0.0, doz_v = 0.0;
bool tr = 0, poisk = 1, fonarik = 0, toch, blink_data=1;
uint8_t GRAPH_max = 5; // максимальное значение за период отображения графика
uint8_t GRAPH_count = 0; // счётчик для поиска максимального значения для графика
#define key_pressed_left 1
#define key_pressed_right 2
#define key_pressed_ok 3
#define key_holded_left 4
#define key_holded_right 5
#define key_holded_ok 6
#define keys_not_pressed 0
uint8_t key_data = 0;
//-------------------------------------------------------------
void setup() {
  //-----------------------------------------------------------
  // настраиваем таймер на секундный интервал
  TCCR1A=(1<<WGM11); //режим14 FAST PWM 
  TCCR1B=(1<<CS12)|(1<<WGM13)|(1<<WGM12); //делить частоту CPU на 256
if (F_CPU == 16000000UL) 
 {
  ICR1=62499;  // (16000000MHz /div256) -1 = 1 раз в секунду
 }
else if (F_CPU == 8000000UL) 
 {
  ICR1=31249;  // (8000000MHz /div256) -1 = 1 раз в секунду
 } 
  TIMSK1=(1<<TOIE1); //разрешить прерывание
  //-----------------------------------------------------------
// Serial.begin(115200);
  ACSR |= 1 << ACD; //отключаем компаратор
  //ADCSRA &= ~(1 << ADEN);  // отключаем АЦП,
  pinMode(3, INPUT_PULLUP); //кнопка
  pinMode(4, INPUT_PULLUP); //кнопка
  pinMode(7, INPUT_PULLUP); //кнопка
  DDRB |= (1 << 0); PORTB &= ~(1 << 0); //пин вибры 8
  DDRC |= (0 << 4); PORTC &= ~(1 << 4); //пин пустой А4
  DDRC |= (0 << 5); PORTC &= ~(1 << 5); //пин пустой А5
  DDRB |= (1 << 1);//пин фонаря
  DDRC |= (1 << 3);//A3 дисплей GND
  DDRC |= (1 << 2);//A2 дисплей Light
  PORTC &= ~(1 << 3); //A3 дисплей GND
  PORTC  |= (1 << 2); //A2 дисплей Light
  eeprom_readS ();
  eeprom_readD ();
  if (podsvetka == 1) 
    {
      PORTC &= ~(1 << 2); //A2 дисплей Light
    }
   else if (podsvetka == 0) 
    {
      PORTC |= (1 << 2); //A2 дисплей Light
    };
  lcd_init();
  attachInterrupt(0, Schet, FALLING);//прерываниям пин 2
  DDRB |= (1 << 5); //пины на выход
  DDRD |= (1 << 5);
  DDRD |= (1 << 6);
  DDRD |= (1 << 6);//пин бузера
  nakachka();
  clear_poisk_variables();
}
//-------------------------------------------------------------
void loop() 
{
key_data = get_key();  // вызываем функцию определения нажатия кнопок, присваивая возвращаемое ней значение переменной, которую далее будем использовать в коде
if (menu == 0) 
  {
    if (key_data == key_pressed_left)   //нажатие <<<
    {
      key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду 
      clear_poisk_variables();
    }
    if (key_data == key_holded_left) //удержание <<< фонарик  
  {
    fonarik = !fonarik; 
    //_delay_ms(500);
    key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
  }   
    if (key_data == key_holded_right) // удержание <<< подсветка
  {
    key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду     
        podsvetka = !podsvetka;
    //    _delay_ms(300);
    }   
    if (key_data == key_pressed_right)  //нажатие >>>
  {
    key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    menu = 4;
    shet = 0;
    bet_z0 = 0;
    bet_z1 = 0;
    bet_r = 0;
    bet_z = 0;
    gotovo = 0;
    sek = 0;
    minute = 0;
    }
 } 
if (menu == 3)
  {
    if (key_data == key_pressed_left)  //нажатие <<<
  {
    key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    menu = 0;
    shet = 0; fon = 0; zam_poisk_counter = 0;
    for (int i = 0; i < 18; i++) { mass_poisk[i] = 0; }//чистим
  }
  } 
if (menu == 4) 
  {
    if (key_data == key_pressed_right)  //нажатие >>>
  {
    key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    menu = 0;
    clear_poisk_variables();
    }
  }
if (fonarik == 0)  //фонарик
  {
    PORTB &= ~(1 << 1);//пин фонаря
  } 
else if (fonarik == 1) 
  {
    PORTB |= (1 << 1);//пин фонаря
  }
if (podsvetka == 1) 
  {
    PORTC &= ~(1 << 2); //A2 дисплей Light
  }
else if (podsvetka == 0) 
  {
    PORTC |= (1 << 2); //A2 дисплей Light
  }
  if (millis() - lcd_milis >= 300)  //скорость отрисовки дисплея
  {
    lcd_milis = millis();
    blink_data = !blink_data;
    if (menu == 0) 
      {
        lcd_poisk();  //вывод на дисплей режима поиск
        poisk_f();    //вызов функции счёта и набора массива
      }
    if (menu == 1) 
      {
        lcd_menu();   //вывод на дисплей меню
        poisk_f();  //вызов функции счёта и набора массива 
      }
    if (menu == 2) 
      {
        lcd_sys();    //вывод на дисплей системного меню
        poisk_f();  //вызов функции счёта и набора массива
      }
    if (menu == 3) 
      {
//          zamer_200s(); //вывод на дисплей замер 180сек
        menu = 0;
      }
    if (menu == 4) 
      {
        zamer_beta();
      }
  }
//-------------------------------------------------------------------------------------------------------------
/* Костыль. Разностный замер и длительный замер вызываются с частотой отрисовки дисплея, 
поэтому сложно поймать нажатия кнопок внутри функций zamer_200s() и zamer_beta().
Возможно в будущем придётся разделить эти функции на обработку данных (вызывать с частотой loop'а) 
и вывод на дисплей (вызывать с частотой обновления дисплея)
*/
if (menu == 4)
{
    if ((key_data == key_pressed_ok) && (gotovo == 0))  //нажатие OK
    {
      key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      gotovo = 1;
      switch (bet_z) //проверяем, находимся ли в первом или втором замере
      {
        case 0: //если в первом замере
          bet_z0 = 0; //обнуляем текущие показания замера 1
          shet = 0; //обнуляем счёт
        case 1: //если во втором замере
          bet_z1 = 0; //обнуляем текущие показания замера 2
          shet = 0; //обнуляем счёт            
      }
    }
}
//--------------------------------------------------------------------------------------------------------------  
generator();//накачка по обратной связи с АЦП
if (shet_s != shet) 
  {
    signa ();//подача сигнала о частичке
  }
if (key_data == key_pressed_ok) { //нажатие ок
if (menu == 2) 
  {
    key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    sys_menu++;
    if (sys_menu > 5) 
      {
        sys_menu = 0;
      }
  }
if (menu == 1) 
  {
    key_data = 0;    // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    n_menu++;
    if (n_menu > 7) 
      {
        n_menu = 0;
      }
  }
if (menu == 0) 
  {
    key_data = 0;   // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    menu = 1;
  }
  } 
if (menu == 0)  // в меню по удержанию кнопки "ок" входим только из режима "поиск"
  {
    if (key_data == key_holded_ok)  //удержание OK
      {
        menu = 2; 
        key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      }
  }
if (menu == 1) 
  {
    if (key_data == key_pressed_right)  //нажатие >>>
      {
        if (n_menu == 0) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду   
            treviga_1++;
          }
        if (n_menu == 1) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду     
            treviga_2++;
          }
        if (n_menu == 2) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду     
            podsvetka = !podsvetka;
          }
        if (n_menu == 3) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            graph_type++;
            if (graph_type>1) {graph_type = 1;}
          }
        if (n_menu == 4) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду     
            scrin_GRAF++;
            if (scrin_GRAF > 10) 
              {
                scrin_GRAF = 1;
              }
          }
        if (n_menu == 5) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду     
            ind_ON++; 
            ind_ON = constrain (ind_ON, 0, 4); //держим значение в диапазоне 0...4
          }
        if (n_menu == 6) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду     
            menu = 0;
          }
        if (n_menu == 7) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду     
            eeprom_wrS ();
            menu = 0;
          }
      }
  }
if (menu == 2) 
  {
    if (key_data == key_pressed_right)  //нажатие >>>
      {
        if (sys_menu == 0) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду 
            opornoe = opornoe + 0.01;
            if (opornoe < 0.98) 
              {
                opornoe = 1.20;
              }
            if (opornoe > 1.20) 
              {
                opornoe = 0.98;
              }
          }
        if (sys_menu == 1) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            puls++;
            if (puls < 1) 
              {
                puls = 200;
              }
            else if (puls > 200) 
              {
                puls = 1;
              }
          }
        if (sys_menu == 2) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            time_doza = 0;//сброс накопленной дозы
            doz_v = 0;//сброс накопленной дозы
            eeprom_wrD ();
            myGLCD.clrScr();
            myGLCD.setFont(SmallFontRus);
            myGLCD.print(utf8rus("ДОЗА И ВРЕМЯ"), CENTER, 16);
            myGLCD.print(utf8rus("ОБНУЛЕНЫ"), CENTER, 24);
            myGLCD.update();
            _delay_ms(1000);
          }
        if (sys_menu == 3) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            menu = 0;
          }
        if (sys_menu == 4) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            eeprom_wrS ();
            menu = 0;
          }
        if (sys_menu == 5) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            beta_time++;
          }
      }
  }
if (menu == 1) 
  {
    if (key_data == key_pressed_left)  //нажатие <<<
      {
        if (n_menu == 0) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            treviga_1--;
          }
        if (n_menu == 1) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            treviga_2--;
          }
        if (n_menu == 2) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            podsvetka = !podsvetka;
          }
        if (n_menu == 3) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            graph_type--;
            if (graph_type > 1) {graph_type = 0;}
          }
        if (n_menu == 4) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            scrin_GRAF--;
            if (scrin_GRAF < 1) 
              {
                scrin_GRAF = 10;
              }
          }
        if (n_menu == 5) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            ind_ON--; 
            ind_ON = constrain (ind_ON, 0, 4); //держим значение в диапазоне 0...4
          }
        if (n_menu == 6) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            menu = 0;
          }
        if (n_menu == 7) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            eeprom_wrS ();
            menu = 0;
          }
      }
  }
if (menu == 2) 
  {
    if (key_data == key_pressed_left)  //нажатие <<<
      {
        if (sys_menu == 0) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            opornoe = opornoe - 0.01;
            if (opornoe < 0.98) 
              {
                opornoe = 1.20;
              }
            else if (opornoe > 1.20) 
              {
                opornoe = 0.98;
              }
          }
        if (sys_menu == 1) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            puls--;
            if (puls < 1) 
              {
                puls = 200;
              }
            else if (puls > 200) 
              {
                puls = 1;
              }
          }
        if (sys_menu == 2) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            time_doza = 0;//сброс накопленной дозы
            doz_v = 0;//сброс накопленной дозы
            eeprom_wrD ();
            myGLCD.clrScr();
            myGLCD.setFont(SmallFontRus);
            myGLCD.print(utf8rus("ДОЗА И ВРЕМЯ"), CENTER, 16);
            myGLCD.print(utf8rus("ОБНУЛЕНЫ"), CENTER, 24);
            myGLCD.update();
            _delay_ms(1000);
          }
        if (sys_menu == 3) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            menu = 0;
          }
        if (sys_menu == 4) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            eeprom_wrS ();
            menu = 0;
          }
        if (sys_menu == 5) 
          {
            key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
            beta_time--;
          }
      }
  }
//------------------------------------------------------------------------------------------------------------------  
if (alarm_sound && (millis() - lcd_milis >= 300)) //если поднят флаг аварийного сигнала (плюс попользуемся интервалом обновления экрана)
  {
    periodical_alarm_variable++; 
    if (periodical_alarm_variable >= 4) {periodical_alarm_variable = 1;} // держим переменную в пределах
    PORTB |= (1 << 0); //включаем вибру
    if (periodical_alarm_variable  > 1 )
      {
        PORTB &= ~(1 << 0); // выключаем вибру  
      }
    if  (periodical_alarm_variable  < 3) // периодичный звук тревоги
      {
        #ifdef buzzer_active //если задефайнен активный бузер
        PORTD |= (1 << 6); // включаем непрерывный сигнал тревоги
        #else //пассивный
        tone (6,1300);  //генерим писк с частотой 1300Гц (значение можно изменить на своё) на пине 6
        #endif
      }
    else 
      {
        #ifdef buzzer_active   //если задефайнен активный бузер
        PORTD &= ~(1 << 6); // выключаем непрерывный сигнал тревоги
        #else //пассивный бузер
        noTone (6); //выключаем писк на 6й ноге
        #endif 
      }
  if ((millis() - alarm_milis) > first_alarm_duration) // проверяем, не истекло ли время подачи сигнала тревоги
    {
      PORTB &= ~(1 << 0); // выключаем вибру
      periodical_alarm_variable = 0; // обнуляем переменную
      #ifdef buzzer_active   //если задефайнен активный бузер
      PORTD &= ~(1 << 6); // выключаем непрерывный сигнал тревоги
      #else //пассивный бузер
      noTone (6); //выключаем писк на 6й ноге
      #endif 
      alarm_sound = 0; // сбрасываем флаг сигнала тревоги
    }
  }
//------------------------------------------------------------------------------------------------------------------
if (!tr && alarm_sound) // если фон ниже порога тревоги, но сигнал тревоги ещё не выключен
  {
    res_first_alarm(); //сбрасываем сигнал тревоги
  }
}
//-------------------------------------------------------------------------------------------------------
void lcd_poisk() 
{//вывод на дисплей режима поиск
if ((shet < treviga_1 && fon < treviga_1)&& treviga_1 != 0) //проверяем тревогу
  {
    tr = 0;
  }
if ((shet > treviga_1 || fon > treviga_1) && treviga_1 != 0) //проверяем тревогу
  {
    check_alarm_signal(); // устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
    tr = 1;
  }
myGLCD.clrScr();
myGLCD.setFont(SmallFontRus);
if (tr == 1)  //опасно
  {
    myGLCD.drawBitmap(0, 0, logo_tr, 24, 8);
  }
myGLCD.setFont(TinyFontRus);
if (fon_254 > 0) 
  {
    if (fon_254 >= 1000) 
      {
        myGLCD.print("\xBC\xBE\xBF", 43, 0); // мР/ч
      }
    if (fon_254 < 1000) 
      {
        myGLCD.print("\xBC\xBD\xBE\xBF", 43, 0);  // мкР/ч
      }
  }
if ((zam_poisk_counter >= 254) || blink_data)
  {
  myGLCD.setFont(TinyFontRus);
  if (fon_254 > 0) 
    {
      if (fon_254 >= 1000) 
        {
          myGLCD.printNumF((float(fon_254)/1000.0), 1, 26, 0);
        }
      if (fon_254 < 1000) 
        {
          if (fon_254 < 100)
            {
              myGLCD.printNumI(fon_254, 32, 0);
            }
          else
            {
              myGLCD.printNumI(fon_254, 26, 0);
            }
        }
    }
  }
if ((zam_poisk_counter >= geiger_counter_seconds) || blink_data)
  {
    myGLCD.setFont(MediumNumbers);
    if (fon > 0) 
      {
        if (fon >= 1000) 
          {
            myGLCD.printNumF((float(fon)/1000), 2, LEFT, 7);
            myGLCD.setFont(SmallFontRus); myGLCD.print(utf8rus("мР/ч"), RIGHT, 12);
          }
        if (fon < 1000) 
          {
            if (fon < 100)
              {
                myGLCD.printNumI(fon, CENTER, 7);
              }
            else
              {
                myGLCD.printNumI(fon, LEFT, 7); 
              }
            myGLCD.setFont(SmallFontRus); myGLCD.print(utf8rus("мкР/ч"), RIGHT, 12);
          }
      }
  }
if (fon > 0) 
  {
    myGLCD.setFont(SmallFontRus);
    if (fon >= 1000) 
      {
        myGLCD.print(utf8rus("мР/ч"), RIGHT, 12);
      }
    if (fon < 1000) 
      {
        myGLCD.print(utf8rus("мкР/ч"), RIGHT, 12);
      }
  }
time_d ();
myGLCD.setFont(TinyFontRus);
ind_doze_time();  //вывод времени накопления дозы на дисплей    
myGLCD.setFont(SmallFontRus);
if (doz_v < 1000) 
  {
    if (doz_v < 100)
      {
        myGLCD.printNumF(doz_v, 1, 41, 24); myGLCD.print(utf8rus("мкР"), RIGHT, 24);
      }
    else
      {
        myGLCD.printNumF(doz_v, 1, 34, 24); myGLCD.print(utf8rus("мкР"), RIGHT, 24);
      }    
  }
if (doz_v >= 1000) 
  {
    myGLCD.printNumF(doz_v / 1000.0, 2, 41, 24); myGLCD.print(utf8rus("мР"), RIGHT, 24);
  }
myGLCD.drawLine(0, 32, 83, 32);//верхняя
battery();
if (graph_type == 0)
  {
  for (uint8_t i = 0; i < 82; i ++)  //печатаем график
    {
      uint8_t max_pixel = map(mass_p[i], 0, GRAPH_max, 0, 15);
      myGLCD.drawLine(i + 1, 47, i + 1, 47 - max_pixel);
    }
  }
else if (graph_type == 1)
  {
  for (int i = 0; i < 82; i ++)  //печатаем график
    {
    if (mass_p[i] > 0) 
      {
        if (mass_p[i] <= 15) 
          {
            myGLCD.drawLine(i + 1, 47, i + 1, 47 - mass_p[i]);
          }
        if (mass_p[i] > 15) 
          {
            myGLCD.drawLine(i + 1, 47, i + 1, 47 - 15);
          }
      }
    }
  }
myGLCD.update();
}
//-------------------------------------------------------------------------------------------------------
void lcd_menu()  //вывод на дисплей меню
{
myGLCD.clrScr();
myGLCD.setFont(TinyFontRus);
myGLCD.print(utf8rus("ПОРОГ 1"), 5, 0); myGLCD.printNumI(treviga_1, 55, 0); myGLCD.print("\xBC\xBD\xBE\xBF", RIGHT, 0);
myGLCD.print(utf8rus("ПОРОГ 2"), 5, 6); myGLCD.printNumI(treviga_2, 55, 6); myGLCD.print("\xBC\xBD\xBE\xBF", RIGHT, 6);
myGLCD.print(utf8rus("ПОДСВЕТКА"), 5, 12); 
if (podsvetka)  { myGLCD.print(utf8rus("ВКЛ."), RIGHT, 12); }
else  { myGLCD.print(utf8rus("ВЫКЛ."), RIGHT, 12);  }
myGLCD.print(utf8rus("ТИП. ГРАФИКА"), 5, 18);  myGLCD.printNumI(graph_type, 59, 18); myGLCD.print("0-1", RIGHT, 18); //
myGLCD.print(utf8rus("ОБН. ГРАФИКА"), 5, 24); myGLCD.printNumI(scrin_GRAF, 59, 24); myGLCD.print(utf8rus("СЕК."), RIGHT, 24);//
myGLCD.print(utf8rus("ИНДИКАЦИЯ"), 5, 30); //пункт меню выбора индикации частиц
switch (ind_ON)
  {
  case 0:
    myGLCD.print(utf8rus("ВЫКЛ."), RIGHT, 30); //индикация выключена
    break;  
  case 1:
    myGLCD.print(utf8rus("ЗВУК"), RIGHT, 30); //индикация звуком
    if (n_menu == 5)
     {
       #ifdef buzzer_active //если задефайнен активный бузер
      {
       PORTD |= (1 << 6); //включаем бузер 
       delay(del_BUZZ); //длительность одиночного сигнала
       PORTD &= ~(1 << 6); //выключаем бузер 
      }
      #else //пассивный бузер
       {
         tone (6,2731,5); //генерим писк   tone (6,1000,30); //генерим писк 1000Гц 30миллисекунд на 6й ноге
       }
     #endif 
    }
    break;  
  case 2:
    myGLCD.print(utf8rus("СВЕТ"), RIGHT, 30); //индикация светом
    if (n_menu == 5){
     PORTB |= (1 << 5); //включаем светодиод
     delay(del_BUZZ); //длительность одиночного сигнала
     PORTB &= ~(1 << 5); //выключаем светодиод
    }
    break;  
  case 3:
    myGLCD.print(utf8rus("ЗВУК+СВЕТ"), RIGHT, 30); //индикация звуком и светом
    if (n_menu == 5)
     {
      #ifdef buzzer_active //если задефайнен активный бузер
       {
        PORTB |= (1 << 5); //включаем светодиод
        PORTD |= (1 << 6); //включаем бузер 
        delay(del_BUZZ); //длительность одиночного сигнала
        PORTD &= ~(1 << 6); //выключаем бузер 
        PORTB &= ~(1 << 5); //выключаем светодиод
       }
       #else //пассивный бузер
        {
         PORTB |= (1 << 5); //включаем светодиод
         tone (6,2730,5); //генерим щелчек  
         delay(del_BUZZ);//длительность задержки мига
         PORTB &= ~(1 << 5);//выключаем светодиод
        }
      #endif
     } 
    break; 
  case 4:
    myGLCD.print(utf8rus("ВИБРО"), RIGHT, 30); //индикация вибрацией
    if (n_menu == 5)
    {
      PORTB |= (1 << 0); //включаем вибру
      delay(del_BUZZ*10); //длительность одиночного сигнала
      PORTB &= ~(1 << 0); // выключаем вибру  
     }
    break; 
    default:
    myGLCD.print("err", RIGHT, 30); //  если значение не равно 1,2,3 или 0 - выводим ошибку 
  }
myGLCD.print(utf8rus("ВЫХОД"), 5, 36);
myGLCD.print(utf8rus("СОХРАНИТЬ"), 5, 42);
myGLCD.print(">", 0, n_menu * 6);
myGLCD.update();
}
//----------------------------------------------------------------------------------------------------------------------
void lcd_sys()  //вывод на дисплей меню
{
VCC_read();
speed_nakachka ();//скорость накачки имлульсы/сек
myGLCD.clrScr();
myGLCD.setFont(TinyFontRus);
myGLCD.print(utf8rus("ОПОРН."), 5, 0); myGLCD.printNumF(opornoe, 2, CENTER, 0); myGLCD.print("VCC", 55, 0); myGLCD.printNumF(VCC, 2, RIGHT, 0);
hv_400 = hv_adc * opornoe * k_delitel / 255; //считем высокео перед выводом
myGLCD.print(utf8rus("НАКАЧКА"), 5, 6); myGLCD.printNumI(puls, 55, 6); myGLCD.printNumI(hv_400, RIGHT, 6);
myGLCD.print(utf8rus("СБРОС ДОЗЫ"), 5, 12); 
myGLCD.print(utf8rus("ВЫХОД"), 5, 18);
myGLCD.print(utf8rus("СОХРАНИТЬ"), 5, 24);
myGLCD.print(utf8rus("БЕТА"), 5, 30); myGLCD.printNumI(beta_time, 55, 30); myGLCD.print(utf8rus("МИН."), RIGHT, 30);
myGLCD.print(">", 0, sys_menu * 6);
myGLCD.print(utf8rus("СКОРОСТЬ"), 5, 40); myGLCD.printNumI(speed_nak, 40, 40); myGLCD.print(utf8rus("ИМП/СЕК"), RIGHT, 40);
myGLCD.update();
}
//---------------------------------------------------------------------------------------------------------------------
void zamer_beta() 
{// замер бета или продуктов
if (gotovo == 0) 
  {
    if (alarm_sound)  //если активен сигнал тревоги первого уровня
      {
        res_first_alarm(); //сбрасываем сигнал тревоги
      }
    myGLCD.clrScr();
    myGLCD.setFont(TinyFontRus);
    if (bet_z == 0)
      {
        myGLCD.drawBitmap(0, 0, beta_prev_1, 84, 48);
        /*
        myGLCD.print(utf8rus("РЕЖИМ РАЗНОСТНОГО"), CENTER, 0);
        myGLCD.print(utf8rus("ЗАМЕРА"), CENTER, 8); 
        myGLCD.drawLine(0, 16, 83, 16); 
        myGLCD.print(utf8rus("УСТАНОВИТЕ ПРИБОР"), CENTER, 20); 
        myGLCD.print(utf8rus("НА ПУСТУЮ КЮВЕТУ И"), CENTER, 28);    
        */
    
      }
    else if (bet_z == 1)
      {
        myGLCD.drawBitmap(0, 0, beta_prev_2, 84, 48); 
        /*
        myGLCD.print(utf8rus("ЗАМЕР ОБРАЗЦА"), CENTER, 0); 
        myGLCD.drawLine(0, 8, 83, 8);     
        myGLCD.print(utf8rus("ЗАПОЛНИТЕ КЮВЕТУ"), CENTER, 12);
        myGLCD.print(utf8rus("ИЗМЕРЯЕМЫМ ВЕЩЕСТВОМ"), CENTER, 20);  
        myGLCD.print(utf8rus("УСТАНОВИТЕ ПРИБОР И"), CENTER, 28);
        */  
      }

//  myGLCD.setFont(SmallFontRus);
//  myGLCD.print(utf8rus("Замер "), 20, 10); myGLCD.printNumI(bet_z, 55, 10);
myGLCD.setFont(SmallFontRus);
myGLCD.print(utf8rus("НАЖМИТЕ OK"), CENTER, 36);
myGLCD.update();
  }  
if (gotovo == 1) 
  {
    if (timer_seconds != beta_seconds) 
      {
        beta_seconds = timer_seconds;
        sek++;
        toch = !toch;
        if (sek >= 60) 
          {
            sek = 0;
            minute++;
          }
      } 
    byte otsup = 0;
    if (minute > 9) 
      {
        otsup = 5;
      }
    myGLCD.clrScr();
    battery();
    if  (bet_z < 2) //таймер выводим только пока идёт первый или второй замер
    {
      myGLCD.setFont(TinyFontRus);
      myGLCD.printNumI(minute, LEFT, 0);
      if (toch == 0) 
        {
          myGLCD.print(":", 5 + otsup, 0);
        }
      else 
        {
          myGLCD.print(" ", 5 + otsup, 0);
        } 
      myGLCD.printNumI(sek, 10 + otsup, 0); myGLCD.print("\xBC"":""\xB9", 23 + otsup, 0);
    }
    myGLCD.drawLine(0, 8, 83, 8);
    myGLCD.setFont(SmallFontRus);
    myGLCD.drawLine(40, 8, 40, 28);
    myGLCD.print(utf8rus("Замер0"), LEFT, 10); myGLCD.print(utf8rus("Замер1"), RIGHT, 10);
    myGLCD.printNumI(bet_z0, LEFT, 20); myGLCD.printNumI(bet_z1, RIGHT, 20);
    myGLCD.drawLine(0, 28, 83, 28);
    if (bet_z < 2) 
    {
      myGLCD.print(utf8rus("Идёт замер"), CENTER, 30); myGLCD.printNumI(bet_z, RIGHT, 30);
      myGLCD.printNumI(bet_r, CENTER, 38);
    }
    if (bet_z == 2) 
    {
      myGLCD.print(utf8rus("Результат"), CENTER, 30);
      myGLCD.printNumI(bet_r, CENTER, 38); myGLCD.print(utf8rus("мкР/ч"), RIGHT, 38);
    }
    myGLCD.update();
    if (bet_z == 0)  //первый замер
    {
      bet_z0 = bet_z0 + shet;
      shet = 0;
      if (minute >= beta_time) 
        {
          bet_z = 1;
          sek = 0;
          minute = 0;
          gotovo = 0; 
          tone (6,2000,70); //генерим писк 2000Гц 70миллисекунд на 6й ноге
        }
    }
    if (bet_z == 1)  //второй замер
  {
    bet_z1 = bet_z1 + shet;
    shet = 0;
    if (minute >= beta_time) 
      {
        bet_z = 2;
        sek = 0;
        minute = 0;
        tone (6,2000,70); //генерим писк 2000Гц 70миллисекунд на 6й ноге    
      }
    }
    if (bet_z == 2)  //результат
    {
      bet_r = bet_z1 - bet_z0;
//      bet_r = bet_r / (1.5 * beta_time);
      bet_r = bet_r / ((60.0/(float)geiger_counter_seconds) * (float)beta_time);
      if (bet_r < 0) {bet_r = 0;} // если результат отрицательный - выводим 0. Можно оставить вывод отрицательного результата, закомментировав данную строчку.
    }
  }
if (key_data == key_pressed_right)  //нажатие >>>
  {
    key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    menu = 0;
    clear_poisk_variables();
  }
}
//-------------------------------------------------------------------------------------------------------------
void poisk_f() //режим поиска
{
int16_t shet_gr = 0;
if (poisk == 1) 
  {
    if (timer_seconds != count_and_dose_seconds) 
      {
        count_and_dose_seconds = timer_seconds;
          for (int i = 0; i < 254; i++)  //сдвигаем
          {
            mass_poisk[i] = mass_poisk[i + 1];
          }
        mass_poisk[254] = shet;
        if ((zam_poisk_counter < 254) && (zam_poisk_counter < geiger_counter_seconds))  //первый набор массива
          {
            fon_vr_poisk = fon_vr_poisk + shet;             
            zam_poisk_counter++;
            fon = fon_vr_poisk*((float(geiger_counter_seconds))/(float(zam_poisk_counter))); 
//            fon_254 = fon;
            fon_254 = 0;
          }
        else if ((zam_poisk_counter < 254) && (zam_poisk_counter == geiger_counter_seconds))  //
          {   
            zam_poisk_counter++;
            fon_vr_poisk = fon_vr_poisk + shet; 
            fon = fon_vr_poisk*((float(geiger_counter_seconds))/(float(zam_poisk_counter)));
            fon_254 = fon;    
            fon_vr254 = fon_vr_poisk;
          }
        else if ((zam_poisk_counter < 254) && (zam_poisk_counter > geiger_counter_seconds))  //
          {
            fon_vr_poisk = 0;
            for (int i = zam_poisk_counter; i > 0; i--) 
              {
                fon_vr254 = fon_vr254 + mass_poisk[254-i];
              }
            for (int j = 254 - geiger_counter_seconds; j < 255; j++) 
              { 
                fon_vr_poisk = fon_vr_poisk + mass_poisk[j];
              }
            fon = fon_vr_poisk;
//            fon_254 = (float(fon_vr254))*((float(geiger_counter_seconds))/(float(zam_poisk_counter)));
            fon_254 = (float)fon_vr254*((float)geiger_counter_seconds/(float)zam_poisk_counter); 
            fon_vr254 = 0;
            zam_poisk_counter++;
          } 
        else if (zam_poisk_counter >= 254)  //набор массива
          {
            fon_vr_poisk = 0;
            fon_vr254 = 0;
            byte geiger_counter_seconds_reverse = 254 - geiger_counter_seconds;
            for (int i = 254; i > 0; i--) 
              {
                fon_vr254 = fon_vr254 + mass_poisk[i];
                if (i > geiger_counter_seconds_reverse)
                  {
                    fon_vr_poisk = fon_vr_poisk + mass_poisk[i];
                  }
              }
            fon = fon_vr_poisk;
            fon_254 = (float(fon_vr254))*((float(geiger_counter_seconds))/254.0);
          }
        shet = 0;
        doz_v = doz_v + fon / 100.0 / 40.0;
        time_doza = time_doza + 1;
        if (doz_v - doza_vr >= save_DOZ)  //а не пора ли сохранить дозу ?
          {
            eeprom_wrD ();
            doza_vr = doz_v;
          }
//Serial.print(" zam_poisk_counter=");
//Serial.println(zam_poisk_counter);            
      }
    if (millis() - gr_milis >= scrin_GRAF * 1000) //счет для графика
      {
      gr_milis = millis();
      if (graph_type == 0)
        {
        val_ok = 0;//сброс удержания системного меню  
        for (uint8_t s = 254; s >= (255 - scrin_GRAF); s--) 
          {
            shet_gr = shet_gr + mass_poisk[s];
          }
        shet_gr = shet_gr / scrin_GRAF;
        for (int i = 0; i < 83; i++) // сдвигаем массив графика
          {
            mass_p[i] = mass_p[i + 1];
          }
        mass_p[82] = byte(shet_gr);
        if (GRAPH_count > 82) 
          {
            GRAPH_max = 5; 
            GRAPH_count = 0;
          }   
        for (int i = 0; i < 82; i++) 
          {
            if (mass_p[i] > GRAPH_max)
              {
                GRAPH_max = mass_p[i];
                GRAPH_count = 0;
              }
          }
        GRAPH_count++;     
        }
      if (graph_type == 1)
        {
          val_ok = 0;//сброс удержания системного меню
          shet_gr = shet - shet_n;
          if (shet_gr < 0) 
            {
              shet_gr = 1;
            }
          shet_n = shet;
          for (int i = 0; i < 83; i++) 
            {
              mass_p[i] = mass_p[i + 1];
            }
          mass_p[82] = byte(shet_gr);
            
        
        }       
      }
  }
}
//----------------------------------------------------------------------------------------------------------------

void clear_poisk_variables ()
{
shet = 0;
fon = 0;
fon_254 = 0;
zam_poisk_counter = 0;
GRAPH_max = 5;
GRAPH_count = 0;
fon_vr254 = 0;
fon_vr_poisk = 0;
for (uint8_t i = 0; i < 83; i++) { mass_p[i] = 0; } // чистим массив графика
for (uint8_t i = 0; i < 254; i++) { mass_poisk[i] = 0; } // чистим массив поиска  
}

void signa ()  //индикация каждой частички звуком светом
{
shet_s = shet;  
if (!alarm_sound) //если флаг сигнала тревоги не поднят, генерим одиночные сигналы, озвучивающие пойманные частицы
    {
    if (!shet_s) {return;} //если залетели в функцию signa() при обнулении переменной shet_s - просто возвращаемся в точку вызова. Детальнее здесь: arduino.ru/forum/proekty/delaem-dozimetr?page=16#comment-318736
    switch (ind_ON) //проверяем, какой тип индикации выбран
      {
        case 0: //индикация выключена
          break;  
        case 1: //индикация звуком
          #ifdef buzzer_active //если задефайнен активный бузер
            {
              PORTD |= (1 << 6); //включаем бузер 
              delay(del_BUZZ); //длительность одиночного сигнала
              PORTD &= ~(1 << 6); //выключаем бузер 
            }
          #else //пассивный бузер
            {
              tone (6,2731,5); //генерим писк   tone (6,1000,30); //генерим писк 1000Гц 30миллисекунд на 6й ноге
            }
          #endif 
          break;  
        case 2: //индикация светом
          PORTB |= (1 << 5); //включаем светодиод
          delay(del_BUZZ); //длительность одиночного сигнала
          PORTB &= ~(1 << 5); //выключаем светодиод
          break;
  
        case 3: //индикация звуком и светом
          #ifdef buzzer_active //если задефайнен активный бузер
            {
              PORTB |= (1 << 5); //включаем светодиод
              PORTD |= (1 << 6); //включаем бузер 
              delay(del_BUZZ); //длительность одиночного сигнала
              PORTD &= ~(1 << 6); //выключаем бузер 
              PORTB &= ~(1 << 5); //выключаем светодиод
            }
          #else //пассивный бузер
            {
              PORTB |= (1 << 5); //включаем светодиод
              tone (6,2731,5); //генерим писк   tone (6,1000,30); //генерим писк 1000Гц 30миллисекунд на 6й ноге  
              delay(del_BUZZ);//длительность одиночного сигнала
              PORTB &= ~(1 << 5);//выключаем светодиод
            }
          #endif 
          break; 
        case 4: // индикация вибрацией
          PORTB |= (1 << 0); //включаем вибру
          delay(del_BUZZ*5); //длительность одиночного сигнала
          PORTB &= ~(1 << 0); // выключаем вибру      
      } 
    }
else // если активен сигнал тревоги, то только мигаем светодиодом (независимо от того, включён или нет светодиод в меню)
  {
    PORTB |= (1 << 5); //включаем светодиод
    delay(del_BUZZ);
    PORTB &= ~(1 << 5);//выключаем светодиод
  }
}
//-------------------------------------------------------------------------------------------------
void Schet()  //прерывание от счетчика на пин 2
{
shet++;
}
//-------------------------------------------------------------------------------------------------
void generator() //накачка по обратной связи с АЦП
{
hv_adc  = Read_HV();
if (hv_adc < ADC_value)  //Значение АЦП при котором на выходе 400В
  {
    int c = puls;
    PORTD |= (1 << 5); //пин накачки
    while (c > 0) 
      {
        asm("nop");
        c--;
      }
    PORTD &= ~(1 << 5);//пин накачки
    speed_nakT++;
  }
}
//--------------------------------------------------------------------------------------------------
byte Read_HV () 
{
ADCSRA = 0b11100111;
#ifdef UNO_DIP //если при компилляции выбрана плата ArduinoUNO
ADMUX = 0b11100101;//выбор внутреннего опорного 1,1В и А5 
#else // если используется промини, нано или голый камень в tqfp
ADMUX = 0b11100110;//выбор внутреннего опорного 1,1В и А6
#endif  
for (int i = 0; i < 10; i++) 
  {
    while ((ADCSRA & 0x10) == 0);
    ADCSRA |= 0x10;
  }
result = 0;
for (int i = 0; i < 10; i++) 
  {
    while ((ADCSRA & 0x10) == 0);
    ADCSRA |= 0x10;
    result += ADCH;
  }
result /= 10;
return result;
}
//----------------------------------------------------------------------------------------------------
void battery()  //батарейка
{
if (bat_mill - millis() > 2000) 
  {
    bat_mill = millis();
    VCC_read();
  }
myGLCD.drawBitmap(59, 0, logo_bat, 24, 8);
myGLCD.setFont(TinyFontRus);
unsigned int BattPercent = 0;
VCC = VCC * 100;
BattPercent = map(VCC, 320, 404, 0, 100);
if (BattPercent >= 100){myGLCD.printNumF(100, 0, 65, 1);}
  else if ((BattPercent >= 10)&&(BattPercent < 100)){myGLCD.printNumF(BattPercent, 0, 69, 1);}
    else if (BattPercent < 10){myGLCD.printNumF(BattPercent, 0, 73, 1); };

myGLCD.print("%", 77, 1);
//VCC = VCC / 100;
//myGLCD.printNumF(VCC, 2, 65, 1);
}
//----------------------------------------------------------------------------------------------------
void VCC_read()  // Чтение напряжения батареи
{
//ADCSRA = 0b11100111;
//ADMUX = 0b01101110;//Выбор внешнего опорного+BG
//_delay_ms(5);
//while ((ADCSRA & 0x10) == 0);
//ADCSRA |= 0x10;
//byte resu = ADCH;
//// ADCSRA &= ~(1 << ADEN);  // отключаем АЦП,
// VCC = (opornoe * 255.0) / resu;

  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(5); // стабилизация Vref
  ADCSRA |= _BV(ADSC); // Запустить преобразование
  while ((ADCSRA & 0x10) == 0);
  uint8_t low  = ADCL; //  читаем нижний  
  uint8_t high = ADCH; // верхний
  long result = (high<<8) | low;
  VCC = (opornoe * 1023) / result; 
}


//----------------------------------------------------------------------------------------------------
void lcd_init() 
{
myGLCD.InitLCD();
myGLCD.setContrast(contrast);
myGLCD.clrScr();
myGLCD.drawBitmap(0, 0, logo_rag, 84, 48);
myGLCD.setFont(SmallFontRus);
myGLCD.print(utf8rus("alexadresat"), CENTER, 32);
myGLCD.print(utf8rus("Дозиметр v1.08"), CENTER, 40);
myGLCD.update();
_delay_ms(500);
}
//----------------------------------------------------------------------------------------------------
void eeprom_wrS ()  //запись настроек в память
{
  EEPROM.write(0, 222);
  EEPROM.write(1, treviga_1);
  EEPROM.write(2, podsvetka);
  EEPROM.write(3, graph_type);
  EEPROM.write(4, scrin_GRAF);
  EEPROM.write(5, ind_ON);
  EEPROM.write(6, puls);
  EEPROM.write(7, opornoe * 100);
  EEPROM.write(8, treviga_2);
  EEPROM.write(17, beta_time);
  myGLCD.clrScr();
  myGLCD.setFont(SmallFontRus);
  myGLCD.print(utf8rus("Сохранено"), CENTER, 20);
  myGLCD.update();
  _delay_ms(1000);
}
//-----------------------------------------------------------------------------------------------------
void eeprom_wrD ()  //запись настроек в память время накопления дозы
{
  EEPROM.put(9, time_doza);
  EEPROM.put(13, doz_v);   
}
//-----------------------------------------------------------------------------------------------------
void eeprom_readD ()  //чтение настроек из памяти время накопления дозы
{
  EEPROM.get(9, time_doza);
  EEPROM.get(13, doz_v);   
}
//-----------------------------------------------------------------------------------------------------
void eeprom_readS ()  //чтение настроек из памяти
{
  if (EEPROM.read(0) == 222) 
  {
    treviga_1 = EEPROM.read(1);
    podsvetka = EEPROM.read(2);
    graph_type = EEPROM.read(3);
    scrin_GRAF = EEPROM.read(4);
    ind_ON = EEPROM.read(5);
    puls = EEPROM.read(6);
    opornoe = EEPROM.read(7) / 100.0;
    treviga_2 = EEPROM.read(8);
    beta_time = EEPROM.read(17);
  }
_delay_ms(10);
}
//------------------------------------------------------------------------------------------------------
void nakachka() //первая накачка
{
byte n = 0;
while (n < 30) 
  {
    PORTD |= (1 << 5);//дергаем пин
    int c = puls;
    while (c > 0) 
      {
        asm("nop");
        c--;
      }
    PORTD &= ~(1 << 5);//дергаем пин
    n++;
    _delay_us(100);
  }
}
//------------------------------------------------------------------------------------------------------
void speed_nakachka ()  //скорость накачки имлульсы/сек
{
if (millis() - spNAK_milis >= 1000) 
  {
    spNAK_milis = millis();
    speed_nak = speed_nakT;
    speed_nakT = 0;
  }
}
//------------------------------------------------------------------------------------------------------
void time_d() 
{
  MONTH = time_doza / 2592000;
  DAY = (time_doza / 86400) % 30 ;
  HOUR = (time_doza / 3600) % 24 ;
  MIN = (time_doza / 60) % 60;
}
//------------------------------------------------------------------------------------------------------
void check_alarm_signal()  // устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
{
  if (!tr) // если счёт превысил аварийный порог, но флаг "tr" ещё не установлен
    {
      alarm_sound = 1; // поднимаем флаг аварийного сигнала
      alarm_milis = millis(); // запоминаем время начала тревоги
    }
}
//------------------------------------------------------------------------------------------------------
void res_first_alarm() //подпрограмма выключения тревоги (ручного или по истечении таймаута)
{
   alarm_sound = 0; // сбрасываем флаг звукового сигнала тревоги
   PORTB &= ~(1 << 0); // выключаем вибру
   periodical_alarm_variable = 0; // обнуляем переменную
   #ifdef buzzer_active //если задефайнен активный бузер
   PORTD &= ~(1 << 6); // выключаем бузер
   #else //пассивный бузер
   noTone(6);   //выключаем генерацию сигнала на 6й ноге
   #endif
}
//------------------------------------------------------------------------------------------------------
void ind_doze_time() //вывод времени накопления дозы на дисплей
{
  myGLCD.setFont(TinyFontRus);
  if (MONTH) // если есть месяцы
    {
      myGLCD.printNumI(MONTH, 0, 26);
      if(MONTH>99)
        {
          myGLCD.print("M", 13, 26);
        }
      else if (MONTH>9)
        {
          myGLCD.print("M", 9, 26);
        }
      else
        {
          myGLCD.print("M", 5, 26);
        }
    myGLCD.printNumI(DAY, 18, 26);
    if (DAY > 9) 
      {
        myGLCD.print("\xBB", 26, 26);
      }
    else
      {
        myGLCD.print("\xBB", 23, 26);
      } 
    }
  else if (DAY) // если нет месяцев, но есть дни
    {
      myGLCD.printNumI(DAY, 0, 26);
      if (DAY > 9) 
        {
          myGLCD.print("\xBB", 9, 26);
        }
      else
        {
          myGLCD.print("\xBB", 5, 26);
        }
      myGLCD.printNumI(HOUR, 18, 26);
      if (HOUR > 9) 
        {
          myGLCD.print("\xBA", 26, 26);
        }
      else 
        {
          myGLCD.print("\xBA", 23, 26);
        }
    }
  else // если нет дней
    {
      myGLCD.printNumI(HOUR, 0, 26);
      if (HOUR > 9) 
        {
          myGLCD.print("\xBA", 9, 26);
        }
      else
        {
          myGLCD.print("\xBA", 5, 26);
        }
      myGLCD.printNumI(MIN, 18, 26);
      if (MIN > 9) 
        {
          myGLCD.print("\xBC", 26, 26);
        }
      else
        {
          myGLCD.print("\xBC", 23, 26);
        }
    }   

}
//--------------------------------------------------------------------------------------------------------
byte get_key() // Функция определения нажатия и удержания кнопок
{
// версия 1 - для кратковременного нажатия значение возвращается при отпускании кнопки, для длительного - пока кнопка остаётся нажатой, с заданным интервалом
uint8_t trigger_push_hold_counter = 10; // задержка триггера кратковременного/длительного нажатия (проходов функции, умноженных на задержку "milliseconds_between_increment")  
uint8_t milliseconds_between_increment = 50; // интервал в миллисекундах между инкрементом счётчика нажатой кнопки 
static uint8_t val_kp, val_kl, val_ok;
static uint32_t key_delay_millis;
static uint32_t key_delay_after_hold_millis;
if ((millis() - key_delay_millis) > milliseconds_between_increment) //обрабатываем нажатия инкрементом переменной только если после предыдущей обработки прошло не менее "milliseconds_between_increment" миллисекунд
  {
    if (!(PIND & (1 << PIND4)))  //нажатие >>>
    {
    val_kp++;  // инкрементируем счётчик
    if (val_kp > trigger_push_hold_counter) // если значение счётчика больше порога детектирования удержания клавиши 
      {
       val_kp = 0; // сбрасываем счётчик 
       key_delay_after_hold_millis = millis(); // запоминаем время
       return key_holded_right; // возвращаем значение
      }
    }
    if (!(PIND & (1 << PIND7)))  //нажатие <<<
    {
    val_kl++;  // инкрементируем счётчик
    if (val_kl > trigger_push_hold_counter) // если значение счётчика больше порога детектирования удержания клавиши
      {
        val_kl = 0; // сбрасываем счётчик
        key_delay_after_hold_millis = millis(); // запоминаем время 
        return key_holded_left; // возвращаем значение
      }   
    }
    if (!(PIND & (1 << PIND3)))  //нажатие OK
    {
    val_ok++; // инкрементируем счётчик
    if (val_ok > trigger_push_hold_counter) // если значение счётчика больше порога детектирования удержания клавиши
      {
        val_ok = 0; // сбрасываем счётчик
        key_delay_after_hold_millis = millis(); // запоминаем время 
        return key_holded_ok; // возвращаем значение
      }       
    }
    key_delay_millis = millis(); // запоминаем время 
  }
if (val_ok > 0) //если клавиша OK перед этим была нажата 
  {
     if ((PIND & (1 << PIND3)) && ((millis() - key_delay_after_hold_millis) > (trigger_push_hold_counter * milliseconds_between_increment))) // если клавиша на данный момент отпущена и с момента последнего удержания любой клавиши прошёл интервал больше, чем один интервал удержания клавиши
      {
        val_ok = 0;  // сбрасываем счётчик
        return key_pressed_ok; // возвращаем значение
      }
  }
if (val_kp > 0) //если клавиша >>> перед этим была нажата 
  {
    if ((PIND & (1 << PIND4)) && ((millis() - key_delay_after_hold_millis) > (trigger_push_hold_counter * milliseconds_between_increment))) // если клавиша на данный момент отпущена и с момента последнего удержания любой клавиши прошёл интервал больше, чем один интервал удержания клавиши
      {
        val_kp = 0;  // сбрасываем счётчик 
        return key_pressed_right; // возвращаем значение
      }
  }
if (val_kl > 0) //если клавиша <<< перед этим была нажата 
  {
    if ((PIND & (1 << PIND7)) && ((millis() - key_delay_after_hold_millis) > (trigger_push_hold_counter * milliseconds_between_increment))) // если клавиша на данный момент отпущена и с момента последнего удержания любой клавиши прошёл интервал больше, чем один интервал удержания клавиши
      {
        val_kl = 0;  // сбрасываем счётчик  
        return key_pressed_left; // возвращаем значение
      }
  }
if (PIND & (1 << PIND4)) {val_kp = 0;} // если добрались до этой точки и кнопка не нажата - обнуляем счётчик (защита от появления "pressed" после "holded")
if (PIND & (1 << PIND7)) {val_kl = 0;} // если добрались до этой точки и кнопка не нажата - обнуляем счётчик (защита от появления "pressed" после "holded")
if (PIND & (1 << PIND3)) {val_ok = 0;} // если добрались до этой точки и кнопка не нажата - обнуляем счётчик (защита от появления "pressed" после "holded")
return 0; // если ни одна из кнопок не была нажата - возвращаем 0
}
//------------------------------------------------------------------------------------------------------------------------------
char *utf8rus(char *source) // функция преобразования utf8 для вывода кириллицы (by arduinec)
{
  int i,j,k;
  unsigned char n;
  char m[2] = { '0', '\0' };

  strcpy(target, ""); k = strlen(source); i = j = 0;

  while (i < k) {
    n = source[i]; i++;

    if (n >= 0xC0) {
      switch (n) {
        case 0xD0: {
          n = source[i]; i++;
          if (n == 0x81) { n = 0xA8; break; }
          if (n >= 0x90 && n <= 0xBF) n = n + 0x30;
          break;
        }
        case 0xD1: {
          n = source[i]; i++;
          if (n == 0x91) { n = 0xB8; break; }
          if (n >= 0x80 && n <= 0x8F) n = n + 0x70;
          break;
        }
      }
    }

    m[0] = n; strcat(target, m);
    j++; if (j >= maxString) break;
  }
  return target;
}

ISR (TIMER1_OVF_vect) // прерывание по таймеру, генерируемое каждую секунду
{ 
timer_seconds++ ; //инкремент переменной каждую секунду
if (timer_seconds > 59){timer_seconds = 0;}
}

// ________________ конец скетча, дальше можно не копировать _____________________




/*
1.08.1 Edit by Arezus 16.02.2019
  - При выборе метода индикации сразу происходит демонстрация режима
  - При уровне тревоги 0 - порог отключен.
  - Писк заменен на щелчки
  - Альтернативное чтение напряжения батареи
  - Индикация заряда в процентах


ChangeLog by tekagi:

1.08    12.01.2019
  -подрихтовано форматирование
  -выброшены неиспользуемые переменные
  -вернул старый график (можно включить вместо нового в пользовательском меню)
  -мелкие багфиксы
  -выброшен отдельный режим длительного замера (показания выводятся на главный экран)
  -если в разностном замере результат отрицательный - теперь выводится 0, а не отрицательное значение

1.07.9    01.01.2019
  -переписан график (ранее график отобржал увеличение кол-ва импульсов над предыдущим временным интервалом, сейчас показывает усреднённое значение за выбранный интервал, масштабируя по максимальному значению за весь отображаемый на экране период)

1.07.8
  -добавлено управление вибросигналом из меню

1.07.7         19.06.2018
  -фикс учёта времени (переведено с миллис на таймер1, код взят из примера, выложенного dimax)
  -сигнал тревоги сделан прерывистым

1.07.6      15.06.2018
  -начато добавление вибро

1.07.5        10.06.2018
  -мелкие изменения в графике: подкорректированы значки батарейки и аварийного сигнала (в батарейке значение напряжения было сдвинуто на пару пикселов, а колокольчик аварии перекрывался цифрами при повышении фона свыше 100мкР/ч);

1.07.4      15.05.2018
  -исправлена лишняя секунда в режиме бета замера и немного изменена обработка тревоги первого уровня;

1.07.3      28.04.2018
  -изменено содержание экранов между бета замерами. В промежуточной 1.07.2 сделал на стандартных функциях вывода библиотеки экрана, на двух экранах съело 12% оперативки. Пришлось переписать в виде картинки, попутно убрав вывод текста с начальной заставки и внеся его в картинку заставки.

1.07.1        25.04.2018
  -добавлен мелкий шрифт, русифицированы меню;

1.07          16.04.2018
  -начато добавление русского языка в интерфейсе. Спасибо kaktuc за русский шрифт к библиотеке и arduinec за функцию перекодирования выводимого на дисплей текста;
  -заменён дефайн "ADC" на "ADC_value", в новых версиях ArduinoIDE из-за этого возникала ошибка компилляции;

1.064         15.04.2018
  -добавлена возможность использования ArduinoUNO или голого камня atmega328p в DIP корпусе. Для переключения раскомментировать #define UNO в начале скетча, это переключит чтение высокого напряжения с делителя с пина A6 на A5;
  -добавлено переключение состояния подсветки при удержании ">>"
  
1.063.7       15.04.2018
  -попытка переписать обработку клавиш (вынесено в отдельную функцию);
  -выключен выход в системное меню из функций длительного и разностного замеров (оставлен только из основного режима "поиск");

1.063.6       25.03.2018
  -пофиксены кракозяблы при выводе "ANALIZ" в начале длительного замера;

1.063.5       14.01.18
  -пофиксена некорректная запись в еепром времени учёта дозы (писалось только 2 байта из четырёх);
  -добавлено преобразование микрорентген/час в миллирентгены/час в режиме поиска и длительного замера при фоне свыше 1000;

  
1.063.4       13.01.18
  -добавлена возможность включать индикацию светодиодом и бузером независимо друг от друга;

  
1.063.3 и ниже    12.11.2017
  -добавлена возможность выбрать активный или пассивный бузер;
  -пофиксен учёт фона во время нахождения в меню (при выходе из меню был скачок фона, поскольку в функции меню не было вызова poisk_f();   arduino.ru/forum/proekty/delaem-dozimetr?page=17#comment-320398   );
  -добавил режим непрерывной аварийной сигнализации при превышении первого порога, длительность сигнала настраивается в дефайне;
  -пофиксен серьёзный баг в режиме разностного замера (счёт импульсов начинался не с нажатия кнопки "ОК" при запуске второго цикла измерения, а сразу после окончания первого измерения, в результате разностный результат сильно завышался);
  -пофиксен паразитный сигнал при значении "shet = 0;"   arduino.ru/forum/proekty/delaem-dozimetr?page=16#comment-318736  ;

  P.S. Спасибо ImaSoft за подсказки и готовые кусочки кода.

*/

 

alexadresat
alexadresat аватар
Offline
Зарегистрирован: 22.02.2017
Arezus -  протестировал Вашу редакцию, мне понравилось, акромя щелчков.
1.08.1 Edit by Arezus 16.02.2019
  - При выборе метода индикации сразу происходит демонстрация режима       V
  - При уровне тревоги 0 - порог отключен.                                                      V
  - Писк заменен на щелчки                                                                  писк както привычнее
  - Альтернативное чтение напряжения батареи                                               V
  - Индикация заряда в процентах                                                                   V
Arezus
Arezus аватар
Offline
Зарегистрирован: 26.06.2013

Спасибо, приятно) По щелчкам — хотел классические щелчки получить, как на старых дозиметрах типа CDV-700, где звук напрямую на пьезодинамик шел, без генератора частоты. Конечно, они не похожи, но хоть как-то ближе стали.

Мне кажется, что отключение порога и батарею в процентах на главном экране можно включить в основную прошивку, индикация тоже не много памяти кушает, тк аналогичный код уже есть в листинге. А для точного напряжения батареи остается отображение в меню в Вольтах.

По поводу звуков вспомнил, я как-то в самолете включил Припять 20.03 с включенным писком, на бодрый перелив в 400-450 мкР по гамме ко мне подошла швейцарская стюардесса и миленько поинтересовалась «что за хрень у меня трещит как заведенная». По глазам видел, что понимает, что таможня не пропустила бычто-то опастное, но все равно очковала. Потом разговорились, объяснил, спросил как им живется с таким фоном, сказала что их пару раз в год ссаживают на регистрацию чтобы не светились в темноте и если захотят детей, то не менее чем за пол года до зачатия уходят на землю в аэропорты работать на регистрации и тп.

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Arezus пишет:
Мне кажется, что отключение порога и батарею в процентах на главном экране можно включить в основную прошивку, индикация тоже не много памяти кушает, тк аналогичный код уже есть в листинге. А для точного напряжения батареи остается отображение в меню в Вольтах.

Тогда уж лучше графически, на заполнение символа батарейки. Кстати, о птичках. На задворках блуждает мысль сделать автовыключение при разряде,  но простым SLEEP_MODE_PWR_DOWN здесь не отделаешься, нужно изменять схему, добавляя ключ на полевике и кой-какую обвязку. Стоит усложнять? 

Arezus
Arezus аватар
Offline
Зарегистрирован: 26.06.2013

Tekagi, графическое представление менее информативно, при красивой пропорциональной батарейке там получится 10-15 градаций, чистое напряжение в вольтах может быть вполне читаемо людям, близким к электронике, но практика показывает, что в эту ветку приходят и те, кто просто хочет собрать устройство и не разбираться «в этом всем вашем электрическом», а проценты — они везде, даже девочка с длинными ногтями поймет, что 100 — хорошо, а 0% - все, сливайте воду. 

По поводу ввода в сон — идея нормальная, но думаю, что усложнять не стоит, практически все используют батареи с защитой, я поставил контроллер заряда с защитой, а кто не догадался сделать ни того ни другого — сам себе злобный буратино, получит убитый аккум. Как вариант можно добавить уведомление длительностью в секунду тем же сигналом, что и выбран для индикации, что осталось 5-10%, при этом выключить фонарик и подсветку. Не заблокировать, а именно выключить, если человек забыл на столе дозиметр с включенными потребителями, то такой ход даст еще пару часов жизни в режиме измерений. Если фонарик реально нужен, то пользователь его включит обратно, но будет в курсе ограничения ресурса.

alexadresat
alexadresat аватар
Offline
Зарегистрирован: 22.02.2017

Я тоже за то чтоб была какая-то сигнализация разряда. Можно еще чтоб при разряде моргала надпись в батарее(где проценты заряда).

Сусемьбек
Offline
Зарегистрирован: 08.02.2019

доброго вечера всем.

подскажите пожалуйста можно ли таким хитровывернутым способом пикать и включать светодиод при регистрации частицы? точнее скетч опробован и работает. но вот допустимо ли так извращаться с динамическими переменными. цель - избавиться от задержки _delay_us в программе. и заменить на микрос

то что хотел выразить в скетче, вроде подробно расписал в комментариях

//  pulse_counter счетчик частиц
//PIK_counter для сохранения текущего значения
if(pulse_counter!=PIK_counter)  

{
  peak_2(); //функция для пиканья
}

}// конец лупа

//проверено работает предел такого пика 30 имп сек выше 30 имп/ сек включать пищалку постоянно
//но придется добавть в меню режим отключения пищалки или регулировать громкость аналог врайт
void peak_2()  
{
  PIK_counter=pulse_counter; // сравниваем значения переменных
  
  static uint16_t TIME_ON_PEAK= 100; // нужно вынести в глобальные волатиле от величины зависит громкость
   static uint16_t TIME_ON_LED= 10000; // время горения светодиодна
 /* если такой фикус не сработает переписать на простых флагах
  но фикус сработал и работает нормально
  конечно есть куча вариантов как зафиксировать время 
  хотя бы так

if(pulse_counter!=PIK_counter)  

{
  static uint32_t micros_peak =micros() // дальше вызов функции и микрос вроде зафиксирован
  peak_2(); //функция для пиканья
}
 */ 
//собственно вопрос из за этого извращения
const static uint32_t *micros_peak = new uint32_t( micros()); // запоминаем стартовое значиние микросекунд
//переменная константа так что значение получает 1 раз и держит до выхода из функции

if(micros() -*micros_peak>TIME_ON_PEAK)
{
 PORTD &=~(1<<5); //если прошо заданное время выключаем пищалку
} 
else
{
 PORTD |=(1<<5); // если время выключение не пришло держим пищалку во включенном состоянии
}

 if(micros() -*micros_peak>TIME_ON_LED)
{
 PORTC &=~(1<<4); // гасим  индикаторный светодиод 
}  
 else
 {
  PORTC |=(1 << 4); // включаем светодиод
 }
   ++y;
  // Serial.println(y);
   delete micros_peak; // освобождаем переменную с стартовым значением микросекунд

  
}

 

Сусемьбек
Offline
Зарегистрирован: 08.02.2019

tekagi пишет:

Arezus пишет:
Мне кажется, что отключение порога и батарею в процентах на главном экране можно включить в основную прошивку, индикация тоже не много памяти кушает, тк аналогичный код уже есть в листинге. А для точного напряжения батареи остается отображение в меню в Вольтах.

Тогда уж лучше графически, на заполнение символа батарейки. Кстати, о птичках. На задворках блуждает мысль сделать автовыключение при разряде,  но простым SLEEP_MODE_PWR_DOWN здесь не отделаешься, нужно изменять схему, добавляя ключ на полевике и кой-какую обвязку. Стоит усложнять? 

у меня была тема на эту тему на Амперке. так можно?

http://forum.amperka.ru/threads/%D0%9F%D0%B5%D1%81%D0%BE%D1%87%D0%BD%D0%B8%D1%86%D0%B0.17585/page-2

только резистор R2 поставить после диода.

(сорри за грамотность, у меня нет автопроверки а печатаю очень быстро слепым методом и на ошибки внимания не обращаю((()

 

blokerun2
Offline
Зарегистрирован: 27.01.2019

Иногда , когда на индикаторе частичка засчитана, звуковая индикация при этом отсутствует. Т.е. бывают "пропуски" по звуку, хотя счетчик работает.

blokerun2
Offline
Зарегистрирован: 27.01.2019

Таки добил преобразователь! Взял такую же гантельку, еще была одна у меня. Первичку намотал 2,5 витка проводом 0,8 мм (был 0,5). Ограничивающий резистор 10 Ом. Выдает 410 В, накачка 5, скорость 420. На пределе правда, но работает.

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Просядет напряжение питания и каюк. В другом причину искать надо... Резисторы в цепи затвора попробовать заменить, транзистор, сердечник другого типа, форму импульса глянуть.

По звуку - но обращал внимания. Светодиод отрабатывает, просто пика нет? Показания на дисплее могут меняться и без прилёта частицы, там же среднее считается.

blokerun2
Offline
Зарегистрирован: 27.01.2019

tekagi пишет:

Просядет напряжение питания и каюк. В другом причину искать надо... Резисторы в цепи затвора попробовать заменить, транзистор, сердечник другого типа, форму импульса глянуть.

По звуку - но обращал внимания. Светодиод отрабатывает, просто пика нет? Показания на дисплее могут меняться и без прилёта частицы, там же среднее считается.

tekagi спасибо! Буду начинать сегодня пробовать с резисторов затвора. На счет пропуска звука. Когда ставлю режим подсчета бета, там хорошо видно, что число увеличивается на единицу после регистрации каждой частички. Но бывает что счетчик увеличился а бузер не пикнул. Пробовал параллельно ограничивающему резистору счетчика ставить пьезик, чтобы слышен был каждый разряд. Так вот бывает что пьезик щелкнул, на индикаторе число увеличилось на единицу а бузер штатный не пикнул.

Dark-Dante
Offline
Зарегистрирован: 09.01.2018

Текаги, баг со звуком был раньше и вы его давно исправили, у меня с прошивки 1.06 этой проблемы больше нет.

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Dark-Dante, в том то и дело, что на фото прошивка из новых. Проверю, на старом вроде выведен светодиод с формирователя импульсов.

blokerun2, не нажимайте "Цитировать", пользуйтесь тегами [quоtе=Имя_пользователя] скопированный текст [/quоtе]

Сусемьбек
Offline
Зарегистрирован: 08.02.2019

всем доброго вечера. сам допинал скетч. может комуто пригодится. (эх потереть бы вышестоящие посты, там глюк все же вылазит с динамической переменной, не годится такой прием) 


//благодаря такому подходу можно раздельно регулировать время "пищания"
//+избавляемся от delay()
  // и время светодиода во включенном состоянии что бы глаз успевал заметить вспышку
   uint32_t  pulse_counter=0; //счетчик импульсов в прерывании
uint32_t PIK_counter =0;
const uint8_t  PEAK_PIN =5;
const uint8_t  BoTT_PIN =8; 
uint16_t y; 
bool fp=1;
//временные интервалы должны быть кратны 4, иначе непонятная хрень начинается
 uint32_t TIME_ON_PEAK= 40; //время пищалки во включенном состоянии в  микросекундах
 uint32_t TIME_ON_LED= 8000; // время вспышки светодиода в микросекундах 
//это значение всегда должно быть больше значания пищалки в включенном состоянии

void Particle_counting ()
{
 ++pulse_counter; // счетчик импульсов
}

{
  
} 


void setup()
{
    DDRD=~((1<<2)|(1<<3)); //        23 пины вход         DDRA&|= (1<<1)|(1<<4);
PORTD |=(1<<3);
attachInterrupt(1, Particle_counting, FALLING);
Serial.begin(9600);
  
pinMode   (PEAK_PIN,1);
pinMode  (BoTT_PIN,0);
}
void loop()
{
  
  static uint32_t micros_peak=0;
  static byte y =0;
  

 //Serial.println("fp");
 
  
  
if(pulse_counter!=PIK_counter)  
{   
 if(fp==1)
  {
  micros_peak = micros() ; 
  fp=0;
  }
 
if((micros() -micros_peak)>TIME_ON_PEAK )// &&(micros() -micros_peak)<TIME_ON_LED &&pulse_counter!=PIK_counter
  {    
   PORTD &=~(1<<5);    //как только превысили время пищания выключаем бузер
  } 
 else
 {
  PORTD |=(1<<5); //пока время (micros() -micros_peak) меньше TIME_ON_PEAK бузер пищит
 }
 
 if((micros() -micros_peak)>TIME_ON_LED)//&&pulse_counter!=PIK_counter
{    
   PORTC &=~(1<<4); // если привысили время включенного состояния выключаем светодиод
   PIK_counter=pulse_counter; // присваиваем счетчику для "пищания)" значение текущего значения счетчика импульсов
} 
 else
 {
   PORTC |=(1 << 4); //если не привысили значения включенного состояния светодиод включен
 }
  
}
   
 if (pulse_counter==PIK_counter)
 {
   fp=1;   
 }
  
}

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

можно детский вопрос? LED диод показывающий регистрацию частицы будет все время работать в импульсном режиме. возможно ли неставить токоограничительный резистор или хотябы меньщего чем положено номинала скажем 50-100 ом?

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Если запас ардуинок бесконечный - то да. Менять только после каждого включения напряжно...

Arezus
Arezus аватар
Offline
Зарегистрирован: 26.06.2013

А смысл его не ставить? Редко какой светик из 3-5 мм работает на токах выше 30 мА, ну поставь на 100-130 Ом, будут токи 30-40 мА, светику ничего, а для дуни — кризис уже. И это же не сигнал тревоги чтобы выжигать глаз при каждой частице. Надо реально мощный светодиод, поставь на 1Вт, через транзистор, базу или затвор кинь на управляющий от дуни. Но такой маневр имеет смысл только для фонарика. У меня с центре значка радиации стоит светик 3мм, красный прозрачный, работает на токе 15 мА, даже днем его видно. По схеме alexadresat уже стоит транзистор на фонарик, переназначь пин фонаря на регистрацию частиц и хоть ампер туда заливай. 

Muxi
Offline
Зарегистрирован: 22.01.2019

Добрый день, я развел плату сразу на 2 счетчика (2 прирывания, 2 цепочки резисторов, 2 транзистора)

Будет ли достаточно добавить attachInterrupt(1, Schet, FALLING); и сократить время geiger_counter_seconds до 20? как я понимаю остальное должно работать как надо? Если нет, прошу не серчать, сильно код еще не копал, прошу дать дельные советы по внесению изменений в код.

Спасибо!

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Заведено на третий пин ардуины? Кнопка меню перенесена? Возможно ещё придётся poisk_f() ковырять, я код наизусть не помню. Может и заведётся, там счёт привязан к geiger_counter_seconds.

Muxi
Offline
Зарегистрирован: 22.01.2019

tekagi пишет:

Заведено на третий пин ардуины? Кнопка меню перенесена? Возможно ещё придётся poisk_f() ковырять, я код наизусть не помню. Может и заведётся, там счёт привязан к geiger_counter_seconds.

Да, все остальное уже переделано, отладил сначало на одном датчике, потом добавил еще один. Первое определение фона проходит как надо, а дальше (после 20 секунд) фон начинает увеличиваться

 
tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Тогда ковыряйте poisk_f(), строки с 890 по 930. Детальнее на данный момент не подскажу.

Muxi
Offline
Зарегистрирован: 22.01.2019

tekagi, скажите, что за 40 в накопленной дозе?


doz_v = doz_v + fon / 100.0 / 40.0;

SergejEU
SergejEU аватар
Offline
Зарегистрирован: 05.11.2018

Samodelkin_YouTube пишет:

Друзья привет. Хочу вернуться к датчику СИ22Г.Чувствительность к излучению по Cs-137 = 228 имп/мкР  , а по Co-60 = 540 имп/мкР. Поэтому получаем разное время счета Cs-137 = 15.7 с. ,Co-60 = 6.7 с. 
Возникает вопрос сколько секунд должен длиться счет?

Есть два известных мне решения этой проблемы. Первое и самое простое. В качестве чувствительности GM датчика можно использовать взвешенное среднее по цезию и кобальту, т.е.

sensitivity = w1 * sensitivity[Cs-137] + w2 * sensitivity[Co-60],

где w1 и w2 лежат между нулём и единицей: 0w1;w21 и составляют в сумме единицу w1+w2=1 (w2=1-w1)Весовые коэффициенты w1, w2 подбираются экспериментальным путем или рассчитываются по графику: зависимость чувствительности датчика от энергии частиц.

Второе решение, использование компенсационного фильтра частиц. Для этого трубку GM заворачивают в тонкую свинцовую фольгу толщиной около 0,5 мм, а чувствительность выбирают обычно по источнику с максимальной энергией фотонов, т.е. в данном случае по Co-60. Так поступают многие производители дозиметров. Из недостатков такого фильтра - бета-излучение полностью или сильно задерживается фильтромПодробнее можно почитать здесь: От скорости счета к дозе. Ход с жесткостью и прочие нехорошие вещи или Photon energy compensationЯ видел ещё одну статью на похожую тематику, но не могу найти ее в сети.

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Muxi пишет:
tekagi, скажите, что за 40 в накопленной дозе?

doz_v = doz_v + fon / 100.0 / 40.0;

Этот кусок не трогал с оригинальных версий. Увы, Бодрый комменты к магическим числам не оставлял. Учитывая, что в ранних версиях было 36 - время счёта.

Я не совсем понимаю, зачем пересчитывать дозу с текущего фона, когда проще считать импульсы. Но до переделки руки пока не дошли.

Muxi
Offline
Зарегистрирован: 22.01.2019

Вот, собрал с большего, еще надо распечатать заглушки для микро-усб порта, придумать, что делать с местом от второго движкового выключателя.
Итак:
БЕЛРАД (Он же сосна анри-01) был приобретен за 3$ на барахолке ради корпуса и трубок ибо внутри даже КМ-ки все выкусили. Сейчас там установлено 2 датчика, каждый на своем порту, литий на 800mAh, контроллер заряда на базе tp4056 с защитой.
Собственно ДО и ПОСЛЕ

 

Мдя... фотки превратились в тыкву :(

Muxi
Offline
Зарегистрирован: 22.01.2019

tekagi пишет:
Я не совсем понимаю, зачем пересчитывать дозу с текущего фона, когда проще считать импульсы. Но до переделки руки пока не дошли.

Надеюсь на ваши руки :) Ибо магические числа уже плохо

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Похоже общими усилиями нашли ещё один косяк.

Версия 1.05: doz_v = doz_v + fon / 100.0 / 36.0; , счёт был 36 секунд.

Версия 1.062 doz_v = doz_v + fon / 100.0 / 40.0; , счёт использован 40секунд.

Учитывая, что вызов ведётся раз в секунду, логично предположить, что текущий уровень фона должен делиться на 3600, т.е. верхнее выражение верное. Видимо, при переходе к 40 секундам по ошибке было изменено и это значение. Но всё равно буду переделывать на другой алгоритм подсчёта.

Muxi
Offline
Зарегистрирован: 22.01.2019

Так 100/36 нифига не 3600

Arezus
Arezus аватар
Offline
Зарегистрирован: 26.06.2013

Muxi, я поставил два датчика в параллель, единственное отличие от оригинальной схемы -- в анодах токоокраничитель у каждой трубки свой, по 10.2 МОм, для подсчета только уменьшил вдвое время подсчета частиц, установил #define geiger_counter_seconds 20. Датчика два, теоретически количество посчитанных частиц вдвое больше. Можно или количество делить пополам для расчета или уменьшить время замера вдвое, чем увеличить скорость реакции. Фон считается верно, реакция на удобрения тоже адекватная.

Muxi
Offline
Зарегистрирован: 22.01.2019

Я тоже поставил 20, пока большие цифры моргают фон совпадает с другими дозиметрами, далее, с 10-11 мр/ч начинает доходить до 20-25.

Замечал, что иногда, без трубок, были фантомные регистрации, но они были очень редко... Завтра поробую добавить по питанию ардуинки 0.1мкФ, может ещё куда поставить, чтобы исключить наводки?

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

tekagi пишет:
doz_v = doz_v + fon / 100.0 / 36.0;

Muxi пишет:
Так 100/36 нифига не 3600

Muxi, в качестве оффтопа, задачка: почему код, приведённый ниже, выдаёт такие результаты?

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  int variable = 0;
  variable = 3600/100/36;  
  Serial.print("3600/100/36="); 
  Serial.println(variable);
  Serial.println(" ");  
  variable = 3600/3600; 
  Serial.print("3600/3600="); 
  Serial.println(variable);
  Serial.println(" ");    
  variable = 3600/(100/36); 
  Serial.print("3600/(100/36)="); 
  Serial.println(variable);
}
void loop() 
{

}

 

Muxi
Offline
Зарегистрирован: 22.01.2019

tekagi, угу, туплю, пора спать:)

Dark-Dante
Offline
Зарегистрирован: 09.01.2018

Так что получается, в текущих скетчах надо 40 заменить на 36?

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Да, только в этой строчке.

Muxi
Offline
Зарегистрирован: 22.01.2019

Нашел еще пару багов

1. После после того как заканчивает мигать уровень фона (большие цифры) и начинают мигать верхние, их значения на какое то время умножается на 2, я бы сказал даже не на 2, а на 2 и + еще что-то, потом через секунду - две все нормализуется.

2. Если уровень фона (большие цифры) превышает 100мр/ч цифры начинают выравниваться по левому краю дисплея

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

1. Есть такое. Пробуйте так:

				else if ((zam_poisk_counter < 254) && (zam_poisk_counter > geiger_counter_seconds))  //
					{
						fon_vr_poisk = 0;
						fon_vr254 = 0;
						for (int i = zam_poisk_counter; i > 0; i--) 

2. Это не баг, это фича :)

Muxi
Offline
Зарегистрирован: 22.01.2019

Скажите, как бы организовать замеры продуктов в Бк/кг? Режим бета отлично подходит для измерения, но в мкР/ч не информативно

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

На любительском приборе - никак. Увидеть, что образец на столько-то попугаев больше пустой кюветы можно, а точные измерения - увы.

Muxi
Offline
Зарегистрирован: 22.01.2019

Ну в той же сосне, рксб, Припяти есть же режимы (или формулы) по расчету объёмной активности, так почему бы тоже самое не организовать? В сосне даже подобие свинцового кубика сделано в рамках корпуса

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Свинцовый "кубик" должен быть не "в рамках корпуса". Пример домика можно посмотреть в радиометре "Бета", который с выносным слюдяным датчиком.
АрДос выдаёт количество импульсов за определённое время. Кто мешает взять "формулу" и посчитать? Вот только достоверность результата будет стремиться к нулю. Ибо не учитывает ни расстояние до датчика, ни геометрию источника и т.д.

bogdannin1
Offline
Зарегистрирован: 27.10.2018

Arezus пишет:

Muxi, я поставил два датчика в параллель, единственное отличие от оригинальной схемы -- в анодах токоокраничитель у каждой трубки свой, по 10.2 МОм, для подсчета только уменьшил вдвое время подсчета частиц, установил #define geiger_counter_seconds 20. Датчика два, теоретически количество посчитанных частиц вдвое больше. Можно или количество делить пополам для расчета или уменьшить время замера вдвое, чем увеличить скорость реакции. Фон считается верно, реакция на удобрения тоже адекватная.

А у Вас не осталось модельки корпуса? Уже вроде и свой сделал, но что-то всё не то....