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

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

Полистал тему, посмотрел видео Бодрого, почему у всех здесь есть значение, а у меня пусто?

На тот диод и выведена индикация тремя проводами от ТП4056, корпус, думаю- да, наш.

Скетч Ваш, последний, не менял ничего глобального, только меню переписал чуть, оттуда багов не появится.

Буду заниматся ПО, при наличии времени, так как не совсем доволен работой.

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

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

Кстати, при переходе с кода с сайта srukami на скетчи из темы рекомендации из поста #957 выполнили?

1707
Offline
Зарегистрирован: 08.02.2017

Dark-Dante
Сколько у Вас показывает в квартире, в частности после 10-20 минут работы?

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

12-14 мкР.

1707
Offline
Зарегистрирован: 08.02.2017

Мне так и не удалось побороть прибор, датчиков 3 штуки разных ставил, все равно пляшет около 30 :(

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

Так может так и есть? Возьмите контрольный промышленный дозиметр для сравнения.

Текаги, а не может у меня фиксировать одну частичку вместо двух из-за резистора на буззере в 300 Ом, читал в теме у кого-то было подобное, хотя если подумать, звучит дико не логично.

Я всегда стираю ИПРОМ при прошивке, но сделал так как в том посте и показания появились.

Остался один жесткий баг с экраном Замер 1 нажмите ОК, он все что нащёлкал на этом экране потом резко добавляет к показаниям. Читал, ранее такое было на экране замер 0, нажмите ОК. Проверьте у себя.

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

Были проблемы когда пытались поставить бузер вовсе без резистора. Отключите бузер в меню и проверьте по миганию светодиода. 

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

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

Что с отключенным, что с включенным буззером одиннаково. Без бузера частички считает даже без моргания светодиода, непонятно почему так. Не смотрели у себя как обстоят дела с экраном Замер 1?

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

Dark-Dante пишет:

Без бузера частички считает даже без моргания светодиода, непонятно почему так.

Иногда единичные пропуски индикации встречал, поскольку на счёт не влияет (только на индикацию) - особо не разбирался.

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

Вы не правильно меня поняли. Проходит замер 0, пишет Замер 1, нажми ОК, не нажимаем ОК 2-3 минуты ждем, можно и дольше и выходим в режим поиск и все что набралось за эти 2-3 минуты скопом добавляется к фону и чем дольше ждешь тем выше будет значение. У меня сразу в режим поиск выйти не получается, только через системное меню, но думаю косяк и у Вас должен быть.

А нельзя ли фонарик перенести на правую кнопку? Было бы логичнее, так как пока держишь левую либо запускается либо обнуляется анализ и опять жди 200 секунд.

А возможно что буззер не правильно индицирует прилет частицы и она действительно одна, а он щелкает дважды? 

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

Такое впечатление, что Вы брали для модификации скетч ниже 1.063 и багфиксы последних версий не добавляли. Все вышеописаные баги (и двойная индикация, и добавление данных к второму замеру) были давно пофиксены. Сотрите чип начисто и залейте прошивку из поста #1111, изменив только коэффициенты делителя и ацп, и пин замера высокого.

Перенести фонарик можно, но самостоятельно :) 

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

 

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

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

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

Зашил чистый скетч без правок. Так же присутствует выпадение в системное меню, счет одной частички при индикации двух и прибавление всего насчитанного при выходе в режим поиск.

Что выяснил- баг с прибавкой происходит только тогда если зайти из экрана замер 1, жми ОК в системное меню и выйти оттуда через выход. Если выйти просто правой кнопкой - бага нет. То есть баг всё таки имеется при определенной комбинации.

По счету- считает строго 2 пика как одну частицу, 3 уже как 2, 4 тоже как 2. Бывает и без какой либо индикации прибавляет частицу. Моя мысль, может он считает правильно, а просто индикация происходит как попало? Фон он ведь меряет нормально, как думаете?

По меню, при значении 7 я вобще не могу попасть в системное меню ниоткуда, методом тыка подобрал значение 5, с ним через раз попадаю в системное меню, через раз в режим замер 1, что тоже не очень. При значении 4 не могу зайти подтвердить замер 1, при значении 6 нет системного меню.

Еще, изначально было 110 импульсов накачки при фоновой нагрузке, чем дольше работает прибор, тем больше растёт количество импульсов, уже не менее 150. Это счётчик уставший немного?

Что думаете по всему этому? 

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

Dark-Dante пишет:

Что выяснил- баг с прибавкой происходит только тогда если зайти из экрана замер 1, жми ОК в системное меню и выйти оттуда через выход. Если выйти просто правой кнопкой - бага нет. То есть баг всё таки имеется при определенной комбинации.

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

Dark-Dante пишет:

По счету- считает строго 2 пика как одну частицу, 3 уже как 2, 4 тоже как 2. Бывает и без какой либо индикации прибавляет частицу.

Воспроизвести баг не могу, один импульс со счётчика - один сигнал бузером и светодиодом.

Dark-Dante пишет:

Еще, изначально было 110 импульсов накачки при фоновой нагрузке, чем дольше работает прибор, тем больше растёт количество импульсов, уже не менее 150. Это счётчик уставший немного?

Аккумулятор садится))

 

Обработку кнопок надо бы переписать, но времени не хватает...

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

А как отключить выход в оба меню в этих режимах, простыми правками не обойтись?

По счету, не может быть это из за космического для кт315 коэффициента передачи тока, вроде 280 был или около того? Есть смысл пробовать другой счётчик? 

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

Если есть ослик - посмотрите форму сигнала на коллекторе формирователя, но вряд ли проблема там. Если бы ардуинка фиксировала два входных импульса, то она не только индицировала бы их светодиодом, но и прибавляла к значению. Тут уж надо в функции void signa () делать вывод переменной shet в сериал монитор и наблюдать за результатами, может так удастся отловить баг. Кстати, и длительность loop не мешало бы померить, не могу понять, откуда появляются проблемы с определением удержания кнопки "Ок"...

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

К сожалению нет ни ТТЛ конвертора, для выводв чего либо в сериал, ни осцилла.

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

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

Кстати, пересмотрел видео Бодрого про новый режим, так у него такой же счёт как и у меня, так что с этим можно не морочить голову. С кнопками бы разобраться... Пробоват пинцетом замыкать напрямую выводы мк, ничего не меняется. 

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

Свежие баги. v1.063.7

/* ArDOs   v1.063.7_alpha 
***Дозиметр на Ардуино
***IDE Arduino 1.8.2
  ветка форума 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); //подключение дисплея
//LCD5110 myGLCD(12, 11, 10, A4, A5); //подключение дисплея
#define contrast 60 //контрастность дисплея
//#define buzzer_active //если используется активный бузер (со встроенным генератором), управляемый транзистором с выхода 6, то раскомментировать эту строчку, если пассивный (с усилителем или без) - оставить закомментированой.
#define first_alarm_duration 7000 //длительность сигнала тревоги при превышении первого аварийного порога в миллисекундах
byte treviga_1 = 30; //первая ступень тревоги
byte treviga_2 = 60; //вторая ступень тревоги
byte del_BUZZ = 7;//длительность одиночного сигнала
#define  ADC 163  //значение АЦП при котором 400В с учетом вашего делителя напряжения (0..255). Для значений делителя с сайта srukami ADC 163. (Тестовая версия tekagi  67)
#define k_delitel 576 //коефициент дельтеля напряжения, зависит от вашего делителя. Для значений делителя с сайта srukami k_delitel 576. (Тестовая версия tekagi  1395)
byte puls = 2; //тонкая настройка длинны импульса высоковольтного транса
byte scrin_GRAF = 1; //скорость построения графика в секундах
byte ind_ON = 1;  //0 - индикация выключена, 1 - включён бузер, 2 - светодиод, 3 - и бузер, и светодиод
bool podsvetka = 0; //подсветка
bool alarm_sound = 0; //флаг индикации превышения порога звуком
bool son_OK = 0; //разрешение или запрет сна
float opornoe = 1.10; //делить на opornoe/10
#define son_t 40 //время засыпания в секундах
#define save_DOZ 20 //как часто сохранять накопленную дозу например каждые 20мкР
byte beta_time = 5; //время замера бета излучения
//настройки //////////////конец
//служебные переменные
extern uint8_t SmallFont[], MediumNumbers[], TinyFont[];
extern uint8_t logo_bat[], logo_rag[], logo_tr[], gif_chast_1[], gif_chast_2[];
volatile int shet = 0;
unsigned long t_milis = 0, gr_milis = 0, lcd_milis = 0, toch_milis = 0, timer_mil = 0;
unsigned long alarm_milis = 0; //для отсчёта длительности сигнала тревоги по превышению порога
unsigned long spNAK_milis = 0, time_doza = 0, bat_mill = 0;
int hv_adc, hv_400, shet_s = 0, fon = 0, shet_gr = 0, shet_n = 0;
int speed_nakT = 0, speed_nak = 0, time_sh_l = 0, result;
byte MIN, DAY, HOUR; //для учёта времени дозы
byte MONTH; //для учёта времени дозы
int doza_vr = 0;
byte mass_p[84], mass_toch[201], m = 0, n_menu = 0, sys_menu = 0, mass_36[41];
byte val_kl = 0, val_ok = 0, menu = 0, zam_180p = 0, zam_36p = 0, gif_x = 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, stat_percent = 99.0;
bool tr = 0, poisk = 1, fonarik = 0, g_fl = 0, toch;
#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() {
  Serial.begin(115200);
  ACSR |= 1 << ACD; //отключаем компаратор
  //ADCSRA &= ~(1 << ADEN);  // отключаем АЦП,
  pinMode(3, INPUT_PULLUP); //кнопка
  pinMode(4, INPUT_PULLUP); //кнопка
  pinMode(7, INPUT_PULLUP); //кнопка
  DDRB |= (0 << 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 ();
  lcd_init();
  attachInterrupt(0, Schet, FALLING);//прерываниям пин 2
  DDRB |= (1 << 5); //пины на выход
  DDRD |= (1 << 5);
  DDRD |= (1 << 6);
  DDRD |= (1 << 6);//пин бузера
  nakachka();
}
//-------------------------------------------------------------
void loop() 
{
key_data = get_key();  // вызываем функцию определения нажатия кнопок, присваивая возвращаемое ней значение переменной, которую далее будем использовать в коде
  if (menu == 0) {
    if (key_data == key_pressed_left) { //нажатие <<<
	  key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      menu = 3;
      shet = 0; zam_180p = 0; fon = 0;
      stat_percent = 99.0;
	 } 
    if (key_data == key_holded_left) //нажатие <<< фонарик  
	{fonarik = !fonarik; 
	key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
	}   
    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_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
  }
  } 
  if (menu == 4) {
    if (key_data == key_pressed_right) { //нажатие >>>
	  key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      menu = 0;
      shet = 0;
      stat_percent = 99.0;
    }
  }
  if (fonarik == 0) { //фонарик
    PORTB &= ~(1 << 1);//пин фонаря
  } else if (fonarik == 1) {
    PORTB |= (1 << 1);//пин фонаря
  }
  if (podsvetka == 1) {
    PORTC &= ~(1 << 2); //A2 дисплей Light
  }
  if (podsvetka == 0) {
    PORTC |= (1 << 2); //A2 дисплей Light
  }
  if (millis() - lcd_milis >= 300) { //скорость отрисовки дисплея
    lcd_milis = millis();
    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сек
    }
    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 == 3) {
    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;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду		  
        son_OK = !son_OK;
      }
      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, 3); //держим значение в диапазоне 0...3
      }
      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;
        }
        if (puls > 200) {
          puls = 1;
        }
      }
      if (sys_menu == 2) {
		key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        time_doza = 0;//сброс накопленной дозы
        doz_v = 0;//сброс накопленной дозы
        eeprom_wrD ();
        myGLCD.clrScr();
        myGLCD.setFont(SmallFont);
        myGLCD.print("SBROS OK", 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;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        son_OK = !son_OK;
      }
      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, 3); //держим значение в диапазоне 0...3
      }
      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;
        }
        if (opornoe > 1.20) {
          opornoe = 0.98;
        }
      }
      if (sys_menu == 1) {
	  	key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        puls--;
        if (puls < 1) {
          puls = 200;
        }
        if (puls > 200) {
          puls = 1;
        }
      }
      if (sys_menu == 2) {
	  	key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        time_doza = 0;//сброс накопленной дозы
        doz_v = 0;//сброс накопленной дозы
        eeprom_wrD ();
        myGLCD.clrScr();
        myGLCD.setFont(SmallFont);
        myGLCD.print("SBROS OK", 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 (!tr && alarm_sound) // если фон ниже порога тревоги, но сигнал тревоги ещё не выключен
  {
res_first_alarm(); //сбрасываем сигнал тревоги
  }
}
//------------------------------------------------------------------------------------------------------------------
void gif_nabor() {
  myGLCD.drawLine(0, 24, 84, 24); myGLCD.drawLine(0, 38, 84, 38);
  for (int i = 83 - zam_180p * 0.47; i < 84; i++) {
    myGLCD.drawLine(i, 24, i, 38);
  }
  g_fl = !g_fl;
  if (g_fl == 0) {
    myGLCD.drawBitmap(gif_x, 27, gif_chast_1, 8, 8);
  } else {
    myGLCD.drawBitmap(gif_x, 27, gif_chast_2, 8, 8);
  }
  myGLCD.setFont(SmallFont);
  if (zam_180p < 200) {
    gif_x = gif_x + 1;
    if (gif_x >= 83 - zam_180p * 0.47) {
      gif_x = 0;
    }
    myGLCD.print("ANALIZ", CENTER, 40);
  }
  else if (zam_180p >= 200) {
    myGLCD.print("OBNOVLENIE", CENTER, 40);
  }
}
//--------------------------------------------------------------
void zamer_200s() 
{
  myGLCD.clrScr();
  myGLCD.setFont(SmallFont);
  myGLCD.print("%", 20, 0); myGLCD.printNumF(stat_percent, 1, 26, 0);
  myGLCD.setFont(MediumNumbers);
      if (alarm_sound)  //сбрасываем сигнал тревоги первого уровня, если активен
    {
       res_first_alarm(); //сбрасываем сигнал тревоги 
    }
  if (fon > 0) {
    if (fon >= 1000) {
      myGLCD.printNumF((float(fon)/1000), 2, LEFT, 7);
        myGLCD.setFont(SmallFont); myGLCD.print("mR/h", RIGHT, 12);
    }
    if (fon < 1000) {
      myGLCD.printNumI(fon, CENTER, 7);
      myGLCD.setFont(SmallFont); myGLCD.print("uR/h", RIGHT, 12);
    }
  }

  gif_nabor();
  battery();
  myGLCD.update();
  if (millis() - toch_milis >= 1000) {
    toch_milis = millis();
    for (int i = 0; i < 200; i++) { //сдвигаем
      mass_toch[i] = mass_toch[i + 1];
    }
    mass_toch[199] = shet;
    shet = 0;
    if (zam_180p < 200) { //первый набор массива
      zam_180p++;
      int fon_vr1 = 0;
      for (int i = 200 - zam_180p; i < 200; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 * (40.0 / zam_180p);
    }
    if (zam_180p >= 200) { //набор массива
      int fon_vr1 = 0;
      for (int i = 0; i < 200; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 / 5;
    }
    if (zam_180p <= 36) {
      stat_percent = stat_percent - 2.0;
    }
    if (zam_180p > 36 && zam_180p <= 72) {
      stat_percent = stat_percent - 0.3;
    }
    if (zam_180p > 72 && zam_180p <= 100) {
      stat_percent = stat_percent - 0.2;
    }
    if (zam_180p > 100 && zam_180p <= 200) {
      stat_percent = stat_percent - 0.1;
    }
    if (stat_percent < 5) {
      stat_percent = 5.0;
    }
  }
}
//-------------------------------------------------------------------------------------------------------
void lcd_poisk() {//вывод на дисплей режима поиск
  if (shet < treviga_1 && fon < treviga_1) {//проверяем тревогу
    tr = 0;
  }
  if (shet > treviga_1 || fon > treviga_1) {//проверяем тревогу
    check_alarm_signal(); // устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
    tr = 1;
  }
  myGLCD.clrScr();
  myGLCD.setFont(SmallFont);
  if (tr == 1) { //опасно
    myGLCD.drawBitmap(0, 0, logo_tr, 24, 8);
  }
  myGLCD.print("%", 20, 0); myGLCD.printNumF(100 - (zam_36p * 2.0), 1, 26, 0);
  myGLCD.setFont(MediumNumbers);
  if (fon > 0) {
    if (fon >= 1000) {
      myGLCD.printNumF((float(fon)/1000), 2, LEFT, 7);
        myGLCD.setFont(SmallFont); myGLCD.print("mR/h", RIGHT, 12);
    }
    if (fon < 1000) {
      myGLCD.printNumI(fon, CENTER, 7);
      myGLCD.setFont(SmallFont); myGLCD.print("uR/h", RIGHT, 12);
    }
  }
  time_d ();
  myGLCD.setFont(TinyFont);
  ind_doze_time();	//вывод времени накопления дозы на дисплей	  
  myGLCD.setFont(SmallFont);
  if (doz_v < 1000) {
    myGLCD.printNumF(doz_v, 1, 41, 24); myGLCD.print("uR", RIGHT, 24);
  }
  if (doz_v >= 1000) {
    myGLCD.printNumF(doz_v / 1000.0, 2, 41, 24); myGLCD.print("mR", RIGHT, 24);
  }
  myGLCD.drawLine(0, 32, 83, 32);//верхняя
  battery();
  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(TinyFont);
  myGLCD.print("OPASN.1", 0, 0); myGLCD.printNumI(treviga_1, CENTER, 0); myGLCD.print("uR/h", RIGHT, 0);
  myGLCD.print("OPASN.2", 0, 6); myGLCD.printNumI(treviga_2, CENTER, 6); myGLCD.print("uR/h", RIGHT, 6);
  myGLCD.print("PODSV.", 0, 12); myGLCD.printNumI(podsvetka, CENTER, 12);
  myGLCD.print("------", 0, 18); myGLCD.printNumI(son_OK, CENTER, 18); myGLCD.print("on/off", RIGHT, 18);//usr
  myGLCD.print("POISK.", 0, 24); myGLCD.printNumI(scrin_GRAF, CENTER, 24);
  myGLCD.print("BUZ/LED", 0, 30); //пункт меню выбора индикации частиц
  switch (ind_ON)
	{
	case 0:
		myGLCD.print("off/off", RIGHT, 30); //индикация выключена
		break;	
	case 1:
		myGLCD.print("on/off", RIGHT, 30); //индикация звуком
		break; 	
	case 2:
		myGLCD.print("off/on", RIGHT, 30); //индикация светом
		break;	
	case 3:
		myGLCD.print("on/on", RIGHT, 30); //индикация звуком и светом
		break; 
		default:
		myGLCD.print("err", RIGHT, 30); //	если значение не равно 1,2,3 или 0 - выводим ошибку	
	} 
  myGLCD.print("OUT", 0, 36);
  myGLCD.print("SAVE", 0, 42);
  myGLCD.print(">", 30, n_menu * 6);
  myGLCD.update();
}
//----------------------------------------------------------------------------------------------------------------------
void lcd_sys() { //вывод на дисплей меню
  VCC_read();
  speed_nakachka ();//скорость накачки имлульсы/сек
  myGLCD.clrScr();
  myGLCD.setFont(TinyFont);
  myGLCD.print("OPORN", 0, 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("NAKAH", 0, 6); myGLCD.printNumI(puls, CENTER, 6); myGLCD.printNumI(hv_400, RIGHT, 6);
  myGLCD.print("DOZA", 0, 12); myGLCD.print(">>", CENTER, 12); myGLCD.print("SBROS", RIGHT, 12);
  myGLCD.print("OUT", 0, 18);
  myGLCD.print("SAVE", 0, 24);
  myGLCD.print("BETA", 0, 30); myGLCD.printNumI(beta_time, CENTER, 30); myGLCD.print("MIN", RIGHT, 30);
  myGLCD.print(">", 30, sys_menu * 6);
  myGLCD.print("SPEED N", 0, 40); myGLCD.printNumI(speed_nak, CENTER, 40); myGLCD.print("imp/sek", RIGHT, 40);
  myGLCD.update();
}
//---------------------------------------------------------------------------------------------------------------------
void zamer_beta() {// замер бета или продуктов

  if (gotovo == 0) {
/*  
//этот кусок кода вынесен в loop, поскольку из-за вызова функции бета замера с частотой обновления дисплея не отрабатывается считывание состояния кнопок внутри функции
    if (key_data == key_pressed_ok) { //нажатие 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; //обнуляем счёт            
      }
    }
*/	
    if (alarm_sound)  //если активен сигнал тревоги первого уровня
    {
       res_first_alarm(); //сбрасываем сигнал тревоги
    }
    myGLCD.clrScr();
    myGLCD.setFont(SmallFont);
    myGLCD.print("Zamer ", 20, 10); myGLCD.printNumI(bet_z, 55, 10);
    myGLCD.print("nagmi OK", CENTER, 20);
    myGLCD.update();
  }  
  if (gotovo == 1) {
    timer_soft();
    byte otsup = 0;
    if (minute > 9) {
      otsup = 5;
    }
    myGLCD.clrScr();
    battery();
    myGLCD.setFont(TinyFont);
    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("time", 23 + otsup, 0);
    myGLCD.drawLine(0, 8, 83, 8);
    myGLCD.setFont(SmallFont);
    myGLCD.drawLine(40, 8, 40, 28);
    myGLCD.print("Zamer0", LEFT, 10); myGLCD.print("Zamer1", 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("Idet zamer", CENTER, 30); myGLCD.printNumI(bet_z, RIGHT, 30);
      myGLCD.printNumI(bet_r, CENTER, 38);
    }
    if (bet_z == 2) {
      myGLCD.print("Rezultat", CENTER, 30);
      myGLCD.printNumI(bet_r, CENTER, 38); myGLCD.print("mkR/h", 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);
    }
  }
  if (key_data == key_pressed_right) { //нажатие >>>
    key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    menu = 0;
    shet = 0; fon = 0; zam_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
  }
}
//-------------------------------------------------------------------------------------------------------------
void poisk_f() {//режим поиска
  if (poisk == 1) {
    if (millis() - gr_milis >= scrin_GRAF * 1000) { //счет для графика
      gr_milis = millis();
      val_ok = 0;//сброс удержания системного меню
      shet_gr = shet - shet_n;
      if (shet_gr < 0) {
        shet_gr = 1;
      }
      mass_p[m] = shet_gr ;
      shet_n = shet;
      if (m < 82) {
        m++;
      }
      if (m == 82) {
        for (int i = 0; i < 83; i++) {
          mass_p[i] = mass_p[i + 1];
        }
        mass_p[82] = shet_gr;
      }
    }
    if (millis() - toch_milis >= 1000) {
      toch_milis = millis();
      for (int i = 0; i < 40; i++) { //сдвигаем
        mass_36[i] = mass_36[i + 1];
      }
      mass_36[40] = shet;
      if (zam_36p < 40) { //первый набор массива
        zam_36p++;
        fon = fon + shet;
      }
      if (zam_36p >= 40) { //набор массива
        int fon_vr1 = 0;
        for (int i = 0; i < 40; i++) {
          fon_vr1 = fon_vr1 + mass_36[i];
        }
        fon = fon_vr1;
      }
      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;
      }
    }
  }
}
//----------------------------------------------------------------------------------------------------------------
void signa () { //индикация каждой частички звуком светом
  shet_s = shet;  
    if (alarm_sound) //если поднят флаг аварийного сигнала
  {
  #ifdef buzzer_active //если задефайнен активный бузер
    PORTD |= (1 << 6); // включаем непрерывный сигнал тревоги
  #else //пассивный
  tone (6, 1300); //генерим писк с частотой 1300Гц (значение можно изменить на своё) на пине 6
  #endif
    if ((millis() - alarm_milis) > first_alarm_duration) // проверяем, не истекло ли время подачи сигнала тревоги
    {
    #ifdef buzzer_active   //если задефайнен активный бузер
    PORTD &= ~(1 << 6); // выключаем непрерывный сигнал тревоги
    #else //пассивный бузер
    noTone (6); //выключаем писк на 6й ноге
    #endif 
    alarm_sound = 0; // сбрасываем флаг сигнала тревоги
    }   
    PORTB |= (1 << 5); //включаем светодиод
    delay(del_BUZZ);
    PORTB &= ~(1 << 5);//выключаем светодиод
  }
  else //если флаг сигнала тревоги не поднят, генерим одиночные сигналы, озвучивающие пойманные частицы  
    {
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,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,1000,30); //генерим писк 1000Гц 30миллисекунд на 6й ноге
					delay(del_BUZZ);//длительность одиночного сигнала
					PORTB &= ~(1 << 5);//выключаем светодиод
				}
			#endif 
			break; 
	} 
    }

  //generator();//накачка по обратной связи с АЦП
}
//-------------------------------------------------------------------------------------------------
void Schet() { //прерывание от счетчика на пин 2
  shet++;
}
//-------------------------------------------------------------------------------------------------
void generator() {//накачка по обратной связи с АЦП
  hv_adc  = Read_HV();
  if (hv_adc < ADC) { //Значение АЦП при котором на выходе 400В
    int c = puls;
    PORTD |= (1 << 5); //пин накачки
    while (c > 0) {
      asm("nop");
      c--;
    }
    PORTD &= ~(1 << 5);//пин накачки
    speed_nakT++;
  }
}
//--------------------------------------------------------------------------------------------------
byte Read_HV () {
  ADCSRA = 0b11100111;
  ADMUX = 0b11100110;//выбор внутреннего опорного 1,1В и А6
  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(TinyFont);
  myGLCD.printNumF(VCC, 2, 63, 2);
}
//----------------------------------------------------------------------------------------------------
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;
}
//----------------------------------------------------------------------------------------------------
void lcd_init() {
  myGLCD.InitLCD();
  myGLCD.setContrast(contrast);
  myGLCD.clrScr();
  myGLCD.drawBitmap(0, 0, logo_rag, 84, 48);
  myGLCD.setFont(SmallFont);
  myGLCD.print("ArdDos", CENTER, 32);
  myGLCD.print("v1.063.7_a", CENTER, 40);
  myGLCD.update();
  _delay_ms(1000);
}
//----------------------------------------------------------------------------------------------------
void eeprom_wrS () { //запись настроек в память
  EEPROM.write(0, 222);
  EEPROM.write(1, treviga_1);
  EEPROM.write(2, podsvetka);
  EEPROM.write(3, son_OK);
  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(SmallFont);
  myGLCD.print("Save OK", CENTER, 24);
  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);
    son_OK = 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;
//  HOUR = time_doza / 3600;
//  MIN = (time_doza / 60) % 60;
}
//------------------------------------------------------------------------------------------------------
void timer_soft() {
  if (millis() - timer_mil >= 1000) {
    timer_mil = millis();
    sek++;
    toch = !toch;
    if (sek > 60) {
      sek = 0;
      minute++;
    }
  }
}
//------------------------------------------------------------------------------------------------------
void check_alarm_signal()  // устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
{
  if (!tr) // если счёт превысил аварийный порог, но флаг "tr" ещё не установлен
    {
    alarm_sound = 1; // поднимаем флаг аварийного сигнала
    alarm_milis = millis(); // запоминаем время начала тревоги
    }  
}
//------------------------------------------------------------------------------------------------------
void res_first_alarm() //подпрограмма выключения тревоги (ручного или по истечении таймаута)
  {
    alarm_sound = 0; // сбрасываем флаг звукового сигнала тревоги
   #ifdef buzzer_active //если задефайнен активный бузер
   PORTD &= ~(1 << 6); // выключаем бузер
   #else //пассивный бузер
   noTone(6);   //выключаем генерацию сигнала на 6й ноге
   #endif
  }
