
#define USE_LCD_KEYPAD_SHIELD 0
#define USE_BEEPER 0 // активный "0", пассивный "1"
#define RELAY_LEVEL 1 // Управление реле: 0 - выключено в LOW, 1 - выключено в HIGH


#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <EEPROM.h>
#include <PinChangeInterrupt.h>

#if USE_LCD_KEYPAD_SHIELD==0
#include <LiquidCrystal_I2C.h>
#else
#include <LiquidCrystal.h>
#endif
#include <TimerOne.h>

#define ONE_WIRE_BUS 3
#define BODY_SWITCH_PIN 11 //Если стоим в режиме голов, притянув эту ногу к земле можно перейти на тело.
//#define ALARM_PIN A7 //пин аварии, должен быть подтянут к питанию

#if USE_LCD_KEYPAD_SHIELD==0
#define RELAY_PIN 9
#define BEEPER_PIN 12
#define ALARM_PIN A3 //пин аварии, должен быть подтянут к питанию
#define STAB_PIN 13
#define COOLING_PIN 10
#define ACCEL_BUTTON 4
#define ACCEL_PIN 5
#define CHANGEFRAC_PIN 6 //пин, который будем прижимать к земле при смене фракции для управления Ironman
#else
#define RELAY_PIN 15
#define BEEPER_PIN 16
#define COOLING_PIN 17
#define ALARM_PIN A7
#endif
//#define BEEPER_PIN 5
#define CUBE_PIN 2 //пин градусника куба
#define EE_RELAY_REPEAT_PERIOD_ADDR    1
#define EE_RELAY_ON_PERIOD_ADDR     3
#define EE_DECREMENT_ADDR       7
#define EE_TEMP_NORM_ADDR        8
#define EE_TEMP_DIFF_ADDR       12
#define EE_INIT_ADDR          0
#define EE_BRIGHTNESS_ADDR     16 
#define EE_FLOWUNIT_ADDR 18
#define EE_RELAY_REPEAT_PERIOD2_ADDR 22
#define EE_RELAY_ON_PERIOD2_ADDR  24
#define EE_PAUSE_ADDR 28 //на себя в минутах int
#define EE_HEADS_ADDR 29 //объем голов UINT_16
#define EE_PREBODY_ADDR 31 //объем подголовников UINT_16
#define EE_TEMP_PRETAILS 33 //Т куба переключения на предхвосты
#define EE_CHANGEMODE 37//режим смены фракций вручную или Айронманом. Вручную пищит пищалка и отбор останавливается. Авто пищит пищалка и идет сигнал на смену фракции

#if USE_LCD_KEYPAD_SHIELD==1
#define KEYRANGE 30
#endif
#define PAUSE_DEFAULT 30 //минуты работы на себя
#define HEADS_DEFAULT 200 //мл голов
#define PREBODY_DEFAULT 1000 //мл подголовников
#define PRETAILS_TEMP_DEFAULT 99.0 //темп перехода на предхвостия
#define CHANGEMODE_DEFAULT 0 //ручной режим смены тары, 1- с Иронманом
#define REPEAT_PERIOD_DEFAULT      10      // период повторения
#define RELAY_ON_PERIOD_DEFAULT     1     // период срабатывания
#define STABTIME           1200000 //Время стабилизации в миллисекундах
#define TIMEOVF_TIMEOUT    600000 //Время в залете
#define WARMUP_TEMP 60 //температура прогрева
#define COOLING_TEMP 75 //температура подачи воды
#define COOLING_TIMEOUT 600000 //время отключения охлаждения после финиша
#define DECREMENT_DEFAULT       1     // процент уменьшения периода срабатывания
#define RELAY_ON_PERIOD_MIN_VALUE   0.50    // минимальное значение периода срабатывания
#define MAX_TEMP            125.00   // максимальная измеряемая температура
#define MIN_TEMP            -55.00   // минимальная измеряемая температура
#define DEFAULT_TEMP_NORM       70.0    // значение нормальной температуры
#define DEFAULT_TEMP_DIFF       0.5     // значение гистерезиса
#define SET_DIFF 2              // режим установки разницы температур
#define SET_BRIGHTNESS_MODE 6       // режим дист или рект
#define SET_REPEAT 3            // режим установки периода повторения
#define SET_PERIOD 4            // режим установки периода срабатывания
#define SET_DEC 5             // режим установки декремента
#define SET_NORM 13              // режим установки нормальной температуры
#define SET_FLOWUNIT 7              // режим установки скорости клапана
#define SET_HEADS 1				//режим отбора голов
#define SET_PAUSE 8 //режим установки паузы на себя
#define SET_HEADSVOLUME 9 //режим установки ОБЪЕМА ГОЛОВ
#define SET_PREBODYVOLUME 10 //режим установки ОБЪЕМА подголовников
#define SET_T_PRETAIL 11 //режим установки Т предхвостий
#define SET_CHANGEMODE 12 //режим установки авто или ручное переключение фракций

#if USE_LCD_KEYPAD_SHIELD==0
//#define BUTTON_PLUS 13  //Выводы батонов
//#define BUTTON_MINUS 12 //Выводы батонов
//#define BUTTON_SET 11 //Выводы батонов
#define BUTTON_PLUS 16  //Выводы батонов (A0)
#define BUTTON_MINUS 15 //Выводы батонов (A1)
#define BUTTON_SET 14 //Выводы батонов (A2)
#endif
#define KEY_PLUS 1              // код кнопки 1 "+"
#define KEY_MINUS 2             // код кнопки 3 "-"
#define KEY_OK 4              // код кнопки 2 "OK/Menu"
#define KEY_ACCEL 9   //код кнопки разгона
#define DS_COUNTER_MAX 100  // значение счетчика dscounter при котором происходит опрос датчика и сброс счетчика

OneWire oneWire(ONE_WIRE_BUS);
OneWire oneWirecube(CUBE_PIN);
DallasTemperature sensors(&oneWire);
DallasTemperature sensorscube(&oneWirecube);
#if USE_LCD_KEYPAD_SHIELD==0
LiquidCrystal_I2C lcd(0x3F,16,2);
#else
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
#endif
//LiquidCrystal lcd(4, 5, 6, 7, 8, 9);

DeviceAddress firstThermometer, secondThermometer, cubeThermometer;

volatile int pause; //сколько работать на себя
volatile unsigned int init_counter; //начало работы на себя происходит при переключении на рабочую мощность. Это время записывается сюда.
volatile float headsvolume, headsleftvolume; //сколько надо взять голов и сколько уже взято
volatile float prebodyvolume, prebodyleftvolume; //сколько надо взять голов и сколько уже взято
volatile uint16_t changestatedelay=10000; //задержка после смены режима
volatile uint16_t currentdelay; //текущее значение задержки
volatile bool delaypass=0; //флаг что задержка после смены режима кончилась 
float pretail_temp; //температура перехода на предхвосты
bool changefrac_mode; //режим смены фракций ручной или авто
bool changefrac; //флаг что пора сменить тару
int state = 0; //состояние контроллера: 0-выключен, 1 - на себя, 2-головы, 3-подголовники,4-тело, 5-предхвостия
bool state_applied=1; //флаг, что применили новое состояние
volatile bool chbutton_pushed = 0; //флажок нажатия кнопки
volatile unsigned int dscounter = 0;          // счетчик для опроса датчика ds18b20, прибавляется в таймере индикации
        
volatile unsigned char dscall = 0;         // флаг опроса датчика ds18b20, устанавливается в 1 при dscounter=DS_COUNTER_MAX и сбрасывается после обработки
unsigned char devices=0;          // количество датчиков
float temp[3]={0,0,0};
 /* переменные приложения */
volatile uint16_t repeat_period;                // период повторения
uint16_t original_relay_on_period;          // исходный период повторения
uint16_t flow;  //скорость отбора
volatile float relay_on_period, relay_on_period_current;   // период срабатывания (полный/текущий)
float current_decrement;              //текущий декремент
uint8_t decrement;                  // процент уменьшения периода срабатывания
float flowunit = 1; // Отбор клапана в секунду
volatile bool temp_ovf;                    // флаг перехода порогового значения температуры
volatile bool temp_err;                    // флаг ошибки датчика температуры
volatile bool lock = 0;                       //флаг отслеживания разности температур
volatile bool devmode = 1;                   // Дист или рект
volatile bool menu = 0;                      //Оператор зашел в меню
volatile bool indistate = 0;   //состояние системы
volatile bool finished = 0;   // флаг что мы кончили
volatile bool done = 0;		//флаг что мы все сделали по финишу
volatile bool param_set = 0; // 0 - первый набор параметров, тело, 1 - второй набор - головы
volatile bool warmup = 0; //прогрелась ли колонна?
volatile int gotobody = 1; //переключались ли уже в режим тела? // 0-клапан выключен, 1- головы, 2-тело
float repeat_counter;               // счётчик периода повторения
float relay_counter;                // счётчик периода срабатывания
unsigned char key = 0;             //кнопочка нажата

