// Мои переменные и дефайны
  #include <Arduino.h>
  #include <EEPROM.h>
  #include <Wire.h>
  #include <LiquidCrystal_I2C.h>

  //#include "LCD_1602_RUS.h"
  //LCD_1602_RUS lcd(0x27, 20, 4); //адрес 0x27 или 0x3f
  LiquidCrystal_I2C lcd(0x27, 20, 4); // адрес 0x27 или 0x3f
  //#include "GyverPID.h"
  #include <GyverNTC.h>
  #include <GyverTimers.h> // библиотека таймера
  #include "GyverEncoder.h"
  #include "EmonLib.h"  // для сети 220 считываем значения
  EnergyMonitor emon1;
  //GyverPID regulator(5, 1, 0.01, 1000);  // коэф. П, коэф. И, коэф. Д, период дискретизации dt (мс)

  #define r_kub                           9900   //10000 //9900  // номинальное сопротивление резистора
  #define r_kolonna                       9900   //10000 //9900  // номинальное сопротивление резистора
  #define r_tsa                           9850   //10000 //9900  // номинальное сопротивление резистора
  #define ZERO_PIN                        3      // пин детектора нуля  < указать 3 для платы темной с PCB или 4 для плат с Зеленограда>
  #define INT_NUM                         1      // соответствующий ему номер прерывания 0 либо 1 < указать 1 для платы темной с PCB>
  #define pause_menu                      5     // тайм-аут нахождения в меню, сек
  #define startEEPROM                     900    // ячёйка для внесения начальных значений в память
  #define KEY_First_start                 20     // ключ первого запуска. на выбор 0-220
  #define Pin_Upravlenija_Simistorom_PWM  4      // плавное управление. без контроля синусойды через 0    Pin_Power_PWM_Vihod_220 = Pin_Upravlenija_Simistorom_PWM
  #define k                               0.01   // коэффициент для температуры
  #define MY_PERIOD                       1000   // период в мс
  // ниже блок Для считывания напряжения сети 
  #define PinReadVoltage                  A2      // для считывания напряжения сети
  int Uk = 151;
  int i = 0,S_online;
  float tenvals = 0.0;
  float minval = 1000;
  float maxval = 0.0;
  float Useti=0, Pset=0;
  // закончен бок переменных напряжения сети
  GyverNTC NTC_A0(0, 10000, 3435, 25, r_kub);      // Датчик Куб
  GyverNTC NTC_A1(1, 10000, 3435, 25, r_kolonna);  // Датчик Колонны
  GyverNTC NTC_A2(2, 10000, 3435, 25, r_tsa);      // Датчик ТСА
                         
  float NTC_Temp_Kolonna                = 0;  // переменная опроса датчика температуры Колонны
  float NTC_Temp_Kub                    = 0;  // переменная опроса датчика температуры Куба
  float NTC_Temp_TSA                    = 0;  // переменная опроса датчика температуры ТСА
  // переменные для хранения режима работы пинов
  byte Pin_Upravlenija_Relay            = 5;                // Pin_Power_Relay_220 = Pin_Upravlenija_Relay
  byte Pin_BEEP                         = 11;
    
  // переменные для хранения времени работы реле в сек.
  uint32_t sec                          = 0;    // полное количество секунд
  int timeHours                         = 0;    // часы
  int timeMins                          = 0;    // минуты
  int timeSecs                          = 0;    // секунды
  int PWN_Signal_na_Simistor            = 0;    // Power_na_220 = PWN_Signal_na_Simistor
  float Vidavaemaja_Power               = 0;
  float       PWN     = 0;
  bool flag                             = false;
  bool Stop_Start_flag                  = false;

  // Мои переменные и дефайны закончились

  #define LINES 4       // количество строк дисплея
  #define SETTINGS_AMOUNT 11  // количество настроек
  #define FAST_STEP 30   // скорость изменения при быстром повороте

  // пины энкодера
  #define CLK 2//2  вниз 2- для моделирования
  #define DT 3//3  вверх  3 - для моделирования
  #define SW 6//4   кнопка 6 - для моделирования
  Encoder enc(CLK, DT, SW);  // для работы c кнопкой



  float vals[SETTINGS_AMOUNT];  // массив параметров
  int8_t arrowPos = 0;
  bool controlState = 0;  // клик
  
  const char name1[] PROGMEM = "TEH HArPy3. ";// vals[0]MO-CTb.
  const char name2[] PROGMEM = "ABTOPA3rOH  ";// vals[1]
  const char name3[] PROGMEM = "T.ABTOPA3-HA";// vals[2]Ky6a
  const char name4[] PROGMEM = "T.CPA6AT.K. ";// vals[3]K-HA
  const char name5[] PROGMEM = "OCTAHOB BP. ";// vals[4]PA6
  const char name6[] PROGMEM = "OCTAHOB TCA ";// vals[5]TCA
  const char name7[] PROGMEM = "OCTAHOB t K.";// vals[6]Ky6a
  const char name8[] PROGMEM = "3AKP.K.HO/H3";// vals[7]
  const char name9[] PROGMEM = "rUCTEPE3UC  ";// vals[8]
  const char name10[]PROGMEM = "M.PA3rOHA K.";// vals[9]Ky6A
  const char name11[]PROGMEM = "R.TEHA B Om ";// vals[10]OMAX
  //const char name12[]PROGMEM = "KOPPEK.U CETu";// vals[10]

  // объявляем таблицу ссылок
  const char* const names[] PROGMEM = {
  name1, name2, name3, name4, name5, name6, name7, name8, name9, name10, name11, //name12, // vals[n+1]
  };

  int Power_Vihoda_na_Ten	      =10;//= EEPROM.get(2, vals[0]); //vals[0];	Power_Vihoda_na_Ten = Power_Vihoda_na_220
  int avtorejim                 =0;//= EEPROM.get(6, vals[1]); //vals[1];
  int Temp_V_Kube_razgon        =70;//= EEPROM.get(10, vals[2]); //vals[2];
  float Temp_Work_Rele          =60;//= EEPROM.get(14, vals[3]); //vals[3]; Temp_Open_Rele_220 = Temp_Work_Rele
  int Vremja_Raboti_Bolshe_Chem =10;//= EEPROM.get(18, vals[4]); //vals[4];
  int Temp_V_TSA_Bolshe_Chem    =30;//= EEPROM.get(22, vals[5]); //vals[5];
  int Temp_V_Kube_Bolshe_Chem   =35;//= EEPROM.get(26, vals[6]); //vals[6];
  int Tip_Rele_NO_NZ            =1;//= EEPROM.get(30, vals[7]); //vals[7]; Rejim_Raboti_Rele_220 = Tip_Rele_NO_NZ
  float gisterezis              =1;//= EEPROM.get(34, vals[8]); //vals[8];
  int Avtorazgon_Power_Tena     =30;//= EEPROM.get(38, vals[9]); //vals[9]; 
  int R_tena                    =16;//= EEPROM.get(42, vals[10]); //vals[10];
  //int Uk                        = EEPROM.get(32, vals[11]); //vals[11];

  