//------------------------------------------------------------------------------------------------------
void ind_doze_time() //вывод времени накопления дозы на дисплей
{
  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("d", 26, 26);
	}
  else
	{
    myGLCD.print("d", 23, 26);
	}	
  }
  else if (DAY) // если нет месяцев, но есть дни
		{
		myGLCD.printNumI(DAY, 0, 26);
		if (DAY > 9) 
		{
		myGLCD.print("d", 9, 26);
		}
		else
		{
		myGLCD.print("d", 5, 26);
		}
		myGLCD.printNumI(HOUR, 18, 26);
		if (HOUR > 9) 
		{
		myGLCD.print("h", 26, 26);
		}
		else 
		{
		myGLCD.print("h", 23, 26);
		}
		}
			else // если нет дней
			{
			myGLCD.printNumI(HOUR, 0, 26);
			if (HOUR > 9) 
			{
			myGLCD.print("h", 9, 26);
			}
			else
			{
			myGLCD.print("h", 5, 26);
			}
			myGLCD.printNumI(MIN, 18, 26);
			if (MIN > 9) 
			{
			myGLCD.print("m", 26, 26);
			}
			else
			{
			myGLCD.print("m", 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
}



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




/*

ChangeLog by tekagi:
1.063.7       16.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 за подсказки и готовые кусочки кода.

*/

-переписана обработка кнопок;

-вход в системное меню теперь возможен только из режима "поиск".

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

Спасибо,  Tekagi!  Постараюсь протестировать в ближайшие дни! Готов быть бета тестером новых версий) Заодно постараюсь сообразить как поменять местами кнопку фонарика.

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

Dark-Dante пишет:

... Заодно постараюсь сообразить как поменять местами кнопку фонарика.

Думаю, в этом уже нет смысла. Длительное и кратковременное нажатия сейчас распознаются раздельно, и при включении/выключении фонарика входа в режим длительного замера не происходит. Плюс фонарик включается только из режима "поиск". Хотя поменять кнопку фонарика сейчас довольно просто. Достаточно в строке:

 if (key_data == key_holded_left) //нажатие <<< фонарик 

вместо key_holded_left написать key_holded_right.  И в комментарии <<< на >>>.

Но я собираюсь на удержание кнопки ">>" повесить включение/выключение подсветки, так что изменение включения фонарика приведёт к путанице.

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

tekagi пишет:

...собираюсь на удержание кнопки ">>" повесить включение/выключение подсветки...

Собственно вот. Пусть будет v1.064:

/* ArDOs   v1.064
***Дозиметр на Ардуино
***IDE Arduino 1.8.2
  ветка форума 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); //подключение дисплея
//LCD5110 myGLCD(12, 11, 10, A4, A5); //подключение дисплея
#define contrast 60 //контрастность дисплея
//#define buzzer_active //если используется активный бузер (со встроенным генератором), управляемый транзистором с выхода 6, то раскомментировать эту строчку, если пассивный (с усилителем или без) - оставить закомментированой.
//#define UNO // если используется ArduinoUNO или плата на голой атмеге328 в корпусе DIP - раскомментируйте данную строчку. Это переключит чтение напряжения с делителя с ноги A6 на ногу A5.
#define first_alarm_duration 7000 //длительность сигнала тревоги при превышении первого аварийного порога в миллисекундах
byte treviga_1 = 30; //первая ступень тревоги
byte treviga_2 = 60; //вторая ступень тревоги
byte del_BUZZ = 7;//длительность одиночного сигнала
#define  ADC 163  //значение АЦП при котором 400В с учетом вашего делителя напряжения (0..255). Для значений делителя с сайта srukami ADC 163. (Тестовая версия tekagi  67)
#define k_delitel 576 //коефициент делителя напряжения, зависит от вашего делителя. Для значений делителя с сайта srukami k_delitel 576. (Тестовая версия tekagi  1395)
byte puls = 2; //тонкая настройка длинны импульса высоковольтного транса
byte scrin_GRAF = 1; //скорость построения графика в секундах
byte ind_ON = 1;  //0 - индикация выключена, 1 - включён бузер, 2 - светодиод, 3 - и бузер, и светодиод
bool podsvetka = 0; //подсветка
bool alarm_sound = 0; //флаг индикации превышения порога звуком
bool son_OK = 0; //разрешение или запрет сна
float opornoe = 1.10; //делить на opornoe/10
#define son_t 40 //время засыпания в секундах
#define save_DOZ 20 //как часто сохранять накопленную дозу например каждые 20мкР
byte beta_time = 5; //время замера бета излучения
//настройки //////////////конец
//служебные переменные
extern uint8_t SmallFont[], MediumNumbers[], TinyFont[];
extern uint8_t logo_bat[], logo_rag[], logo_tr[], gif_chast_1[], gif_chast_2[];
volatile int shet = 0;
unsigned long t_milis = 0, gr_milis = 0, lcd_milis = 0, toch_milis = 0, timer_mil = 0;
unsigned long alarm_milis = 0; //для отсчёта длительности сигнала тревоги по превышению порога
unsigned long spNAK_milis = 0, time_doza = 0, bat_mill = 0;
int hv_adc, hv_400, shet_s = 0, fon = 0, shet_gr = 0, shet_n = 0;
int speed_nakT = 0, speed_nak = 0, time_sh_l = 0, result;
byte MIN, DAY, HOUR, MONTH; //для учёта времени дозы
int doza_vr = 0;
byte mass_p[84], mass_toch[201], m = 0, n_menu = 0, sys_menu = 0, mass_36[41];
byte val_kl = 0, val_ok = 0, menu = 0, zam_180p = 0, zam_36p = 0, gif_x = 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, stat_percent = 99.0;
bool tr = 0, poisk = 1, fonarik = 0, g_fl = 0, toch;
#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() {
  //Serial.begin(115200);
  ACSR |= 1 << ACD; //отключаем компаратор
  //ADCSRA &= ~(1 << ADEN);  // отключаем АЦП,
  pinMode(3, INPUT_PULLUP); //кнопка
  pinMode(4, INPUT_PULLUP); //кнопка
  pinMode(7, INPUT_PULLUP); //кнопка
  DDRB |= (0 << 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 ();
  lcd_init();
  attachInterrupt(0, Schet, FALLING);//прерываниям пин 2
  DDRB |= (1 << 5); //пины на выход
  DDRD |= (1 << 5);
  DDRD |= (1 << 6);
  DDRD |= (1 << 6);//пин бузера
  nakachka();
}
//-------------------------------------------------------------
void loop() 
{
key_data = get_key();  // вызываем функцию определения нажатия кнопок, присваивая возвращаемое ней значение переменной, которую далее будем использовать в коде
  if (menu == 0) {
    if (key_data == key_pressed_left) { //нажатие <<<
	  key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      menu = 3;
      shet = 0; zam_180p = 0; fon = 0;
      stat_percent = 99.0;
	 } 
    if (key_data == key_holded_left) //нажатие <<< фонарик  
	{fonarik = !fonarik; 
	key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
	}  	
    if (key_data == key_holded_right) // удержание <<< подсветка
	 {
		key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду		  
        podsvetka = !podsvetka;
     }		
    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_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
  }
  } 
  if (menu == 4) {
    if (key_data == key_pressed_right) { //нажатие >>>
	  key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      menu = 0;
      shet = 0;
      stat_percent = 99.0;
    }
  }
  if (fonarik == 0) { //фонарик
    PORTB &= ~(1 << 1);//пин фонаря
  } else if (fonarik == 1) {
    PORTB |= (1 << 1);//пин фонаря
  }
  if (podsvetka == 1) {
    PORTC &= ~(1 << 2); //A2 дисплей Light
  }
  if (podsvetka == 0) {
    PORTC |= (1 << 2); //A2 дисплей Light
  }
  if (millis() - lcd_milis >= 300) { //скорость отрисовки дисплея
    lcd_milis = millis();
    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сек
    }
    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;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду		  
        son_OK = !son_OK;
      }
      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, 3); //держим значение в диапазоне 0...3
      }
      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;
        }
        if (puls > 200) {
          puls = 1;
        }
      }
      if (sys_menu == 2) {
		key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        time_doza = 0;//сброс накопленной дозы
        doz_v = 0;//сброс накопленной дозы
        eeprom_wrD ();
        myGLCD.clrScr();
        myGLCD.setFont(SmallFont);
        myGLCD.print("SBROS OK", 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;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        son_OK = !son_OK;
      }
      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, 3); //держим значение в диапазоне 0...3
      }
      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;
        }
        if (opornoe > 1.20) {
          opornoe = 0.98;
        }
      }
      if (sys_menu == 1) {
	  	key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        puls--;
        if (puls < 1) {
          puls = 200;
        }
        if (puls > 200) {
          puls = 1;
        }
      }
      if (sys_menu == 2) {
	  	key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        time_doza = 0;//сброс накопленной дозы
        doz_v = 0;//сброс накопленной дозы
        eeprom_wrD ();
        myGLCD.clrScr();
        myGLCD.setFont(SmallFont);
        myGLCD.print("SBROS OK", 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 (!tr && alarm_sound) // если фон ниже порога тревоги, но сигнал тревоги ещё не выключен
  {
res_first_alarm(); //сбрасываем сигнал тревоги
  }
}
//------------------------------------------------------------------------------------------------------------------
void gif_nabor() {
  myGLCD.drawLine(0, 24, 84, 24); myGLCD.drawLine(0, 38, 84, 38);
  for (int i = 83 - zam_180p * 0.47; i < 84; i++) {
    myGLCD.drawLine(i, 24, i, 38);
  }
  g_fl = !g_fl;
  if (g_fl == 0) {
    myGLCD.drawBitmap(gif_x, 27, gif_chast_1, 8, 8);
  } else {
    myGLCD.drawBitmap(gif_x, 27, gif_chast_2, 8, 8);
  }
  myGLCD.setFont(SmallFont);
  if (zam_180p < 200) {
    gif_x = gif_x + 1;
    if (gif_x >= 83 - zam_180p * 0.47) {
      gif_x = 0;
    }
    myGLCD.print("ANALIZ", CENTER, 40);
  }
  else if (zam_180p >= 200) {
    myGLCD.print("OBNOVLENIE", CENTER, 40);
  }
}
//--------------------------------------------------------------
void zamer_200s() 
{
  myGLCD.clrScr();
  myGLCD.setFont(SmallFont);
  myGLCD.print("%", 20, 0); myGLCD.printNumF(stat_percent, 1, 26, 0);
  myGLCD.setFont(MediumNumbers);
      if (alarm_sound)  //сбрасываем сигнал тревоги первого уровня, если активен
    {
       res_first_alarm(); //сбрасываем сигнал тревоги 
    }
  if (fon > 0) {
    if (fon >= 1000) {
      myGLCD.printNumF((float(fon)/1000), 2, LEFT, 7);
        myGLCD.setFont(SmallFont); myGLCD.print("mR/h", RIGHT, 12);
    }
    if (fon < 1000) {
      myGLCD.printNumI(fon, CENTER, 7);
      myGLCD.setFont(SmallFont); myGLCD.print("uR/h", RIGHT, 12);
    }
  }

  gif_nabor();
  battery();
  myGLCD.update();
  if (millis() - toch_milis >= 1000) {
    toch_milis = millis();
    for (int i = 0; i < 200; i++) { //сдвигаем
      mass_toch[i] = mass_toch[i + 1];
    }
    mass_toch[199] = shet;
    shet = 0;
    if (zam_180p < 200) { //первый набор массива
      zam_180p++;
      int fon_vr1 = 0;
      for (int i = 200 - zam_180p; i < 200; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 * (40.0 / zam_180p);
    }
    if (zam_180p >= 200) { //набор массива
      int fon_vr1 = 0;
      for (int i = 0; i < 200; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 / 5;
    }
    if (zam_180p <= 36) {
      stat_percent = stat_percent - 2.0;
    }
    if (zam_180p > 36 && zam_180p <= 72) {
      stat_percent = stat_percent - 0.3;
    }
    if (zam_180p > 72 && zam_180p <= 100) {
      stat_percent = stat_percent - 0.2;
    }
    if (zam_180p > 100 && zam_180p <= 200) {
      stat_percent = stat_percent - 0.1;
    }
    if (stat_percent < 5) {
      stat_percent = 5.0;
    }
  }
}
//-------------------------------------------------------------------------------------------------------
void lcd_poisk() {//вывод на дисплей режима поиск
  if (shet < treviga_1 && fon < treviga_1) {//проверяем тревогу
    tr = 0;
  }
  if (shet > treviga_1 || fon > treviga_1) {//проверяем тревогу
    check_alarm_signal(); // устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
    tr = 1;
  }
  myGLCD.clrScr();
  myGLCD.setFont(SmallFont);
  if (tr == 1) { //опасно
    myGLCD.drawBitmap(0, 0, logo_tr, 24, 8);
  }
  myGLCD.print("%", 20, 0); myGLCD.printNumF(100 - (zam_36p * 2.0), 1, 26, 0);
  myGLCD.setFont(MediumNumbers);
  if (fon > 0) {
    if (fon >= 1000) {
      myGLCD.printNumF((float(fon)/1000), 2, LEFT, 7);
        myGLCD.setFont(SmallFont); myGLCD.print("mR/h", RIGHT, 12);
    }
    if (fon < 1000) {
      myGLCD.printNumI(fon, CENTER, 7);
      myGLCD.setFont(SmallFont); myGLCD.print("uR/h", RIGHT, 12);
    }
  }
  time_d ();
  myGLCD.setFont(TinyFont);
  ind_doze_time();	//вывод времени накопления дозы на дисплей	  
  myGLCD.setFont(SmallFont);
  if (doz_v < 1000) {
    myGLCD.printNumF(doz_v, 1, 41, 24); myGLCD.print("uR", RIGHT, 24);
  }
  if (doz_v >= 1000) {
    myGLCD.printNumF(doz_v / 1000.0, 2, 41, 24); myGLCD.print("mR", RIGHT, 24);
  }
  myGLCD.drawLine(0, 32, 83, 32);//верхняя
  battery();
  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(TinyFont);
  myGLCD.print("OPASN.1", 0, 0); myGLCD.printNumI(treviga_1, CENTER, 0); myGLCD.print("uR/h", RIGHT, 0);
  myGLCD.print("OPASN.2", 0, 6); myGLCD.printNumI(treviga_2, CENTER, 6); myGLCD.print("uR/h", RIGHT, 6);
  myGLCD.print("PODSV.", 0, 12); myGLCD.printNumI(podsvetka, CENTER, 12);
  myGLCD.print("------", 0, 18); myGLCD.printNumI(son_OK, CENTER, 18); myGLCD.print("on/off", RIGHT, 18);//usr
  myGLCD.print("POISK.", 0, 24); myGLCD.printNumI(scrin_GRAF, CENTER, 24);
  myGLCD.print("BUZ/LED", 0, 30); //пункт меню выбора индикации частиц
  switch (ind_ON)
	{
	case 0:
		myGLCD.print("off/off", RIGHT, 30); //индикация выключена
		break;	
	case 1:
		myGLCD.print("on/off", RIGHT, 30); //индикация звуком
		break; 	
	case 2:
		myGLCD.print("off/on", RIGHT, 30); //индикация светом
		break;	
	case 3:
		myGLCD.print("on/on", RIGHT, 30); //индикация звуком и светом
		break; 
		default:
		myGLCD.print("err", RIGHT, 30); //	если значение не равно 1,2,3 или 0 - выводим ошибку	
	} 
  myGLCD.print("OUT", 0, 36);
  myGLCD.print("SAVE", 0, 42);
  myGLCD.print(">", 30, n_menu * 6);
  myGLCD.update();
}
//----------------------------------------------------------------------------------------------------------------------
void lcd_sys() { //вывод на дисплей меню
  VCC_read();
  speed_nakachka ();//скорость накачки имлульсы/сек
  myGLCD.clrScr();
  myGLCD.setFont(TinyFont);
  myGLCD.print("OPORN", 0, 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("NAKAH", 0, 6); myGLCD.printNumI(puls, CENTER, 6); myGLCD.printNumI(hv_400, RIGHT, 6);
  myGLCD.print("DOZA", 0, 12); myGLCD.print(">>", CENTER, 12); myGLCD.print("SBROS", RIGHT, 12);
  myGLCD.print("OUT", 0, 18);
  myGLCD.print("SAVE", 0, 24);
  myGLCD.print("BETA", 0, 30); myGLCD.printNumI(beta_time, CENTER, 30); myGLCD.print("MIN", RIGHT, 30);
  myGLCD.print(">", 30, sys_menu * 6);
  myGLCD.print("SPEED N", 0, 40); myGLCD.printNumI(speed_nak, CENTER, 40); myGLCD.print("imp/sek", RIGHT, 40);
  myGLCD.update();
}
//---------------------------------------------------------------------------------------------------------------------
void zamer_beta() {// замер бета или продуктов
  if (gotovo == 0) 
{
/*  
//этот кусок кода вынесен в loop, поскольку из-за вызова функции бета замера с частотой обновления дисплея не отрабатывается считывание состояния кнопок внутри функции
    if (key_data == key_pressed_ok) { //нажатие 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; //обнуляем счёт            
      }
    }
*/	
    if (alarm_sound)  //если активен сигнал тревоги первого уровня
    {
       res_first_alarm(); //сбрасываем сигнал тревоги
    }
    myGLCD.clrScr();
    myGLCD.setFont(SmallFont);
    myGLCD.print("Zamer ", 20, 10); myGLCD.printNumI(bet_z, 55, 10);
    myGLCD.print("nagmi OK", CENTER, 20);
    myGLCD.update();
  }  
  if (gotovo == 1) {
    timer_soft();
    byte otsup = 0;
    if (minute > 9) {
      otsup = 5;
    }
    myGLCD.clrScr();
    battery();
    myGLCD.setFont(TinyFont);
    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("time", 23 + otsup, 0);
    myGLCD.drawLine(0, 8, 83, 8);
    myGLCD.setFont(SmallFont);
    myGLCD.drawLine(40, 8, 40, 28);
    myGLCD.print("Zamer0", LEFT, 10); myGLCD.print("Zamer1", 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("Idet zamer", CENTER, 30); myGLCD.printNumI(bet_z, RIGHT, 30);
      myGLCD.printNumI(bet_r, CENTER, 38);
    }
    if (bet_z == 2) {
      myGLCD.print("Rezultat", CENTER, 30);
      myGLCD.printNumI(bet_r, CENTER, 38); myGLCD.print("mkR/h", 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);
    }
  }
  if (key_data == key_pressed_right) { //нажатие >>>
    key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    menu = 0;
    shet = 0; fon = 0; zam_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
  }
}
//-------------------------------------------------------------------------------------------------------------
void poisk_f() {//режим поиска
  if (poisk == 1) {
    if (millis() - gr_milis >= scrin_GRAF * 1000) { //счет для графика
      gr_milis = millis();
      val_ok = 0;//сброс удержания системного меню
      shet_gr = shet - shet_n;
      if (shet_gr < 0) {
        shet_gr = 1;
      }
      mass_p[m] = shet_gr ;
      shet_n = shet;
      if (m < 82) {
        m++;
      }
      if (m == 82) {
        for (int i = 0; i < 83; i++) {
          mass_p[i] = mass_p[i + 1];
        }
        mass_p[82] = shet_gr;
      }
    }
    if (millis() - toch_milis >= 1000) {
      toch_milis = millis();
      for (int i = 0; i < 40; i++) { //сдвигаем
        mass_36[i] = mass_36[i + 1];
      }
      mass_36[40] = shet;
      if (zam_36p < 40) { //первый набор массива
        zam_36p++;
        fon = fon + shet;
      }
      if (zam_36p >= 40) { //набор массива
        int fon_vr1 = 0;
        for (int i = 0; i < 40; i++) {
          fon_vr1 = fon_vr1 + mass_36[i];
        }
        fon = fon_vr1;
      }
      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;
      }
    }
  }
}
//----------------------------------------------------------------------------------------------------------------
void signa () { //индикация каждой частички звуком светом
  shet_s = shet;  
    if (alarm_sound) //если поднят флаг аварийного сигнала
  {
  #ifdef buzzer_active //если задефайнен активный бузер
    PORTD |= (1 << 6); // включаем непрерывный сигнал тревоги
  #else //пассивный
  tone (6, 1300); //генерим писк с частотой 1300Гц (значение можно изменить на своё) на пине 6
  #endif
    if ((millis() - alarm_milis) > first_alarm_duration) // проверяем, не истекло ли время подачи сигнала тревоги
    {
    #ifdef buzzer_active   //если задефайнен активный бузер
    PORTD &= ~(1 << 6); // выключаем непрерывный сигнал тревоги
    #else //пассивный бузер
    noTone (6); //выключаем писк на 6й ноге
    #endif 
    alarm_sound = 0; // сбрасываем флаг сигнала тревоги
    }   
    PORTB |= (1 << 5); //включаем светодиод
    delay(del_BUZZ);
    PORTB &= ~(1 << 5);//выключаем светодиод
  }
  else //если флаг сигнала тревоги не поднят, генерим одиночные сигналы, озвучивающие пойманные частицы  
    {
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,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,1000,30); //генерим писк 1000Гц 30миллисекунд на 6й ноге
					delay(del_BUZZ);//длительность одиночного сигнала
					PORTB &= ~(1 << 5);//выключаем светодиод
				}
			#endif 
			break; 
	} 
    }

  //generator();//накачка по обратной связи с АЦП
}
//-------------------------------------------------------------------------------------------------
void Schet() { //прерывание от счетчика на пин 2
  shet++;
}
//-------------------------------------------------------------------------------------------------
void generator() {//накачка по обратной связи с АЦП
  hv_adc  = Read_HV();
  if (hv_adc < ADC) { //Значение АЦП при котором на выходе 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 //если при компилляции выбрана плата 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(TinyFont);
  myGLCD.printNumF(VCC, 2, 63, 2);
}
//----------------------------------------------------------------------------------------------------
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;
}
//----------------------------------------------------------------------------------------------------
void lcd_init() {
  myGLCD.InitLCD();
  myGLCD.setContrast(contrast);
  myGLCD.clrScr();
  myGLCD.drawBitmap(0, 0, logo_rag, 84, 48);
  myGLCD.setFont(SmallFont);
  myGLCD.print("Arduino+", CENTER, 32);
  myGLCD.print("Dosimeter v1.064", CENTER, 40);
  myGLCD.update();
  _delay_ms(1000);
}
//----------------------------------------------------------------------------------------------------
void eeprom_wrS () { //запись настроек в память
  EEPROM.write(0, 222);
  EEPROM.write(1, treviga_1);
  EEPROM.write(2, podsvetka);
  EEPROM.write(3, son_OK);
  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(SmallFont);
  myGLCD.print("Save OK", CENTER, 24);
  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);
    son_OK = 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 timer_soft() {
  if (millis() - timer_mil >= 1000) {
    timer_mil = millis();
    sek++;
    toch = !toch;
    if (sek > 60) {
      sek = 0;
      minute++;
    }
  }
}
//------------------------------------------------------------------------------------------------------
void check_alarm_signal()  // устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
{
  if (!tr) // если счёт превысил аварийный порог, но флаг "tr" ещё не установлен
    {
    alarm_sound = 1; // поднимаем флаг аварийного сигнала
    alarm_milis = millis(); // запоминаем время начала тревоги
    }  
}
//------------------------------------------------------------------------------------------------------
void res_first_alarm() //подпрограмма выключения тревоги (ручного или по истечении таймаута)
  {
    alarm_sound = 0; // сбрасываем флаг звукового сигнала тревоги
   #ifdef buzzer_active //если задефайнен активный бузер
   PORTD &= ~(1 << 6); // выключаем бузер
   #else //пассивный бузер
   noTone(6);   //выключаем генерацию сигнала на 6й ноге
   #endif
  }