//uint16_t info_counter;                // счётчик отображения информации на LED
//bool info_ovf;                    // флаг вида информации
float temp_norm;                  // предельная температура термостата для диста
float lock_norm = 0;              //фикс дельты для стабилизации
float prev_lock_norm = 0;         //предыдущая разница
bool temper_flag = 0; //пореже читаем температуру
unsigned long starttime;          //время начала стабилизации
unsigned long curtime;             //текущее время
bool coolenable = 0; //флаг включения охлаждения
bool accel_enabled = 0; //флаг включенного разгонного тэна
unsigned long ovf_time = 0;
unsigned long ovf_cur_time = 0;
unsigned long cooling_counter =0; //счетчик времени до выключения охлаждения воды
float temp_diff;                  // порог разницы температур термостата
float temp_old[3];                   // значение предыдущего замера температуры
unsigned char brightness = 0;     // яркость (0..MAX_BRIGHTNESS)
volatile bool relay_disabled = 1; // флаг того, что реле отбора включено

uint8_t Ya[8] = {B01111, B10001, B10001, B01111, B00101, B01001, B10001};
uint8_t I[8] = {0x11, 0x13, 0x13, 0x15, 0x19, 0x19, 0x11};
uint8_t L[8] = {0x3, 0x7, 0x5, 0x5, 0xD, 0x9, 0x19};
uint8_t bI[8] = {B10001, B10001, B10001, B11001, B10101, B10101, B11001};
uint8_t P[8] = {0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
uint8_t G[8] = {B11111, B10001, B10000, B10000, B10000, B10000, B10000};
uint8_t ZH[8] = {B10101, B10101, B10101, B11111, B10101, B10101, B10101};
//переменные от лупа
unsigned char save = 0; //Флаг сохранения параметров
  float dt = 0.1; //Шаг перебора температуры порогов
  unsigned char click=0; //Вспомогательный флаг для изменения значения настройки
  unsigned char mode=0, prevmode=0; /*текущий режим*/
  unsigned char tmpkey=0, prevkey=0; unsigned int keycount=0; //временные переменны для обработки кнопок
  unsigned char i; //переменная для циклов



void apply_param(bool param_mode){  //переключение наборов параметров
	
	if(param_mode){
	EEPROM_uint16t_write(EE_RELAY_REPEAT_PERIOD_ADDR, repeat_period);
	EEPROM_float_write(EE_RELAY_ON_PERIOD_ADDR, relay_on_period);
	repeat_period = EEPROM_uint16t_read(EE_RELAY_REPEAT_PERIOD2_ADDR);
	relay_on_period = EEPROM_float_read(EE_RELAY_ON_PERIOD2_ADDR);
	relay_on_period_current = relay_on_period;
	original_relay_on_period=relay_on_period;
	current_decrement = 100;
	lock_norm = 0;              //фикс дельты для стабилизации
	prev_lock_norm = 0;
	repeat_counter = repeat_period;	
	CalcFlow();
	starttime = millis();
	}else{
	EEPROM_uint16t_write(EE_RELAY_REPEAT_PERIOD2_ADDR, repeat_period);
	EEPROM_float_write(EE_RELAY_ON_PERIOD2_ADDR, relay_on_period);
	repeat_period = EEPROM_uint16t_read(EE_RELAY_REPEAT_PERIOD_ADDR);
	relay_on_period = EEPROM_float_read(EE_RELAY_ON_PERIOD_ADDR);
	relay_on_period_current = relay_on_period;
	original_relay_on_period=relay_on_period;
	current_decrement = 100;
	lock_norm = 0;              //фикс дельты для стабилизации
	prev_lock_norm = 0;
	repeat_counter = repeat_period;
	CalcFlow();
	starttime = millis();	
		
	}
	
}

void ChangeState(int newstate){ //функция для перехода в новое состояние
	//если режим ручной начинаем бибикать пока кнопку не нажмут и просить сменить тару
	//если автомат отсылаем команду на Айронмана
	if (changefrac_mode==0){ //ручной режим
		relay_disabled =1;
		MyRelay(RELAY_PIN, LOW );
		lcd.clear();
		lcd.setCursor(1, 0);
		lcd.print("CMEH");lcd.write((byte)1);lcd.print("TE TAPY");
		lcd.setCursor(0, 1);
		lcd.print("HA ");
		switch (newstate){
			case(3):
			lcd.write((byte)4);lcd.print("OD");lcd.write((byte)5);lcd.print("O");lcd.write((byte)2);lcd.print("OBH");lcd.write((byte)1);lcd.print("K");lcd.write((byte)1);
			break;
			case(4):
			lcd.print("TE");lcd.write((byte)2);lcd.print("O");
			break;
			case(5):
			lcd.write((byte)4);lcd.print("PEDXBOCT");lcd.write((byte)3);
			break;
		}
		while (!chbutton_pushed){
			pinMode(BEEPER_PIN, OUTPUT);
			
			#if USE_BEEPER==0
			digitalWrite(BEEPER_PIN,HIGH);
			delay(200);
			digitalWrite(BEEPER_PIN,LOW);
			delay(200);
			#else
			//Serial.println("BEEP!!");
			tone(BEEPER_PIN, 500); //включаем на 500 Гц
			delay(200); //ждем 500 Мс
			tone(BEEPER_PIN, 1000); //включаем на 1000 Гц
			delay(200); //ждем 500 Мс
			#endif
			pinMode(BEEPER_PIN, INPUT);
		}
		relay_disabled =0;
		chbutton_pushed=0;
		
	}else{ //автомат с Иронманом
		/*pinMode(CHANGEFRAC_PIN,OUTPUT);
		digitalWrite(CHANGEFRAC_PIN,HIGH);
		relay_disabled =1;
		digitalWrite(CHANGEFRAC_PIN,LOW);
		delay(500);
		digitalWrite(CHANGEFRAC_PIN,HIGH);
		relay_disabled =0;
		pinMode(CHANGEFRAC_PIN,INPUT);*/
	}
	
	
}


/*lcd.createChar(0, Ya);
lcd.createChar(1, I);
lcd.createChar(2, L);
lcd.createChar(3, bI);
lcd.createChar(4, P);
lcd.createChar(5, G);
lcd.createChar(6, ZH);*/
void CheckState(){ //функция перехода в новое состояние
	if (chbutton_pushed){
			pinMode(BEEPER_PIN, OUTPUT);
			#if USE_BEEPER==0
			digitalWrite(BEEPER_PIN,HIGH);
			delay(500);
			digitalWrite(BEEPER_PIN,LOW);
			delay(500);
			#else
			//Serial.println("BEEP!!");
			tone(BEEPER_PIN, 500); //включаем на 500 Гц
			delay(500); //ждем 500 Мс
			tone(BEEPER_PIN, 1000); //включаем на 1000 Гц
			delay(500); //ждем 500 Мс
			#endif
			pinMode(BEEPER_PIN, INPUT);

	if((changefrac_mode == 1 )|| chbutton_pushed){
	state++;
	}
	if (state>5){
		state=0;
		lock=0;
	}
	state_applied=0;
	chbutton_pushed=0;
	}
	if (!state_applied){ //если флаг что пора сменить состояние
	switch (state) {
		case 0: //отрубаем клапан
		relay_disabled =1;
		MyRelay(RELAY_PIN, LOW );
		state_applied=1;
		//пишем разгон
		lcd.clear();
		for (int i=0;i<3;i++){
		lcd.setCursor(3, 0);
		lcd.print("PA3");lcd.write((byte)5);lcd.print("OH ");
		delay(500);
		lcd.clear();
		delay(500);	
		}
		break;
		case 1: //взводим таймер обратного отсчета	
		init_counter=millis();
		state_applied=1;
		//пишем на себя
		lcd.clear();
		for (i=0;i<3;i++){
			lcd.setCursor(3, 0);
			lcd.print("HA CEb");lcd.write((byte)0);
			delay(500);
			lcd.clear();
			delay(500);
		}
		break;
		case 2: //выставляем настройки голов, включаем клапан, взводим таймер голов
		param_set=1; apply_param(1);save=1;relay_counter = relay_on_period_current;
		headsleftvolume=0; //на самом деле это счетчик голов, увеличивающийся до headsvolume
		//пишем отбор голов
		lcd.clear();
		for (i=0;i<3;i++){
			lcd.setCursor(3, 0);
			lcd.write((byte)5);lcd.print("O");lcd.write((byte)2);lcd.print("OB");lcd.write((byte)3);
			delay(500);
			lcd.clear();
			delay(500);
		}
		state_applied=1;
		
		break;
		case 3: //выставляем настройки подголовников, взводим таймер подголовников
		ChangeState(3);
		param_set=0; apply_param(0);save=1; relay_counter = relay_on_period_current;
		prebodyleftvolume=0;
		//пишем отбор подголовников
		lcd.clear();
		for (i=0;i<3;i++){
			lcd.setCursor(1, 0);
			lcd.write((byte)4);lcd.print("OD");lcd.write((byte)5);lcd.print("O");lcd.write((byte)2);lcd.print("OBH");lcd.write((byte)1);lcd.print("K");lcd.write((byte)1);
			delay(500);
			lcd.clear();
			delay(500);
		}
		state_applied=1;
		break;
		case 4: //выставляем настройки тела
		ChangeState(4);
		//пишем отбор тела
		lcd.clear();
		for (i=0;i<3;i++){
			lcd.setCursor(4, 0);
			lcd.print("TE");lcd.write((byte)2);lcd.print("O");
			delay(500);
			lcd.clear();
			delay(500);
		}
		state_applied=1;
		
		break;
		case 5: //выставляем настройки предхвостий
		ChangeState(5);
		//пишем отбор предхвостий
		lcd.clear();
		for (i=0;i<3;i++){
			lcd.setCursor(4, 0);
			lcd.write((byte)4);lcd.print("PEDXBOCT");lcd.write((byte)3);
			delay(500);
			lcd.clear();
			delay(500);
		}
	
		state_applied=1;
		
		break;
	}
		
	}else{ //проверяем выполнение условий перехода к следующему состоянию
		switch (state) {
			case 0: //смотрим что прогрелось - переходим на себя работать
			if (warmup==1){
				state=1;
				state_applied=0;
			}
			break;
			case 1: //проверяем таймер
			if((millis()-init_counter)>pause*60000){
				state=2;
				state_applied=0;	
			}
			break;
			case 2: //если набрали голов переходим на подголовники
			if (headsleftvolume>headsvolume){
				headsleftvolume=0;
				state=3;
				state_applied=0;
			}
			break;
			case 3: //выставляем настройки подголовников, взводим таймер подголовников
			if (prebodyleftvolume>prebodyvolume){
				prebodyleftvolume=0;
				state=4;
				state_applied=0;
			}
			break;
			case 4: //выставляем настройки тела
			if(temp[2]>pretail_temp){
				state=5;
				state_applied=0;
			}
			break;
		}
	}
}
void CalcStab(){
  if (lock==0 && state>=4) { //если т не залочена и режим отбора тела
  lock_norm=temp[1]-temp[0]; //читаем текущую дельту
  curtime=millis();
  //Serial.println(curtime-starttime);
    if (abs (lock_norm-prev_lock_norm) <temp_diff) { //если температуры совпадают
		//Serial.println("ROVNO");
        if ((curtime-starttime>STABTIME) && (!param_set)) {
          lock=1;
        }
    }else{
    prev_lock_norm=lock_norm;
    starttime = millis();  
    }
  }
  
}
void MyRelay(int RelNum, int State ){
	#if RELAY_LEVEL == 1
		if (State == HIGH){
			digitalWrite(RelNum, LOW);
		} else {
			digitalWrite(RelNum, HIGH);	
		}
	#else
		if (State == HIGH){
			digitalWrite(RelNum, HIGH);
			} else {
			digitalWrite(RelNum, LOW);
		}
	
	#endif
	
}

void get_temp(){
	
  sensors.requestTemperatures();
  temp[0] = sensors.getTempC(firstThermometer);
  temp[1] = sensors.getTempC(secondThermometer);
    sensorscube.requestTemperatures();
  temp[2] = sensorscube.getTempC(cubeThermometer);
  
	
 //Serial.println(temp[0]); 
 //Serial.println(temp[1]);

  
}

void EEPROM_float_write(int addr, float val) // запись в ЕЕПРОМ
  { 
    byte *x = (byte *)&val;
    for(byte i = 0; i < 4; i++) EEPROM.write(i+addr, x[i]);
  }

  float EEPROM_float_read(int addr) // чтение из ЕЕПРОМ
  {   
    byte x[4];
    for(byte i = 0; i < 4; i++) x[i] = EEPROM.read(i+addr);
    float *y = (float *)&x;
    return y[0];
  }

  void EEPROM_uint16t_write(int addr, uint16_t val) // запись в ЕЕПРОМ
  { 
    byte *x = (byte *)&val;
    for(byte i = 0; i < 2; i++) EEPROM.write(i+addr, x[i]);
  }

  float EEPROM_uint16t_read(int addr) // чтение из ЕЕПРОМ
  {   
    byte x[2];
    for(byte i = 0; i < 2; i++) x[i] = EEPROM.read(i+addr);
    uint16_t *y = (uint16_t *)&x;
    return y[0];
  }

  void save_params(void) {
  EEPROM.write(EE_BRIGHTNESS_ADDR, brightness);
  EEPROM.write(EE_INIT_ADDR, 1);
  EEPROM.write(EE_DECREMENT_ADDR, decrement);
  
  if(!param_set){
  EEPROM_uint16t_write(EE_RELAY_REPEAT_PERIOD_ADDR, repeat_period);
  EEPROM_float_write(EE_RELAY_ON_PERIOD_ADDR, relay_on_period);
  } else{
	EEPROM_uint16t_write(EE_RELAY_REPEAT_PERIOD2_ADDR, repeat_period);
	EEPROM_float_write(EE_RELAY_ON_PERIOD2_ADDR, relay_on_period);  
  }
  
  EEPROM_float_write(EE_TEMP_NORM_ADDR, temp_norm);
  EEPROM_float_write(EE_TEMP_DIFF_ADDR, temp_diff);
  EEPROM_float_write(EE_FLOWUNIT_ADDR, flowunit);
  
  EEPROM.write(EE_PAUSE_ADDR, pause);
  EEPROM.write(EE_CHANGEMODE, changefrac_mode);
  EEPROM_uint16t_write(EE_HEADS_ADDR,headsvolume);
  EEPROM_uint16t_write(EE_PREBODY_ADDR,prebodyvolume);
  EEPROM_float_write(EE_TEMP_PRETAILS,pretail_temp);
  
}

void Timer1_action()
{
  
  if (temp_err) return;
  
  if (++dscounter > DS_COUNTER_MAX) {
    dscounter=0; //Сброс счетчика
    dscall = 1; //Установка флага опроса датчика
  }
  /*Serial.print("devmode ");
  Serial.println(devmode);
    Serial.print("relayonpercur ");
  Serial.println(relay_on_period_current);
  Serial.print("tempovf ");
  Serial.println(temp_ovf);*/
   
  /* обрабатываем счётчики периодов повтора/срабатывания */
  if ((temp_ovf == false) && (relay_on_period_current >= 0.20) && devmode && (menu == 0) && (!relay_disabled)) {
   //Serial.print("relay counter ");
  //Serial.println(relay_counter);
    //Serial.print("repeat counter ");
  //Serial.println(repeat_counter);
    /* при обнулении счётчика срабатывания выключаем реле, иначе уменьшаем счётчик */
    if (relay_counter <= 0){
		MyRelay(RELAY_PIN, LOW );
		
		}else {relay_counter -= 0.01;}
    
    /* при обнулении счётчика повтора вкючаем реле, иначе уменьшаем счётчик */
    if (repeat_counter > 0) {repeat_counter -= 0.01;}
    else {
        if(repeat_period>0 && relay_on_period_current>0){
      switch(state){
	      case(2):
	      headsleftvolume+=relay_on_period_current*flowunit;
	      //Serial.println(headsleftvolume);
	      break;
	      case(3):
	      prebodyleftvolume+=relay_on_period_current*flowunit;
		  //Serial.println(prebodyleftvolume);
	      break;
      }
      MyRelay(RELAY_PIN, HIGH); relay_counter = relay_on_period_current; repeat_counter = repeat_period;}
    }
  }
}
void CalcFlow(){
	flow = (uint16_t) 3600/repeat_period*flowunit*relay_on_period_current;
	/*Serial.print("Re Period=");
	Serial.println(repeat_period);
	Serial.print("flowunit=");
	Serial.println(flowunit);
	Serial.print("relayonpercur=");
	Serial.println(relay_on_period_current);
	Serial.print("flow=");
	Serial.println(flow);*/
}
void signalization(){
if (finished == 1)	{
	if(!done){
		//MyRelay(COOLING_PIN, HIGH ); // если закончили включаем реле окончания
		Serial.println("AT+ON=0");
		done=1;
		cooling_counter=millis();
		pinMode(BEEPER_PIN, OUTPUT);
		for (i=0;i<6;i++){
			//Serial.println("BEEP!!");
			#if USE_BEEPER==0
			digitalWrite(BEEPER_PIN,HIGH);
			delay(500);
			digitalWrite(BEEPER_PIN,LOW);
			delay(500);
			#else
			//Serial.println("BEEP!!");
			tone(BEEPER_PIN, 500); //включаем на 500 Гц
			delay(500); //ждем 500 Мс
			tone(BEEPER_PIN, 1000); //включаем на 1000 Гц
			delay(500); //ждем 500 Мс
			#endif
			
		}
		pinMode(BEEPER_PIN, INPUT);
	}
}

}
	
void indication()
{
if(indistate == true){
digitalWrite(STAB_PIN,HIGH);	
} else {
digitalWrite(STAB_PIN,LOW);		
}
if (param_set == 0){
	if (!lock) {
		indistate=!indistate;
		lcd.setCursor(8, 1);
		lcd.print("-");
	} else {
	indistate = false;
	lcd.setCursor(8, 1);
	lcd.print("*");	
	}
	if (temp_ovf) {
		indistate = true;
		lcd.setCursor(8, 1);
		lcd.print("!");
	}
} else{
	lcd.setCursor(8, 1);
	lcd.print("^");
}
}


void check_temp()
{
  uint8_t i; //счетчик
  String rmv_response;
  if (((temp[0]>WARMUP_TEMP) ||(temp[1]>WARMUP_TEMP)) && (warmup==false) ){
	 Serial.println("AT+ON?");
	 //Serial.println("AT+SM=1");
	 for (int y=0;y<2;y++){
		 if (Serial.available()){
			 rmv_response=Serial.readString();
			 if(rmv_response.startsWith("ON")){
			 Serial.println("AT+SM=1");
			 
			 }
		 }
		_delay_ms(200);
	 }
	 warmup=true;
	 lcd.clear();
	 lcd.setCursor(3, 0);
	// lcd.print(rmv_response);
	 lcd.print("PA3O");lcd.write((byte)5);lcd.print("PEB");
	 accel_enabled=false;
	 digitalWrite(ACCEL_PIN,LOW);
	 pinMode(BEEPER_PIN, OUTPUT);
	 for (i=0;i<6;i++){
		 //	 Serial.println("BEEP!!");
		 #if USE_BEEPER==0
		 digitalWrite(BEEPER_PIN,HIGH);
		 delay(500);
		 digitalWrite(BEEPER_PIN,LOW);
		 delay(500);
		 #else
		 //  Serial.println("BEEP!!");
		 tone(BEEPER_PIN, 500); //включаем на 500 Гц
		 delay(500); //ждем 500 Мс
		 tone(BEEPER_PIN, 1000); //включаем на 1000 Гц
		 delay(500); //ждем 500 Мс
		 #endif
	 }
	 pinMode(BEEPER_PIN, INPUT);
	 lcd.clear();
		 	  
  }
  if (devmode && lock) { /* если рект и дельта стабильна*/
    /* если достигли или перешли пороговое значение */
    if ((temp[1]-temp[0] >= lock_norm + temp_diff)||(temp[1]-temp[0] <= lock_norm - temp_diff)) {
      /* если это первый переход за период повторения */
      if (!temp_ovf) {
		/* устанавливаем флаг */
		   temp_ovf = true;
		   ovf_time = millis();
        /* отключаем реле */
		MyRelay(RELAY_PIN, LOW );
		
         relay_counter = 0;
		 //Serial.println("devmode+lock");
         repeat_counter =0;
		pinMode(BEEPER_PIN, OUTPUT); 
		 for (i=0;i<6;i++){
		//	 Serial.println("BEEP!!");
			 #if USE_BEEPER==0
			 digitalWrite(BEEPER_PIN,HIGH);
			 delay(500);
			 digitalWrite(BEEPER_PIN,LOW);
			 delay(500);
			  #else
			//  Serial.println("BEEP!!");
			  tone(BEEPER_PIN, 500); //включаем на 500 Гц
			  delay(500); //ждем 500 Мс
			  tone(BEEPER_PIN, 1000); //включаем на 1000 Гц
			  delay(500); //ждем 500 Мс
			  #endif
			 
		 }
		 pinMode(BEEPER_PIN, INPUT);
        
       
        /* если декремент не равен нулю, то уменьшаем текущий период срабатывания */
        if (decrement > 0 && current_decrement > 0) {
          current_decrement -= decrement;
          if (current_decrement>0){relay_on_period_current = relay_on_period*(float)(current_decrement/100);}
          //relay_on_period_current -= (relay_on_period/((float)100/decrement));
        }
        
		/* проверяем значение текущего периода срабатывания */
        if ((current_decrement <= 0 )|| (repeat_period <= 0)) {
          MyRelay(RELAY_PIN, LOW );
          relay_on_period_current = 0;
          repeat_counter = 9999.00;
		  finished = 1;
          return;}
        /* инициализируем счётчики */
        relay_counter = relay_on_period_current;
        repeat_counter = 0.00;
      }
    /* если температура опустилась ниже порогового значения, то снимаем флаг */
	//Serial.println(lock_norm);
    } else if ((temp[1] - temp[0] <= lock_norm + 0.0625) && (temp[1] - temp[0] >= lock_norm - 0.0625) && (temp_ovf == true)) {temp_ovf = false;ovf_time=0;ovf_cur_time=0; CalcFlow();}
  } else { /* если дист */
    if ((temp[2] >= temp_norm)&& (devmode == 0)) {  //Если дист и температура выше
      /* если это первый переход за период повторения */
      if (!temp_ovf) {
        /* выключаем реле */
        MyRelay(RELAY_PIN, LOW );
		accel_enabled=false;
		digitalWrite(ACCEL_PIN,LOW);
        devmode=1;
        relay_on_period_current = 0;
        repeat_counter = 9999.00;
        brightness = 0;
		finished = 1;
		save=1;
        temp_ovf = true;
        return;
        
      }
    }
  }
}
void handleCooling()
{
	if ((coolenable == false) &&(temp[2]>COOLING_TEMP)){
		pinMode(BEEPER_PIN, OUTPUT);
		for (i=0;i<6;i++){
			//	 Serial.println("BEEP!!");
			#if USE_BEEPER==0
			digitalWrite(BEEPER_PIN,HIGH);
			delay(500);
			digitalWrite(BEEPER_PIN,LOW);
			delay(500);
			#else
			//  Serial.println("BEEP!!");
			tone(BEEPER_PIN, 500); //включаем на 500 Гц
			delay(500); //ждем 500 Мс
			tone(BEEPER_PIN, 1000); //включаем на 1000 Гц
			delay(500); //ждем 500 Мс
			#endif
		}
		pinMode(BEEPER_PIN, INPUT);
		MyRelay(COOLING_PIN, HIGH );
		coolenable=true;
	}
	if((done == true) && (coolenable == true) &&((millis()-cooling_counter)>COOLING_TIMEOUT)){
		MyRelay(COOLING_PIN, LOW );
		coolenable=false;
	}
	
}

void handleIncident(){
	unsigned int alarmreading = analogRead(ALARM_PIN);
	if(alarmreading<512){
	MyRelay(RELAY_PIN, LOW );
	accel_enabled=false;
	digitalWrite(ACCEL_PIN,LOW);
	devmode=1;
	state=0;
	relay_on_period_current = 0;
	repeat_counter = 9999.00;
	brightness = 0;
	finished = 1;
	save=1;
	temp_ovf = true;
	lcd.clear();
	lcd.setCursor(3, 0);
	 lcd.print("ABAP");lcd.write((byte)1);lcd.write((byte)0);lcd.print("!");
	 pinMode(BEEPER_PIN, OUTPUT);
	 for (i=0;i<6;i++){
		 //	 Serial.println("BEEP!!");
		 #if USE_BEEPER==0
		 digitalWrite(BEEPER_PIN,HIGH);
		 delay(500);
		 digitalWrite(BEEPER_PIN,LOW);
		 delay(500);
		 #else
		 //  Serial.println("BEEP!!");
		 tone(BEEPER_PIN, 500); //включаем на 500 Гц
		 delay(500); //ждем 500 Мс
		 tone(BEEPER_PIN, 1000); //включаем на 1000 Гц
		 delay(500); //ждем 500 Мс
		 #endif
	 }
	 pinMode(BEEPER_PIN, INPUT);
	}
	
}

void init_sensors(unsigned char errnum)
{
  unsigned char err=1;
  MyRelay(RELAY_PIN, LOW );
  while (err) {
    devices = sensors.getDeviceCount();
    if (devices){
      err = 0;
      temp_err = false;
      get_temp();
      temp_old[0] = temp[0];
      temp_old[1] = temp[1];
	  temp_old[2] = temp[2];
      
    } else errnum = 0;
  }
}

void first_start(void){
  temp_norm = DEFAULT_TEMP_NORM;
  temp_diff = DEFAULT_TEMP_DIFF;
  brightness = 0;
  finished = 0;
  state = 0;
  //digitalWrite(COOLING_PIN,HIGH);
  relay_on_period = relay_on_period_current = RELAY_ON_PERIOD_DEFAULT;
  repeat_period = REPEAT_PERIOD_DEFAULT;
  EEPROM_uint16t_write(EE_RELAY_REPEAT_PERIOD2_ADDR, repeat_period);
  EEPROM_float_write(EE_RELAY_ON_PERIOD2_ADDR, relay_on_period);
  original_relay_on_period=relay_on_period;
  decrement = DECREMENT_DEFAULT;
  current_decrement = 100;
  param_set = 0;
  temp_ovf = false;
  //temp_err = true;
  //info_counter = SHOW_TEMP_COUNTER_VALUE;
  //info_ovf = true;
  relay_counter = relay_on_period_current; 
  repeat_counter = repeat_period;
  
  pause=PAUSE_DEFAULT;
  changefrac_mode = CHANGEMODE_DEFAULT;
  headsvolume = HEADS_DEFAULT;
  prebodyvolume = PREBODY_DEFAULT;
  pretail_temp = PRETAILS_TEMP_DEFAULT;
  EEPROM.write(EE_PAUSE_ADDR, pause);
  EEPROM.write(EE_CHANGEMODE, changefrac_mode);
  EEPROM_uint16t_write(EE_HEADS_ADDR,headsvolume);
  EEPROM_uint16t_write(EE_PREBODY_ADDR,prebodyvolume);
  EEPROM_float_write(EE_TEMP_PRETAILS,pretail_temp);
  
    lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("C");lcd.write((byte)4);lcd.write((byte)1);lcd.print("PTO");lcd.write((byte)5);lcd.print("OH-PMB");
  lcd.setCursor(3, 1);
  lcd.print("BEPC");lcd.write((byte)1);lcd.write((byte)0);lcd.print(" 0.1");
  _delay_ms(2000);
  lcd.clear();
  lock=0;
  CalcFlow();
  starttime = millis(); 
  accel_enabled=false;
  digitalWrite(ACCEL_PIN,LOW);
  save=1;
  
}

void re_start(void){
temp_ovf = false;
lock = 0;
finished = 0;
done=0;
state = 0;
/* выключаем реле */
MyRelay(RELAY_PIN, LOW );
//MyRelay(COOLING_PIN, LOW );

temp_norm = EEPROM_float_read(EE_TEMP_NORM_ADDR);
temp_diff = EEPROM_float_read(EE_TEMP_DIFF_ADDR);
brightness = EEPROM.read(EE_BRIGHTNESS_ADDR);
repeat_period = EEPROM_uint16t_read(EE_RELAY_REPEAT_PERIOD_ADDR);
relay_on_period = EEPROM_float_read(EE_RELAY_ON_PERIOD_ADDR);
flowunit = EEPROM_float_read(EE_FLOWUNIT_ADDR);
relay_on_period_current = relay_on_period;
original_relay_on_period=relay_on_period;
decrement = EEPROM.read(EE_DECREMENT_ADDR);


pause=EEPROM.read(EE_PAUSE_ADDR);
changefrac_mode = EEPROM.read(EE_CHANGEMODE);
headsvolume = EEPROM_uint16t_read(EE_HEADS_ADDR);
prebodyvolume = EEPROM_uint16t_read(EE_PREBODY_ADDR);
pretail_temp = EEPROM_float_read(EE_TEMP_PRETAILS);
//temp_err = true;
current_decrement = 100;
lock_norm = 0;              //фикс дельты для стабилизации
prev_lock_norm = 0;
repeat_counter = repeat_period;
param_set = 0;
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("C");lcd.write((byte)4);lcd.write((byte)1);lcd.print("PTO");lcd.write((byte)5);lcd.print("OH-PMB");
lcd.setCursor(3, 1);
lcd.print("BEPC");lcd.write((byte)1);lcd.write((byte)0);lcd.print(" 0.1");
  _delay_ms(2000);
  lcd.clear();
  CalcFlow();
  starttime = millis(); 
//info_counter = SHOW_TEMP_COUNTER_VALUE;
//info_ovf = true;
accel_enabled=false;
digitalWrite(ACCEL_PIN,LOW);
}

 uint8_t GetKey(){
  uint8_t tmpkey = 0;
  #if USE_LCD_KEYPAD_SHIELD==0
  if (digitalRead(BUTTON_PLUS)==LOW){
    tmpkey += KEY_PLUS;
  }
  if (digitalRead(BUTTON_MINUS)==LOW){
    tmpkey += KEY_MINUS;
  }
  if (digitalRead(BUTTON_SET)==LOW){
    tmpkey += KEY_OK;
  }
  if (digitalRead(ACCEL_BUTTON)==LOW){
	  tmpkey = KEY_ACCEL;
  }
  #else
 uint16_t keyIN=analogRead(A0); 
  if (keyIN>=1000){/*Serial.println("NO KEY PRESSED");*/ return tmpkey;}
  if (keyIN < 50){
    tmpkey = KEY_PLUS;
   // Serial.println(keyIN);
   // Serial.println("KEY PLUS");
  
    return tmpkey;
  }
  if (keyIN < 200){
    tmpkey = KEY_PLUS+KEY_MINUS;
   // Serial.println(keyIN);
   // Serial.println("KEY PLUS+KEY MINUS ");
  
    return tmpkey;
  }
  if (keyIN < 400){
    tmpkey = 0;
  //  Serial.println(keyIN);
  //  Serial.println("NOT USED ");
  
    return tmpkey;
  }
  if (keyIN < 600){
    tmpkey = KEY_MINUS;
   // Serial.println(keyIN);
  //  Serial.println("KEY MINUS ");
  
    return tmpkey;
  }
    if (keyIN < 800){
    tmpkey = KEY_OK;
  //  Serial.println(keyIN);
   // Serial.println("KEY OK ");
  
    return tmpkey;
  }
  #endif
  //Serial.print("KEY PRESSED ");
  //Serial.println(tmpkey);
  return tmpkey;
  //return 0;
}

void StandardModeDisplay(){
  //Serial.print("Display!");
  //Здесь будет обычный режим отображения
  lcd.setCursor(0,0);
  lcd.print("dT=");
  lcd.setCursor(3, 0);
  lcd.print(abs(temp[0]-temp[1]));
  //lcd.setCursor(8, 0);
  lcd.print(" ");
  lcd.setCursor(0,1);
  lcd.print("TK=");
  lcd.setCursor(3, 1);
  lcd.print(temp[2]);
  lcd.setCursor(9, 1);
  lcd.print("OT=");
  lcd.setCursor(12, 1);
  if (state<2){
	  lcd.print("----");
  }else{
  lcd.print(flow);
  if (flow<1000){lcd.setCursor(15, 1);lcd.print(" ");}
  if (flow<100){lcd.setCursor(14, 1);lcd.print(" ");}
  if (flow<10){lcd.setCursor(13, 1);lcd.print(" ");}
  }
  lcd.setCursor(7, 0);
    
  if (state==0){
  lcd.print(" PA3");lcd.write((byte)5);lcd.print("OH ");	  
  }else{
  lcd.print(" OCT=");
  lcd.setCursor(12, 0);
  }
  
  uint16_t minleft=(uint16_t)((pause*60000-(millis()-init_counter))/60000);
  uint16_t headsleft=(uint16_t)(headsvolume-headsleftvolume);
  uint16_t prebodyleft = (uint16_t)(prebodyvolume-prebodyleftvolume);
  switch(state){
	  case (1): //на себя
	  lcd.print(minleft);
	  if (minleft<100){lcd.print(" ");}
	  if (minleft<10){lcd.print(" ");}
	  break;
	  case(2):
	  lcd.print(headsleft);
	  if (headsleft<100){lcd.print(" ");}
	  if (headsleft<10){lcd.print(" ");}
	  break;
	  case(3):
	  lcd.print(prebodyleft);
	  if (prebodyleft<100){lcd.print(" ");}
	  if (prebodyleft<10){lcd.print(" ");}
	  break;
	  case(4):
  if(relay_counter>0) {
    lcd.print((uint16_t) relay_counter);
    if (relay_counter<100){lcd.print(" ");}
    if (relay_counter<10){lcd.print(" ");}
  }else {
    lcd.print((uint16_t) repeat_counter);
    if (repeat_counter<100){lcd.print(" ");}
    if (repeat_counter<10){lcd.print(" ");}
	}
	break;
	case(5):
	if(relay_counter>0) {
		lcd.print((uint16_t) relay_counter);
		if (relay_counter<100){lcd.print(" ");}
		if (relay_counter<10){lcd.print(" ");}
		}else {
		lcd.print((uint16_t) repeat_counter);
		if (repeat_counter<100);{lcd.print(" ");}
		if (repeat_counter<10){lcd.print(" ");}
	}
	break;
	}
 /* lcd.print(current_decrement);
  lcd.setCursor(15, 0);
  lcd.print("%");
  if (current_decrement<100){lcd.setCursor(14, 0);lcd.print("% ");}
  if (current_decrement<10){lcd.setCursor(13, 0);lcd.print("%  ");}*/
 
}


void setup() {
  int InputVoltage=0;
  state=0;
  relay_disabled =1;
  pinMode(RELAY_PIN, OUTPUT);   
  pinMode(BODY_SWITCH_PIN,INPUT_PULLUP); // притягиваем пин к 5в
  pinMode(ALARM_PIN, INPUT_PULLUP);
   //lcd.begin(16, 2);
   #if USE_LCD_KEYPAD_SHIELD==0
   lcd.init();
   lcd.backlight();// Включаем подсветку дисплея
   #else
	lcd.begin(16, 2);
   #endif
   lcd.createChar(0, Ya);
   lcd.createChar(1, I);
   lcd.createChar(2, L);
   lcd.createChar(3, bI);
   lcd.createChar(4, P);
   lcd.createChar(5, G);
   lcd.createChar(6, ZH);
   Serial.begin(9600);
   sensors.begin();
   sensorscube.begin();
  //Serial.print("Locating devices...");
 // Serial.print("Found ");
 // Serial.print(sensors.getDeviceCount(), DEC);
 // Serial.println(" devices.");
  /*asm("sei");*/
  
  MyRelay(RELAY_PIN, LOW );
  #if USE_LCD_KEYPAD_SHIELD==1
	pinMode (A0, INPUT_PULLUP);
  #endif
  lcd.setCursor(2, 0);
  lcd.print("C");lcd.write((byte)4);lcd.write((byte)1);lcd.print("PTO");lcd.write((byte)5);lcd.print("OH-PMB");
  lcd.setCursor(3, 1);
  lcd.print("BEPC");lcd.write((byte)1);lcd.write((byte)0);lcd.print(" 0.1");
  //_delay_ms(2000);
  lcd.clear();
  //поищем РМВ-К
  Serial.println("AT+VI?");
  for (int y=0;y<3;y++){
	  if (Serial.available()){
		String voltage = Serial.readString();  
		InputVoltage = voltage.toInt(); 
	  }
	_delay_ms(1000);  
  }
  if (InputVoltage>0){
	lcd.setCursor(3, 0);
	lcd.print("PMB-K ECTb");
	lcd.setCursor(3, 1);
	lcd.print("V CET");lcd.write((byte)1);lcd.print(" = ");lcd.print(InputVoltage);lcd.print("V");		
	//Serial.println("AT+ON=1");
  } else {
	lcd.setCursor(3, 0);
	lcd.print("PMB-K HET");  
  }
  _delay_ms(2000);  
  lcd.clear();
  starttime = millis();
  float temp_norm_tmp, temp_diff_tmp, temp_param;
  temp_norm_tmp = EEPROM_float_read(EE_TEMP_NORM_ADDR);
  temp_diff_tmp = EEPROM_float_read(EE_TEMP_DIFF_ADDR);
  temp_param = EEPROM_uint16t_read(EE_RELAY_REPEAT_PERIOD2_ADDR);
  
  if ((temp_param>999)||(EEPROM.read(EE_INIT_ADDR) != 1) || ((temp_norm_tmp + temp_diff_tmp) > MAX_TEMP)) { //Первый запуск или некорректные значения
      first_start();
      save_params();
      } else {
      re_start();
    }
 if (!sensors.getAddress(firstThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
  if (!sensors.getAddress(secondThermometer, 1)) Serial.println("Unable to find address for Device 1");
  if (!sensorscube.getAddress(cubeThermometer, 0)) Serial.println("Unable to find address for Device 2");
  sensors.setResolution(firstThermometer, 12);
  sensors.setResolution(secondThermometer, 12);
  sensorscube.setResolution(cubeThermometer, 12);
    if (sensors.getAddress(firstThermometer, 0))
  {
    // Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: 125,000 kHz
    /*TCCR1A=0x00;
    TCCR1B=0x03;
    TCNT1=0xfb1d;
    
    TIMSK1 |= 0x04;*/
    Timer1.initialize(10000);
    Timer1.attachInterrupt(Timer1_action);
	attachPCINT(digitalPinToPCINT(BODY_SWITCH_PIN), bodyChange, FALLING);
	
    temp_err = false;
    get_temp();
    temp_old[0] = temp[0];
    temp_old[1] = temp[1];
	temp_old[2] = temp[2];
    CalcFlow();
    StandardModeDisplay();
  }
  
  _delay_ms(250); 
  prev_lock_norm =temp[1]-temp[0];

//готовим батоны к бою. Кнопы идут второй ногой на землю.
#if USE_LCD_KEYPAD_SHIELD==0
pinMode(BUTTON_PLUS, INPUT_PULLUP);
pinMode(BUTTON_MINUS, INPUT_PULLUP);
pinMode(BUTTON_SET, INPUT_PULLUP);
pinMode(ACCEL_BUTTON, INPUT_PULLUP);
pinMode(CHANGEFRAC_PIN,OUTPUT);
digitalWrite(CHANGEFRAC_PIN,HIGH);
pinMode(ACCEL_PIN, OUTPUT);
#endif
pinMode(BEEPER_PIN, OUTPUT);

pinMode(STAB_PIN, OUTPUT); //пин стабилизации на выдачу
pinMode(COOLING_PIN, OUTPUT); //пин реле охлаждения
digitalWrite(BEEPER_PIN,LOW);
MyRelay(COOLING_PIN, LOW ); //пока охл-е выключено
lock=0;

  

}

void bodyChange(void){
	
	if(chbutton_pushed==0){
	chbutton_pushed=1;
	}
	
}

void loop() {
  
  
  
  //Serial.print(millis());
  if (menu == 0 && mode != 0){ //оператор вошел в меню
	menu = 1; //флаг меню наверх
	MyRelay(RELAY_PIN, LOW ); //вырубаем клапан
  }
  tmpkey = GetKey();
  _delay_ms(10);
   if (tmpkey == GetKey()) // Повторно проверяем состояние кнопок для избежание дребезга
      {
        key = tmpkey;
      } //Если был дребезг, то состояние нажатой кнопки не меняем
     
if (key == prevkey) {
      //  Serial.print("keycount is ");
  //Serial.println(keycount);
  
        if (keycount < 65000) keycount++;
        if (keycount >= 5) click=1;
        if (keycount > 105) {
			
			
        dt = 0.5;
        switch (mode) {
          case SET_DEC:
          case SET_REPEAT: dt = 1; break;
		  case SET_DIFF: dt = 0.1; break;
		  case SET_FLOWUNIT: dt = 0.1;break;
		  case SET_PAUSE: dt=5;break;
		  case SET_HEADSVOLUME: dt=100;break;
		  case SET_PREBODYVOLUME: dt=100;break;
		  case SET_T_PRETAIL: dt=0.1;break;
          default: break;
        }
        } else {
        dt = 0.1;
        switch (mode) {
          case SET_DEC:
          case SET_REPEAT: dt = 1; break;
		  case SET_DIFF: dt = 0.0625; break;
		  case SET_FLOWUNIT: dt = 0.01;break;
		  case SET_PAUSE: dt=1;break;
		  case SET_HEADSVOLUME: dt=50;break;
		  case SET_PREBODYVOLUME: dt=50;break;
		  case SET_T_PRETAIL: dt=0.0625;break;
          default: break;
        }
      }
     } else {
       //Serial.print("key is ");
  //Serial.println(key);
  
        keycount=0;
        if (key == 0) click=1; //Короткий клик
        if (key == KEY_OK) if (mode++ > 11) mode = 1;
       //Serial.print("mode is ");
	   //Serial.println(mode); 
      }
      if (((key == KEY_PLUS) || (key == KEY_MINUS)) && (mode == 0)) {
        //lcd.clear();
        lcd.setCursor(0, 0);
		//lcd.print("C");lcd.write((byte)4);lcd.write((byte)1);lcd.print("PTO");lcd.write((byte)5);lcd.print("OH");
		//lcd.setCursor(3, 1);
		//lcd.print("BEPC");lcd.write((byte)1);lcd.write((byte)0);lcd.print(" 1.1");
        lcd.print("D");lcd.write((byte)1);lcd.print("CT ");lcd.write((byte)4);lcd.print("OPO");lcd.write((byte)5);lcd.print("=");
        lcd.setCursor(11, 0);
        lcd.print(temp_norm);
        lcd.setCursor(15, 0);
        lcd.print(" ");
        lcd.setCursor(0, 1);
        lcd.print("                ");
        //StandardModeDisplay();
        mode = SET_NORM;
        _delay_ms(1000);
        //click=0;
        key=0;
        prevkey=0;
        keycount=0;
      }
      if (click){
        switch(prevkey){
          case KEY_PLUS: //Нажата кнопка "+"
          switch(mode){
            case SET_NORM: temp_norm += dt; if ((temp_norm+temp_diff) > MAX_TEMP) temp_norm=MAX_TEMP-temp_diff;lock=0; save=1;  break;
            case SET_DIFF: temp_diff += dt; if (((temp_norm+temp_diff) > MAX_TEMP) || ((temp_norm-temp_diff) < MIN_TEMP)) temp_diff -= dt; save=1; break;
            case SET_BRIGHTNESS_MODE: if (brightness == 0) {brightness++; save=1;devmode = 0;MyRelay(RELAY_PIN, HIGH );repeat_counter=0;} break;
			case SET_HEADS: if (param_set == 0) {param_set=1; apply_param(1);save=1;} break;
            case SET_REPEAT: repeat_period += dt; if (repeat_period > 999) repeat_period = 999; repeat_counter = 0.00;current_decrement=100; save = 1;  break;
            case SET_FLOWUNIT: flowunit +=dt; if (flowunit >99) flowunit = 99; save = 1; break;
            case SET_PERIOD:
              relay_on_period += dt;
              if (relay_on_period > repeat_period) relay_on_period -= dt;
              if (relay_on_period > 100) relay_on_period = 100;
              relay_on_period_current = relay_on_period;
              original_relay_on_period = relay_on_period;
              current_decrement=100;
              save = 1;
              break;
            case SET_DEC: decrement += dt; if (decrement > 99) decrement = 99; save = 1; break;
			case SET_PAUSE: pause += dt; if (pause > 360) pause = 360; save = 1; break;
			case SET_HEADSVOLUME: headsvolume += dt;if (headsvolume > 5000) headsvolume = 5000; save = 1; break;
			case SET_PREBODYVOLUME: prebodyvolume += dt;if (prebodyvolume > 5000) prebodyvolume = 5000; save = 1; break;
			case SET_T_PRETAIL: pretail_temp += dt; if ((pretail_temp+temp_diff) > temp_norm) pretail_temp=temp_norm-temp_diff; save=1;  break;
			case SET_CHANGEMODE: if (changefrac_mode == 0) {changefrac_mode=1; save=1;} break;
			
          }
          break;
          case KEY_MINUS: //Нажата кнопка "-"
          switch(mode){
            case SET_NORM: temp_norm -= dt; if ((temp_norm-temp_diff) < MIN_TEMP) temp_norm=MIN_TEMP+temp_diff;lock=0; save=1; break;
            case SET_DIFF: temp_diff -= dt; if (temp_diff <= 0) temp_diff += dt; save=1; break;
            case SET_BRIGHTNESS_MODE: if (brightness == 1) {brightness--;devmode = 1; save=1;} break;
			case SET_HEADS: if (param_set == 1) {param_set=0; apply_param(0);save=1;} break;
            case SET_REPEAT: repeat_period -= dt; if ((float)repeat_period <= relay_on_period) repeat_period += dt; repeat_counter = 0.00; save = 1; break;
            case SET_FLOWUNIT: flowunit -=dt; if (flowunit <=0) flowunit += dt; save = 1; break;
            case SET_PERIOD:
              relay_on_period -= dt;
              if (relay_on_period <= 0.2) relay_on_period = 0.2;
              relay_on_period_current = relay_on_period;
              original_relay_on_period = relay_on_period;
              current_decrement=100;
              save = 1;
              break;
            case SET_DEC:
              if (decrement == 0) {save = 1; break;}
              decrement -= dt;
              save = 1;
            break;
			case SET_PAUSE: pause -= dt; if (pause < 1) pause = 1; save = 1; break;
			case SET_HEADSVOLUME: headsvolume -= dt;if (headsvolume < 50) headsvolume = 50; save = 1; break;
			case SET_PREBODYVOLUME: prebodyvolume -= dt;if (prebodyvolume < 50) prebodyvolume = 50; save = 1; break;
			case SET_T_PRETAIL: pretail_temp -= dt; if (pretail_temp <WARMUP_TEMP ) {pretail_temp=WARMUP_TEMP+dt;} save=1;  break;
			case SET_CHANGEMODE: if (changefrac_mode == 1) {changefrac_mode=0; save=1;} break;
          }
          break;
          case (KEY_PLUS+KEY_MINUS+KEY_OK): //Сброс до заводских настроек
          first_start();
          mode=0;
		  menu = 0;
          save=1;
          break;
		  case (KEY_OK+KEY_PLUS): //Принудительная стабилизация с текущей разницей температур
		  if (lock == 0 && param_set == 0) {
			  lock = 1;
			  #if USE_BEEPER==0
			  digitalWrite(BEEPER_PIN, HIGH);
			  delay(50);
			  digitalWrite(BEEPER_PIN, LOW);
			  #else
			  tone(BEEPER_PIN, 2000); //включаем на 2000 Гц
			  delay(50); //ждем 50 Мс
			  noTone(BEEPER_PIN); //выключаем бипер
			  #endif
			  mode = 0; menu = 0;
		  }
		  break;
        case (KEY_OK+KEY_MINUS):
          relay_on_period_current = relay_on_period;
          mode = 0;
		  menu = 0;
          break;
        case (KEY_PLUS+KEY_MINUS):
        EEPROM_float_write(EE_RELAY_ON_PERIOD_ADDR, relay_on_period);
        re_start();
        relay_on_period = original_relay_on_period;
        repeat_counter = 1;
        mode = 0;
		menu = 0;
        break;
		case(KEY_ACCEL):
			if (!accel_enabled){
				digitalWrite(ACCEL_PIN,HIGH);
				accel_enabled=true;
			}else {
				accel_enabled=false;
				digitalWrite(ACCEL_PIN,LOW);
			}
			pinMode(BEEPER_PIN, OUTPUT); //гуднем
			#if USE_BEEPER==0
			digitalWrite(BEEPER_PIN,HIGH);
			delay(200);
			digitalWrite(BEEPER_PIN,LOW);
			delay(200);
			#else
			//Serial.println("BEEP!!");
			tone(BEEPER_PIN, 500); //включаем на 500 Гц
			delay(200); //ждем 500 Мс
			tone(BEEPER_PIN, 1000); //включаем на 1000 Гц
			delay(200); //ждем 500 Мс
			#endif
			pinMode(BEEPER_PIN, INPUT);
		break;
        }
		
        click = 0;
        _delay_ms(30);
      } else _delay_ms(100);
      prevkey = key;
     if ((keycount > 100) && (key == 0) && (mode != 0)) { //Если долго не нажимаются кнопки в режимах настроек
        mode = 0; //Переходим в дежурный режим
		menu = 0; //спускаем флаг меню
      }
	 // Serial.println(mode);
     switch(mode){
       case SET_NORM: //Установка temp_norm
        lcd.setCursor(11, 0);
        lcd.print(temp_norm);
        lcd.setCursor(15, 0);
        lcd.print(" ");
        lcd.setCursor(0, 1);
        lcd.print("                ");
        break;
        case SET_DIFF: //Установка temp_diff
        if (prevmode != mode) {
        lcd.setCursor(0, 0);
        lcd.print("DE");lcd.write((byte)2);lcd.print("bTA=");
        lcd.setCursor(7, 0);
        lcd.print(temp_diff);
        lcd.setCursor(11, 0);
        lcd.print("     ");
        lcd.setCursor(0, 1);
        lcd.print("                ");
          }
        
        lcd.setCursor(7, 0);
        lcd.print(temp_diff);
        lcd.setCursor(11, 0);
        lcd.print("     ");
        break;
        case SET_BRIGHTNESS_MODE: //Установка brightness
        if (prevmode != mode) {
        lcd.setCursor(0, 0);
        lcd.print("D");lcd.write((byte)1);lcd.print("CT BK");lcd.write((byte)2);lcd.print("=");
        lcd.setCursor(9, 0);
        lcd.print(brightness);
        lcd.setCursor(10, 0);
        lcd.print("       ");
        lcd.setCursor(0, 1);
        lcd.print("                ");
        }
        lcd.setCursor(9, 0);
        lcd.print(brightness);
        break;
		case SET_HEADS: //Установка режима параметров
		if (prevmode != mode) {
			lcd.setCursor(0, 0);
			lcd.print("PE");lcd.write((byte)6);lcd.write((byte)1);lcd.print("M=");
			lcd.setCursor(6, 0);
			if (param_set == 0){
				lcd.print("TE");lcd.write((byte)2);lcd.print("O");
				lcd.setCursor(10, 0);
				lcd.print("      ");
			} else {
			lcd.write((byte)5);lcd.print("O");lcd.write((byte)2);lcd.print("OB");lcd.write((byte)3);
			lcd.setCursor(12, 0);
			lcd.print("    ");	
			}
			lcd.setCursor(0, 1);
			lcd.print("                ");
		}
		if (param_set == 0){
			lcd.setCursor(6, 0);
			lcd.print("TE");lcd.write((byte)2);lcd.print("O");
			lcd.setCursor(10, 0);
			lcd.print("      ");
			} else {
			lcd.setCursor(6, 0);
			lcd.write((byte)5);lcd.print("O");lcd.write((byte)2);lcd.print("OB");lcd.write((byte)3);
			lcd.setCursor(12, 0);
			lcd.print("    ");
		}
		break;
      case SET_REPEAT:
        if (prevmode != mode) {
        lcd.setCursor(0, 0);
        lcd.write((byte)4);lcd.print("EP");lcd.write((byte)1);lcd.print("OD=");
        lcd.setCursor(7, 0);
        lcd.print(repeat_period);
        lcd.setCursor(10, 0);
        lcd.print("      ");
        if (repeat_period<100){lcd.setCursor(9, 0);lcd.print(" ");}
		if (repeat_period<10){lcd.setCursor(8, 0);lcd.print(" ");}
        lcd.setCursor(0, 1);
        lcd.print("                ");
        }
        lcd.setCursor(7, 0);
        lcd.print(repeat_period);
        lcd.setCursor(10, 0);
        lcd.print("      ");
        if (repeat_period<100){lcd.setCursor(9, 0);lcd.print(" ");}
		if (repeat_period<10){lcd.setCursor(8, 0);lcd.print(" ");}
        break;
      case SET_PERIOD:
        if (prevmode != mode) {
        lcd.setCursor(0, 0);
        lcd.print("OTKP");lcd.write((byte)3);lcd.print("T");lcd.write((byte)1);lcd.print("E=");
        lcd.setCursor(9, 0);
        lcd.print(relay_on_period);
        lcd.setCursor(13, 0);
        lcd.print("   ");
        if (relay_on_period<10){lcd.setCursor(12, 0);lcd.print(" ");}
        lcd.setCursor(0, 1);
        lcd.print("                ");
        }
        lcd.setCursor(9, 0);
        lcd.print(relay_on_period);
        lcd.setCursor(13, 0);
        lcd.print("   ");
        if (relay_on_period<10){lcd.setCursor(12, 0);lcd.print(" ");}
        break;
        case SET_DEC:
        if (prevmode != mode) {
        lcd.setCursor(0, 0);
        lcd.print("DEKPEMEHT=");
        lcd.setCursor(10, 0);
        lcd.print(decrement);
        lcd.setCursor(13, 0);
        lcd.print("  ");
		if (decrement<100){lcd.setCursor(12, 0);lcd.print(" ");}
        if (decrement<10){lcd.setCursor(11, 0);lcd.print(" ");}
        lcd.setCursor(0, 1);
        lcd.print("                ");
        }
        lcd.setCursor(10, 0);
        lcd.print(decrement);
        lcd.setCursor(13, 0);
        lcd.print("   ");
		if (decrement<100){lcd.setCursor(12, 0);lcd.print(" ");}
        if (decrement<10){lcd.setCursor(11, 0);lcd.print(" ");}
        break;
        case SET_FLOWUNIT:
        if (prevmode != mode) {
        lcd.setCursor(0, 0);
        lcd.print("K");lcd.write((byte)2);lcd.print("A");lcd.write((byte)4);lcd.print("AH=");
        lcd.setCursor(7, 0);
        lcd.print(flowunit);
        lcd.setCursor(11, 0);
        lcd.print("     ");
        if (flowunit<1){lcd.setCursor(10, 0);lcd.print("  ");}
        lcd.setCursor(0, 1);
        lcd.print("                ");
        }
        lcd.setCursor(7, 0);
        lcd.print(flowunit);
        lcd.setCursor(11, 0);
        lcd.print("     ");
        if (flowunit<1){lcd.setCursor(10, 0);lcd.print("  ");}
        break;
		/*lcd.createChar(0, Ya);
		lcd.createChar(1, I);
		lcd.createChar(2, L);
		lcd.createChar(3, bI);
		lcd.createChar(4, P);
		lcd.createChar(5, G);
		lcd.createChar(6, ZH);*/
		case SET_PAUSE: 
		if (prevmode != mode) {
		lcd.clear();
		lcd.setCursor(0, 0);
		lcd.print("PA6OTA HA CE6");lcd.write((byte)0);
		lcd.setCursor(0, 1);
		lcd.print("(M");lcd.write((byte)1);lcd.print("H): ");
		lcd.print(pause);
		//lcd.setCursor(12, 1);
		lcd.print(" ");
		//if (pause<100){lcd.setCursor(11, 1);lcd.print("       ");}
		//if (decrement<10){lcd.setCursor(10, 1);lcd.print("        ");}
		}
		lcd.setCursor(0, 1);
		lcd.print("(M");lcd.write((byte)1);lcd.print("H): ");
		lcd.print(pause);
		//lcd.setCursor(12, 1);
		lcd.print(" ");
		//if (pause<100){lcd.setCursor(11, 1);lcd.print("       ");}
		//if (decrement<10){lcd.setCursor(10, 1);lcd.print("        ");}
		break;
		case SET_HEADSVOLUME:
		if (prevmode != mode) {
		lcd.clear();
		lcd.setCursor(0, 0);
		lcd.print("KO");lcd.write((byte)2);lcd.print("-BO ");lcd.write((byte)5);lcd.print("O");lcd.write((byte)2);lcd.print("OB:");
		lcd.setCursor(0, 1);
		lcd.print(headsvolume);
		lcd.print("M");lcd.write((byte)2);lcd.print("    ");
		}
		lcd.setCursor(0, 1);
		lcd.print(headsvolume);
		lcd.print("M");lcd.write((byte)2);lcd.print("    ");
		break;
		case SET_PREBODYVOLUME:
		if (prevmode != mode) {
			lcd.clear();
			lcd.setCursor(0, 0);
			lcd.print("KO");lcd.write((byte)2);lcd.print("-BO O6OPOTK");lcd.write((byte)1);
			lcd.setCursor(0, 1);
			lcd.print(prebodyvolume);
			lcd.print("M");lcd.write((byte)2);lcd.print("    ");
		}
		lcd.setCursor(0, 1);
		lcd.print(prebodyvolume);
		lcd.print("M");lcd.write((byte)2);lcd.print("    ");
		break;
		case SET_T_PRETAIL:
		if (prevmode != mode) {
			lcd.clear();
			lcd.setCursor(0, 0);
			lcd.print("T ");lcd.write((byte)4);lcd.print("PEDXBOCTOB:");
			lcd.setCursor(0, 1);
			lcd.print(pretail_temp);lcd.print("    ");
		}
		lcd.setCursor(0, 1);
		lcd.print(pretail_temp);lcd.print("    ");
		break;
		
		case SET_CHANGEMODE: 
		if (prevmode != mode) {
			lcd.clear();
			lcd.setCursor(0, 0);
			lcd.print("PE");lcd.write((byte)6);lcd.write((byte)1);lcd.print("M CMEH");lcd.write((byte)3);
			lcd.setCursor(0, 1);lcd.print("TAP");lcd.write((byte)3);lcd.print(": ");
			if(changefrac_mode == 1){lcd.print("ABTO     ");}else{lcd.print("PY4HO");lcd.write((byte)1);lcd.print("    ");}
		}
		lcd.setCursor(6, 1);
		if(changefrac_mode == 1){lcd.print("ABTO     ");}else{lcd.print("PY4HO");lcd.write((byte)1);lcd.print("    ");}
		break;
		
		
        
        default: //Дежурный режим контроля температуры
        if (dscall && mode == 0) {
          //Serial.print("DSCALL!");
          if (sensors.getAddress(firstThermometer, 0)){
            temp_err = false;
            while (dscall) {
              get_temp();                 // Чтение температуры
              for (i=0;i<2;i++){
              if (temp[i] > (temp_old[i] + 10)) {temp_err = true; init_sensors(2);}
              if (temp[i] < (temp_old[i] - 10)) {temp_err = true; init_sensors(1);}
               if (temp[i] < MIN_TEMP) {temp_err = true; init_sensors(1);}    //Ошибка! Температура ниже минимальной
              else if (temp[i] > MAX_TEMP) {temp_err = true; init_sensors(2);} //Ошибка! Температура выше максимальной
              }
                
              dscall=0;
            }
          } else {
             MyRelay(RELAY_PIN, LOW );
//           relay_on_period_current = 0;
             temp_err = true;
             init_sensors(0);
          }
        }
        check_temp();
        
        if (save == 1) {
          save_params(); // Сохранить установленные параметры если были изменения
          for (i=0; i<3;i++){
            lcd.setCursor(0, 1);
            lcd.print("   COXPAH");lcd.write((byte)0);lcd.print("EM     ");
            _delay_ms(300);
            lcd.setCursor(0, 1);
            lcd.print("                ");
            _delay_ms(200);
          }
          lcd.clear();
          CalcFlow();
		  relay_disabled = 0;
          save=0;
        }
      if (mode == 0) StandardModeDisplay();   
      break;
      }
      prevmode=mode; 
      //Serial.print("mode at finish is ");
  //Serial.println(mode);
  if (temp_ovf){  //проверяем не превысили ли мы время ожидания
	  ovf_cur_time = millis();
	  if (ovf_cur_time-ovf_time>TIMEOVF_TIMEOUT) {
		  relay_on_period_current = 0;
		  repeat_counter = 9999.00;
		  finished = 1;
	  }
  }
      CalcStab();
	  if (menu == 0) indication();
	  signalization();
	  handleCooling();
	  handleIncident();
	  CheckState();
     // StandardModeDisplay();
      //ПРИКРУТИТЬ ВКЛЮЧЕНИЕ КОНТРОЛЯ ДЕЛЬТЫ!!!!!!!!!!!!!!!

}