void setup() {
  lcd.init();
  lcd.backlight();
  emon1.voltage(PinReadVoltage, Uk, 1.7);  //считывание напряжения где 150 (uk) поправочный коэффичиент
  //regulator.setDirection(NORMAL); // направление регулирования (NORMAL/REVERSE). ПО УМОЛЧАНИЮ СТОИТ NORMAL  
  NTC_Temp_Kub = (NTC_A0.getTemp());
  NTC_Temp_Kolonna = (NTC_A1.getTempAverage());
  NTC_Temp_TSA = (NTC_A2.getTemp());  
  pinMode(ZERO_PIN, INPUT_PULLUP);
  pinMode(Pin_Upravlenija_Simistorom_PWM, OUTPUT);  
  attachInterrupt(INT_NUM, isr, RISING);  // для самодельной схемы ставь FALLING    CHANGE  изначально - RISING
  Timer2.enableISR();
  Serial.begin(9600);
  enc.setType(TYPE2);
  enc.setFastTimeout(250); 
  printGUI();
}

void loop() {
  enc.tick();
  //    EEPROM.put(2, 100); EEPROM.put(6, 1); EEPROM.put(10, 50);EEPROM.put(14, 68.0);EEPROM.put(18, 14);EEPROM.put(22, 45);EEPROM.put(26, 96);EEPROM.put(30, 1);EEPROM.put(34, 0.1);EEPROM.put(38, 90);EEPROM.put(42, 16);
  time();  // работает всегда. время с момента включения.
  timing_menu();  
  vibor_logiki();  
 //analogWrite(pin, computePID(sensorRead, 30, 1.0, 2.0, 3.0, 0.02, 0, 255));
}