//------------------------------------------------------------------------------------------------------
void ind_doze_time() //вывод времени накопления дозы на дисплей
{
  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("d", 26, 26);
	}
  else
	{
    myGLCD.print("d", 23, 26);
	}	
  }
  else if (DAY) // если нет месяцев, но есть дни
		{
		myGLCD.printNumI(DAY, 0, 26);
		if (DAY > 9) 
		{
		myGLCD.print("d", 9, 26);
		}
		else
		{
		myGLCD.print("d", 5, 26);
		}
		myGLCD.printNumI(HOUR, 18, 26);
		if (HOUR > 9) 
		{
		myGLCD.print("h", 26, 26);
		}
		else 
		{
		myGLCD.print("h", 23, 26);
		}
		}
			else // если нет дней
			{
			myGLCD.printNumI(HOUR, 0, 26);
			if (HOUR > 9) 
			{
			myGLCD.print("h", 9, 26);
			}
			else
			{
			myGLCD.print("h", 5, 26);
			}
			myGLCD.printNumI(MIN, 18, 26);
			if (MIN > 9) 
			{
			myGLCD.print("m", 26, 26);
			}
			else
			{
			myGLCD.print("m", 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
}



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




/*

ChangeLog by tekagi:

1.064         16.04.2018
  -добавлена возможность использования ArduinoUNO или голого камня atmega328p в DIP корпусе. Для переключения раскомментировать #define UNO в начале скетча, это переключит чтение высокого напряжения с делителя с пина A6 на A5;
  -добавлено переключение состояния подсветки при удержании ">>"
  
1.063.7       16.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 за подсказки и готовые кусочки кода.

*/

-добавлено включение подсветки удержанием кнопки ">>"

-добавлена возможность использовать атмегу в DIP корпусе или UNO на её основе. Для этого надо раскомментировать строчку //#define UNO и использовать A5 для чтения напряжения с делителя.

Dark-Dante, протестируйте переключение через дефайн, мне не на чем. Только СБМку отсоедините, мало ли.

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

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

Для ещё большей универсальности можно в дефайне еще переключение красный/синий дисплей добавить либо инверсию подсветки. Ну Вы поняли о чём я.

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

Думал об этом, но пока нет необходимости. Это было критично пока был режим сна, в котором отключались все дополнительные потребители. Тогда у владельцев синих дисплеев включалась подсветка. Сейчас на синих просто инверсно отображается состояние подсветки в меню, 0 при включеной и 1 при выключеной. Если когда-нибудь наберусь ума вернуть спящий режим - тогда и прикручу.

Osty_Mate
Offline
Зарегистрирован: 17.04.2018

Пытался загрузить скетч v1.05_oled, но столкнулся с ошибкой.

C:\Users\User\Documents\Arduino\аааа\ARDOs_noSleep_v105_oled\ARDOs_noSleep_v105_oled.ino:19:0: warning: "ADC" redefined
 
In file included from c:\users\user\appdata\local\arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2\avr\include\avr\io.h:272:0,
 
                 from c:\users\user\appdata\local\arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2\avr\include\avr\pgmspace.h:90,
 
                 from C:\Users\User\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\cores\arduino/Arduino.h:28,
 
                 from sketch\ARDOs_noSleep_v105_oled.ino.cpp:1:
 
c:\users\user\appdata\local\arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2\avr\include\avr\iom328p.h:455:0: note: this is the location of the previous definition
 
 #define ADC     _SFR_MEM16(0x78)
 
 ^
C:\Users\User\Documents\Arduino\аааа\ARDOs_noSleep_v105_oled\ARDOs_noSleep_v105_oled.ino: In function 'void loop()':
И далее как в последней строчке, нечто подобное шлёт
 
Dark-Dante
Offline
Зарегистрирован: 09.01.2018

Tekagi, прошил я последнюю версию- прошивка идеальная! Кнопки обрабатываются очень четко, никаких задержек или ложных срабатываний. В режиме разностного замера показания начали соответствовать пикам буззера и нет никаких проблем с входом в режим Замер 1. Переключение А5/А6 работает корректно. Так же ранее в системном меню если нажимать ок, то резко возрастало количество импульсов накачки до максимума и падало напряжение, процессор не испевал генерировать ШИМ и обрабатывать кнопки- теперь такого нет.

Мой вариант скетча с изменёнными меню и подписями, так же вылизал все комментарии, исправил опечатки и т.д. Подсветка под синий дисплей.

/* ArDOs   v1.064
***Дозиметр на Ардуино
***IDE Arduino 1.8.2
  ветка форума 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); //подключение дисплея
//LCD5110 myGLCD(12, 11, 10, A4, A5); //подключение дисплея
#define contrast 66 //контрастность дисплея
//#define buzzer_active //если используется активный бузер (со встроенным генератором), управляемый транзистором с выхода 6, то раскомментировать эту строчку, если пассивный (с усилителем или без) - оставить закомментированой
#define UNO //если используется Arduino UNO или плата на голой атмеге328 в корпусе DIP - раскомментируйте данную строчку. Это переключит чтение напряжения с делителя с ноги A6 на ногу A5
#define first_alarm_duration 7000 //длительность сигнала тревоги при превышении первого аварийного порога в миллисекундах
byte treviga_1 = 30; //первая ступень тревоги
byte treviga_2 = 60; //вторая ступень тревоги
byte del_BUZZ = 8; //длительность одиночного сигнала
#define  ADC 201  //значение АЦП при котором 400В с учетом вашего делителя напряжения (0..255)
#define k_delitel 472 //коефициент делителя напряжения, зависит от вашего делителя
byte puls = 7; //тонкая настройка длинны импульса высоковольтного транса
byte scrin_GRAF = 1; //скорость построения графика в секундах
byte ind_ON = 3;  //0 - индикация выключена, 1 - включён бузер, 2 - светодиод, 3 - и бузер, и светодиод
bool podsvetka = 0; //подсветка
bool alarm_sound = 1; //флаг индикации превышения порога звуком
bool son_OK = 0; //разрешение или запрет сна
float opornoe = 1.08; //делить на opornoe/10
#define son_t 40 //время засыпания в секундах
#define save_DOZ 20 //как часто сохранять накопленную дозу например каждые 20мкР
byte beta_time = 10; //время замера Бета излучения
//настройки //////////////конец
//служебные переменные
extern uint8_t SmallFont[], MediumNumbers[], TinyFont[];
extern uint8_t logo_bat[], logo_rag[], logo_tr[], gif_chast_1[], gif_chast_2[];
volatile int shet = 0;
unsigned long t_milis = 0, gr_milis = 0, lcd_milis = 0, toch_milis = 0, timer_mil = 0;
unsigned long alarm_milis = 0; //для отсчёта длительности сигнала тревоги по превышению порога
unsigned long spNAK_milis = 0, time_doza = 0, bat_mill = 0;
int hv_adc, hv_400, shet_s = 0, fon = 0, shet_gr = 0, shet_n = 0;
int speed_nakT = 0, speed_nak = 0, time_sh_l = 0, result;
byte MIN, DAY, HOUR, MONTH; //для учёта времени дозы
int doza_vr = 0;
byte mass_p[84], mass_toch[201], m = 0, n_menu = 0, sys_menu = 0, mass_36[41];
byte val_kl = 0, val_ok = 0, menu = 0, zam_180p = 0, zam_36p = 0, gif_x = 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, stat_percent = 99.0;
bool tr = 0, poisk = 1, fonarik = 0, g_fl = 0, toch;
#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() {
  //Serial.begin(115200);
  ACSR |= 1 << ACD; //отключаем компаратор
  //ADCSRA &= ~(1 << ADEN);  //отключаем АЦП
  pinMode(3, INPUT_PULLUP); //кнопка
  pinMode(4, INPUT_PULLUP); //кнопка
  pinMode(7, INPUT_PULLUP); //кнопка
  DDRB |= (0 << 0); PORTB &= ~(1 << 0); //пин пустой 8
  DDRC |= (0 << 4); PORTC &= ~(1 << 4); //пин пустой А4
  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 ();
  lcd_init();
  attachInterrupt(0, Schet, FALLING); //прерывания на пин 2
  DDRB |= (1 << 5); //пины на выход
  DDRD |= (1 << 5);
  DDRD |= (1 << 6);
  DDRD |= (1 << 6); //пин бузера
  nakachka();
}
//-------------------------------------------------------------
void loop() 
{
key_data = get_key();  //вызываем функцию определения нажатия кнопок, присваивая возвращаемое ей значение переменной, которую далее будем использовать в коде
  if (menu == 0) {
    if (key_data == key_pressed_left) { //нажатие <<<
    key_data = 0;  //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      menu = 3;
      shet = 0; zam_180p = 0; fon = 0;
      stat_percent = 99.0;
   } 
    if (key_data == key_holded_left) //нажатие <<< фонарик  
  {fonarik = !fonarik; 
  key_data = 0;  //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
  }   
    if (key_data == key_holded_right) //удержание <<< подсветка
   {
    key_data = 0;  //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду     
        podsvetka = !podsvetka;
     }    
    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_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
  }
  } 
  if (menu == 4) {
    if (key_data == key_pressed_right) { //нажатие >>>
    key_data = 0;  //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      menu = 0;
      shet = 0;
      stat_percent = 99.0;
    }
  }
  if (fonarik == 0) { //фонарик
    PORTB &= ~(1 << 1); //пин фонаря
  } else if (fonarik == 1) {
    PORTB |= (1 << 1); //пин фонаря
  }
  if (podsvetka == 1) {
    PORTC |= (1 << 2); //A2 дисплей Light
  }
  if (podsvetka == 0) {
    PORTC &= ~(1 << 2); //A2 дисплей Light
  }
  if (millis() - lcd_milis >= 300) { //скорость отрисовки дисплея
    lcd_milis = millis();
    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сек
    }
    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; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду     
        son_OK = !son_OK;
      }
      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, 3); //держим значение в диапазоне 0...3
      }
      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;
        }
        if (puls > 200) {
          puls = 1;
        }
      }
      if (sys_menu == 2) {
    key_data = 0; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        time_doza = 0; //сброс накопленной дозы
        doz_v = 0; //сброс накопленной дозы
        eeprom_wrD ();
        myGLCD.clrScr();
        myGLCD.setFont(SmallFont);
        myGLCD.print("Sbrosheno!", 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; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        son_OK = !son_OK;
      }
      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, 3); //держим значение в диапазоне 0...3
      }
      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;
        }
        if (opornoe > 1.20) {
          opornoe = 0.98;
        }
      }
      if (sys_menu == 1) {
      key_data = 0; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        puls--;
        if (puls < 1) {
          puls = 200;
        }
        if (puls > 200) {
          puls = 1;
        }
      }
      if (sys_menu == 2) {
      key_data = 0; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        time_doza = 0; //сброс накопленной дозы
        doz_v = 0; //сброс накопленной дозы
        eeprom_wrD ();
        myGLCD.clrScr();
        myGLCD.setFont(SmallFont);
        myGLCD.print("Sbrosheno!", 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 (!tr && alarm_sound) //если фон ниже порога тревоги, но сигнал тревоги ещё не выключен
  {
res_first_alarm(); //сбрасываем сигнал тревоги
  }
}
//------------------------------------------------------------------------------------------------------------------
void gif_nabor() {
  myGLCD.drawLine(0, 24, 84, 24); myGLCD.drawLine(0, 38, 84, 38);
  for (int i = 83 - zam_180p * 0.47; i < 84; i++) {
    myGLCD.drawLine(i, 24, i, 38);
  }
  g_fl = !g_fl;
  if (g_fl == 0) {
    myGLCD.drawBitmap(gif_x, 27, gif_chast_1, 8, 8);
  } else {
    myGLCD.drawBitmap(gif_x, 27, gif_chast_2, 8, 8);
  }
  myGLCD.setFont(SmallFont);
  if (zam_180p < 200) {
    gif_x = gif_x + 1;
    if (gif_x >= 83 - zam_180p * 0.47) {
      gif_x = 0;
    }
    myGLCD.print("Analiz...", CENTER, 40);
  }
  else if (zam_180p >= 200) {
    myGLCD.print("Obnovlenie...", CENTER, 40);
  }
}
//--------------------------------------------------------------
void zamer_200s() 
{
  myGLCD.clrScr();
  myGLCD.setFont(SmallFont);
  myGLCD.print("%", 20, 0); myGLCD.printNumF(stat_percent, 1, 26, 0);
  myGLCD.setFont(MediumNumbers);
      if (alarm_sound) //сбрасываем сигнал тревоги первого уровня, если активен
    {
       res_first_alarm(); //сбрасываем сигнал тревоги 
    }
  if (fon > 0) {
    if (fon >= 1000) {
      myGLCD.printNumF((float(fon)/1000), 2, LEFT, 7);
        myGLCD.setFont(SmallFont); myGLCD.print("mR/h", RIGHT, 12);
    }
    if (fon < 1000) {
      myGLCD.printNumI(fon, CENTER, 7);
      myGLCD.setFont(SmallFont); myGLCD.print("uR/h", RIGHT, 12);
    }
  }

  gif_nabor();
  battery();
  myGLCD.update();
  if (millis() - toch_milis >= 1000) {
    toch_milis = millis();
    for (int i = 0; i < 200; i++) { //сдвигаем
      mass_toch[i] = mass_toch[i + 1];
    }
    mass_toch[199] = shet;
    shet = 0;
    if (zam_180p < 200) { //первый набор массива
      zam_180p++;
      int fon_vr1 = 0;
      for (int i = 200 - zam_180p; i < 200; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 * (40.0 / zam_180p);
    }
    if (zam_180p >= 200) { //набор массива
      int fon_vr1 = 0;
      for (int i = 0; i < 200; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 / 5;
    }
    if (zam_180p <= 36) {
      stat_percent = stat_percent - 2.0;
    }
    if (zam_180p > 36 && zam_180p <= 72) {
      stat_percent = stat_percent - 0.3;
    }
    if (zam_180p > 72 && zam_180p <= 100) {
      stat_percent = stat_percent - 0.2;
    }
    if (zam_180p > 100 && zam_180p <= 200) {
      stat_percent = stat_percent - 0.1;
    }
    if (stat_percent < 5) {
      stat_percent = 5.0;
    }
  }
}
//-------------------------------------------------------------------------------------------------------
void lcd_poisk() { //вывод на дисплей режима поиск
  if (shet < treviga_1 && fon < treviga_1) { //проверяем тревогу
    tr = 0;
  }
  if (shet > treviga_1 || fon > treviga_1) { //проверяем тревогу
    check_alarm_signal(); //устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
    tr = 1;
  }
  myGLCD.clrScr();
  myGLCD.setFont(SmallFont);
  if (tr == 1) { //опасно
    myGLCD.drawBitmap(0, 0, logo_tr, 24, 8);
  }
  myGLCD.print("%", 20, 0); myGLCD.printNumF(100 - (zam_36p * 2.0), 1, 26, 0);
  myGLCD.setFont(MediumNumbers);
  if (fon > 0) {
    if (fon >= 1000) {
      myGLCD.printNumF((float(fon)/1000), 2, LEFT, 7);
        myGLCD.setFont(SmallFont); myGLCD.print("mR/h", RIGHT, 12);
    }
    if (fon < 1000) {
      myGLCD.printNumI(fon, CENTER, 7);
      myGLCD.setFont(SmallFont); myGLCD.print("uR/h", RIGHT, 12);
    }
  }
  time_d ();
  myGLCD.setFont(TinyFont);
  ind_doze_time(); //вывод времени накопления дозы на дисплей    
  myGLCD.setFont(SmallFont);
  if (doz_v < 1000) {
    myGLCD.printNumF(doz_v, 1, 41, 24); myGLCD.print("uR", RIGHT, 24);
  }
  if (doz_v >= 1000) {
    myGLCD.printNumF(doz_v / 1000.0, 2, 41, 24); myGLCD.print("mR", RIGHT, 24);
  }
  myGLCD.drawLine(0, 32, 83, 32); //верхняя
  battery();
  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(TinyFont);
  myGLCD.print("Trevoga 1", 0, 0); myGLCD.printNumI(treviga_1, 54, 0); myGLCD.print("uR/h", RIGHT, 0);
  myGLCD.print("Trevoga 2", 0, 6); myGLCD.printNumI(treviga_2, 54, 6); myGLCD.print("uR/h", RIGHT, 6);
  myGLCD.print("Podsvetka", 0, 12); myGLCD.printNumI(podsvetka, 54, 12); myGLCD.print("on/off", RIGHT, 12);
  myGLCD.print("---------", 0, 18); //usr
  myGLCD.print("Obn. grafika", 0, 24); myGLCD.printNumI(scrin_GRAF, 54, 24); myGLCD.print("sek", RIGHT, 24);
  myGLCD.print("Buzzer/LED", 0, 30); //пункт меню выбора индикации частиц
  switch (ind_ON)
  {
  case 0:
    myGLCD.print("off/off", RIGHT, 30); //индикация выключена
    break;  
  case 1:
    myGLCD.print("on/off", RIGHT, 30); //индикация звуком
    break;  
  case 2:
    myGLCD.print("off/on", RIGHT, 30); //индикация светом
    break;  
  case 3:
    myGLCD.print("on/on", RIGHT, 30); //индикация звуком и светом
    break; 
    default:
    myGLCD.print("err", RIGHT, 30); //если значение не равно 1,2,3 или 0 - выводим ошибку 
  } 
  myGLCD.print("Vyhod", 0, 36);
  myGLCD.print("Sohranit", 0, 42);
  myGLCD.print(">", 49, n_menu * 6);
  myGLCD.update();
}
//----------------------------------------------------------------------------------------------------------------------
void lcd_sys() { //вывод на дисплей меню
  VCC_read();
  speed_nakachka (); //скорость накачки имлульсы/сек
  myGLCD.clrScr();
  myGLCD.setFont(TinyFont);
  myGLCD.print("Oporn.", 0, 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("Gener.", 0, 6); myGLCD.printNumI(puls, CENTER, 6); myGLCD.printNumI(hv_400, RIGHT, 6);
  myGLCD.print("Doza", 0, 12); myGLCD.print("sbros dozy", RIGHT, 12);
  myGLCD.print("Vyhod", 0, 18);
  myGLCD.print("Sohran.", 0, 24);
  myGLCD.print("Beta", 0, 30); myGLCD.printNumI(beta_time, CENTER, 30); myGLCD.print("min", RIGHT, 30);
  myGLCD.print(">", 30, sys_menu * 6);
  myGLCD.print("Skorost", 0, 40); myGLCD.printNumI(speed_nak, CENTER, 40); myGLCD.print("imp./sek", RIGHT, 40);
  myGLCD.update();
}
//---------------------------------------------------------------------------------------------------------------------
void zamer_beta() { //замер Бета или продуктов
  if (gotovo == 0) 
{
/*  
//этот кусок кода вынесен в loop, поскольку из-за вызова функции бета замера с частотой обновления дисплея не отрабатывается считывание состояния кнопок внутри функции
    if (key_data == key_pressed_ok) { //нажатие 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; //обнуляем счёт            
      }
    }
*/  
    if (alarm_sound) //если активен сигнал тревоги первого уровня
    {
       res_first_alarm(); //сбрасываем сигнал тревоги
    }
    myGLCD.clrScr();
    myGLCD.setFont(SmallFont);
    myGLCD.print("Zamer ", 20, 10); myGLCD.printNumI(bet_z, 55, 10);
    myGLCD.print("Nagmite OK", CENTER, 20);
    myGLCD.update();
  }  
  if (gotovo == 1) {
    timer_soft();
    byte otsup = 0;
    if (minute > 9) {
      otsup = 5;
    }
    myGLCD.clrScr();
    battery();
    myGLCD.setFont(TinyFont);
    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("time", 23 + otsup, 0);
    myGLCD.drawLine(0, 8, 83, 8);
    myGLCD.setFont(SmallFont);
    myGLCD.drawLine(40, 8, 40, 28);
    myGLCD.print("Zamer0", LEFT, 10); myGLCD.print("Zamer1", 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("Idet zamer", CENTER, 30); myGLCD.printNumI(bet_z, RIGHT, 30);
      myGLCD.printNumI(bet_r, CENTER, 38);
    }
    if (bet_z == 2) {
      myGLCD.print("Rezultat", CENTER, 30);
      myGLCD.printNumI(bet_r, CENTER, 38); myGLCD.print("mkR/h", 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);
    }
  }
  if (key_data == key_pressed_right) { //нажатие >>>
    key_data = 0; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    menu = 0;
    shet = 0; fon = 0; zam_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
  }
}
//-------------------------------------------------------------------------------------------------------------
void poisk_f() { //режим поиска
  if (poisk == 1) {
    if (millis() - gr_milis >= scrin_GRAF * 1000) { //счет для графика
      gr_milis = millis();
      val_ok = 0; //сброс удержания системного меню
      shet_gr = shet - shet_n;
      if (shet_gr < 0) {
        shet_gr = 1;
      }
      mass_p[m] = shet_gr ;
      shet_n = shet;
      if (m < 82) {
        m++;
      }
      if (m == 82) {
        for (int i = 0; i < 83; i++) {
          mass_p[i] = mass_p[i + 1];
        }
        mass_p[82] = shet_gr;
      }
    }
    if (millis() - toch_milis >= 1000) {
      toch_milis = millis();
      for (int i = 0; i < 40; i++) { //сдвигаем
        mass_36[i] = mass_36[i + 1];
      }
      mass_36[40] = shet;
      if (zam_36p < 40) { //первый набор массива
        zam_36p++;
        fon = fon + shet;
      }
      if (zam_36p >= 40) { //набор массива
        int fon_vr1 = 0;
        for (int i = 0; i < 40; i++) {
          fon_vr1 = fon_vr1 + mass_36[i];
        }
        fon = fon_vr1;
      }
      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;
      }
    }
  }
}
//----------------------------------------------------------------------------------------------------------------
void signa () { //индикация каждой частички звуком светом
  shet_s = shet;  
    if (alarm_sound) //если поднят флаг аварийного сигнала
  {
  #ifdef buzzer_active //если задефайнен активный бузер
    PORTD |= (1 << 6); //включаем непрерывный сигнал тревоги
  #else //пассивный
  tone (6, 1300); //генерим писк с частотой 1300Гц (значение можно изменить на своё) на пине 6
  #endif
    if ((millis() - alarm_milis) > first_alarm_duration) //проверяем, не истекло ли время подачи сигнала тревоги
    {
    #ifdef buzzer_active //если задефайнен активный бузер
    PORTD &= ~(1 << 6); //выключаем непрерывный сигнал тревоги
    #else //пассивный бузер
    noTone (6); //выключаем писк на 6й ноге
    #endif 
    alarm_sound = 0; //сбрасываем флаг сигнала тревоги
    }   
    PORTB |= (1 << 5); //включаем светодиод
    delay(del_BUZZ);
    PORTB &= ~(1 << 5); //выключаем светодиод
  }
  else //если флаг сигнала тревоги не поднят, генерим одиночные сигналы, озвучивающие пойманные частицы  
    {
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,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,1000,30); //генерим писк 1000Гц 30 миллисекунд на 6й ноге
          delay(del_BUZZ); //длительность одиночного сигнала
          PORTB &= ~(1 << 5); //выключаем светодиод
        }
      #endif 
      break; 
  } 
    }

  //generator(); //накачка по обратной связи с АЦП
}
//-------------------------------------------------------------------------------------------------
void Schet() { //прерывание от счетчика на пин 2
  shet++;
}
//-------------------------------------------------------------------------------------------------
void generator() { //накачка по обратной связи с АЦП
  hv_adc  = Read_HV();
  if (hv_adc < ADC) { //значение АЦП при котором на выходе 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 //если при компилляции выбрана плата Arduino UNO
  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(TinyFont);
  myGLCD.printNumF(VCC, 2, 63, 2);
}
//----------------------------------------------------------------------------------------------------
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;
}
//----------------------------------------------------------------------------------------------------
void lcd_init() {
  myGLCD.InitLCD();
  myGLCD.setContrast(contrast);
  myGLCD.clrScr();
  myGLCD.drawBitmap(0, 0, logo_rag, 84, 48);
  myGLCD.setFont(SmallFont);
  myGLCD.print("Dosimetr", CENTER, 32);
  myGLCD.print("FW v.1.64", CENTER, 40);
  myGLCD.update();
  _delay_ms(1000);
}
//----------------------------------------------------------------------------------------------------
void eeprom_wrS () { //запись настроек в память
  EEPROM.write(0, 222);
  EEPROM.write(1, treviga_1);
  EEPROM.write(2, podsvetka);
  EEPROM.write(3, son_OK);
  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(SmallFont);
  myGLCD.print("Sohraneno!", CENTER, 24);
  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);
    son_OK = 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 timer_soft() {
  if (millis() - timer_mil >= 1000) {
    timer_mil = millis();
    sek++;
    toch = !toch;
    if (sek > 60) {
      sek = 0;
      minute++;
    }
  }
}
//------------------------------------------------------------------------------------------------------
void check_alarm_signal()  //устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
{
  if (!tr) //если счёт превысил аварийный порог, но флаг "tr" ещё не установлен
    {
    alarm_sound = 1; //поднимаем флаг аварийного сигнала
    alarm_milis = millis(); //запоминаем время начала тревоги
    }  
}
//------------------------------------------------------------------------------------------------------
void res_first_alarm() //подпрограмма выключения тревоги (ручного или по истечении таймаута)
  {
    alarm_sound = 0; //сбрасываем флаг звукового сигнала тревоги
   #ifdef buzzer_active //если задефайнен активный бузер
   PORTD &= ~(1 << 6); //выключаем бузер
   #else //пассивный бузер
   noTone(6); //выключаем генерацию сигнала на 6й ноге
   #endif
  }