void glavMEHU (){
  enc.tick();
   // смена контроля
  if (enc.isClick()) {
    flag = true;
    controlState = !controlState;
    printGUI();
  }

  if (enc.isTurn()) {
    Stop_Start_flag = false;
    flag = true;
    float increment = 0;  // локальная переменная направления

    // получаем направление
    if (!controlState) {
      if (enc.isRight()) increment = 1;
      if (enc.isLeft()) increment = -1;
      arrowPos += increment;  // двигаем курсор
      arrowPos = constrain(arrowPos, 0, SETTINGS_AMOUNT - 1); // ограничиваем
    }

    increment = 0;  // обнуляем инкремент
    

    if ((arrowPos==0 && controlState && enc.isRight()) || enc.isRightH()) increment = 50;
    if ((arrowPos==0 && controlState && enc.isLeft())  || enc.isLeftH()) increment = -50;

    if ((arrowPos==1 && controlState && enc.isRight()) || enc.isRightH()) vals[1] =1; 
    if ((arrowPos==1 && controlState && enc.isLeft())  || enc.isLeftH())  vals[1] =0; 

    if ((arrowPos==2 && controlState && enc.isRight()) || enc.isRightH()) increment = 1;
    if ((arrowPos==2 && controlState && enc.isLeft())  || enc.isLeftH())  increment = -1;

    if ((arrowPos==3 && controlState && enc.isRight()) || enc.isRightH()) increment = 0.1; 
    if ((arrowPos==3 && controlState && enc.isLeft())  || enc.isLeftH()) increment = -0.1; 

    if ((arrowPos==4 && controlState && enc.isRight()) || enc.isRightH()) increment = 1;
    if ((arrowPos==4 && controlState && enc.isLeft())  || enc.isLeftH()) increment = -1;

    if ((arrowPos==5 && controlState && enc.isRight()) || enc.isRightH()) increment = 1;
    if ((arrowPos==5 && controlState && enc.isLeft())  || enc.isLeftH()) increment = -1;

    if ((arrowPos==6 && controlState && enc.isRight()) || enc.isRightH()) increment = 1;
    if ((arrowPos==6 && controlState && enc.isLeft())  || enc.isLeftH()) increment = -1;

    if ((arrowPos==7 && controlState && enc.isRight()) || enc.isRightH()) vals[7] =1; 
    if ((arrowPos==7 && controlState && enc.isLeft())  || enc.isLeftH())  vals[7] =0; 

    if ((arrowPos==8 && controlState && enc.isRight()) || enc.isRightH()) increment = 0.1;
    if ((arrowPos==8 && controlState && enc.isLeft())  || enc.isLeftH()) increment = -0.1;

    if ((arrowPos==9 && controlState && enc.isRight()) || enc.isRightH()) increment = 1;
    if ((arrowPos==9 && controlState && enc.isLeft())  || enc.isLeftH()) increment = -1;

    if ((arrowPos==10 && controlState && enc.isRight()) || enc.isRightH()) increment = 1;
    if ((arrowPos==10 && controlState && enc.isLeft())  || enc.isLeftH()) increment = -1;

    // if ((controlState && enc.isRight()) || enc.isRightH()) increment = 1;
    // if ((controlState && enc.isLeft()) || enc.isLeftH()) increment = -1;
    
    if (controlState && enc.isFastR()) increment = FAST_STEP;
    if (controlState && enc.isFastL()) increment = -FAST_STEP;
    vals[arrowPos] += increment;  // меняем параметры

    //
      //float i = 220/R_tena; float Pras_ten=(220*i)+100;
      vals[0] = constrain (vals[0], 0, 3100); //u=i*r p=u*i i=u/r     Pras_ten
      vals[1] = constrain (vals[1], 0, 1); 
      vals[2] = constrain (vals[2], 0, 100); 
      vals[3] = constrain (vals[3], 0, 100);        
      vals[4] = constrain (vals[4], 1, 18); 
      vals[5] = constrain (vals[5], 25, 100);
      vals[6] = constrain (vals[6], 25, 100);
      vals[7] = constrain (vals[7], 0, 1);
      vals[8] = constrain (vals[8], 0, 5);
      vals[9] = constrain (vals[9], 5, 100);
      vals[10] = constrain (vals[10], 1, 1200);
      //vals[11] = constrain (vals[11], 100, 200);

      Power_Vihoda_na_Ten       = vals[0];  EEPROM.put (2,  vals[0]); 
      avtorejim                 = vals[1];  EEPROM.put (6,  vals[1]); 
      Temp_V_Kube_razgon        = vals[2];  EEPROM.put (10, vals[2]);
      Temp_Work_Rele            = vals[3];	EEPROM.put (14, vals[3]); 
      Vremja_Raboti_Bolshe_Chem = vals[4];	EEPROM.put (18, vals[4]);
      Temp_V_TSA_Bolshe_Chem    = vals[5];  EEPROM.put (22, vals[5]);
      Temp_V_Kube_Bolshe_Chem   = vals[6];  EEPROM.put (26, vals[6]); 
      Tip_Rele_NO_NZ            = vals[7];  EEPROM.put (30, vals[7]); 
      gisterezis                = vals[8];  EEPROM.put (34, vals[8]); 
      Avtorazgon_Power_Tena     = vals[9];  EEPROM.put (38, vals[9]); 
      R_tena                    = vals[10]; EEPROM.put (50, vals[10]);       
        //int Uk                  = vals[11]; EEPROM.put (32, vals[11]);
      
    //
    printGUI();
  }
}