//------------------------------------------------------------------------------------------------------
void ind_doze_time() //вывод времени накопления дозы на дисплей
{
  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("d", 26, 26);
  }
  else
  {
    myGLCD.print("d", 23, 26);
  } 
  }
  else if (DAY) //если нет месяцев, но есть дни
    {
    myGLCD.printNumI(DAY, 0, 26);
    if (DAY > 9) 
    {
    myGLCD.print("d", 9, 26);
    }
    else
    {
    myGLCD.print("d", 5, 26);
    }
    myGLCD.printNumI(HOUR, 18, 26);
    if (HOUR > 9) 
    {
    myGLCD.print("h", 26, 26);
    }
    else 
    {
    myGLCD.print("h", 23, 26);
    }
    }
      else //если нет дней
      {
      myGLCD.printNumI(HOUR, 0, 26);
      if (HOUR > 9) 
      {
      myGLCD.print("h", 9, 26);
      }
      else
      {
      myGLCD.print("h", 5, 26);
      }
      myGLCD.printNumI(MIN, 18, 26);
      if (MIN > 9) 
      {
      myGLCD.print("m", 26, 26);
      }
      else
      {
      myGLCD.print("m", 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
}



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




/*

ChangeLog by tekagi:

1.064         16.04.2018
  -добавлена возможность использования ArduinoUNO или голого камня atmega328p в DIP корпусе. Для переключения раскомментировать #define UNO в начале скетча, это переключит чтение высокого напряжения с делителя с пина A6 на A5;
  -добавлено переключение состояния подсветки при удержании ">>"
  
1.063.7       16.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 за подсказки и готовые кусочки кода.

*/

 

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

  Osty_Mate, ArduinoIDE новой версии? Сегодня столкнулся с такой же пробемой на 1.8.5, видимо где-то в подключаемых файлах появился дефайн с таким же именем. Лечится заменой в скетче "ADC" на "ADC_value" в двух местах: непосредственно в строчке

#define ADC
и в функции замера высокого и накачки void generator()  в строчке
  if (hv_adc < ADC) { //значение АЦП при котором на выходе 400В

Вечером поменяю и в текущей версии, дабы в будущем проблем не возникало.

Dark-Dante, спасибо за тест. Если в течении недели будет время - выкачу апдейт интерфейса v1.07.
Dark-Dante пишет:
, ...процессор не испевал генерировать ШИМ...
Там нет шима ) Просто при нажатии кнопок проц работал вхолостую в делеях антидребезга, функции замера и накачки даже не вызывались.
Dark-Dante
Offline
Зарегистрирован: 09.01.2018

Я писал ранее, что в кодинге я не понимаю. Еще раз спасибо за баг фикс!

Ооо, с нетерпением жду на тест 1.07!

Osty_Mate
Offline
Зарегистрирован: 17.04.2018

Ресетнул на старую версию, вроде пошло, но как вдруг опять что-то

На сей раз это:

In file included from ARDOs_noSleep_v105_oled.ino:8:0:
c:\users\user\desktop\arduino-1.6.1\hardware\tools\avr\avr\include\util\delay.h: In function 'void signa()':
c:\users\user\desktop\arduino-1.6.1\hardware\tools\avr\avr\include\util\delay.h:245:40: error: __builtin_avr_delay_cycles expects a compile time integer constant
  __builtin_avr_delay_cycles(__ticks_dc);
                                        ^
c:\users\user\desktop\arduino-1.6.1\hardware\tools\avr\avr\include\util\delay.h:245:40: error: __builtin_avr_delay_cycles expects a compile time integer constant
  __builtin_avr_delay_cycles(__ticks_dc);
 
Ошибка компиляции.
tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Osty_Mate, на древних версиях IDE был такой глюк со встроеной библиотекой delay. Обычно в скетче в верхнем комментарии пишется, на какой версии IDE производилась тестовая сборка. Поставьте текущую версию 1.8.5 и попробуйте такой скетч:

/* ArDOs   v105 без режима сна
 *  Mod for OLED 128*64 I2C by Lazy_Dragon
***Дозиметр на Ардуино
***IDE Arduino 1.8.5
  ветка форума arduino.ru/forum/proekty/delaem-dozimetr
  сайт srukami.inf.ua/ardos.html
*/
#include <util/delay.h> //уже есть
#include <EEPROM.h>//уже есть
#include <OLED_I2C.h>


//настройки /////////////начало
OLED myGLCD(SDA, SCL); //подключение дисплея
#define contrast 65 //контрастность дисплея
byte treviga_1 = 30; //первая ступень тревоги
byte treviga_2 = 60; //вторая ступень тревоги
byte ton_BUZZ = 70; //тональность буззера
#define  ADC_value 163  //значение АЦП при котором 400В с учетом вашего делителя напряжения (0..255)
#define k_delitel 567 //коефициент дельтеля напряжения, зависит от вашего делителя.
byte puls = 2; //тонкая настройка длинны импульса высоковольтного транса
byte scrin_GRAF = 1; //скорость построения графика в секундах
bool buzz_ON = 1;  //включить индикацию бузером (1)
bool podsvetka = 0; //подсветка
bool Lcd_Inv = 0; //разрешение или запрет сна
float opornoe = 1.10; //делить на opornoe/10
#define son_t 40 //время засыпания в секундах
#define save_DOZ 20 //как часто сохранять накопленную доху например каждые 20мкР
//настройки //////////////конец

extern uint8_t SmallFont[], MediumNumbers[], TinyFont[], BigNumbers[];
extern uint8_t logo_bat[], logo_rag[], logo_tr_OLED[], logo_tr[], gif_chast_1[], gif_chast_2[];
volatile int shet = 0;
unsigned long t_milis = 0, gr_milis = 0, lcd_milis = 0, toch_milis = 0;
unsigned long spNAK_milis = 0, time_doza = 75000;
int hv_adc, hv_400, shet_s = 0, fon = 0, shet_gr = 0, shet_n = 0;
int speed_nakT = 0, speed_nak = 0, time_sh_l = 0, MIN, HOUR;
int doza_vr = 0, val_dr_pr = 0, val_dr_OK = 0;
byte mass_p[84];
byte mass_toch[181], m = 0, n_menu = 0, sys_menu = 0, mass_36[37];
byte val_kl = 0, val_ok = 0, menu = 0, zam_180p = 0, zam_36p = 0, gif_x = 0;
float VCC = 0.0, doz_v = 0.0, stat_percent = 99.0;
bool tr = 0, poisk = 1, fonarik = 0, g_fl = 0;
//-------------------------------------------------------------
void setup() {
  Serial.begin(57600);
  ACSR |= 1 << ACD; //отключаем компаратор
  ADCSRA &= ~(1 << ADEN);  // отключаем АЦП,
  pinMode(3, INPUT_PULLUP); //кнопка
  pinMode(4, INPUT_PULLUP); //кнопка
  pinMode(7, INPUT_PULLUP); //кнопка
  DDRB |= (0 << 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 ();
  lcd_init();
  attachInterrupt(0, Schet, FALLING);//прерываниям пин 2
  DDRB |= (1 << 5); //пины на выход
  DDRD |= (1 << 5);
  DDRD |= (1 << 6);
  DDRD |= (1 << 6);//пин бузера
  nakachka();
}
//-------------------------------------------------------------
void loop() {
  if (menu == 0) {
    if (!(PIND & (1 << PIND7))) { //нажатие <<<
      _delay_ms(500);//антидребезг
      menu = 3;
      shet = 0; zam_180p = 0; fon = 0;
      stat_percent = 99.0;
      if (!(PIND & (1 << PIND7))) {//нажатие <<< фонарик
        val_kl++;
        if (val_kl == 6) {
          val_kl = 0;
          fonarik = !fonarik;
        }
      }
    }
  }
  if (fonarik == 0) { //фонарик
    PORTB &= ~(1 << 1);//пин фонаря
  } else if (fonarik == 1) {
    PORTB |= (1 << 1);//пин фонаря
  }
  if (podsvetka == 1) {
    PORTC &= ~(1 << 2); //A2 дисплей Light
  }
  if (podsvetka == 0) {
    PORTC |= (1 << 2); //A2 дисплей Light
  }
  if (millis() - lcd_milis >= 100) { //скорость отрисоаки дисплея
    lcd_milis = millis();
    if (menu == 0) {
      lcd_poisk();//вывод на дисплей режима поиск
      poisk_f();
    }
    if (menu == 1) {
      lcd_menu();//вывод на дисплей меню
    }
    if (menu == 2) {
      lcd_sys();//вывод на дисплей системного меню
    }
    if (menu == 3) {
      zamer_180s();//вывод на дисплей замер 180сек
    }
  }
  generator();//накачка по обратной связи с АЦП
  if (shet_s != shet) {
    signa ();//подача сигнала о частичке
  }
  if (!(PIND & (1 << PIND3))) { //нажатие ок
    _delay_ms(500);//антидребезг
    OK();
  }
  if (menu == 1) {
    if (!(PIND & (1 << PIND4))) { //нажатие >>>
      _delay_ms(500);//антидребезг
      if (n_menu == 0) {
        treviga_1++;
      }
      if (n_menu == 1) {
        treviga_2++;
      }
      if (n_menu == 2) {
        podsvetka = !podsvetka;
      }
      if (n_menu == 3) {
        Lcd_Inv = !Lcd_Inv;
      }
      if (n_menu == 4) {
        scrin_GRAF++;
        if (scrin_GRAF > 10) {
          scrin_GRAF = 1;
        }
      }
      if (n_menu == 5) {
        buzz_ON = !buzz_ON;
      }
      if (n_menu == 6) {
        menu = 0;
      }
      if (n_menu == 7) {
        eeprom_wrS ();
        menu = 0;
      }
    }
  }
  if (menu == 2) {
    if (!(PIND & (1 << PIND4))) { //нажатие >>>
      _delay_ms(500);//антидребезг
      if (sys_menu == 0) {
        opornoe = opornoe + 0.01;
        if (opornoe < 0.98) {
          opornoe = 1.20;
        }
        if (opornoe > 1.20) {
          opornoe = 0.98;
        }
      }
      if (sys_menu == 1) {
        puls++;
        if (puls < 1) {
          puls = 10;
        }
        if (puls > 10) {
          puls = 1;
        }
      }
      if (sys_menu == 2) {
        time_doza = 0;//сброс накопленной дозы
        doz_v = 0;//сброс накопленной дозы
        eeprom_wrD();
        myGLCD.clrScr();
        myGLCD.setFont(SmallFont);
        myGLCD.print("SBROS OK", CENTER, 24);
        myGLCD.update();
        _delay_ms(1000);
      }
      if (sys_menu == 3) {
        menu = 0;
      }
      if (sys_menu == 4) {
        eeprom_wrS ();
        menu = 0;
      }
    }
  }
  if (menu == 1) {
    if (!(PIND & (1 << PIND7))) { //нажатие <<<
      _delay_ms(500);//антидребезг
      if (n_menu == 0) {
        treviga_1--;
      }
      if (n_menu == 1) {
        treviga_2--;
      }
      if (n_menu == 2) {
        podsvetka = !podsvetka;
      }
      if (n_menu == 3) {
        Lcd_Inv = !Lcd_Inv;
      }
      if (n_menu == 4) {
        scrin_GRAF--;
        if (scrin_GRAF < 1) {
          scrin_GRAF = 10;
        }
      }
      if (n_menu == 5) {
        buzz_ON = !buzz_ON;
      }
      if (n_menu == 6) {
        menu = 0;
      }
      if (n_menu == 7) {
        eeprom_wrS ();
        menu = 0;
      }
    }
  }
  if (menu == 2) {
    if (!(PIND & (1 << PIND7))) { //нажатие <<<
      _delay_ms(500);//антидребезг
      if (sys_menu == 0) {
        opornoe = opornoe - 0.01;
        if (opornoe < 0.98) {
          opornoe = 1.20;
        }
        if (opornoe > 1.20) {
          opornoe = 0.98;
        }
      }
      if (sys_menu == 1) {
        puls--;
        if (puls < 1) {
          puls = 10;
        }
        if (puls > 10) {
          puls = 1;
        }
      }
      if (sys_menu == 2) {
        time_doza = 0;//сброс накопленной дозы
        doz_v = 0;//сброс накопленной дозы
        eeprom_wrD();
        myGLCD.clrScr();
        myGLCD.setFont(SmallFont);
        myGLCD.print("SBROS OK", CENTER, 24);
        myGLCD.update();
        _delay_ms(1000);
      }
      if (sys_menu == 3) {
        menu = 0;
      }
      if (sys_menu == 4) {
        eeprom_wrS ();
        menu = 0;
      }
    }
  }
}
//-------------------------------------------------------------
void OK () { //нажатие ОК
  if (!(PIND & (1 << PIND3))) { //удержаиние OK
    val_ok++;
    if (val_ok == 10) {
      val_ok = 0;
      menu = 2;
    }
  }
  if (menu == 2) {
    sys_menu++;
    if (sys_menu > 4) {
      sys_menu = 0;
    }
  }
  if (menu == 1) {
    n_menu++;
    if (n_menu > 7) {
      n_menu = 0;
    }
  }
  if (menu == 0) {
    menu = 1;
  }
  if (menu == 3) {
    menu = 1;
  }
}
//--------------------------------------------------------------
void gif_nabor() {
  myGLCD.setFont(SmallFont);
  myGLCD.drawLine(0, 50, 127, 50); myGLCD.drawLine(0, 63, 127, 63);
  for (int i = 127 - zam_180p * 0.72; i < 127; i++) {
    myGLCD.drawLine(i, 50, i, 63);
  }
  g_fl = !g_fl;
  if (g_fl == 0) {
    myGLCD.drawBitmap(gif_x, 53, gif_chast_1, 8, 8);
  } else {
    myGLCD.drawBitmap(gif_x, 53, gif_chast_2, 8, 8);
  }
  if (zam_180p < 180) {
    gif_x = gif_x + 1;
    if (gif_x >= 123 - zam_180p * 0.72) {
      gif_x = 0;
    }
    myGLCD.print("ANALIZ", CENTER, 40);
  }

  if (zam_180p >= 180) {
    myGLCD.print("OBNOVLENIE", CENTER, 40);
  }
}
//--------------------------------------------------------------
void zamer_180s() {
  myGLCD.clrScr();
  myGLCD.setFont(TinyFont);
  myGLCD.print("ACCURACY", 93, 10);
  myGLCD.setFont(SmallFont);
  myGLCD.printNumF(stat_percent, 1, 93, 18, '.', 4); myGLCD.print("%", 117, 18);
  myGLCD.setFont(BigNumbers);
  myGLCD.drawRect(0, 0, 88, 30);
  if (fon >= 1000) {
    float mZV = float(fon) / 1000;
    myGLCD.printNumF(mZV, 1, 4, 4, '.', 4, '0');
    myGLCD.setFont(SmallFont); myGLCD.print("mR/h", 62, 19);
  }
  if (fon < 1000) {
    myGLCD.printNumI(fon, 4, 4, 4, '0');
    myGLCD.setFont(SmallFont); myGLCD.print("uR/h", 62, 19);
  }

  gif_nabor();
  battery();
  myGLCD.update();
  if (millis() - toch_milis >= 1000) {
    toch_milis = millis();
    for (int i = 0; i < 180; i++) { //сдвигаем
      mass_toch[i] = mass_toch[i + 1];
    }
    mass_toch[179] = shet;
    shet = 0;
    if (zam_180p < 180) { //первый набор массива
      zam_180p++;
      int fon_vr1 = 0;
      for (int i = 180 - zam_180p; i < 180; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 * (18.0 / zam_180p);
    }
    if (zam_180p >= 180) { //набор массива
      int fon_vr1 = 0;
      for (int i = 0; i < 180; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 / 10;
    }
    if (zam_180p <= 36) {
      stat_percent = stat_percent - 2.0;
    }
    if (zam_180p > 36 && zam_180p <= 72) {
      stat_percent = stat_percent - 0.3;
    }
    if (zam_180p > 72 && zam_180p <= 100) {
      stat_percent = stat_percent - 0.2;
    }
    if (zam_180p > 100 && zam_180p <= 180) {
      stat_percent = stat_percent - 0.1;
    }
    if (stat_percent < 5) {
      stat_percent = 5.0;
    }
  }
  if (!(PIND & (1 << PIND7))) { //нажатие <<<
    _delay_ms(500);//антидребезг
    menu = 0;
    shet = 0; fon = 0; zam_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
    if (!(PIND & (1 << PIND7))) {//нажатие <<< фонарик
      val_kl++;
      if (val_kl == 6) {
        val_kl = 0;
        fonarik = !fonarik;
      }
    }
  }
}
//--------------------------------------------------------------
void lcd_poisk() {//вывод на дисплей режима поиск
  if (shet < treviga_1 && fon < treviga_1) {//проверяем тревогу
    tr = 0;
  }
  if (shet > treviga_1 || fon > treviga_1) {//проверяем тревогу
    tr = 1;
  }

  myGLCD.clrScr();
  if (tr == 1) { //опасно
    myGLCD.drawBitmap(91, 29, logo_tr_OLED, 32, 32);
  }
  else myGLCD.drawCircle(107, 45, 2);
  myGLCD.setFont(BigNumbers);
  myGLCD.drawRect(0, 0, 88, 41);
  myGLCD.drawRect(0, 30, 88, 63);
  if (fon >= 1000) {
    float mZV = float(fon) / 1000;
    myGLCD.printNumF(mZV, 1, 4, 4, '.', 4, '0');
    myGLCD.setFont(SmallFont); myGLCD.print("mR/h", 62, 19);
  }
  if (fon < 1000) {
    myGLCD.printNumI(fon, 4, 4, 4, '0');
    myGLCD.setFont(SmallFont); myGLCD.print("uR/h", 62, 19);
  }

  time_d ();
  myGLCD.setFont(TinyFont);
  myGLCD.print("ACCURACY", 93, 10);
  myGLCD.printNumI(HOUR, 2, 34);
  if (HOUR >= 9) {
    myGLCD.print("h", 15, 34);
  }
  if (HOUR < 9) {
    myGLCD.print("h", 7, 34);
  }
  myGLCD.printNumI(MIN, 20, 34);
  if (MIN >= 9) {
    myGLCD.print("m", 28, 34);
  }
  if (MIN < 9) {
    myGLCD.print("m", 25, 34);
  }
  myGLCD.setFont(SmallFont);
  if (doz_v < 1000) {
    myGLCD.printNumF(doz_v, 1, 35, 33, '.', 6); myGLCD.print("uR", 72, 33);
  }
  if (doz_v >= 1000) {
    myGLCD.printNumF(doz_v / 1000.0, 2, 35, 33, '.', 6); myGLCD.print("mR", 72, 33);
  }
  myGLCD.printNumF(100 - (zam_36p * 2.2), 1, 93, 18, '.', 4); myGLCD.print("%", 117, 18);


  battery();
  for (int i = 0; i < 5; i++) {
    myGLCD.drawLine(1, (4 * i) + 46, 4, (4 * i) + 46);
  }
  for (int i = 0; i < 82; i ++) { //печатаем график
    if (mass_p[i] > 0) {
      if (mass_p[i] <= 20) {
        myGLCD.drawLine(i + 5, 63, i + 5, 63 - mass_p[i]);
      }
      if (mass_p[i] > 20) {
        myGLCD.drawLine(i + 5, 63, i + 5, 63 - 20);
      }
    }
  }
  myGLCD.update();
}
//-------------------------------------------------------------
void lcd_menu() { //вывод на дисплей меню
  myGLCD.clrScr();
  myGLCD.setFont(SmallFont);
  myGLCD.print("OPASN.1", 8, 0); myGLCD.printNumI(treviga_1, 75, 0); myGLCD.print("uR/h", RIGHT, 0);
  myGLCD.print("OPASN.2", 8, 8); myGLCD.printNumI(treviga_2, 75, 8); myGLCD.print("uR/h", RIGHT, 8);
  myGLCD.print("PODSV.", 8, 16); myGLCD.printNumI(podsvetka, 75, 16);
  myGLCD.print("INVERT", 8, 24); myGLCD.printNumI(Lcd_Inv, 75, 24); myGLCD.print("on/off", RIGHT, 24);//usr
  myGLCD.print("POISK R", 8, 32); myGLCD.printNumI(scrin_GRAF, 75, 32); myGLCD.print("SEK", RIGHT, 32);
  myGLCD.print("ZVUK", 8, 40); myGLCD.printNumI(buzz_ON, 75, 40);
  myGLCD.print("OUT", 8, 48);
  myGLCD.print("SAVE", 8, 56);
  myGLCD.print(">", 0, n_menu * 8);
  myGLCD.update();
}
//-------------------------------------------------------------
void lcd_sys() { //вывод на дисплей меню
  VCC_read();
  speed_nakachka ();//скорость накачки имлульсы/сек
  myGLCD.clrScr();
  myGLCD.setFont(SmallFont);
  myGLCD.print("OPORN", 8, 0); myGLCD.printNumF(opornoe, 2, 44, 0); myGLCD.print("VCC", 75, 0); myGLCD.printNumF(VCC, 2, RIGHT, 0);
  hv_400 = hv_adc * opornoe * k_delitel / 255; //считем высокео перед выводом
  myGLCD.print("NAKAH", 8, 10); myGLCD.printNumI(puls, 75, 10); myGLCD.printNumI(hv_400, RIGHT, 10);
  myGLCD.print("DOZA", 8, 20); myGLCD.print(">>", 75, 20); myGLCD.print("SBROS", RIGHT, 20);
  myGLCD.print("OUT", 8, 30);
  myGLCD.print("SAVE", 8, 40);
  myGLCD.print(">", 0, sys_menu * 10);
  myGLCD.print("SPEED N", 0, 56); myGLCD.printNumI(speed_nak, 50, 56); myGLCD.print("imp/sek", RIGHT, 56);
  myGLCD.update();
}
//-------------------------------------------------------------
void poisk_f() {//режим поиска
  if (poisk == 1) {
    if (millis() - gr_milis >= scrin_GRAF * 1000) { //счет для графика
      gr_milis = millis();
      val_ok = 0;//сброс удержания системного меню
      shet_gr = shet - shet_n;
      if (shet_gr < 0) {
        shet_gr = 1;
      }
      mass_p[m] = shet_gr ;
      shet_n = shet;
      if (m < 82) {
        m++;
      }
      if (m == 82) {
        for (int i = 0; i < 83; i++) {
          mass_p[i] = mass_p[i + 1];
        }
        mass_p[82] = shet_gr;
      }
    }
    if (millis() - toch_milis >= 1000) {
      toch_milis = millis();
      for (int i = 0; i < 36; i++) { //сдвигаем
        mass_36[i] = mass_36[i + 1];
      }
      mass_36[36] = shet;
      if (zam_36p < 36) { //первый набор массива
        zam_36p++;
        fon = fon + shet;
      }
      if (zam_36p >= 36) { //набор массива
        int fon_vr1 = 0;
        for (int i = 0; i < 36; i++) {
          fon_vr1 = fon_vr1 + mass_36[i];
        }
        fon = fon_vr1;
      }
      shet = 0;
      /*
        for (int i = 0; i < 36; i++) {
          Serial.print( mass_36[i]); Serial.print(",");
          }
          Serial.print(","); Serial.print(fon); Serial.println(" ");
      */
      doz_v = doz_v + fon / 100.0 / 36.0;
      time_doza = time_doza + 1;
      if (doz_v - doza_vr >= save_DOZ) { //а не пора ли сохранить дозу ?)
        eeprom_wrD ();
        doza_vr = doz_v;
      }
    }
  }
}
//-------------------------------------------------------------
void signa () { //индикация каждой частички звуком светом
  shet_s = shet;
  if (buzz_ON == 1) {//включаем бузер
    PORTB |= (1 << 5); //светодиод
    int d = 30;
    while (d > 0) {
      PORTD |= (1 << 6);
      _delay_us(ton_BUZZ);
      PORTD &= ~(1 << 6);
      _delay_us(ton_BUZZ);
      d--;
    }
    PORTB &= ~(1 << 5);//светодиод
  }
  generator();//накачка по обратной связи с АЦП
}
//-------------------------------------------------------------
void Schet() { //прерывание от счетчика на пин 2
  //detachInterrupt(0);
  shet++;
  //attachInterrupt(0, Schet, FALLING);
}
//-------------------------------------------------------------
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++;
  }
}
//-------------------------------------------------------------
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;
}
//-------------------------------------------------------------
byte Read_HV () {
  ADMUX = 0b11100110;//выбор внутреннего опорного 1,1В и А6
  ADCSRA = 0b11100111;
  _delay_us(20);
  while ((ADCSRA & 0x10) == 0);
  ADCSRA |= 0x10;
  byte result = ADCH;
  ADCSRA &= ~(1 << ADEN);  // отключаем АЦП,
  return result;
}
//-------------------------------------------------------------

void lcd_init() {
  myGLCD.begin();
  myGLCD.setBrightness(contrast);
  myGLCD.invert(Lcd_Inv);
  myGLCD.clrScr();
  myGLCD.drawBitmap(0, 0, logo_rag, 84, 48);
  myGLCD.setFont(SmallFont);
  myGLCD.print("Arduino+", CENTER, 32);
  myGLCD.print("Dosimetr v1.03", CENTER, 40);
  myGLCD.update();
  delay(1000);
}
//-------------------------------------------------------------
void eeprom_wrS () { //запись настроек в память
  EEPROM.write(0, 222);
  EEPROM.write(1, treviga_1);
  EEPROM.write(2, podsvetka);
  EEPROM.write(3, Lcd_Inv);
  EEPROM.write(4, scrin_GRAF);
  EEPROM.write(5, buzz_ON);
  EEPROM.write(6, puls);
  EEPROM.write(7, opornoe * 100);
  EEPROM.write(8, treviga_2);
  myGLCD.clrScr();
  myGLCD.setFont(SmallFont);
  myGLCD.print("Save OK", CENTER, 24);
  myGLCD.update();
  _delay_ms(1000);
}
//-------------------------------------------------------------
void eeprom_wrD () { //запись настроек в память время накопления дозы
  byte hi = time_doza >> 8;
  byte low = time_doza;
  EEPROM.write(9, hi);
  EEPROM.write(10, low);
  hi = int(doz_v) >> 8;
  low = int(doz_v);
  EEPROM.write(11, hi);
  EEPROM.write(12, low);
}
//-------------------------------------------------------------
void eeprom_readD () { //чтание настроек из памяти время накопления дозы
  byte hi  = EEPROM.read(9);
  byte low  = EEPROM.read(10);
  time_doza = (hi << 8) | low;
  hi  = EEPROM.read(11);
  low  = EEPROM.read(12);
  doz_v = (hi << 8) | low;

}
//-------------------------------------------------------------
void eeprom_readS () { //чтание настроек из памяти
  if (EEPROM.read(0) == 222) {
    treviga_1 = EEPROM.read(1);
    podsvetka = EEPROM.read(2);
    Lcd_Inv = EEPROM.read(3);
    scrin_GRAF = EEPROM.read(4);
    buzz_ON = EEPROM.read(5);
    puls = EEPROM.read(6);
    opornoe = EEPROM.read(7) / 100.0;
    treviga_2 = EEPROM.read(8);
  }
  _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() {
  HOUR = time_doza / 3600;
  MIN = (time_doza / 60) % 60;
}
//-------------------------------------------------------------
void battery() { //батарейка
  VCC_read();
  myGLCD.drawBitmap(99, 0, logo_bat, 24, 8);
  myGLCD.setFont(TinyFont);
  myGLCD.printNumF(VCC, 2, 103, 2);
}

Не забудьте поставить свои значения ADC_value и k_delitel в дефайнах (строки 19-20.)

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

Osty_Mate
Offline
Зарегистрирован: 17.04.2018

Вроде загрузил, спасибо. Сейчас попробую всё вместе включить.

Так получилось, что я не мотал блокинг, взял готовый транс из старого принтера(есть там вкусная высоковольтная часть). На первичке чёрт знает сколько витков, думаю 6-10. Это как-то может повлиять на работу дозиметра?

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

Пробуйте, методика настройки есть в топике. Транс должен быть с зазором. Микропотребления, скорее всего, не выйдет. Только пока не настроите работу высоковольтной части - не устанавливайте счётчик Гейгера, они не любят завышеного напряжения.

Кстати, хорошо подходят трансы со старых плёночных фотоаппаратов -"мыльниц", там как раз преобразователь на блокинге стоял.

Osty_Mate
Offline
Зарегистрирован: 17.04.2018

Всё поставил кроме счётчика, включился хорошо, но заметил странную вещь. Показывал около 2-3 мкР, но счётчика не было и пикал, иногда даже по многу раз (по 5 за несколько секунд). Мульметром пытался замерить высоковольтную часть, всё по нулям. oled прошивка

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

Ищите проблемы в железе... Без счётчика счёта быть не должно, высокое должно генериться. Счёт, возможно, обусловлен просачиванием наводок от цепей генератора. По высокому ничего не могу подсказать, поскольку применены элементы, не тестировавшиеся в АрДосе.

Osty_Mate
Offline
Зарегистрирован: 17.04.2018

Думаю дело в транзисторе, взял 5N80. Можно туда воткнуть биполярник?

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

Нет. irlml2502, irlml6346. Кто-то из форумчан успешно ставил irlz34, но мне такое решение не нравится. Если менять - то только на logik level полевик с минимальной ёмкостью затвора, малым сопротивлением в открытом состоянии. Ну и напряжением и быстродействием не ниже вышеуказаных.
Фото собраного выложите, желательно с хорошим разрешением через сторонний имиджхостинг.

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

v1.07. Частичная русификация. Спасибо kaktuc за русский шрифт для библиотеки Ринки-динк и arduinec за перекодировщик. А также Dark-Dante за бета-тест.

/* ArDOs   v1.07
***Дозиметр на Ардуино
***IDE Arduino 1.8.5
  ветка форума 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 60 //контрастность дисплея
//#define buzzer_active //если используется активный бузер (со встроенным генератором), управляемый транзистором с выхода 6, то раскомментировать эту строчку, если пассивный (с усилителем или без) - оставить закомментированой.
//#define UNO_DIP // если используется ArduinoUNO или плата на голой атмеге328 в корпусе DIP - раскомментируйте данную строчку. Это переключит чтение напряжения с делителя с ноги A6 на ногу A5.
#define first_alarm_duration 7000 //длительность сигнала тревоги при превышении первого аварийного порога в миллисекундах
byte treviga_1 = 30; //первая ступень тревоги
byte treviga_2 = 60; //вторая ступень тревоги
byte del_BUZZ = 7;//длительность одиночного сигнала
#define  ADC_value 163  //значение АЦП при котором 400В с учетом вашего делителя напряжения (0..255). Для значений делителя с сайта srukami ADC 163. (Тестовая версия tekagi  67)
#define k_delitel 576 //коефициент делителя напряжения, зависит от вашего делителя. Для значений делителя с сайта srukami k_delitel 576. (Тестовая версия tekagi  1395)
byte puls = 2; //тонкая настройка длинны импульса высоковольтного транса
byte scrin_GRAF = 1; //скорость построения графика в секундах
byte ind_ON = 1;  //0 - индикация выключена, 1 - включён бузер, 2 - светодиод, 3 - и бузер, и светодиод
bool podsvetka = 0; //подсветка
bool alarm_sound = 0; //флаг индикации превышения порога звуком
bool son_OK = 0; //разрешение или запрет сна
float opornoe = 1.10; //делить на opornoe/10
#define son_t 40 //время засыпания в секундах
#define save_DOZ 20 //как часто сохранять накопленную дозу например каждые 20мкР
byte beta_time = 5; //время замера бета излучения
//настройки //////////////конец
//служебные переменные
extern uint8_t rus_font_6x8[], MediumNumbers[], TinyFont[];
#define maxString 21 // для работы функции преобразования кодировки utf8us
char target[maxString + 1] = ""; // для работы функции преобразования кодировки utf8us
extern uint8_t logo_bat[], logo_rag[], logo_tr[], gif_chast_1[], gif_chast_2[];
volatile int shet = 0;
unsigned long t_milis = 0, gr_milis = 0, lcd_milis = 0, toch_milis = 0, timer_mil = 0;
unsigned long alarm_milis = 0; //для отсчёта длительности сигнала тревоги по превышению порога
unsigned long spNAK_milis = 0, time_doza = 0, bat_mill = 0;
int hv_adc, hv_400, shet_s = 0, fon = 0, shet_gr = 0, shet_n = 0;
int speed_nakT = 0, speed_nak = 0, time_sh_l = 0, result;
byte MIN, DAY, HOUR, MONTH; //для учёта времени дозы
int doza_vr = 0;
byte mass_p[84], mass_toch[201], m = 0, n_menu = 0, sys_menu = 0, mass_36[41];
byte val_kl = 0, val_ok = 0, menu = 0, zam_180p = 0, zam_36p = 0, gif_x = 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, stat_percent = 99.0;
bool tr = 0, poisk = 1, fonarik = 0, g_fl = 0, toch;
#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() {
  //Serial.begin(115200);
  ACSR |= 1 << ACD; //отключаем компаратор
  //ADCSRA &= ~(1 << ADEN);  // отключаем АЦП,
  pinMode(3, INPUT_PULLUP); //кнопка
  pinMode(4, INPUT_PULLUP); //кнопка
  pinMode(7, INPUT_PULLUP); //кнопка
  DDRB |= (0 << 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 ();
  lcd_init();
  attachInterrupt(0, Schet, FALLING);//прерываниям пин 2
  DDRB |= (1 << 5); //пины на выход
  DDRD |= (1 << 5);
  DDRD |= (1 << 6);
  DDRD |= (1 << 6);//пин бузера
  nakachka();
}
//-------------------------------------------------------------
void loop() 
{
key_data = get_key();  // вызываем функцию определения нажатия кнопок, присваивая возвращаемое ней значение переменной, которую далее будем использовать в коде
  if (menu == 0) {
    if (key_data == key_pressed_left) { //нажатие <<<
	  key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      menu = 3;
      shet = 0; zam_180p = 0; fon = 0;
      stat_percent = 99.0;
	 } 
    if (key_data == key_holded_left) //нажатие <<< фонарик  
	{fonarik = !fonarik; 
	key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
	}  	
    if (key_data == key_holded_right) // удержание <<< подсветка
	 {
		key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду		  
        podsvetka = !podsvetka;
     }		
    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_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
  }
  } 
  if (menu == 4) {
    if (key_data == key_pressed_right) { //нажатие >>>
	  key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      menu = 0;
      shet = 0;
      stat_percent = 99.0;
    }
  }
  if (fonarik == 0) { //фонарик
    PORTB &= ~(1 << 1);//пин фонаря
  } else if (fonarik == 1) {
    PORTB |= (1 << 1);//пин фонаря
  }
  if (podsvetka == 1) {
    PORTC &= ~(1 << 2); //A2 дисплей Light
  }
  if (podsvetka == 0) {
    PORTC |= (1 << 2); //A2 дисплей Light
  }
  if (millis() - lcd_milis >= 300) { //скорость отрисовки дисплея
    lcd_milis = millis();
    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сек
    }
    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;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду		  
        son_OK = !son_OK;
      }
      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, 3); //держим значение в диапазоне 0...3
      }
      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;
        }
        if (puls > 200) {
          puls = 1;
        }
      }
      if (sys_menu == 2) {
		key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        time_doza = 0;//сброс накопленной дозы
        doz_v = 0;//сброс накопленной дозы
        eeprom_wrD ();
        myGLCD.clrScr();
        myGLCD.setFont(rus_font_6x8);
        myGLCD.print(utf8rus("СБРОС OK"), 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;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        son_OK = !son_OK;
      }
      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, 3); //держим значение в диапазоне 0...3
      }
      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;
        }
        if (opornoe > 1.20) {
          opornoe = 0.98;
        }
      }
      if (sys_menu == 1) {
	  	key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        puls--;
        if (puls < 1) {
          puls = 200;
        }
        if (puls > 200) {
          puls = 1;
        }
      }
      if (sys_menu == 2) {
	  	key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        time_doza = 0;//сброс накопленной дозы
        doz_v = 0;//сброс накопленной дозы
        eeprom_wrD ();
        myGLCD.clrScr();
        myGLCD.setFont(rus_font_6x8);
        myGLCD.print(utf8rus("СБРОС OK"), 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 (!tr && alarm_sound) // если фон ниже порога тревоги, но сигнал тревоги ещё не выключен
  {
res_first_alarm(); //сбрасываем сигнал тревоги
  }
}
//------------------------------------------------------------------------------------------------------------------
void gif_nabor() {
  myGLCD.drawLine(0, 24, 84, 24); myGLCD.drawLine(0, 38, 84, 38);
  for (int i = 83 - zam_180p * 0.47; i < 84; i++) {
    myGLCD.drawLine(i, 24, i, 38);
  }
  g_fl = !g_fl;
  if (g_fl == 0) {
    myGLCD.drawBitmap(gif_x, 27, gif_chast_1, 8, 8);
  } else {
    myGLCD.drawBitmap(gif_x, 27, gif_chast_2, 8, 8);
  }
  myGLCD.setFont(rus_font_6x8);
  if (zam_180p < 200) {
    gif_x = gif_x + 1;
    if (gif_x >= 83 - zam_180p * 0.47) {
      gif_x = 0;
    }
    myGLCD.print(utf8rus("АНАЛИЗ"), CENTER, 40);
  }
  else if (zam_180p >= 200) {
    myGLCD.print(utf8rus("ОБНОВЛЕНИЕ"), CENTER, 40);
  }
}
//--------------------------------------------------------------
void zamer_200s() 
{
  myGLCD.clrScr();
  myGLCD.setFont(rus_font_6x8);
  myGLCD.print("%", 20, 0); myGLCD.printNumF(stat_percent, 1, 26, 0);
  myGLCD.setFont(MediumNumbers);
      if (alarm_sound)  //сбрасываем сигнал тревоги первого уровня, если активен
    {
       res_first_alarm(); //сбрасываем сигнал тревоги 
    }
  if (fon > 0) {
    if (fon >= 1000) {
		myGLCD.printNumF((float(fon)/1000), 2, LEFT, 7);
        myGLCD.setFont(rus_font_6x8); myGLCD.print(utf8rus("мР/ч"), RIGHT, 12);
    }
    if (fon < 1000) 
	{
		if (fon < 100)
			{
			myGLCD.printNumI(fon, CENTER, 7);
			}
		else
			{
			myGLCD.printNumI(fon, LEFT, 7);	
			}
      myGLCD.setFont(rus_font_6x8); myGLCD.print(utf8rus("мкР/ч"), RIGHT, 12);
    }
  }

  gif_nabor();
  battery();
  myGLCD.update();
  if (millis() - toch_milis >= 1000) {
    toch_milis = millis();
    for (int i = 0; i < 200; i++) { //сдвигаем
      mass_toch[i] = mass_toch[i + 1];
    }
    mass_toch[199] = shet;
    shet = 0;
    if (zam_180p < 200) { //первый набор массива
      zam_180p++;
      int fon_vr1 = 0;
      for (int i = 200 - zam_180p; i < 200; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 * (40.0 / zam_180p);
    }
    if (zam_180p >= 200) { //набор массива
      int fon_vr1 = 0;
      for (int i = 0; i < 200; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 / 5;
    }
    if (zam_180p <= 36) {
      stat_percent = stat_percent - 2.0;
    }
    if (zam_180p > 36 && zam_180p <= 72) {
      stat_percent = stat_percent - 0.3;
    }
    if (zam_180p > 72 && zam_180p <= 100) {
      stat_percent = stat_percent - 0.2;
    }
    if (zam_180p > 100 && zam_180p <= 200) {
      stat_percent = stat_percent - 0.1;
    }
    if (stat_percent < 5) {
      stat_percent = 5.0;
    }
  }
}
//-------------------------------------------------------------------------------------------------------
void lcd_poisk() {//вывод на дисплей режима поиск
  if (shet < treviga_1 && fon < treviga_1) {//проверяем тревогу
    tr = 0;
  }
  if (shet > treviga_1 || fon > treviga_1) {//проверяем тревогу
    check_alarm_signal(); // устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
    tr = 1;
  }
  myGLCD.clrScr();
  myGLCD.setFont(rus_font_6x8);
  if (tr == 1) { //опасно
    myGLCD.drawBitmap(0, 0, logo_tr, 24, 8);
  }
  myGLCD.print("%", 20, 0); myGLCD.printNumF(100 - (zam_36p * 2.0), 1, 26, 0);
  myGLCD.setFont(MediumNumbers);
  if (fon > 0) {
    if (fon >= 1000) {
      myGLCD.printNumF((float(fon)/1000), 2, LEFT, 7);
        myGLCD.setFont(rus_font_6x8); myGLCD.print(utf8rus("мР/ч"), RIGHT, 12);
    }
    if (fon < 1000) 
		{
		if (fon < 100)
			{
			myGLCD.printNumI(fon, CENTER, 7);
			}
		else
			{
			myGLCD.printNumI(fon, LEFT, 7);	
			}
      myGLCD.setFont(rus_font_6x8); myGLCD.print(utf8rus("мкР/ч"), RIGHT, 12);
    }
  }
  time_d ();
  myGLCD.setFont(TinyFont);
  ind_doze_time();	//вывод времени накопления дозы на дисплей	  
  myGLCD.setFont(rus_font_6x8);
  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();
  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(TinyFont);
  myGLCD.print("OPASN.1", 0, 0); myGLCD.printNumI(treviga_1, CENTER, 0); myGLCD.print("uR/h", RIGHT, 0);
  myGLCD.print("OPASN.2", 0, 6); myGLCD.printNumI(treviga_2, CENTER, 6); myGLCD.print("uR/h", RIGHT, 6);
  myGLCD.print("PODSV.", 0, 12); myGLCD.printNumI(podsvetka, CENTER, 12);
  myGLCD.print("------", 0, 18); myGLCD.printNumI(son_OK, CENTER, 18); myGLCD.print("on/off", RIGHT, 18);//usr
  myGLCD.print("POISK.", 0, 24); myGLCD.printNumI(scrin_GRAF, CENTER, 24);
  myGLCD.print("BUZ/LED", 0, 30); //пункт меню выбора индикации частиц
  switch (ind_ON)
	{
	case 0:
		myGLCD.print("off/off", RIGHT, 30); //индикация выключена
		break;	
	case 1:
		myGLCD.print("on/off", RIGHT, 30); //индикация звуком
		break; 	
	case 2:
		myGLCD.print("off/on", RIGHT, 30); //индикация светом
		break;	
	case 3:
		myGLCD.print("on/on", RIGHT, 30); //индикация звуком и светом
		break; 
		default:
		myGLCD.print("err", RIGHT, 30); //	если значение не равно 1,2,3 или 0 - выводим ошибку	
	} 
  myGLCD.print("OUT", 0, 36);
  myGLCD.print("SAVE", 0, 42);
  myGLCD.print(">", 30, n_menu * 6);
  myGLCD.update();
}
//----------------------------------------------------------------------------------------------------------------------
void lcd_sys() { //вывод на дисплей меню
  VCC_read();
  speed_nakachka ();//скорость накачки имлульсы/сек
  myGLCD.clrScr();
  myGLCD.setFont(TinyFont);
  myGLCD.print("OPORN", 0, 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("NAKAH", 0, 6); myGLCD.printNumI(puls, CENTER, 6); myGLCD.printNumI(hv_400, RIGHT, 6);
  myGLCD.print("DOZA", 0, 12); myGLCD.print(">>", CENTER, 12); myGLCD.print("SBROS", RIGHT, 12);
  myGLCD.print("OUT", 0, 18);
  myGLCD.print("SAVE", 0, 24);
  myGLCD.print("BETA", 0, 30); myGLCD.printNumI(beta_time, CENTER, 30); myGLCD.print("MIN", RIGHT, 30);
  myGLCD.print(">", 30, sys_menu * 6);
  myGLCD.print("SPEED N", 0, 40); myGLCD.printNumI(speed_nak, CENTER, 40); myGLCD.print("imp/sek", RIGHT, 40);
  myGLCD.update();
}
//---------------------------------------------------------------------------------------------------------------------
void zamer_beta() {// замер бета или продуктов
  if (gotovo == 0) 
{
/*  
//этот кусок кода вынесен в loop, поскольку из-за вызова функции бета замера с частотой обновления дисплея не отрабатывается считывание состояния кнопок внутри функции
    if (key_data == key_pressed_ok) { //нажатие 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; //обнуляем счёт            
      }
    }
*/	
    if (alarm_sound)  //если активен сигнал тревоги первого уровня
    {
       res_first_alarm(); //сбрасываем сигнал тревоги
    }
    myGLCD.clrScr();
    myGLCD.setFont(rus_font_6x8);
    myGLCD.print(utf8rus("Замер "), 20, 10); myGLCD.printNumI(bet_z, 55, 10);
    myGLCD.print(utf8rus("нажми OK"), CENTER, 20);
    myGLCD.update();
  }  
  if (gotovo == 1) {
    timer_soft();
    byte otsup = 0;
    if (minute > 9) {
      otsup = 5;
    }
    myGLCD.clrScr();
    battery();
    myGLCD.setFont(TinyFont);
    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("time", 23 + otsup, 0);
    myGLCD.drawLine(0, 8, 83, 8);
    myGLCD.setFont(rus_font_6x8);
    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);
    }
  }
  if (key_data == key_pressed_right) { //нажатие >>>
    key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    menu = 0;
    shet = 0; fon = 0; zam_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
  }
}
//-------------------------------------------------------------------------------------------------------------
void poisk_f() {//режим поиска
  if (poisk == 1) {
    if (millis() - gr_milis >= scrin_GRAF * 1000) { //счет для графика
      gr_milis = millis();
      val_ok = 0;//сброс удержания системного меню
      shet_gr = shet - shet_n;
      if (shet_gr < 0) {
        shet_gr = 1;
      }
      mass_p[m] = shet_gr ;
      shet_n = shet;
      if (m < 82) {
        m++;
      }
      if (m == 82) {
        for (int i = 0; i < 83; i++) {
          mass_p[i] = mass_p[i + 1];
        }
        mass_p[82] = shet_gr;
      }
    }
    if (millis() - toch_milis >= 1000) {
      toch_milis = millis();
      for (int i = 0; i < 40; i++) { //сдвигаем
        mass_36[i] = mass_36[i + 1];
      }
      mass_36[40] = shet;
      if (zam_36p < 40) { //первый набор массива
        zam_36p++;
        fon = fon + shet;
      }
      if (zam_36p >= 40) { //набор массива
        int fon_vr1 = 0;
        for (int i = 0; i < 40; i++) {
          fon_vr1 = fon_vr1 + mass_36[i];
        }
        fon = fon_vr1;
      }
      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;
      }
    }
  }
}
//----------------------------------------------------------------------------------------------------------------
void signa () { //индикация каждой частички звуком светом
  shet_s = shet;  
    if (alarm_sound) //если поднят флаг аварийного сигнала
  {
  #ifdef buzzer_active //если задефайнен активный бузер
    PORTD |= (1 << 6); // включаем непрерывный сигнал тревоги
  #else //пассивный
  tone (6, 1300); //генерим писк с частотой 1300Гц (значение можно изменить на своё) на пине 6
  #endif
    if ((millis() - alarm_milis) > first_alarm_duration) // проверяем, не истекло ли время подачи сигнала тревоги
    {
    #ifdef buzzer_active   //если задефайнен активный бузер
    PORTD &= ~(1 << 6); // выключаем непрерывный сигнал тревоги
    #else //пассивный бузер
    noTone (6); //выключаем писк на 6й ноге
    #endif 
    alarm_sound = 0; // сбрасываем флаг сигнала тревоги
    }   
    PORTB |= (1 << 5); //включаем светодиод
    delay(del_BUZZ);
    PORTB &= ~(1 << 5);//выключаем светодиод
  }
  else //если флаг сигнала тревоги не поднят, генерим одиночные сигналы, озвучивающие пойманные частицы  
    {
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,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,1000,30); //генерим писк 1000Гц 30миллисекунд на 6й ноге
					delay(del_BUZZ);//длительность одиночного сигнала
					PORTB &= ~(1 << 5);//выключаем светодиод
				}
			#endif 
			break; 
	} 
    }

  //generator();//накачка по обратной связи с АЦП
}
//-------------------------------------------------------------------------------------------------
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(TinyFont);
  myGLCD.printNumF(VCC, 2, 63, 2);
}
//----------------------------------------------------------------------------------------------------
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;
}
//----------------------------------------------------------------------------------------------------
void lcd_init() {
  myGLCD.InitLCD();
  myGLCD.setContrast(contrast);
  myGLCD.clrScr();
  myGLCD.drawBitmap(0, 0, logo_rag, 84, 48);
  myGLCD.setFont(rus_font_6x8);
  myGLCD.print(utf8rus("Ардуино+"), CENTER, 32);
  myGLCD.print(utf8rus("Дозиметр v1.07"), CENTER, 40);
  myGLCD.update();
  _delay_ms(1000);
}
//----------------------------------------------------------------------------------------------------
void eeprom_wrS () { //запись настроек в память
  EEPROM.write(0, 222);
  EEPROM.write(1, treviga_1);
  EEPROM.write(2, podsvetka);
  EEPROM.write(3, son_OK);
  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(rus_font_6x8);
  myGLCD.print(utf8rus("Сохранено"), CENTER, 24);
  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);
    son_OK = 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 timer_soft() {
  if (millis() - timer_mil >= 1000) {
    timer_mil = millis();
    sek++;
    toch = !toch;
    if (sek > 60) {
      sek = 0;
      minute++;
    }
  }
}
//------------------------------------------------------------------------------------------------------
void check_alarm_signal()  // устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
{
  if (!tr) // если счёт превысил аварийный порог, но флаг "tr" ещё не установлен
    {
    alarm_sound = 1; // поднимаем флаг аварийного сигнала
    alarm_milis = millis(); // запоминаем время начала тревоги
    }  
}
//------------------------------------------------------------------------------------------------------
void res_first_alarm() //подпрограмма выключения тревоги (ручного или по истечении таймаута)
  {
    alarm_sound = 0; // сбрасываем флаг звукового сигнала тревоги
   #ifdef buzzer_active //если задефайнен активный бузер
   PORTD &= ~(1 << 6); // выключаем бузер
   #else //пассивный бузер
   noTone(6);   //выключаем генерацию сигнала на 6й ноге
   #endif
  }