void Infomenu(){
  enc.tick(); if (enc.isTurn() && enc.isClick()  ) { flag = true; glavMEHU(); }
  lcd.setCursor(0, 0);  lcd.print((String("TEM.KO-HA:") + String(NTC_Temp_Kolonna, 1)));  lcd.write(223);  lcd.print("C");
  lcd.setCursor(0, 1);  lcd.print((String("TEM.B TCA:") + String(NTC_Temp_TSA, 1)));  lcd.write(223);  lcd.print("C");
  lcd.setCursor(0, 2);  lcd.print((String("TEM.B Ky6:") + String(NTC_Temp_Kub, 1)));  lcd.write(223); lcd.print("C");
  lcd.setCursor(0, 3);  lcd.print((String("U=") + String(Useti, 0)));  lcd.print("B");
   if (avtorejim == 1) {
    lcd.setCursor(7, 3);  lcd.print((String("P=") + String((Avtorazgon_Power_Tena/100) * vals[0])));  lcd.print("Bm ");
  }
  if (avtorejim == 0) {
   lcd.setCursor(7, 3);  lcd.print((String("P=") + String(S_online,0)));  lcd.print("Bm ");   // 203c242
  }
  
  lcd.setCursor(16, 3);  lcd.print(String(PWN,0) );  lcd.print("%");
   if (avtorejim == 1) {
    lcd.setCursor(17, 0);
    lcd.print("[A]");
  }
  if (avtorejim == 0) {
    lcd.setCursor(17, 0);
    lcd.print("   ");
  }

}

void timing_menu() {
  glavMEHU(); 
  static byte g;
  static int count;
  static uint32_t pause;
  uint32_t vremja = millis() / 1000ul;
  if (pause - vremja >= 1 && g != 1) {                                                                            // изменения
    pause = vremja;
    count++;
  }
  if (flag == true && count < pause_menu ) {
    glavMEHU(); 
    count = 0;      
    flag = false; 
    g=0;
  }
  if (count >= pause_menu) {
    flag = false;
    count = 0;
    lcd.clear();    
    g=1;
  }
   if (g >=1 && flag == false  && NTC_Temp_Kub <= Temp_V_Kube_Bolshe_Chem  && NTC_Temp_TSA <= Temp_V_TSA_Bolshe_Chem && timeHours <= Vremja_Raboti_Bolshe_Chem )//&& Stop_Start_flag == false
  {
    Infomenu();
    voltage ();
  }
}

void read_temp() {
    NTC_Temp_Kolonna += (NTC_A1.getTemp() - NTC_Temp_Kolonna) * k;
    //NTC_Temp_Kolonna += (NTC_A1.getTempAverage() - NTC_Temp_Kolonna) * k;
    NTC_Temp_TSA += (NTC_A2.getTemp() - NTC_Temp_TSA) * k;
    NTC_Temp_Kub += (NTC_A0.getTemp() - NTC_Temp_Kub) * k;  
   /*
    Температура будет немного “шуметь”, несмотря на чтение с усреднением. 
    Для более точных измерений можно использовать простейший фильтр – экспоненциальное скользящее среднее, 
    которое реализуется так: filt_val += (new_val - filt_val) * k, где k – число от 0.0 до 1.0. 
    Фильтр даёт плавное изменение, что позволяет получать максимально точное значение с течением времени.
    Результат работы данной программы лучше наблюдать во встроенном плоттере графиков:
    */
}

void Logik_Work() {
  read_temp();
  PWN_Signal_na_Simistor = PWN;   

  //______________________ Клапан 220 НО и NTC > t срабатывания клапана
  if (NTC_Temp_Kolonna >= Temp_Work_Rele && Tip_Rele_NO_NZ == 0) {
    pinMode(Pin_Upravlenija_Relay, OUTPUT);
    digitalWrite(Pin_Upravlenija_Relay, HIGH);
  }
  //______________________ Клапан 220 НО и NTC < t срабатывания клапана
  if (NTC_Temp_Kolonna <= (Temp_Work_Rele - gisterezis)  && Tip_Rele_NO_NZ == 0 ) {
     digitalWrite(Pin_Upravlenija_Relay, LOW);
    pinMode(Pin_Upravlenija_Relay, INPUT);   
  }

  //______________________ Клапан 220 НЗ и NTC > t срабатывания клапана
  if (Tip_Rele_NO_NZ == 1  && NTC_Temp_Kolonna >= Temp_Work_Rele) {
    digitalWrite(Pin_Upravlenija_Relay, LOW);
    pinMode(Pin_Upravlenija_Relay, INPUT);
    
  }
  //______________________ Клапан 220 НЗ и NTC < t срабатывания клапана
  if (Tip_Rele_NO_NZ == 1 && NTC_Temp_Kolonna <= (Temp_Work_Rele - gisterezis)) {
    pinMode(Pin_Upravlenija_Relay, OUTPUT);
    digitalWrite(Pin_Upravlenija_Relay, HIGH);
  }

    if (NTC_Temp_TSA >= Temp_V_TSA_Bolshe_Chem) {
      pinMode(Pin_Upravlenija_Simistorom_PWM, INPUT);        
      pinMode(Pin_BEEP, OUTPUT);
      STOP_TCA();
      Stop_Start_flag = true;
    }
    if (timeHours >= Vremja_Raboti_Bolshe_Chem) {
      pinMode(Pin_Upravlenija_Simistorom_PWM, INPUT);       
      pinMode(Pin_BEEP, OUTPUT); 
      STOP_Time();
      Stop_Start_flag = true;
    }

    if (NTC_Temp_Kub >= Temp_V_Kube_Bolshe_Chem) {
      pinMode(Pin_Upravlenija_Simistorom_PWM, INPUT);  
      pinMode(Pin_BEEP, OUTPUT);
      STOP_Kyb();
      Stop_Start_flag = true;      
    }
//Stop_Start_flag== true
     while (Stop_Start_flag && NTC_Temp_TSA < Temp_V_TSA_Bolshe_Chem){
      STOP_TCA();
      enc.tick();
      Serial.println(Stop_Start_flag); 
        if ( enc.isTurn()) {          
        //enc.tick();            // ========================================================
          pinMode(Pin_BEEP, INPUT);
          lcd.clear();
          Infomenu();
          Stop_Start_flag = false;
          pinMode(Pin_Upravlenija_Simistorom_PWM, OUTPUT);
          Serial.println(Stop_Start_flag); 
          //break;
        }
      }

 

}