//------------------------------------------------------------------------------------------------------
void ind_doze_time() //вывод времени накопления дозы на дисплей
{
  myGLCD.setFont(TinyFont);
  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("d", 26, 26);
	}
  else
	{
    myGLCD.print("d", 23, 26);
	}	
  }
  else if (DAY) // если нет месяцев, но есть дни
		{
		myGLCD.printNumI(DAY, 0, 26);
		if (DAY > 9) 
		{
		myGLCD.print("d", 9, 26);
		}
		else
		{
		myGLCD.print("d", 5, 26);
		}
		myGLCD.printNumI(HOUR, 18, 26);
		if (HOUR > 9) 
		{
		myGLCD.print("h", 26, 26);
		}
		else 
		{
		myGLCD.print("h", 23, 26);
		}
		}
			else // если нет дней
			{
			myGLCD.printNumI(HOUR, 0, 26);
			if (HOUR > 9) 
			{
			myGLCD.print("h", 9, 26);
			}
			else
			{
			myGLCD.print("h", 5, 26);
			}
			myGLCD.printNumI(MIN, 18, 26);
			if (MIN > 9) 
			{
			myGLCD.print("m", 26, 26);
			}
			else
			{
			myGLCD.print("m", 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;
}

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




/*

ChangeLog by tekagi:

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 за подсказки и готовые кусочки кода.

*/

В папку библиотеки LCD5110_Graph по пути .../Arduino/libraries/LCD5110_Graph/ нужно положить файл fonts.c с содержанием:

#if defined(__AVR__)
    #include <avr/pgmspace.h>
    #define fontdatatype const uint8_t
#elif defined(__PIC32MX__)
    #define PROGMEM
    #define fontdatatype const unsigned char
#elif defined(__arm__)
    #define PROGMEM
    #define fontdatatype const unsigned char
#endif

// Font size    : 6x8 pixels
fontdatatype rus_font_6x8[] PROGMEM={
0x06,0x08,0x20,0x5F,
0x00,0x00,0x00,0x00,0x00,0x00,  // <space>
0x00,0x00,0x00,0x2F,0x00,0x00,  // !
0x00,0x00,0x07,0x00,0x07,0x00,  // "
0x00,0x14,0x7F,0x14,0x7F,0x14,  // #
0x00,0x24,0x2A,0x7F,0x2A,0x12,  // $
0x00,0x23,0x13,0x08,0x64,0x62,  // %
0x00,0x36,0x49,0x55,0x22,0x50,  // &
0x00,0x00,0x05,0x03,0x00,0x00,  // '
0x00,0x00,0x1C,0x22,0x41,0x00,  // (
0x00,0x00,0x41,0x22,0x1C,0x00,  // )
0x00,0x14,0x08,0x3E,0x08,0x14,  // *
0x00,0x08,0x08,0x3E,0x08,0x08,  // +
0x00,0x00,0x00,0xA0,0x60,0x00,  // ,
0x00,0x08,0x08,0x08,0x08,0x08,  // -
0x00,0x00,0x60,0x60,0x00,0x00,  // .
0x00,0x20,0x10,0x08,0x04,0x02,  // /

0x00,0x3E,0x51,0x49,0x45,0x3E,  // 0
0x00,0x00,0x42,0x7F,0x40,0x00,  // 1
0x00,0x42,0x61,0x51,0x49,0x46,  // 2
0x00,0x21,0x41,0x45,0x4B,0x31,  // 3
0x00,0x18,0x14,0x12,0x7F,0x10,  // 4
0x00,0x27,0x45,0x45,0x45,0x39,  // 5
0x00,0x3C,0x4A,0x49,0x49,0x30,  // 6
0x00,0x01,0x71,0x09,0x05,0x03,  // 7
0x00,0x36,0x49,0x49,0x49,0x36,  // 8
0x00,0x06,0x49,0x49,0x29,0x1E,  // 9
0x00,0x00,0x36,0x36,0x00,0x00,  // :
0x00,0x00,0x56,0x36,0x00,0x00,  // ;
0x00,0x08,0x14,0x22,0x41,0x00,  // <
0x00,0x14,0x14,0x14,0x14,0x14,  // =
0x00,0x00,0x41,0x22,0x14,0x08,  // >
0x00,0x02,0x01,0x51,0x09,0x06,  // ?

0x00,0x32,0x49,0x59,0x51,0x3E,  // @
0x00,0x7C,0x12,0x11,0x12,0x7C,  // A
0x00,0x7F,0x49,0x49,0x49,0x36,  // B
0x00,0x3E,0x41,0x41,0x41,0x22,  // C
0x00,0x7F,0x41,0x41,0x22,0x1C,  // D
0x00,0x7F,0x49,0x49,0x49,0x41,  // E
0x00,0x7F,0x09,0x09,0x09,0x01,  // F
0x00,0x3E,0x41,0x49,0x49,0x7A,  // G
0x00,0x7F,0x08,0x08,0x08,0x7F,  // H
0x00,0x00,0x41,0x7F,0x41,0x00,  // I
0x00,0x20,0x40,0x41,0x3F,0x01,  // J
0x00,0x7F,0x08,0x14,0x22,0x41,  // K
0x00,0x7F,0x40,0x40,0x40,0x40,  // L
0x00,0x7F,0x02,0x0C,0x02,0x7F,  // M
0x00,0x7F,0x04,0x08,0x10,0x7F,  // N
0x00,0x3E,0x41,0x41,0x41,0x3E,  // O

0x00,0x7F,0x09,0x09,0x09,0x06,  // P
0x00,0x3E,0x41,0x51,0x21,0x5E,  // Q
0x00,0x7F,0x09,0x19,0x29,0x46,  // R
0x00,0x46,0x49,0x49,0x49,0x31,  // S
0x00,0x01,0x01,0x7F,0x01,0x01,  // T
0x00,0x3F,0x40,0x40,0x40,0x3F,  // U
0x00,0x1F,0x20,0x40,0x20,0x1F,  // V
0x00,0x3F,0x40,0x38,0x40,0x3F,  // W
0x00,0x63,0x14,0x08,0x14,0x63,  // X
0x00,0x07,0x08,0x70,0x08,0x07,  // Y
0x00,0x61,0x51,0x49,0x45,0x43,  // Z
0x00,0x00,0x7F,0x41,0x41,0x00,  // [
0xAA,0x55,0xAA,0x55,0xAA,0x55,  // <backslash>
0x00,0x00,0x41,0x41,0x7F,0x00,  // ]
0x00,0x04,0x02,0x01,0x02,0x04,  // ^
0x00,0x40,0x40,0x40,0x40,0x40,  // _

0x00,0x00,0x03,0x05,0x00,0x00,  // `
0x00,0x7C,0x12,0x11,0x12,0x7C,  // a
0x00,0x7F,0x49,0x49,0x49,0x36,  // b
0x00,0x7F,0x49,0x49,0x49,0x36,  // c
0x00,0x7F,0x01,0x01,0x01,0x01,  // d
0x00,0x60,0x3E,0x23,0x3F,0x60,  // e
0x00,0x7F,0x49,0x49,0x49,0x41,  // f
0x00,0x77,0x08,0x3E,0x08,0x77,  // g
0x00,0x22,0x49,0x49,0x5D,0x36,  // h
0x00,0x00,0x44,0x7D,0x40,0x00,  // i
0x00,0x40,0x80,0x84,0x7D,0x00,  // j
0x00,0x7F,0x10,0x28,0x44,0x00,  // k
0x00,0x00,0x41,0x7F,0x40,0x00,  // l
0x00,0x7C,0x04,0x18,0x04,0x78,  // m
0x00,0x7C,0x08,0x04,0x04,0x78,  // n
0x00,0x38,0x44,0x44,0x44,0x38,  // o

0x00,0xFC,0x24,0x24,0x24,0x18,  // p
0x00,0x18,0x24,0x24,0x18,0xFC,  // q
0x00,0x7C,0x08,0x04,0x04,0x08,  // r
0x00,0x48,0x54,0x54,0x54,0x20,  // s
0x00,0x04,0x3F,0x44,0x40,0x20,  // t
0x00,0x3C,0x40,0x40,0x20,0x7C,  // u
0x00,0x1C,0x20,0x40,0x20,0x1C,  // v
0x00,0x3C,0x40,0x30,0x40,0x3C,  // w
0x00,0x44,0x28,0x10,0x28,0x44,  // x
0x00,0x1C,0xA0,0xA0,0xA0,0x7C,  // y
0x00,0x44,0x64,0x54,0x4C,0x44,  // z
0x00,0x00,0x10,0x7C,0x82,0x00,  // {
0x00,0x00,0x00,0xFF,0x00,0x00,  // |
0x00,0x00,0x82,0x7C,0x10,0x00,  // }
0x00,0x00,0x06,0x09,0x09,0x06,  // ~
//-----------------------------------
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  //
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 

0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 

0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x7E,0x4B,0x4A,0x4B,0x42,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 

0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  //
0x00,0x00,0x00,0x00,0x00,0x20,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x38,0x55,0x54,0x55,0x58,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  //
0x00,0x00,0x00,0x00,0x00,0x00,  //
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 

0x00,0x00,0x03,0x05,0x00,0x00,  // 
0x00,0x7C,0x12,0x11,0x12,0x7C,  // 
0x00,0x7F,0x49,0x49,0x49,0x30,  // 
0x00,0x7F,0x49,0x49,0x49,0x36,  // 
0x00,0x7F,0x01,0x01,0x01,0x01,  // 
0x00,0x60,0x3E,0x23,0x3F,0x60,  // 
0x00,0x7F,0x49,0x49,0x49,0x41,  //
0x00,0x77,0x08,0x3E,0x08,0x77,  // 
0x00,0x22,0x49,0x49,0x5D,0x36,  // 
0x00,0x7F,0x30,0x08,0x06,0x7F,  // 
0x00,0x7F,0x30,0x19,0x0C,0x7F,  // 
0x00,0x7F,0x08,0x08,0x14,0x63,  // 
0x00,0x40,0x7E,0x01,0x01,0x7F,  // 
0x00,0x7F,0x02,0x0C,0x02,0x7F,  // 
0x00,0x7F,0x08,0x08,0x08,0x7F,  // 
0x00,0x3E,0x41,0x41,0x41,0x3E,  // 

0x00,0x7F,0x01,0x01,0x01,0x7F,  // 
0x00,0x7F,0x09,0x09,0x09,0x06,  // 
0x00,0x3E,0x41,0x41,0x41,0x22,  // 
0x00,0x01,0x01,0x7F,0x01,0x01,  // 
0x00,0x07,0x48,0x48,0x48,0x3F,  // 
0x00,0x0E,0x11,0x7F,0x11,0x0E,  // 
0x00,0x63,0x14,0x08,0x14,0x63,  // 
0x00,0x3F,0x20,0x20,0x3F,0x60,  // 
0x00,0x07,0x08,0x08,0x08,0x7F,  // 
0x00,0x7F,0x40,0x7E,0x40,0x7F,  // 
0x00,0x3F,0x20,0x3F,0x20,0x7F,  // 
0x40,0x01,0x7F,0x48,0x48,0x30,  // 
0x00,0x7F,0x48,0x30,0x00,0x7F,  // 
0x00,0x7F,0x48,0x48,0x30,0x00,  // 
0x41,0x49,0x49,0x49,0x3E,0x00,  // 
0x00,0x7F,0x08,0x3E,0x41,0x3E,
0x00,0x46,0x29,0x19,0x09,0x7F,
//-----------------------------------
//0x00,0x00,0x00,0x00,0x00,0x00,
//0x00,0x7C,0x10,0x7C,0x44,0x7C,
0x00,0x20,0x54,0x54,0x54,0x78,  // 
0x00,0x3C,0x4A,0x4A,0x4A,0x30,  // 
0x00,0x7C,0x54,0x54,0x54,0x28,  // 
0x00,0x7C,0x04,0x04,0x04,0x00,  // 
0x00,0x60,0x3C,0x24,0x3C,0x60,  // 
0x00,0x38,0x54,0x54,0x54,0x18,  // 
0x00,0x6C,0x10,0x7C,0x10,0x6C,  // 
0x00,0x28,0x44,0x54,0x54,0x28,  // 
0x00,0x7C,0x20,0x10,0x08,0x7C,  // 
0x00,0x7C,0x20,0x12,0x08,0x7C,  // 
0x00,0x7C,0x10,0x10,0x28,0x44,  // 
0x00,0x40,0x7C,0x04,0x04,0x7C,  // 
0x00,0x7C,0x08,0x10,0x08,0x7C,  // 
0x00,0x7C,0x10,0x10,0x10,0x7C,  // 
0x00,0x38,0x44,0x44,0x44,0x38,  // 

0x00,0x7C,0x04,0x04,0x04,0x7C,  // 
0x00,0x7C,0x24,0x24,0x24,0x18,  // 
0x00,0x38,0x44,0x44,0x44,0x28,  // 
0x00,0x04,0x04,0x7C,0x04,0x04,  // 
0x00,0x0C,0x50,0x50,0x50,0x3C,  // 
0x00,0x18,0x24,0x7C,0x24,0x18,  // 
0x00,0x44,0x28,0x10,0x28,0x44,  // 
0x00,0x3C,0x20,0x20,0x3C,0x60,  // 
0x00,0x1C,0x20,0x20,0x7C,0x00,  // 
0x00,0x7C,0x40,0x78,0x40,0x7C,  // 
0x00,0x3C,0x20,0x3C,0x20,0x7C,  // 
0x40,0x04,0x7C,0x50,0x50,0x20,  //
0x00,0x7C,0x50,0x70,0x00,0x7C,  // 
0x00,0x7C,0x50,0x50,0x20,0x00,  // 
0x44,0x54,0x54,0x54,0x38,0x00,  // 
0x00,0x7C,0x10,0x7C,0x44,0x7C,
0x00,0x48,0x54,0x34,0x14,0x7C,
};

 

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

Версия 1.07 с изменёнными меню и косметикой под синий дисплей, под Мегу в ДИП.

/* ArDOs   v1.07
***Дозиметр на Ардуино
***IDE Arduino 1.8.5
  ветка форума 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 66 //контрастность дисплея
//#define buzzer_active //если используется активный буззер (со встроенным генератором), управляемый транзистором с выхода 6, то раскомментировать эту строчку, если пассивный (с усилителем или без)- оставить закомментированой
#define UNO_DIP //если используется Arduino UNO или плата на голой Атмега 328 в корпусе DIP- раскомментируйте данную строчку. Это переключит чтение напряжения с делителя с ноги A6 на ногу A5
#define first_alarm_duration 7000 //длительность сигнала тревоги при превышении первого аварийного порога в миллисекундах
byte treviga_1 = 30; //первая ступень тревоги
byte treviga_2 = 60; //вторая ступень тревоги
byte del_BUZZ = 8; //длительность одиночного сигнала
#define  ADC_value 201  //значение АЦП при котором 400В с учетом вашего делителя напряжения (0..255)
#define k_delitel 472 //коэффициент делителя напряжения, зависит от вашего делителя
byte puls = 7; //тонкая настройка длины импульса высоковольтного трансформатора
byte scrin_GRAF = 1; //скорость построения графика в секундах
byte ind_ON = 3;  //0 - индикация выключена, 1 - включён буззер, 2 - светодиод, 3 - и буззер, и светодиод
bool podsvetka = 0; //подсветка
bool alarm_sound = 1; //флаг индикации превышения порога звуком
bool son_OK = 0; //разрешение или запрет сна
float opornoe = 1.08; //опорное напряжение
#define son_t 40 //время засыпания в секундах
#define save_DOZ 20 //как часто сохранять накопленную дозу, например каждые 20мкР
byte beta_time = 10; //время замера Бета излучения
//настройки //////////////конец
//служебные переменные
extern uint8_t rus_font_6x8[], MediumNumbers[], TinyFont[];
#define maxString 21 //для работы функции преобразования кодировки utf8us
char target[maxString + 1] = ""; //для работы функции преобразования кодировки utf8us
extern uint8_t logo_bat[], logo_rag[], logo_tr[], gif_chast_1[], gif_chast_2[];
volatile int shet = 0;
unsigned long t_milis = 0, gr_milis = 0, lcd_milis = 0, toch_milis = 0, timer_mil = 0;
unsigned long alarm_milis = 0; //для отсчёта длительности сигнала тревоги по превышению порога
unsigned long spNAK_milis = 0, time_doza = 0, bat_mill = 0;
int hv_adc, hv_400, shet_s = 0, fon = 0, shet_gr = 0, shet_n = 0;
int speed_nakT = 0, speed_nak = 0, time_sh_l = 0, result;
byte MIN, DAY, HOUR, MONTH; //для учёта времени дозы
int doza_vr = 0;
byte mass_p[84], mass_toch[201], m = 0, n_menu = 0, sys_menu = 0, mass_36[41];
byte val_kl = 0, val_ok = 0, menu = 0, zam_180p = 0, zam_36p = 0, gif_x = 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, stat_percent = 99.0;
bool tr = 0, poisk = 1, fonarik = 0, g_fl = 0, toch;
#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() {
  //Serial.begin(115200);
  ACSR |= 1 << ACD; //отключаем компаратор
  //ADCSRA &= ~(1 << ADEN); //отключаем АЦП
  pinMode(3, INPUT_PULLUP); //кнопка
  pinMode(4, INPUT_PULLUP); //кнопка
  pinMode(7, INPUT_PULLUP); //кнопка
  DDRB |= (0 << 0); PORTB &= ~(1 << 0); //пин пустой 8
  DDRC |= (0 << 4); PORTC &= ~(1 << 4); //пин пустой А4
  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 ();
  lcd_init();
  attachInterrupt(0, Schet, FALLING); //прерывания на пин 2
  DDRB |= (1 << 5); //пины на выход
  DDRD |= (1 << 5);
  DDRD |= (1 << 6);
  DDRD |= (1 << 6); //пин буззера
  nakachka();
}
//-------------------------------------------------------------
void loop() 
{
key_data = get_key(); //вызываем функцию определения нажатия кнопок, присваивая возвращаемое ей значение переменной, которую далее будем использовать в коде
  if (menu == 0) {
    if (key_data == key_pressed_left) { //нажатие <<<
    key_data = 0; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      menu = 3;
      shet = 0; zam_180p = 0; fon = 0;
      stat_percent = 99.0;
   } 
    if (key_data == key_holded_left) //нажатие <<< фонарик  
  {fonarik = !fonarik; 
  key_data = 0; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
  }   
    if (key_data == key_holded_right) //удержание <<< подсветка
   {
    key_data = 0; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду     
        podsvetka = !podsvetka;
     }    
    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_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
  }
  } 
  if (menu == 4) {
    if (key_data == key_pressed_right) { //нажатие >>>
    key_data = 0; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      menu = 0;
      shet = 0;
      stat_percent = 99.0;
    }
  }
  if (fonarik == 0) { //фонарик
    PORTB &= ~(1 << 1); //пин фонаря
  } else if (fonarik == 1) {
    PORTB |= (1 << 1); //пин фонаря
  }
  if (podsvetka == 1) {
    PORTC |= (1 << 2); //A2 дисплей Light
  }
  if (podsvetka == 0) {
    PORTC &= ~(1 << 2); //A2 дисплей Light
  }
  if (millis() - lcd_milis >= 300) { //скорость отрисовки дисплея
    lcd_milis = millis();
    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сек
    }
    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; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду     
        son_OK = !son_OK;
      }
      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, 3); //держим значение в диапазоне 0...3
      }
      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;
        }
        if (puls > 200) {
          puls = 1;
        }
      }
      if (sys_menu == 2) {
    key_data = 0; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        time_doza = 0; //сброс накопленной дозы
        doz_v = 0; //сброс накопленной дозы
        eeprom_wrD ();
        myGLCD.clrScr();
        myGLCD.setFont(rus_font_6x8);
        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; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        son_OK = !son_OK;
      }
      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, 3); //держим значение в диапазоне 0...3
      }
      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;
        }
        if (opornoe > 1.20) {
          opornoe = 0.98;
        }
      }
      if (sys_menu == 1) {
      key_data = 0; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        puls--;
        if (puls < 1) {
          puls = 200;
        }
        if (puls > 200) {
          puls = 1;
        }
      }
      if (sys_menu == 2) {
      key_data = 0; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        time_doza = 0; //сброс накопленной дозы
        doz_v = 0; //сброс накопленной дозы
        eeprom_wrD ();
        myGLCD.clrScr();
        myGLCD.setFont(rus_font_6x8);
        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 (!tr && alarm_sound) //если фон ниже порога тревоги, но сигнал тревоги ещё не выключен
  {
res_first_alarm(); //сбрасываем сигнал тревоги
  }
}
//------------------------------------------------------------------------------------------------------------------
void gif_nabor() {
  myGLCD.drawLine(0, 24, 84, 24); myGLCD.drawLine(0, 38, 84, 38);
  for (int i = 83 - zam_180p * 0.47; i < 84; i++) {
    myGLCD.drawLine(i, 24, i, 38);
  }
  g_fl = !g_fl;
  if (g_fl == 0) {
    myGLCD.drawBitmap(gif_x, 27, gif_chast_1, 8, 8);
  } else {
    myGLCD.drawBitmap(gif_x, 27, gif_chast_2, 8, 8);
  }
  myGLCD.setFont(rus_font_6x8);
  if (zam_180p < 200) {
    gif_x = gif_x + 1;
    if (gif_x >= 83 - zam_180p * 0.47) {
      gif_x = 0;
    }
    myGLCD.print(utf8rus("Анализ..."), CENTER, 40);
  }
  else if (zam_180p >= 200) {
    myGLCD.print(utf8rus("Обновление..."), CENTER, 40);
  }
}
//--------------------------------------------------------------
void zamer_200s() 
{
  myGLCD.clrScr();
  myGLCD.setFont(rus_font_6x8);
  myGLCD.print("%", 20, 0); myGLCD.printNumF(stat_percent, 1, 26, 0);
  myGLCD.setFont(MediumNumbers);
      if (alarm_sound)  //сбрасываем сигнал тревоги первого уровня, если активен
    {
       res_first_alarm(); //сбрасываем сигнал тревоги 
    }
  if (fon > 0) {
    if (fon >= 1000) {
    myGLCD.printNumF((float(fon)/1000), 2, LEFT, 7);
        myGLCD.setFont(rus_font_6x8); myGLCD.print(utf8rus("мР/ч"), RIGHT, 12);
    }
    if (fon < 1000) 
  {
    if (fon < 100)
      {
      myGLCD.printNumI(fon, CENTER, 7);
      }
    else
      {
      myGLCD.printNumI(fon, LEFT, 7); 
      }
      myGLCD.setFont(rus_font_6x8); myGLCD.print(utf8rus("мкР/ч"), RIGHT, 12);
    }
  }

  gif_nabor();
  battery();
  myGLCD.update();
  if (millis() - toch_milis >= 1000) {
    toch_milis = millis();
    for (int i = 0; i < 200; i++) { //сдвигаем
      mass_toch[i] = mass_toch[i + 1];
    }
    mass_toch[199] = shet;
    shet = 0;
    if (zam_180p < 200) { //первый набор массива
      zam_180p++;
      int fon_vr1 = 0;
      for (int i = 200 - zam_180p; i < 200; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 * (40.0 / zam_180p);
    }
    if (zam_180p >= 200) { //набор массива
      int fon_vr1 = 0;
      for (int i = 0; i < 200; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 / 5;
    }
    if (zam_180p <= 36) {
      stat_percent = stat_percent - 2.0;
    }
    if (zam_180p > 36 && zam_180p <= 72) {
      stat_percent = stat_percent - 0.3;
    }
    if (zam_180p > 72 && zam_180p <= 100) {
      stat_percent = stat_percent - 0.2;
    }
    if (zam_180p > 100 && zam_180p <= 200) {
      stat_percent = stat_percent - 0.1;
    }
    if (stat_percent < 5) {
      stat_percent = 5.0;
    }
  }
}
//-------------------------------------------------------------------------------------------------------
void lcd_poisk() { //вывод на дисплей режима поиск
  if (shet < treviga_1 && fon < treviga_1) { //проверяем тревогу
    tr = 0;
  }
  if (shet > treviga_1 || fon > treviga_1) { //проверяем тревогу
    check_alarm_signal(); //устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
    tr = 1;
  }
  myGLCD.clrScr();
  myGLCD.setFont(rus_font_6x8);
  if (tr == 1) { //опасно
    myGLCD.drawBitmap(0, 0, logo_tr, 24, 8);
  }
  myGLCD.print("%", 20, 0); myGLCD.printNumF(100 - (zam_36p * 2.0), 1, 26, 0);
  myGLCD.setFont(MediumNumbers);
  if (fon > 0) {
    if (fon >= 1000) {
      myGLCD.printNumF((float(fon)/1000), 2, LEFT, 7);
        myGLCD.setFont(rus_font_6x8); myGLCD.print(utf8rus("мР/ч"), RIGHT, 12);
    }
    if (fon < 1000) 
    {
    if (fon < 100)
      {
      myGLCD.printNumI(fon, CENTER, 7);
      }
    else
      {
      myGLCD.printNumI(fon, LEFT, 7); 
      }
      myGLCD.setFont(rus_font_6x8); myGLCD.print(utf8rus("мкР/ч"), RIGHT, 12);
    }
  }
  time_d ();
  myGLCD.setFont(TinyFont);
  ind_doze_time(); //вывод времени накопления дозы на дисплей    
  myGLCD.setFont(rus_font_6x8);
  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();
  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(TinyFont);
  myGLCD.print("Trevoga 1", 0, 0); myGLCD.printNumI(treviga_1, 54, 0); myGLCD.print("uR/h", RIGHT, 0);
  myGLCD.print("Trevoga 2", 0, 6); myGLCD.printNumI(treviga_2, 54, 6); myGLCD.print("uR/h", RIGHT, 6);
  myGLCD.print("Podsvetka", 0, 12); myGLCD.printNumI(podsvetka, 54, 12); myGLCD.print("on/off", RIGHT, 12);
  myGLCD.print("---------", 0, 18); //usr
  myGLCD.print("Obn. grafika", 0, 24); myGLCD.printNumI(scrin_GRAF, 54, 24); myGLCD.print("sek", RIGHT, 24);
  myGLCD.print("Buzzer/LED", 0, 30); //пункт меню выбора индикации частиц
  switch (ind_ON)
  {
  case 0:
    myGLCD.print("off/off", RIGHT, 30); //индикация выключена
    break;  
  case 1:
    myGLCD.print("on/off", RIGHT, 30); //индикация звуком
    break;  
  case 2:
    myGLCD.print("off/on", RIGHT, 30); //индикация светом
    break;  
  case 3:
    myGLCD.print("on/on", RIGHT, 30); //индикация звуком и светом
    break; 
    default:
    myGLCD.print("err.", RIGHT, 30); //если значение не равно 1,2,3 или 0- выводим ошибку 
  } 
  myGLCD.print("Vyhod", 0, 36);
  myGLCD.print("Sohranit", 0, 42);
  myGLCD.print(">", 49, n_menu * 6);
  myGLCD.update();
}
//----------------------------------------------------------------------------------------------------------------------
void lcd_sys() { //вывод на дисплей меню
  VCC_read();
  speed_nakachka (); //скорость накачки имлульсы/сек
  myGLCD.clrScr();
  myGLCD.setFont(TinyFont);
  myGLCD.print("Oporn.", 0, 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("Gener.", 0, 6); myGLCD.printNumI(puls, CENTER, 6); myGLCD.printNumI(hv_400, RIGHT, 6);
  myGLCD.print("Doza", 0, 12); myGLCD.print("sbros dozy", RIGHT, 12);
  myGLCD.print("Vyhod", 0, 18);
  myGLCD.print("Sohran.", 0, 24);
  myGLCD.print("Beta", 0, 30); myGLCD.printNumI(beta_time, CENTER, 30); myGLCD.print("min", RIGHT, 30);
  myGLCD.print(">", 30, sys_menu * 6);
  myGLCD.print("Skorost", 0, 40); myGLCD.printNumI(speed_nak, CENTER, 40); myGLCD.print("imp./sek", RIGHT, 40);
  myGLCD.update();
}
//---------------------------------------------------------------------------------------------------------------------
void zamer_beta() { //замер Бета или продуктов
  if (gotovo == 0) 
{
/*  
//этот кусок кода вынесен в loop, поскольку из-за вызова функции бета замера с частотой обновления дисплея не отрабатывается считывание состояния кнопок внутри функции
    if (key_data == key_pressed_ok) { //нажатие 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; //обнуляем счёт            
      }
    }
*/  
    if (alarm_sound)  //если активен сигнал тревоги первого уровня
    {
       res_first_alarm(); //сбрасываем сигнал тревоги
    }
    myGLCD.clrScr();
    myGLCD.setFont(rus_font_6x8);
    myGLCD.print(utf8rus("Замер "), 20, 10); myGLCD.printNumI(bet_z, 55, 10);
    myGLCD.print(utf8rus("Нажмите OK"), CENTER, 20);
    myGLCD.update();
  }  
  if (gotovo == 1) {
    timer_soft();
    byte otsup = 0;
    if (minute > 9) {
      otsup = 5;
    }
    myGLCD.clrScr();
    battery();
    myGLCD.setFont(TinyFont);
    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("min:sek", 23 + otsup, 0);
    myGLCD.drawLine(0, 8, 83, 8);
    myGLCD.setFont(rus_font_6x8);
    myGLCD.drawLine(42, 8, 42, 28);
    myGLCD.print(utf8rus("Замер 0"), -1, 10); myGLCD.print(utf8rus("Замер 1"), 43, 10);
    myGLCD.printNumI(bet_z0, -1, 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);
    }
  }
  if (key_data == key_pressed_right) { //нажатие >>>
    key_data = 0; //обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    menu = 0;
    shet = 0; fon = 0; zam_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
  }
}
//-------------------------------------------------------------------------------------------------------------
void poisk_f() { //режим поиска
  if (poisk == 1) {
    if (millis() - gr_milis >= scrin_GRAF * 1000) { //счет для графика
      gr_milis = millis();
      val_ok = 0; //сброс удержания системного меню
      shet_gr = shet - shet_n;
      if (shet_gr < 0) {
        shet_gr = 1;
      }
      mass_p[m] = shet_gr ;
      shet_n = shet;
      if (m < 82) {
        m++;
      }
      if (m == 82) {
        for (int i = 0; i < 83; i++) {
          mass_p[i] = mass_p[i + 1];
        }
        mass_p[82] = shet_gr;
      }
    }
    if (millis() - toch_milis >= 1000) {
      toch_milis = millis();
      for (int i = 0; i < 40; i++) { //сдвигаем
        mass_36[i] = mass_36[i + 1];
      }
      mass_36[40] = shet;
      if (zam_36p < 40) { //первый набор массива
        zam_36p++;
        fon = fon + shet;
      }
      if (zam_36p >= 40) { //набор массива
        int fon_vr1 = 0;
        for (int i = 0; i < 40; i++) {
          fon_vr1 = fon_vr1 + mass_36[i];
        }
        fon = fon_vr1;
      }
      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;
      }
    }
  }
}
//----------------------------------------------------------------------------------------------------------------
void signa () { //индикация каждой частички звуком/светом
  shet_s = shet;  
    if (alarm_sound) //если поднят флаг аварийного сигнала
  {
  #ifdef buzzer_active //если задефайнен активный буззер
    PORTD |= (1 << 6); //включаем непрерывный сигнал тревоги
  #else //пассивный
  tone (6, 1300); //генерим писк с частотой 1300Гц (значение можно изменить на своё) на пине 6
  #endif
    if ((millis() - alarm_milis) > first_alarm_duration) //проверяем, не истекло ли время подачи сигнала тревоги
    {
    #ifdef buzzer_active //если задефайнен активный буззер
    PORTD &= ~(1 << 6); //выключаем непрерывный сигнал тревоги
    #else //пассивный буззер
    noTone (6); //выключаем писк на 6й ноге
    #endif 
    alarm_sound = 0; //сбрасываем флаг сигнала тревоги
    }   
    PORTB |= (1 << 5); //включаем светодиод
    delay(del_BUZZ);
    PORTB &= ~(1 << 5); //выключаем светодиод
  }
  else //если флаг сигнала тревоги не поднят, генерим одиночные сигналы, озвучивающие пойманные частицы  
    {
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,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,1000,30); //генерим писк 1000Гц 30 миллисекунд на 6й ноге
          delay(del_BUZZ); //длительность одиночного сигнала
          PORTB &= ~(1 << 5); //выключаем светодиод
        }
      #endif 
      break; 
  } 
    }

  //generator(); //накачка по обратной связи с АЦП
}
//-------------------------------------------------------------------------------------------------
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 //если при компилляции выбрана плата Arduino UNO
  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(TinyFont);
  myGLCD.printNumF(VCC, 2, 63, 2);
}
//----------------------------------------------------------------------------------------------------
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;
}
//----------------------------------------------------------------------------------------------------
void lcd_init() {
  myGLCD.InitLCD();
  myGLCD.setContrast(contrast);
  myGLCD.clrScr();
  myGLCD.drawBitmap(0, 0, logo_rag, 84, 48);
  myGLCD.setFont(rus_font_6x8);
  myGLCD.print(utf8rus("Дозиметр"), CENTER, 32);
  myGLCD.print(utf8rus("Версия ПО 1.7"), CENTER, 40);
  myGLCD.update();
  _delay_ms(1000);
}
//----------------------------------------------------------------------------------------------------
void eeprom_wrS () { //запись настроек в память
  EEPROM.write(0, 222);
  EEPROM.write(1, treviga_1);
  EEPROM.write(2, podsvetka);
  EEPROM.write(3, son_OK);
  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(rus_font_6x8);
  myGLCD.print(utf8rus("Сохранено!"), CENTER, 24);
  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);
    son_OK = 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 timer_soft() {
  if (millis() - timer_mil >= 1000) {
    timer_mil = millis();
    sek++;
    toch = !toch;
    if (sek > 60) {
      sek = 0;
      minute++;
    }
  }
}
//------------------------------------------------------------------------------------------------------
void check_alarm_signal() //устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
{
  if (!tr) //если счёт превысил аварийный порог, но флаг "tr" ещё не установлен
    {
    alarm_sound = 1; //поднимаем флаг аварийного сигнала
    alarm_milis = millis(); //запоминаем время начала тревоги
    }  
}
//------------------------------------------------------------------------------------------------------
void res_first_alarm() //подпрограмма выключения тревоги (ручного или по истечении таймаута)
  {
    alarm_sound = 0; //сбрасываем флаг звукового сигнала тревоги
   #ifdef buzzer_active //если задефайнен активный буззер
   PORTD &= ~(1 << 6); //выключаем буззер
   #else //пассивный буззер
   noTone(6); //выключаем генерацию сигнала на 6й ноге
   #endif
  }