void avtorazgon_logik() {
  bool flag_1;
  
  read_temp();
  if (avtorejim == 1 && NTC_Temp_Kub <= Temp_V_Kube_razgon) {      

      PWN_Signal_na_Simistor = map(Avtorazgon_Power_Tena, 100, 0, 500, 9300);

    if (NTC_Temp_Kolonna >= Temp_Work_Rele &&  Tip_Rele_NO_NZ == 0 ) {
      pinMode(Pin_Upravlenija_Relay, OUTPUT);
      digitalWrite(Pin_Upravlenija_Relay, HIGH);  // температура выше установленной! закрываем
    }
    //______________________ Клапан 220 НО и NTC < t срабатывания клапана
    if (NTC_Temp_Kolonna <= (Temp_Work_Rele - gisterezis) &&  Tip_Rele_NO_NZ == 0 ) {
      digitalWrite(Pin_Upravlenija_Relay, LOW);  // температура ниже установленной! открываем
      pinMode(Pin_Upravlenija_Relay, INPUT);      
    }
    //______________________ Клапан 220 НЗ и NTC > t срабатывания клапана
    if (Tip_Rele_NO_NZ == 1 && NTC_Temp_Kolonna >= Temp_Work_Rele) {
      digitalWrite(Pin_Upravlenija_Relay, LOW);
      pinMode(Pin_Upravlenija_Relay, INPUT);      
    }
    //______________________ Клапан 220 НЗ и NTC < t срабатывания клапана
    if (Tip_Rele_NO_NZ == 1 && NTC_Temp_Kolonna <= (Temp_Work_Rele - gisterezis)) {
      pinMode(Pin_Upravlenija_Relay, OUTPUT);
      digitalWrite(Pin_Upravlenija_Relay, HIGH);
    }
    if (NTC_Temp_Kub >= Temp_V_Kube_Bolshe_Chem) {
      pinMode(Pin_Upravlenija_Simistorom_PWM, INPUT); 
      pinMode(Pin_BEEP, OUTPUT);
      STOP_Kyb();
      Stop_Start_flag = true;
    }
    if (NTC_Temp_TSA >= Temp_V_TSA_Bolshe_Chem) {
      pinMode(Pin_Upravlenija_Simistorom_PWM, INPUT); 
      pinMode(Pin_BEEP, OUTPUT);
      STOP_TCA();
      Stop_Start_flag = true;
    }
    if (timeHours >= Vremja_Raboti_Bolshe_Chem) {
      pinMode(Pin_Upravlenija_Simistorom_PWM, INPUT); 
      pinMode(Pin_BEEP, OUTPUT);
      STOP_Time();
      Stop_Start_flag = true;
    }

    if  (NTC_Temp_TSA <= Temp_V_TSA_Bolshe_Chem  &&  Stop_Start_flag == true) {
      STOP_TCA () ;
      flag_1 = true;
      pinMode(Pin_BEEP, INPUT);
    }
    if (flag_1 == true && Stop_Start_flag == true) {
      lcd.clear();
      Infomenu();
      //Stop_Start_flag = false;
      pinMode(Pin_Upravlenija_Simistorom_PWM, OUTPUT);
      flag_1 = false;
    }



  }
  if (avtorejim == 1 && NTC_Temp_Kub >= Temp_V_Kube_razgon) {
    PWN_Signal_na_Simistor = PWN;   
    avtorejim = 0;
  }

}

void voltage () { 
  static unsigned long tStart;
  int tEnd = 2000;
  if(millis() - tStart > tEnd)  {
    emon1.calcVI(20,500);        

    float Vrms = (emon1.Vrms);
    
    tenvals += Vrms;
   
      // Serial.print("Avg: ");    Serial.print(tenvals/10);    Serial.print(" (");     Serial.print(Vrms);    Serial.print(") Min: ");    Serial.print(minval);    Serial.print(" Max: ");    Serial.println(maxval);
      Useti=tenvals;
      tenvals = 0;
      Pset = (Useti*Useti)/R_tena;
      PWN = (1-(Pset - Power_Vihoda_na_Ten)/Pset)*100;
      S_online = (PWN*Pset)/100;
      if (PWN >100){ PWN =100; }
    
    tStart += tEnd;
  }


}

void vibor_logiki() {
  if (avtorejim == 1) {
    avtorazgon_logik();
  }
  if (avtorejim == 0) {
    Logik_Work();
  }
}

void STOP_TCA(){
  signal();
  static uint32_t tmr;
  if (millis() - tmr >= 1000) {
    tmr = millis();
    lcd.clear();
  }
    lcd.setCursor(2, 1);
    lcd.print("CTOП пo t TCA"); 
}