//------------------------------------------------------------------------------------------------------
void ind_doze_time() //вывод времени накопления дозы на дисплей
{
  myGLCD.setFont(TinyFont);
  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("d", 26, 26);
  }
  else
  {
    myGLCD.print("d", 23, 26);
  } 
  }
  else if (DAY) //если нет месяцев, но есть дни
    {
    myGLCD.printNumI(DAY, 0, 26);
    if (DAY > 9) 
    {
    myGLCD.print("d", 9, 26);
    }
    else
    {
    myGLCD.print("d", 5, 26);
    }
    myGLCD.printNumI(HOUR, 18, 26);
    if (HOUR > 9) 
    {
    myGLCD.print("h", 26, 26);
    }
    else 
    {
    myGLCD.print("h", 23, 26);
    }
    }
      else //если нет дней
      {
      myGLCD.printNumI(HOUR, 0, 26);
      if (HOUR > 9) 
      {
      myGLCD.print("h", 9, 26);
      }
      else
      {
      myGLCD.print("h", 5, 26);
      }
      myGLCD.printNumI(MIN, 18, 26);
      if (MIN > 9) 
      {
      myGLCD.print("m", 26, 26);
      }
      else
      {
      myGLCD.print("m", 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;
}

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




/*

ChangeLog by tekagi:

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 за подсказки и готовые кусочки кода.

*/

 

 

Несколько фото изменений версии 1.07

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

DEL

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

Полная русификация. v1.07.3.

/* ArDOs   v1.07.3
***Дозиметр на Ардуино
***IDE Arduino 1.8.5
  ветка форума 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 60 //контрастность дисплея
//#define buzzer_active //если используется активный бузер (со встроенным генератором), управляемый транзистором с выхода 6, то раскомментировать эту строчку, если пассивный (с усилителем или без) - оставить закомментированой.
//#define UNO_DIP // если используется ArduinoUNO или плата на голой атмеге328 в корпусе DIP - раскомментируйте данную строчку. Это переключит чтение напряжения с делителя с ноги A6 на ногу A5.
#define first_alarm_duration 7000 //длительность сигнала тревоги при превышении первого аварийного порога в миллисекундах
byte treviga_1 = 30; //первая ступень тревоги
byte treviga_2 = 60; //вторая ступень тревоги
byte del_BUZZ = 7;//длительность одиночного сигнала
#define  ADC_value 163  //значение АЦП при котором 400В с учетом вашего делителя напряжения (0..255). Для значений делителя с сайта srukami ADC 163. (Тестовая версия tekagi  67)
#define k_delitel 576 //коефициент делителя напряжения, зависит от вашего делителя. Для значений делителя с сайта srukami k_delitel 576. (Тестовая версия tekagi  1395)
byte puls = 2; //тонкая настройка длинны импульса высоковольтного транса
byte scrin_GRAF = 1; //скорость построения графика в секундах
byte ind_ON = 1;  //0 - индикация выключена, 1 - включён бузер, 2 - светодиод, 3 - и бузер, и светодиод
bool podsvetka = 0; //подсветка
bool alarm_sound = 0; //флаг индикации превышения порога звуком
bool son_OK = 0; //разрешение или запрет сна
float opornoe = 1.10; //делить на opornoe/10
#define son_t 40 //время засыпания в секундах
#define save_DOZ 20 //как часто сохранять накопленную дозу например каждые 20мкР
byte beta_time = 5; //время замера бета излучения
//настройки //////////////конец
//служебные переменные
extern uint8_t SmallFontRus[], MediumNumbers[], TinyFontRus[];
#define maxString 21 // для работы функции преобразования кодировки utf8us
char target[maxString + 1] = ""; // для работы функции преобразования кодировки utf8us
extern uint8_t logo_bat[], logo_rag[], logo_tr[], gif_chast_1[], gif_chast_2[], beta_prev_1[], beta_prev_2[];
volatile int shet = 0;
unsigned long t_milis = 0, gr_milis = 0, lcd_milis = 0, toch_milis = 0, timer_mil = 0;
unsigned long alarm_milis = 0; //для отсчёта длительности сигнала тревоги по превышению порога
unsigned long spNAK_milis = 0, time_doza = 0, bat_mill = 0;
int hv_adc, hv_400, shet_s = 0, fon = 0, shet_gr = 0, shet_n = 0;
int speed_nakT = 0, speed_nak = 0, time_sh_l = 0, result;
byte MIN, DAY, HOUR, MONTH; //для учёта времени дозы
int doza_vr = 0;
byte mass_p[84], mass_toch[201], m = 0, n_menu = 0, sys_menu = 0, mass_36[41];
byte val_kl = 0, val_ok = 0, menu = 0, zam_180p = 0, zam_36p = 0, gif_x = 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, stat_percent = 99.0;
bool tr = 0, poisk = 1, fonarik = 0, g_fl = 0, toch;
#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() {
  //Serial.begin(115200);
  ACSR |= 1 << ACD; //отключаем компаратор
  //ADCSRA &= ~(1 << ADEN);  // отключаем АЦП,
  pinMode(3, INPUT_PULLUP); //кнопка
  pinMode(4, INPUT_PULLUP); //кнопка
  pinMode(7, INPUT_PULLUP); //кнопка
  DDRB |= (0 << 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 ();
  lcd_init();
  attachInterrupt(0, Schet, FALLING);//прерываниям пин 2
  DDRB |= (1 << 5); //пины на выход
  DDRD |= (1 << 5);
  DDRD |= (1 << 6);
  DDRD |= (1 << 6);//пин бузера
  nakachka();
}
//-------------------------------------------------------------
void loop() 
{
key_data = get_key();  // вызываем функцию определения нажатия кнопок, присваивая возвращаемое ней значение переменной, которую далее будем использовать в коде
  if (menu == 0) {
    if (key_data == key_pressed_left) { //нажатие <<<
	  key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      menu = 3;
      shet = 0; zam_180p = 0; fon = 0;
      stat_percent = 99.0;
	 } 
    if (key_data == key_holded_left) //нажатие <<< фонарик  
	{fonarik = !fonarik; 
	key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
	}  	
    if (key_data == key_holded_right) // удержание <<< подсветка
	 {
		key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду		  
        podsvetka = !podsvetka;
     }		
    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_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
  }
  } 
  if (menu == 4) {
    if (key_data == key_pressed_right) { //нажатие >>>
	  key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
      menu = 0;
      shet = 0;
      stat_percent = 99.0;
    }
  }
  if (fonarik == 0) { //фонарик
    PORTB &= ~(1 << 1);//пин фонаря
  } else if (fonarik == 1) {
    PORTB |= (1 << 1);//пин фонаря
  }
  if (podsvetka == 1) {
    PORTC &= ~(1 << 2); //A2 дисплей Light
  }
  if (podsvetka == 0) {
    PORTC |= (1 << 2); //A2 дисплей Light
  }
  if (millis() - lcd_milis >= 300) { //скорость отрисовки дисплея
    lcd_milis = millis();
    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сек
    }
    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;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду		  
        son_OK = !son_OK;
      }
      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, 3); //держим значение в диапазоне 0...3
      }
      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;
        }
        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;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        son_OK = !son_OK;
      }
      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, 3); //держим значение в диапазоне 0...3
      }
      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;
        }
        if (opornoe > 1.20) {
          opornoe = 0.98;
        }
      }
      if (sys_menu == 1) {
	  	key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
        puls--;
        if (puls < 1) {
          puls = 200;
        }
        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 (!tr && alarm_sound) // если фон ниже порога тревоги, но сигнал тревоги ещё не выключен
  {
res_first_alarm(); //сбрасываем сигнал тревоги
  }
}
//------------------------------------------------------------------------------------------------------------------
void gif_nabor() {
  myGLCD.drawLine(0, 24, 84, 24); myGLCD.drawLine(0, 38, 84, 38);
  for (int i = 83 - zam_180p * 0.47; i < 84; i++) {
    myGLCD.drawLine(i, 24, i, 38);
  }
  g_fl = !g_fl;
  if (g_fl == 0) {
    myGLCD.drawBitmap(gif_x, 27, gif_chast_1, 8, 8);
  } else {
    myGLCD.drawBitmap(gif_x, 27, gif_chast_2, 8, 8);
  }
  myGLCD.setFont(SmallFontRus);
  if (zam_180p < 200) {
    gif_x = gif_x + 1;
    if (gif_x >= 83 - zam_180p * 0.47) {
      gif_x = 0;
    }
    myGLCD.print(utf8rus("АНАЛИЗ"), CENTER, 40);
  }
  else if (zam_180p >= 200) {
    myGLCD.print(utf8rus("ОБНОВЛЕНИЕ"), CENTER, 40);
  }
}
//--------------------------------------------------------------
void zamer_200s() 
{
  myGLCD.clrScr();
  myGLCD.setFont(SmallFontRus);
  myGLCD.print("%", 20, 0); myGLCD.printNumF(stat_percent, 1, 26, 0);
  myGLCD.setFont(MediumNumbers);
      if (alarm_sound)  //сбрасываем сигнал тревоги первого уровня, если активен
    {
       res_first_alarm(); //сбрасываем сигнал тревоги 
    }
  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);
    }
  }

  gif_nabor();
  battery();
  myGLCD.update();
  if (millis() - toch_milis >= 1000) {
    toch_milis = millis();
    for (int i = 0; i < 200; i++) { //сдвигаем
      mass_toch[i] = mass_toch[i + 1];
    }
    mass_toch[199] = shet;
    shet = 0;
    if (zam_180p < 200) { //первый набор массива
      zam_180p++;
      int fon_vr1 = 0;
      for (int i = 200 - zam_180p; i < 200; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 * (40.0 / zam_180p);
    }
    if (zam_180p >= 200) { //набор массива
      int fon_vr1 = 0;
      for (int i = 0; i < 200; i++) {
        fon_vr1 = fon_vr1 + mass_toch[i];
      }
      fon = fon_vr1 / 5;
    }
    if (zam_180p <= 36) {
      stat_percent = stat_percent - 2.0;
    }
    if (zam_180p > 36 && zam_180p <= 72) {
      stat_percent = stat_percent - 0.3;
    }
    if (zam_180p > 72 && zam_180p <= 100) {
      stat_percent = stat_percent - 0.2;
    }
    if (zam_180p > 100 && zam_180p <= 200) {
      stat_percent = stat_percent - 0.1;
    }
    if (stat_percent < 5) {
      stat_percent = 5.0;
    }
  }
}
//-------------------------------------------------------------------------------------------------------
void lcd_poisk() {//вывод на дисплей режима поиск
  if (shet < treviga_1 && fon < treviga_1) {//проверяем тревогу
    tr = 0;
  }
  if (shet > treviga_1 || fon > treviga_1) {//проверяем тревогу
    check_alarm_signal(); // устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
    tr = 1;
  }
  myGLCD.clrScr();
  myGLCD.setFont(SmallFontRus);
  if (tr == 1) { //опасно
    myGLCD.drawBitmap(0, 0, logo_tr, 24, 8);
  }
  myGLCD.print("%", 20, 0); myGLCD.printNumF(100 - (zam_36p * 2.0), 1, 26, 0);
  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);
    }
  }
  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();
  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("----------", 5, 18); /* myGLCD.printNumI(son_OK, CENTER, 18); */ myGLCD.print("-----------", RIGHT, 18);//usr
  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); //индикация звуком
		break; 	
	case 2:
		myGLCD.print(utf8rus("СВЕТ"), RIGHT, 30); //индикация светом
		break;	
	case 3:
		myGLCD.print(utf8rus("ЗВУК+СВЕТ"), RIGHT, 30); //индикация звуком и светом
		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(">>", CENTER, 12); myGLCD.print("SBROS", RIGHT, 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) 
{
/*  
//этот кусок кода вынесен в loop, поскольку из-за вызова функции бета замера с частотой обновления дисплея не отрабатывается считывание состояния кнопок внутри функции
    if (key_data == key_pressed_ok) { //нажатие 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; //обнуляем счёт            
      }
    }
*/	
    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) {
    timer_soft();
    byte otsup = 0;
    if (minute > 9) {
      otsup = 5;
    }
    myGLCD.clrScr();
    battery();
    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);
    }
  }
  if (key_data == key_pressed_right) { //нажатие >>>
    key_data = 0;  // обнуляем переменную функции кнопок для предотвращения ложных срабатываний далее по коду
    menu = 0;
    shet = 0; fon = 0; zam_36p = 0;
    for (int i = 0; i < 18; i++) { //чистим
      mass_36[i] = 0;
    }
  }
}
//-------------------------------------------------------------------------------------------------------------
void poisk_f() {//режим поиска
  if (poisk == 1) {
    if (millis() - gr_milis >= scrin_GRAF * 1000) { //счет для графика
      gr_milis = millis();
      val_ok = 0;//сброс удержания системного меню
      shet_gr = shet - shet_n;
      if (shet_gr < 0) {
        shet_gr = 1;
      }
      mass_p[m] = shet_gr ;
      shet_n = shet;
      if (m < 82) {
        m++;
      }
      if (m == 82) {
        for (int i = 0; i < 83; i++) {
          mass_p[i] = mass_p[i + 1];
        }
        mass_p[82] = shet_gr;
      }
    }
    if (millis() - toch_milis >= 1000) {
      toch_milis = millis();
      for (int i = 0; i < 40; i++) { //сдвигаем
        mass_36[i] = mass_36[i + 1];
      }
      mass_36[40] = shet;
      if (zam_36p < 40) { //первый набор массива
        zam_36p++;
        fon = fon + shet;
      }
      if (zam_36p >= 40) { //набор массива
        int fon_vr1 = 0;
        for (int i = 0; i < 40; i++) {
          fon_vr1 = fon_vr1 + mass_36[i];
        }
        fon = fon_vr1;
      }
      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;
      }
    }
  }
}
//----------------------------------------------------------------------------------------------------------------
void signa () { //индикация каждой частички звуком светом
  shet_s = shet;  
    if (alarm_sound) //если поднят флаг аварийного сигнала
  {
  #ifdef buzzer_active //если задефайнен активный бузер
    PORTD |= (1 << 6); // включаем непрерывный сигнал тревоги
  #else //пассивный
  tone (6, 1300); //генерим писк с частотой 1300Гц (значение можно изменить на своё) на пине 6
  #endif
    if ((millis() - alarm_milis) > first_alarm_duration) // проверяем, не истекло ли время подачи сигнала тревоги
    {
    #ifdef buzzer_active   //если задефайнен активный бузер
    PORTD &= ~(1 << 6); // выключаем непрерывный сигнал тревоги
    #else //пассивный бузер
    noTone (6); //выключаем писк на 6й ноге
    #endif 
    alarm_sound = 0; // сбрасываем флаг сигнала тревоги
    }   
    PORTB |= (1 << 5); //включаем светодиод
    delay(del_BUZZ);
    PORTB &= ~(1 << 5);//выключаем светодиод
  }
  else //если флаг сигнала тревоги не поднят, генерим одиночные сигналы, озвучивающие пойманные частицы  
    {
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,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,1000,30); //генерим писк 1000Гц 30миллисекунд на 6й ноге
					delay(del_BUZZ);//длительность одиночного сигнала
					PORTB &= ~(1 << 5);//выключаем светодиод
				}
			#endif 
			break; 
	} 
    }

  //generator();//накачка по обратной связи с АЦП
}
//-------------------------------------------------------------------------------------------------
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);
  myGLCD.printNumF(VCC, 2, 63, 2);
}
//----------------------------------------------------------------------------------------------------
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;
}
//----------------------------------------------------------------------------------------------------
void lcd_init() {
  myGLCD.InitLCD();
  myGLCD.setContrast(contrast);
  myGLCD.clrScr();
  myGLCD.drawBitmap(0, 0, logo_rag, 84, 48);
  myGLCD.setFont(SmallFontRus);
//  myGLCD.print(utf8rus("Ардуино+"), CENTER, 32);
//  myGLCD.print(utf8rus("Дозиметр v1.07"), CENTER, 40);
  myGLCD.update();
  _delay_ms(1000);
}
//----------------------------------------------------------------------------------------------------
void eeprom_wrS () { //запись настроек в память
  EEPROM.write(0, 222);
  EEPROM.write(1, treviga_1);
  EEPROM.write(2, podsvetka);
  EEPROM.write(3, son_OK);
  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, 24);
  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);
    son_OK = 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 timer_soft() {
  if (millis() - timer_mil >= 1000) {
    timer_mil = millis();
    sek++;
    toch = !toch;
    if (sek > 60) {
      sek = 0;
      minute++;
    }
  }
}
//------------------------------------------------------------------------------------------------------
void check_alarm_signal()  // устанавливаем сигнал непрерывной тревоги, если "tr" переключился в "1"
{
  if (!tr) // если счёт превысил аварийный порог, но флаг "tr" ещё не установлен
    {
    alarm_sound = 1; // поднимаем флаг аварийного сигнала
    alarm_milis = millis(); // запоминаем время начала тревоги
    }  
}
//------------------------------------------------------------------------------------------------------
void res_first_alarm() //подпрограмма выключения тревоги (ручного или по истечении таймаута)
  {
    alarm_sound = 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;
}

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




/*

ChangeLog by tekagi:

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 за подсказки и готовые кусочки кода.

*/

Содержимое файла gif.c также изменилось:

// файл gif.c
// должен находиться в папке со скетчем

#include <avr/pgmspace.h>
#ifndef fontdatatype
#define fontdatatype const uint8_t
#endif
const unsigned char PROGMEM gif_chast_1[] =
{ 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00};
const unsigned char PROGMEM gif_chast_2[] =
{ 0x3C, 0x7E, 0xC3, 0xC3, 0xC3, 0xC3, 0x7E, 0x3C};
const unsigned char PROGMEM logo_bat[] =
{ 0x1C, 0xFF, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xFF
};
const unsigned char PROGMEM  logo_tr[] =
{ 0x3C, 0x42, 0x99, 0x24,
  0x00, 0x60, 0x90, 0x98,
  0x8E, 0x81, 0x81, 0x8E,
  0x98, 0x90, 0x60, 0x00,
  0x24, 0x99, 0x42, 0x3C
};

const unsigned char PROGMEM logo_rag[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF0, 0xF8, 0xF8,
  0xF8, 0xF8, 0xF8, 0xF0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8,
  0xF8, 0xF8, 0x78, 0x78, 0x78, 0x78, 0xF8, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0,
  0xC0, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF0, 0xF8, 0x98, 0x18,
  0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0x9F, 0x81,
  0x81, 0x81, 0x9F, 0xFF, 0xFF, 0xFC, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFC, 0x1E, 0x0F, 0x0F, 0x0F, 0x06, 0x00, 0xFF, 0xFF,
  0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xCF, 0xFF, 0xFF,
  0xFF, 0xFF, 0x00, 0xFC, 0xFF, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x36,
  0x78, 0x78, 0x78, 0x36, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF, 0xFC,
  0x00, 0xFC, 0xFE, 0xFF, 0xEF, 0xC7, 0xC7, 0x8F, 0x0F, 0x0E, 0x00, 0x00,
  0x00, 0x00, 0x00, 0xC0, 0xFC, 0xFF, 0xFF, 0xFF, 0x1F, 0x07, 0x07, 0x07,
  0x07, 0x07, 0x07, 0x07, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0xC0, 0x00, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
  0xFF, 0xFF, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x7E, 0x7F, 0x3F, 0x3F,
  0x0F, 0x07, 0x00, 0x01, 0x0F, 0x1E, 0x38, 0x70, 0x60, 0xF0, 0xFE, 0xFF,
  0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0x60, 0x70, 0x38, 0x1F, 0x07, 0x01,
  0x00, 0x79, 0xF9, 0xF1, 0xF3, 0xF7, 0xFF, 0xFF, 0x7F, 0x3E, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C,
  0x00, 0x7C, 0x24, 0x24, 0x24, 0x18, 0x00, 0x60, 0x3C, 0x24, 0x3C, 0x60,
  0x00, 0x0C, 0x50, 0x50, 0x50, 0x3C, 0x00, 0x7C, 0x20, 0x10, 0x08, 0x7C,
  0x00, 0x7C, 0x10, 0x10, 0x10, 0x7C, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38,
  0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x60, 0x3E, 0x23, 0x3F, 0x60, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38,
  0x00, 0x28, 0x44, 0x54, 0x54, 0x28, 0x00, 0x7C, 0x20, 0x10, 0x08, 0x7C,
  0x00, 0x7C, 0x08, 0x10, 0x08, 0x7C, 0x00, 0x38, 0x54, 0x54, 0x54, 0x18,
  0x00, 0x04, 0x04, 0x7C, 0x04, 0x04, 0x00, 0x7C, 0x24, 0x24, 0x24, 0x18,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C,
  0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00,
  0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x01, 0x71, 0x09, 0x05, 0x03};


// заставка БЕТА режима первая
const unsigned char PROGMEM beta_prev_1[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x05,
  0x02, 0x00, 0x1F, 0x15, 0x11, 0x00, 0x1B, 0x1F, 0x1B, 0x00, 0x1F, 0x0C,
  0x1F, 0x00, 0x1F, 0x07, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x05,
  0x02, 0x00, 0x1E, 0x05, 0x1E, 0x00, 0x11, 0x15, 0x0A, 0x00, 0x1F, 0x04,
  0x1F, 0x00, 0x0E, 0x11, 0x0E, 0x00, 0x0E, 0x11, 0x0A, 0x00, 0x01, 0x1F,
  0x01, 0x00, 0x1F, 0x04, 0x1F, 0x00, 0x0E, 0x11, 0x0E, 0x00, 0x1F, 0x01,
  0x01, 0x00, 0x0E, 0x11, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x15, 0x0A, 0x00,
  0x1E, 0x05, 0x1E, 0x00, 0x1F, 0x07, 0x1F, 0x00, 0x1F, 0x15, 0x11, 0x00,
  0x1F, 0x05, 0x02, 0x00, 0x1E, 0x05, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x71, 0x41,
  0xF1, 0x01, 0xE1, 0x11, 0xA1, 0x01, 0x11, 0xF1, 0x11, 0x01, 0xE1, 0x51,
  0xE1, 0x01, 0xF1, 0x41, 0xF1, 0x01, 0xE1, 0x11, 0xE1, 0x01, 0xF1, 0x51,
  0xA1, 0x01, 0xF1, 0xC1, 0xF1, 0x01, 0x11, 0xF1, 0x11, 0x01, 0xF1, 0x51,
  0x11, 0x01, 0x01, 0x01, 0x01, 0x01, 0xF1, 0x11, 0xF1, 0x01, 0xF1, 0x51,
  0x21, 0x01, 0xF1, 0xC1, 0xF1, 0x01, 0xF1, 0x51, 0x91, 0x01, 0xE1, 0x11,
  0xE1, 0x01, 0xF1, 0x51, 0x21, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x40, 0xF1, 0x01,
  0xE0, 0x50, 0xE0, 0x01, 0x00, 0x00, 0xF0, 0x11, 0xF0, 0x00, 0x71, 0x40,
  0xF1, 0x00, 0xE1, 0x10, 0xA1, 0x00, 0x10, 0xF1, 0x10, 0x00, 0x71, 0x41,
  0xF0, 0x00, 0xF1, 0xE0, 0x11, 0xE0, 0x00, 0x01, 0x00, 0xF0, 0x41, 0x91,
  0x01, 0xF0, 0xE0, 0x10, 0xE0, 0x00, 0xF1, 0x50, 0xA1, 0x00, 0xF1, 0x50,
  0x10, 0x00, 0x11, 0xF0, 0x11, 0x00, 0x71, 0x41, 0xF0, 0x00, 0x00, 0x01,
  0xF0, 0xC0, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
  0x01, 0xF0, 0x81, 0x80, 0x80, 0xF0, 0x01, 0xC0, 0x21, 0x10, 0x21, 0xC1,
  0x00, 0x70, 0x80, 0xE1, 0x80, 0x70, 0x00, 0xF1, 0x20, 0xC0, 0x21, 0xF1,
  0x00, 0xF0, 0x01, 0x80, 0x61, 0xF0, 0x00, 0x10, 0x10, 0xF1, 0x10, 0x11,
  0x00, 0xF1, 0x90, 0x91, 0x90, 0x10, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
  0x01, 0xE0, 0x10, 0x11, 0x10, 0xE0, 0x01, 0xF1, 0x80, 0x40, 0x20, 0x10,
  0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x01, 0x01, 0x01, 0x07,
  0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07,
  0x00, 0x07, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
  0x00, 0x07, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x03, 0x04, 0x04, 0x04, 0x03, 0x00, 0x07, 0x00, 0x01, 0x02, 0x04,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  
// заставка БЕТА режима вторая
const unsigned char PROGMEM beta_prev_2[] =

  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x11, 0x15, 0x0A, 0x00, 0x1E, 0x05, 0x1E, 0x00,
  0x1F, 0x07, 0x1F, 0x00, 0x1F, 0x15, 0x11, 0x00, 0x1F, 0x05, 0x02, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x0E, 0x11, 0x0E, 0x00, 0x1F, 0x15, 0x1D, 0x00,
  0x1F, 0x05, 0x02, 0x00, 0x1E, 0x05, 0x1E, 0x00, 0x11, 0x15, 0x0A, 0x00,
  0x1F, 0x10, 0x1F, 0x30, 0x1E, 0x05, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x51,
  0xA1, 0x01, 0xE1, 0x51, 0xE1, 0x01, 0xF1, 0x11, 0xF1, 0x01, 0xE1, 0x11,
  0xE1, 0x01, 0xE1, 0x11, 0xF1, 0x01, 0xF1, 0x41, 0xF1, 0x01, 0xF1, 0xC1,
  0xF1, 0x01, 0x11, 0xF1, 0x11, 0x01, 0xF1, 0x51, 0x11, 0x01, 0x01, 0x01,
  0x01, 0x01, 0xF1, 0x41, 0x91, 0x01, 0xF1, 0xE1, 0x11, 0xE1, 0x01, 0xF1,
  0x51, 0xA1, 0x01, 0xF1, 0x51, 0x11, 0x01, 0x11, 0xF1, 0x11, 0x01, 0x71,
  0x41, 0xF1, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
  0x00, 0x00, 0xF0, 0xC0, 0xF0, 0x00, 0x10, 0x50, 0xA0, 0x00, 0xF1, 0x71,
  0xF0, 0x00, 0xF1, 0x50, 0x11, 0x00, 0xF1, 0x50, 0x21, 0x00, 0xA0, 0x51,
  0xF0, 0x00, 0xF1, 0x50, 0x11, 0x00, 0xF1, 0x70, 0xF1, 0x00, 0xF1, 0x40,
  0x81, 0xF0, 0x00, 0xF1, 0x70, 0xF0, 0x01, 0x01, 0x01, 0x00, 0xF0, 0x50,
  0xA0, 0x00, 0xF1, 0x50, 0x11, 0x00, 0xF1, 0xC0, 0xF1, 0x00, 0xF0, 0x51,
  0x11, 0x00, 0xE0, 0x11, 0xA1, 0x01, 0x10, 0xF0, 0x11, 0x00, 0xF0, 0x51,
  0xA1, 0x00, 0xE0, 0x10, 0xE0, 0x00, 0xF0, 0x70, 0xF0, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x71, 0x41, 0xF0, 0x00, 0xE1, 0x10,
  0xA1, 0x00, 0x11, 0xF1, 0x11, 0x00, 0xE1, 0x50, 0xE0, 0x00, 0xF1, 0x40,
  0xF1, 0x00, 0xE1, 0x11, 0xE1, 0x00, 0xF1, 0x50, 0xA1, 0x00, 0xF1, 0xC1,
  0xF0, 0x01, 0x10, 0xF1, 0x10, 0x01, 0xF0, 0x50, 0x10, 0x00, 0x01, 0x01,
  0x00, 0x00, 0xF1, 0x11, 0xF1, 0x00, 0xF1, 0x51, 0x23, 0x00, 0xF1, 0xC1,
  0xF1, 0x00, 0xF0, 0x51, 0xD0, 0x00, 0xE0, 0x11, 0xE0, 0x00, 0xF1, 0x51,
  0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0xF1, 0xC0, 0xF1, 0x00, 0x03, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01,
  0x00, 0xF0, 0x80, 0x81, 0x80, 0xF0, 0x01, 0xC0, 0x21, 0x10, 0x21, 0xC0,
  0x01, 0x70, 0x80, 0xE1, 0x80, 0x70, 0x01, 0xF1, 0x20, 0xC0, 0x21, 0xF0,
  0x01, 0xF0, 0x00, 0x81, 0x60, 0xF0, 0x01, 0x11, 0x11, 0xF0, 0x10, 0x10,
  0x00, 0xF0, 0x91, 0x90, 0x91, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
  0x01, 0xE0, 0x11, 0x11, 0x11, 0xE0, 0x00, 0xF1, 0x80, 0x40, 0x21, 0x10,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x01, 0x01, 0x01, 0x07,
  0x00, 0x07, 0x00, 0x03, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07,
  0x00, 0x07, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
  0x00, 0x07, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x03, 0x04, 0x04, 0x04, 0x03, 0x00, 0x07, 0x00, 0x01, 0x02, 0x04,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};


//----------------------------------------------------------------------
// Секция шрифтов