void STOP_Kyb(){   
  signal();       
  static uint32_t tmr;
    if (millis() - tmr >= 1000) {
      tmr = millis();
      lcd.clear();
      }
    lcd.setCursor(2, 1);
    lcd.print("CTOП пo t Ky6A"); 
}

void STOP_Time(){
  signal();
    static uint32_t tmr;
    if (millis() - tmr >= 1000) {
    tmr = millis();
    lcd.clear();
    }
    lcd.setCursor(2, 1);
    lcd.print("CTOП пo BPEMEHИ");   
}

void printGUI() {
  static int8_t screenPos = 0; // номер "экрана"
  static int8_t lastScreen = 0; // предыдущий номер "экрана"

  screenPos = arrowPos / LINES;   // ищем номер экрана (0..3 - 0, 4..7 - 1)
  if (lastScreen != screenPos) lcd.clear(); // если экран сменился - очищаем
  lastScreen = screenPos;

  for (byte i = 0; i < LINES; i++) {  // для всех строк
    lcd.setCursor(0, i);              // курсор в начало

    // если курсор находится на выбранной строке
    smartArrow(arrowPos == LINES * screenPos + i);  // рисуем стрелку или пробел

    // если пункты меню закончились, покидаем цикл for
    if (LINES * screenPos + i == SETTINGS_AMOUNT) break;

    // выводим имя и значение пункта меню
    printFromPGM(&names[LINES * screenPos + i]);
    lcd.print(F(":"));
    lcd.print(vals[LINES * screenPos + i],1);
    lcd.print(F("  ")); // пробелы для очистки
    if (arrowPos >=0  && arrowPos <=3  && vals[1] ==1) {lcd.setCursor(14, 1); lcd.print("BK.");} if (arrowPos >=0  && arrowPos <=3  && vals[1] ==0) {lcd.setCursor(14, 1); lcd.print("OTK");} 
    if (arrowPos >=4  && arrowPos <=7  && vals[7] ==1) {lcd.setCursor(14, 3); lcd.print("Н/3");}if (arrowPos >=4  &&  arrowPos <=7  && vals[7] ==0) {lcd.setCursor(14, 3); lcd.print("Н/O");}
  }
}

// очень хитрая функция для печати из PROGMEM
void printFromPGM(int charMap) {
  uint16_t ptr = pgm_read_word(charMap);    // получаем адрес из таблицы ссылок
  while (pgm_read_byte(ptr) != NULL) {      // всю строку до нулевого символа
    lcd.print(char(pgm_read_byte(ptr)));    // выводим в монитор или куда нам надо
    ptr++;                                  // следующий символ
  }
}

void smartArrow(bool state) {  // рисует стрелку, галку или пробел
  lcd.write(state ? (controlState ? 62 : 126) : 32);//62 : 126)      
}

void time() {
  sec = millis() / 1000ul;           // полное количество секунд
  timeHours = (sec / 3600ul);        // часы
  timeMins = (sec % 3600ul) / 60ul;  // минуты
  timeSecs = (sec % 3600ul) % 60ul;  // секунды
}

int computePID(float input, float setpoint, float kp, float ki, float kd, float dt, int minOut, int maxOut) {
  float err = setpoint - input;
  static float integral = 0, prevErr = 0;
  integral = constrain(integral + (float)err * dt * ki, minOut, maxOut);
  float D = (err - prevErr) / dt;
  prevErr = err;
  return constrain(err * kp + integral + D * kd, minOut, maxOut);
}

void signal() {
  uint32_t Global_timer = millis() / 1000ul;  // полное количество секунд
  if (Global_timer % 2 == 0) {
    digitalWrite(Pin_BEEP, 1);
  } else {
    digitalWrite(Pin_BEEP, 0);    
  }
}

ISR (TIMER2_A) {
  digitalWrite(Pin_Upravlenija_Simistorom_PWM, 1);  // включаем симистор
  Timer2.stop();                             // останавливаем таймер
}

void isr() {
  static int lastDim;
  digitalWrite(Pin_Upravlenija_Simistorom_PWM, 0);  // выключаем симистор
  if (lastDim != PWN_Signal_na_Simistor) Timer2.setPeriod(lastDim = PWN_Signal_na_Simistor);
  else Timer2.restart();
}