// Font size    : 6x8 pixels
fontdatatype SmallFontRus[] PROGMEM={
0x06,0x08,0x20,0x5F,
0x00,0x00,0x00,0x00,0x00,0x00,  // <space>
0x00,0x00,0x00,0x2F,0x00,0x00,  // !
0x00,0x00,0x07,0x00,0x07,0x00,  // "
0x00,0x14,0x7F,0x14,0x7F,0x14,  // #
0x00,0x24,0x2A,0x7F,0x2A,0x12,  // $
0x00,0x23,0x13,0x08,0x64,0x62,  // %
0x00,0x36,0x49,0x55,0x22,0x50,  // &
0x00,0x00,0x05,0x03,0x00,0x00,  // '
0x00,0x00,0x1C,0x22,0x41,0x00,  // (
0x00,0x00,0x41,0x22,0x1C,0x00,  // )
0x00,0x14,0x08,0x3E,0x08,0x14,  // *
0x00,0x08,0x08,0x3E,0x08,0x08,  // +
0x00,0x00,0x00,0xA0,0x60,0x00,  // ,
0x00,0x08,0x08,0x08,0x08,0x08,  // -
0x00,0x00,0x60,0x60,0x00,0x00,  // .
0x00,0x20,0x10,0x08,0x04,0x02,  // /

0x00,0x3E,0x51,0x49,0x45,0x3E,  // 0
0x00,0x00,0x42,0x7F,0x40,0x00,  // 1
0x00,0x42,0x61,0x51,0x49,0x46,  // 2
0x00,0x21,0x41,0x45,0x4B,0x31,  // 3
0x00,0x18,0x14,0x12,0x7F,0x10,  // 4
0x00,0x27,0x45,0x45,0x45,0x39,  // 5
0x00,0x3C,0x4A,0x49,0x49,0x30,  // 6
0x00,0x01,0x71,0x09,0x05,0x03,  // 7
0x00,0x36,0x49,0x49,0x49,0x36,  // 8
0x00,0x06,0x49,0x49,0x29,0x1E,  // 9
0x00,0x00,0x36,0x36,0x00,0x00,  // :
0x00,0x00,0x56,0x36,0x00,0x00,  // ;
0x00,0x08,0x14,0x22,0x41,0x00,  // <
0x00,0x14,0x14,0x14,0x14,0x14,  // =
0x00,0x00,0x41,0x22,0x14,0x08,  // >
0x00,0x02,0x01,0x51,0x09,0x06,  // ?

0x00,0x32,0x49,0x59,0x51,0x3E,  // @
0x00,0x7C,0x12,0x11,0x12,0x7C,  // A
0x00,0x7F,0x49,0x49,0x49,0x36,  // B
0x00,0x3E,0x41,0x41,0x41,0x22,  // C
0x00,0x7F,0x41,0x41,0x22,0x1C,  // D
0x00,0x7F,0x49,0x49,0x49,0x41,  // E
0x00,0x7F,0x09,0x09,0x09,0x01,  // F
0x00,0x3E,0x41,0x49,0x49,0x7A,  // G
0x00,0x7F,0x08,0x08,0x08,0x7F,  // H
0x00,0x00,0x41,0x7F,0x41,0x00,  // I
0x00,0x20,0x40,0x41,0x3F,0x01,  // J
0x00,0x7F,0x08,0x14,0x22,0x41,  // K
0x00,0x7F,0x40,0x40,0x40,0x40,  // L
0x00,0x7F,0x02,0x0C,0x02,0x7F,  // M
0x00,0x7F,0x04,0x08,0x10,0x7F,  // N
0x00,0x3E,0x41,0x41,0x41,0x3E,  // O

0x00,0x7F,0x09,0x09,0x09,0x06,  // P
0x00,0x3E,0x41,0x51,0x21,0x5E,  // Q
0x00,0x7F,0x09,0x19,0x29,0x46,  // R
0x00,0x46,0x49,0x49,0x49,0x31,  // S
0x00,0x01,0x01,0x7F,0x01,0x01,  // T
0x00,0x3F,0x40,0x40,0x40,0x3F,  // U
0x00,0x1F,0x20,0x40,0x20,0x1F,  // V
0x00,0x3F,0x40,0x38,0x40,0x3F,  // W
0x00,0x63,0x14,0x08,0x14,0x63,  // X
0x00,0x07,0x08,0x70,0x08,0x07,  // Y
0x00,0x61,0x51,0x49,0x45,0x43,  // Z
0x00,0x00,0x7F,0x41,0x41,0x00,  // [
0xAA,0x55,0xAA,0x55,0xAA,0x55,  // <backslash>
0x00,0x00,0x41,0x41,0x7F,0x00,  // ]
0x00,0x04,0x02,0x01,0x02,0x04,  // ^
0x00,0x40,0x40,0x40,0x40,0x40,  // _

0x00,0x00,0x03,0x05,0x00,0x00,  // `
0x00,0x7C,0x12,0x11,0x12,0x7C,  // a
0x00,0x7F,0x49,0x49,0x49,0x36,  // b
0x00,0x7F,0x49,0x49,0x49,0x36,  // c
0x00,0x7F,0x01,0x01,0x01,0x01,  // d
0x00,0x60,0x3E,0x23,0x3F,0x60,  // e
0x00,0x7F,0x49,0x49,0x49,0x41,  // f
0x00,0x77,0x08,0x3E,0x08,0x77,  // g
0x00,0x22,0x49,0x49,0x5D,0x36,  // h
0x00,0x00,0x44,0x7D,0x40,0x00,  // i
0x00,0x40,0x80,0x84,0x7D,0x00,  // j
0x00,0x7F,0x10,0x28,0x44,0x00,  // k
0x00,0x00,0x41,0x7F,0x40,0x00,  // l
0x00,0x7C,0x04,0x18,0x04,0x78,  // m
0x00,0x7C,0x08,0x04,0x04,0x78,  // n
0x00,0x38,0x44,0x44,0x44,0x38,  // o

0x00,0xFC,0x24,0x24,0x24,0x18,  // p
0x00,0x18,0x24,0x24,0x18,0xFC,  // q
0x00,0x7C,0x08,0x04,0x04,0x08,  // r
0x00,0x48,0x54,0x54,0x54,0x20,  // s
0x00,0x04,0x3F,0x44,0x40,0x20,  // t
0x00,0x3C,0x40,0x40,0x20,0x7C,  // u
0x00,0x1C,0x20,0x40,0x20,0x1C,  // v
0x00,0x3C,0x40,0x30,0x40,0x3C,  // w
0x00,0x44,0x28,0x10,0x28,0x44,  // x
0x00,0x1C,0xA0,0xA0,0xA0,0x7C,  // y
0x00,0x44,0x64,0x54,0x4C,0x44,  // z
0x00,0x00,0x10,0x7C,0x82,0x00,  // {
0x00,0x00,0x00,0xFF,0x00,0x00,  // |
0x00,0x00,0x82,0x7C,0x10,0x00,  // }
0x00,0x00,0x06,0x09,0x09,0x06,  // ~
//-----------------------------------
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  //
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 

0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 

0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x7E,0x4B,0x4A,0x4B,0x42,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 

0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  //
0x00,0x00,0x00,0x00,0x00,0x20,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x38,0x55,0x54,0x55,0x58,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  //
0x00,0x00,0x00,0x00,0x00,0x00,  //
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 
0x00,0x00,0x00,0x00,0x00,0x00,  // 

0x00,0x00,0x03,0x05,0x00,0x00,  // 
0x00,0x7C,0x12,0x11,0x12,0x7C,  // 
0x00,0x7F,0x49,0x49,0x49,0x30,  // 
0x00,0x7F,0x49,0x49,0x49,0x36,  // 
0x00,0x7F,0x01,0x01,0x01,0x01,  // 
0x00,0x60,0x3E,0x23,0x3F,0x60,  // 
0x00,0x7F,0x49,0x49,0x49,0x41,  //
0x00,0x77,0x08,0x3E,0x08,0x77,  // 
0x00,0x22,0x49,0x49,0x5D,0x36,  // 
0x00,0x7F,0x30,0x08,0x06,0x7F,  // 
0x00,0x7F,0x30,0x19,0x0C,0x7F,  // 
0x00,0x7F,0x08,0x08,0x14,0x63,  // 
0x00,0x40,0x7E,0x01,0x01,0x7F,  // 
0x00,0x7F,0x02,0x0C,0x02,0x7F,  // 
0x00,0x7F,0x08,0x08,0x08,0x7F,  // 
0x00,0x3E,0x41,0x41,0x41,0x3E,  // 

0x00,0x7F,0x01,0x01,0x01,0x7F,  // 
0x00,0x7F,0x09,0x09,0x09,0x06,  // 
0x00,0x3E,0x41,0x41,0x41,0x22,  // 
0x00,0x01,0x01,0x7F,0x01,0x01,  // 
0x00,0x07,0x48,0x48,0x48,0x3F,  // 
0x00,0x0E,0x11,0x7F,0x11,0x0E,  // 
0x00,0x63,0x14,0x08,0x14,0x63,  // 
0x00,0x3F,0x20,0x20,0x3F,0x60,  // 
0x00,0x07,0x08,0x08,0x08,0x7F,  // 
0x00,0x7F,0x40,0x7E,0x40,0x7F,  // 
0x00,0x3F,0x20,0x3F,0x20,0x7F,  // 
0x40,0x01,0x7F,0x48,0x48,0x30,  // 
0x00,0x7F,0x48,0x30,0x00,0x7F,  // 
0x00,0x7F,0x48,0x48,0x30,0x00,  // 
0x41,0x49,0x49,0x49,0x3E,0x00,  // 
0x00,0x7F,0x08,0x3E,0x41,0x3E,
0x00,0x46,0x29,0x19,0x09,0x7F,
//-----------------------------------
//0x00,0x00,0x00,0x00,0x00,0x00,
//0x00,0x7C,0x10,0x7C,0x44,0x7C,
0x00,0x20,0x54,0x54,0x54,0x78,  // 
0x00,0x3C,0x4A,0x4A,0x4A,0x30,  // 
0x00,0x7C,0x54,0x54,0x54,0x28,  // 
0x00,0x7C,0x04,0x04,0x04,0x00,  // 
0x00,0x60,0x3C,0x24,0x3C,0x60,  // 
0x00,0x38,0x54,0x54,0x54,0x18,  // 
0x00,0x6C,0x10,0x7C,0x10,0x6C,  // 
0x00,0x28,0x44,0x54,0x54,0x28,  // 
0x00,0x7C,0x20,0x10,0x08,0x7C,  // 
0x00,0x7C,0x20,0x12,0x08,0x7C,  // 
0x00,0x7C,0x10,0x10,0x28,0x44,  // 
0x00,0x40,0x7C,0x04,0x04,0x7C,  // 
0x00,0x7C,0x08,0x10,0x08,0x7C,  // 
0x00,0x7C,0x10,0x10,0x10,0x7C,  // 
0x00,0x38,0x44,0x44,0x44,0x38,  // 

0x00,0x7C,0x04,0x04,0x04,0x7C,  // 
0x00,0x7C,0x24,0x24,0x24,0x18,  // 
0x00,0x38,0x44,0x44,0x44,0x28,  // 
0x00,0x04,0x04,0x7C,0x04,0x04,  // 
0x00,0x0C,0x50,0x50,0x50,0x3C,  // 
0x00,0x18,0x24,0x7C,0x24,0x18,  // 
0x00,0x44,0x28,0x10,0x28,0x44,  // 
0x00,0x3C,0x20,0x20,0x3C,0x60,  // 
0x00,0x1C,0x20,0x20,0x7C,0x00,  // 
0x00,0x7C,0x40,0x78,0x40,0x7C,  // 
0x00,0x3C,0x20,0x3C,0x20,0x7C,  // 
0x40,0x04,0x7C,0x50,0x50,0x20,  //
0x00,0x7C,0x50,0x70,0x00,0x7C,  // 
0x00,0x7C,0x50,0x50,0x20,0x00,  // 
0x44,0x54,0x54,0x54,0x38,0x00,  // 
0x00,0x7C,0x10,0x7C,0x44,0x7C,
0x00,0x48,0x54,0x34,0x14,0x7C,
};

/*
fontdatatype rus_4x6[] PROGMEM =
{
0x04, 0x08, 0xC0, 0x20,
0x00, 0x3c, 0x12, 0x3c,                        // Code for char А
0x00, 0x3E, 0x2A, 0x12,                        // Code for char Б
0x00, 0x3E, 0x2A, 0x14,                        // Code for char В
0x00, 0x3E, 0x02, 0x02,                        // Code for char Г
0x00, 0x30, 0x1E, 0x30,                        // Code for char Д
0x00, 0x3E, 0x2A, 0x22,                        // Code for char Е
0x00, 0x36, 0x3E, 0x36,                        // Code for char Ж
0x00, 0x22, 0x2A, 0x14,                        // Code for char З
0x00, 0x3E, 0x18, 0x3E,                        // Code for char И
0x00, 0x3E, 0x19, 0x3E,                        // Code for char Й
0x00, 0x3E, 0x08, 0x22,                        // Code for char К
0x00, 0x3C, 0x02, 0x3E,                        // Code for char Л
0x00, 0x3E, 0x0E, 0x3E,                        // Code for char М
0x00, 0x3E, 0x08, 0x3E,                        // Code for char Н
0x00, 0x1C, 0x22, 0x1C,                        // Code for char О
0x00, 0x3E, 0x02, 0x3E,                        // Code for char П
0x00, 0x3E, 0x0A, 0x04,                        // Code for char Р
0x00, 0x1C, 0x22, 0x14,                        // Code for char С
0x00, 0x02, 0x3E, 0x02,                        // Code for char Т
0x00, 0x06, 0x28, 0x1E,                        // Code for char У
0x00, 0x1C, 0x3E, 0x1C,                        // Code for char Ф
0x00, 0x36, 0x08, 0x36,                        // Code for char Х
0x00, 0x1E, 0x10, 0x2E,                        // Code for char Ц
0x00, 0x0E, 0x08, 0x3E,                        // Code for char Ч
0x00, 0x3E, 0x38, 0x3E,                        // Code for char Ш
0x00, 0x1E, 0x1C, 0x3E,                        // Code for char Щ
0x00, 0x3E, 0x28, 0x10,                        // Code for char Ъ
0x3E, 0x30, 0x00, 0x3E,                        // Code for char Ы
0x00, 0x3E, 0x28, 0x10,                        // Code for char Ь
0x00, 0x14, 0x2A, 0x1C,                        // Code for char Э
0x3E, 0x08, 0x3E, 0x3E,                        // Code for char Ю
0x00, 0x34, 0x0A, 0x3E,                        // Code for char Я
};
*/

fontdatatype TinyFontRus[] PROGMEM =
{
0x04, 0x06, 0x20, 0x5f,
0x00, 0x00, 0x00, 0x03, 0xa0, 0x00, 0xc0, 0x0c, 0x00, 0xf9, 0x4f, 0x80, 0x6b, 0xeb, 0x00, 0x98, 0x8c, 0x80, 0x52, 0xa5, 0x80, 0x03, 0x00, 0x00,  // Space, !"#$%&'
0x01, 0xc8, 0x80, 0x89, 0xc0, 0x00, 0x50, 0x85, 0x00, 0x21, 0xc2, 0x00, 0x08, 0x40, 0x00, 0x20, 0x82, 0x00, 0x00, 0x20, 0x00, 0x18, 0x8c, 0x00,  // ()*+,-./
0xfa, 0x2f, 0x80, 0x4b, 0xe0, 0x80, 0x5a, 0x66, 0x80, 0x8a, 0xa5, 0x00, 0xe0, 0x8f, 0x80, 0xea, 0xab, 0x00, 0x72, 0xa9, 0x00, 0x9a, 0x8c, 0x00,  // 01234567
0xfa, 0xaf, 0x80, 0x4a, 0xa7, 0x00, 0x01, 0x40, 0x00, 0x09, 0x40, 0x00, 0x21, 0x48, 0x80, 0x51, 0x45, 0x00, 0x89, 0x42, 0x00, 0x42, 0x66, 0x00,  // 89:;<=>?
0x72, 0xa6, 0x80, 0x7a, 0x87, 0x80, 0xfa, 0xa5, 0x00, 0x72, 0x25, 0x00, 0xfa, 0x27, 0x00, 0xfa, 0xa8, 0x80, 0xfa, 0x88, 0x00, 0x72, 0x2b, 0x00,  // @ABCDEFG
0xf8, 0x8f, 0x80, 0x8b, 0xe8, 0x80, 0x8b, 0xe8, 0x00, 0xf8, 0x8d, 0x80, 0xf8, 0x20, 0x80, 0xf9, 0x0f, 0x80, 0xf9, 0xcf, 0x80, 0x72, 0x27, 0x00,  // HIJKLMNO
0xfa, 0x84, 0x00, 0x72, 0x27, 0x40, 0xfa, 0x85, 0x80, 0x4a, 0xa9, 0x00, 0x83, 0xe8, 0x00, 0xf0, 0x2f, 0x00, 0xe0, 0x6e, 0x00, 0xf0, 0xef, 0x00,  // PQRSTUVW
0xd8, 0x8d, 0x80, 0xc0, 0xec, 0x00, 0x9a, 0xac, 0x80, 0x03, 0xe8, 0x80, 0xc0, 0x81, 0x80, 0x8b, 0xe0, 0x00, 0x42, 0x04, 0x00, 0x08, 0x20, 0x80,  // XYZ[\]^_
0x02, 0x04, 0x00, 0x31, 0x23, 0x80, 0xf9, 0x23, 0x00, 0x31, 0x24, 0x80, 0x31, 0x2f, 0x80, 0x31, 0x62, 0x80, 0x23, 0xea, 0x00, 0x25, 0x53, 0x80,  // `abcdefg
0xf9, 0x03, 0x80, 0x02, 0xe0, 0x00, 0x06, 0xe0, 0x00, 0xf8, 0x42, 0x80, 0x03, 0xe0, 0x00, 0x79, 0x87, 0x80, 0x39, 0x03, 0x80, 0x31, 0x23, 0x00,  // hijklmno
0x7d, 0x23, 0x00, 0x31, 0x27, 0xc0, 0x78, 0x84, 0x00, 0x29, 0x40, 0x00, 0x43, 0xe4, 0x00, 0x70, 0x27, 0x00, 0x60, 0x66, 0x00, 0x70, 0x67, 0x00,  // pqrstuvw
0x48, 0xc4, 0x80, 0x74, 0x57, 0x80, 0x59, 0xe6, 0x80, 0x23, 0xe8, 0x80, 0x03, 0x60, 0x00, 0x8b, 0xe2, 0x00, 0x61, 0x0c, 0x00,                     // zyx{|}~
0x00, 0x00, 0x1E, // Index: 95 (0x005F)  Character: 0x007F ('')
0x01, 0x07, 0x96, // Index: 96 (0x0060)  Character: 0x0080 ('?')
0x00, 0x07, 0x90, // Index: 97 (0x0061)  Character: 0x0081 ('?')
0x00, 0x30, 0x00, // Index: 98 (0x0062)  Character: 0x0082 ('?')
0x00, 0x00, 0x00, // Index: 99 (0x0063)  Character: 0x0083 ('?')
0x0C, 0x00, 0x00, // Index: 100 (0x0064)  Character: 0x0084 ('?')
0x00, 0x00, 0x00, // Index: 101 (0x0065)  Character: 0x0085 ('?')
0x00, 0x00, 0x00, // Index: 102 (0x0066)  Character: 0x0086 ('?')
0x00, 0x00, 0x00, // Index: 103 (0x0067)  Character: 0x0087 ('?')
0x00, 0x00, 0x00, // Index: 104 (0x0068)  Character: 0x0088 ('?')
0x00, 0x00, 0x00, // Index: 105 (0x0069)  Character: 0x0089 ('?')
0x00, 0x00, 0x00, // Index: 106 (0x006A)  Character: 0x008A ('?')
0x00, 0x01, 0x0A, // Index: 107 (0x006B)  Character: 0x008B ('?')
0x00, 0x00, 0x00, // Index: 108 (0x006C)  Character: 0x008C ('?')
0x01, 0xE3, 0x12, // Index: 109 (0x006D)  Character: 0x008D ('?')
0x01, 0x07, 0x96, // Index: 110 (0x006E)  Character: 0x008E ('?')
0x01, 0xE0, 0xDE, // Index: 111 (0x006F)  Character: 0x008F ('?')
0x01, 0xE1, 0x80, // Index: 112 (0x0070)  Character: 0x0090 ('?')
0x01, 0x00, 0x00, // Index: 113 (0x0071)  Character: 0x0091 ('?')
0x01, 0x00, 0x00, // Index: 114 (0x0072)  Character: 0x0092 ('?')
0x40, 0x00, 0x00, // Index: 115 (0x0073)  Character: 0x0093 ('?')
0x00, 0x00, 0x00, // Index: 116 (0x0074)  Character: 0x0094 ('?')
0x00, 0x00, 0x00, // Index: 117 (0x0075)  Character: 0x0095 ('?')
0x00, 0x00, 0x00, // Index: 118 (0x0076)  Character: 0x0096 ('?')
0x00, 0x00, 0x00, // Index: 119 (0x0077)  Character: 0x0097 ('?')
0x00, 0x00, 0x00, // Index: 120 (0x0078)  Character: 0x0098 ('')
0x00, 0x00, 0x00, // Index: 121 (0x0079)  Character: 0x0099 ('?')
0x00, 0x00, 0x00, // Index: 122 (0x007A)  Character: 0x009A ('?')
0x00, 0x02, 0x84, // Index: 123 (0x007B)  Character: 0x009B ('?')
0x00, 0x00, 0x00, // Index: 124 (0x007C)  Character: 0x009C ('?')
0x00, 0x00, 0x00, // Index: 125 (0x007D)  Character: 0x009D ('?')
0x00, 0x00, 0x00, // Index: 126 (0x007E)  Character: 0x009E ('?')
0x00, 0x00, 0x00, // Index: 127 (0x007F)  Character: 0x009F ('?')
0x00, 0x00, 0x00, // Index: 128 (0x0080)  Character: 0x00A0 (' ')
0x00, 0x00, 0x00, // Index: 129 (0x0081)  Character: 0x00A1 ('?')
0x00, 0x00, 0x00, // Index: 130 (0x0082)  Character: 0x00A2 ('?')
0x00, 0x00, 0x9C, // Index: 131 (0x0083)  Character: 0x00A3 ('?')
0x00, 0x00, 0x00, // Index: 132 (0x0084)  Character: 0x00A4 ('¤')
0x00, 0x00, 0x00, // Index: 133 (0x0085)  Character: 0x00A5 ('?')
0x00, 0x00, 0x00, // Index: 134 (0x0086)  Character: 0x00A6 ('¦')
0x00, 0x00, 0x00, // 0xA7  
0x03, 0xFF, 0xFF, // 0xA8   |||
0x00, 0x0F, 0xFF, // 0xA9    ||
0x00, 0x00, 0x3F, // 0xAA     |
0x82, 0x08, 0x20, // 0xAB 1-
0xC3, 0x0C, 0x30, // 0xAC 2-
0xE3, 0x8E, 0x38, // 0xAD 3-
0xF3, 0xCF, 0x3C, // 0xAE 4-
0xFB, 0xEF, 0xBE, // 0xAF 5-
0x3C, 0xF3, 0xCF, // 0xB0 5_
0x3C, 0xF3, 0xCF, // 0xB1 4_
0x1C, 0x71, 0xC7, // 0xB2 3_
0x0C, 0x30, 0xC3, // 0xB3 2_
0x04, 0x10, 0x41, // 0xB4 1_
0xFF, 0xFF, 0xFF, // 0xB5 ||||
0xFF, 0xFF, 0xC0, // 0xB6 |||
0xFF, 0xF0, 0x00, // 0xB7 ||
0xFC, 0x00, 0x00, // 0xB8 |
0x38, 0xA2, 0x80, // 0xB9 с
0x30, 0x43, 0x80, // 0xBA ч
0x18, 0xC1, 0x80, // 0xBB д 
0x38, 0xC3, 0x80, // 0xBC м
0x38, 0x42, 0x80, // 0xBD к
0xFA, 0x84, 0x8C, // 0xBE Р/
0x40, 0xC1, 0x0E, // 0xBF /ч
0x7A, 0x87, 0x80, // А
0xFA, 0xAB, 0x80, // Б
0xFA, 0xA5, 0x00, // В
0xFA, 0x08, 0x00, // Г
0x1B, 0xC1, 0x80, // Д
0xFA, 0xA8, 0x80, // Е
0xDB, 0xED, 0x80, // Ж
0x8A, 0xA5, 0x00, // З
0xF8, 0xCF, 0x80, // И
0x7A, 0xC7, 0x80, // Й
0xF8, 0x89, 0x80, // К
0x7A, 0x0F, 0x80, // Л
0xFB, 0x8F, 0x80, // М
0xF8, 0x8F, 0x80, // Н
0x72, 0x27, 0x00, // О
0xFA, 0x0F, 0x80, // П
0xFA, 0x84, 0x00, // Р
0x72, 0x28, 0x80, // С
0x83, 0xE8, 0x00, // Т
0xE8, 0xAF, 0x00, // У
0x73, 0xE7, 0x00, // Ф
0x89, 0xC8, 0x80, // Х
0xF8, 0x2F, 0x83, // Ц
0xE0, 0x8F, 0x80, // Ч
0xF8, 0xEF, 0x80, // Ш
0xF8, 0xEF, 0xC0, // Щ
0x83, 0xE2, 0x84, // Ъ
0xF8, 0xA1, 0x3E, // Ы
0xF8, 0xA1, 0x00, // Ь
0x8A, 0xA7, 0x00, // Э
0xF9, 0xC8, 0x9C, // Ю
0x5A, 0x8F, 0x80, // Я
};

 

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

Tekagi, а какую максималюную дозу может сосчитать наш дозиметр? Или количество частиц?

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

Как-то не задавался подобным вопросом в надежде, что с такой какой не доведётся столкнуться. Как вариант отправить Айзону с просьбой потестировать, мож заодно порекомендует, что изменить/улучшить в конструкции. )) Бодрый обещал сдать на проверку в лабораторию, но неизвестно, когда он вернётся к проекту.
Кстати, подкинул мысль. Надо будет сделать отслеживание среднего значения количества импульсов накачки и напряжения, для контроля тлеющего разряда или зашкала. Вопрос только как сэмулировать зашкал, такие мощные источники есть только в лабораториях. Разве что поставить "подуставший" датчик и поднять напряжение...

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

Да вот довелось сегодня поднести его к камушку который испускает 20000 частиц, меряли каким то радиометром со штангой, в режиме разностного замера было конкретно видно что он не успевает считать, в режиме поиск показал 8 мили Рентген и завис. Накачка поднималась от 80 импульсов до максимума в 500.

Кстати, звук тревоги подаётся со второго, третьего раза при превышении фона, хотя колокольчик появляется всегда.

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

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

По зашкалу рекомендую ознакомиться.

По тревоге посмотрю.

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

Пришлось перезагружать, завис наглухо.

Morroc
Offline
Зарегистрирован: 24.10.2016

20k импульсов в минуту ? Для зашкала вроде рановато. Накачка успевает 400 вольт давать ? От зашкала можно посмотреть как в "сталкере" сделано - там кроме импульсов еще контролируют общий ток через датчик (заведено на АЦП), при зашкале датчик перестает давать импульсы, превратившись в неоновую лампочку, но ток через него есть и чем больше частиц - тем выше.

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

Я не посмотрел было ли 400 Вольт, не хотелось сильно наклонятся к нему, увидел что импульсы в зашкале.

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

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

Ватчдог не помешал бы, но сразу посыпятся вопросы "почему перестал включаться". Загрузчик-то не все поменять могут.

ortus
Offline
Зарегистрирован: 16.10.2017

у меня 5,70 держит спокойно, работает... 

lov62
Offline
Зарегистрирован: 06.05.2018

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