#1 2025-01-18 22:33:40

daniil
Учасник
Зареєстрований: 2024-11-17
Повідомлень: 8

Створення чи ремонт теплового насосу STEEL на базі Arduino

Матеріяли для створення або ремонту теплового насосу:

Дозволено використання у особистих цілях.
Заборонено використання у комерційних цілях.

Для виготовлення потрібен зовнішній блок ON|OFF 24 kBtu на фреоні R410 чи R32.
блок треба дообладнати кабелем підігріву та пускачем якщо його немає.
Кабель підігріву саморгулюючий він шукається у пошуку "Гнучкий ТЕН 3м"
Мідна трубка 3/8 -30 м.
Лист сталі 3 мм
Трубогиб.
Вміння варити та паяти.

Електросхема складається з двох частин
верхня закріплена на лицьовій стороні
нижня внизу блоку поряд з теном.
архів з схемами:
електросхема
електросхема не передбачає що плата буде запускати компресор вона повинна запускати пускач або силове реле у зовнішньому блоці.
до силових реле додати діоди захисні до котушок реле (шукайте у пошуку діод для реле)
чи просто використовуйте плати у проекті та вмонтуйте діоди у плату
силові реле для тенів:   
HLS-T91-16F-2-12VDC-30A

печатна плата


фото плати
фото плати

фото плати 2
фото плати 2


3 д модель друку дісплею
3 д модель друку дісплею
дісплей 2004 синього кольору якщо іншого треба міняти адресу у прошивці
кнопки 12.12 із кришкою

фото дісплею 1
фото 1
фото дісплею 2
фото

Розпіновка МК

Інструкція ТН STEEL

зборочні  без кожуху тільки теплообмінник

В середині укаласти три однакові спіралі по 10 метрів мідної труби 3/8 (9,52) з'єднані паралельно,  можна гнути трубогибом але однакова кількіть гибів повинна бути і однакова довжина відтинків труби, для рывного гыдравлычного супротиву. краще спіраль тоді фреон постійно міняє напрям руху що посилює теплообмін. меньше мідної труби не можна, 12 не можна 6 тне можна бо малий обїєм
можна використовувати пластинчастий теплообмінник але тоді на обратку ставиться бойлер 50 л і в программі треба вносити зміни щоб циркуляційний насос правцював весь час під чам розморозки бо порве теплообмінник.

Монтажні розміри монтажні розміри

інструкція по переобладнанню зовнішнього блоку

Прошивка
Прошивка

#include <Wire.h>             // библиотека 
#include <LiquidCrystal_I2C.h>// дисплей
#include <Time.h>              //часы
#include <EEPROM.h>
#include <avr/wdt.h>
#include <GyverButton.h>


//////////////////////////////////// порты реле
#define pin_Comp     9
#define pin_Valve    8
#define pin_Wentil   7
#define pin_Podogrev 6
#define pin_Pomp     5
#define pin_Ten2     4
#define pin_Ten4     3
#define pin_Gas      2

////////////////////////////////////порты датчиков
#define tempPin0     A0   // улица
#define tempPin1     A1   //дом
#define tempPin2     A2   //подача
#define tempPin3     A3   //хладагент
//#define B            3950  // B-коэффициент термистора
#define SERIAL_R     8000  // сопротивление последовательного резистора, 9,1 кОм
#define THERMISTOR_R 10000 // номинальное сопротивления термистора, 10 кОм

//////////////порты кнопок
#define pin_left     10
#define pin_enter    11
#define pin_rite     12
////////////////////////////////////порты доп устройств
//#define pin_press    A6
#define pin_termost  13
////////////////////////////////////мощность наружного блока
char nomer [] = "15X_02.24_WiFi";
const float powertn = 3.0;
const float powerten = 4.0;
int out = 10 ;                         // тепловой выбег
///////////////////////////////////дисплей
//LiquidCrystal_I2C lcd(0x3F,20,4);     //(3F - зеленый ) устанавливаем адрес lcd, кол-во символов и строк
LiquidCrystal_I2C lcd(0x27, 20, 4); //(27 - синий   ) устанавливаем адрес lcd, кол-во символов и строк
////////////////////////////////////////////////////////переменные датчиков

float v0, v1, v2, v3, tr0, tr1, tr2, tr3;
float TempA0, TempA1, TempA2, TempA3;
int   t0, t1, t2, t3;

class Rele
{ public:
    byte pin = 0     ;
    bool signalon = 0;
    bool prevsost = 0;
    bool sost1 = 0   ;
    char*sost2 = "-" ;
};

Rele Comp    ;
Rele Valve   ;
Rele Wentil  ;
Rele Podogrev;
Rele Ten2    ;
Rele Ten4    ;
Rele Pomp    ;
Rele Gas     ;

////////////////////////////////переменные приема передачи данных

#define parse_in1 9         // число значений в массиве, который хотим получить
int intData[parse_in1];     // массив численных значений после парсинга
boolean recievedFlag;
boolean getStarted;
boolean send1 = 0, send2 = 0, send3 = 0;
byte index;
String string_convert = "";
boolean all_stop = 1;

///////////////////////////символ вертикальная палка

byte man[8] = {
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100
};
//////////////////////////////////////////////менять здесь назначение портов

GButton left  (pin_left );
GButton enter (pin_enter);
GButton rite  (pin_rite );
//      int left  = pin_left;
//      int enter = pin_enter;
//      int rite  = pin_rite;


///////////////////////////////////////////////////////// тайминг

unsigned long currentTime;  //тайминг
unsigned long loopTime;     //тайминг
unsigned long currentTime1;  //тайминг
unsigned long loopTime1;     //тайминг
unsigned long currentTime2;  //тайминг
unsigned long loopTime2;     //тайминг

////////////////////////////////////////////////// переменные для настройки

float tul  ; float etul;
float tdom ; float etdom;
float tpod ; float etpod;
float thlad; float ethlad;
float tzad = 40 ;
int   razm ;
float ptpod = 0;
float ttepl = 0;
float Pten = 0;  //
float Ptn = 0;
float prevPten;
float prevPtn;
const int adrPten = 20;
const int adrPtn = 30;

// чтение значения переменных сохраненных из еепром.

int8_t  koeffb ;  // int8_t  indkoeffb ;
int8_t  vspom  ;  // int8_t  indvspom  ;
int8_t  gradtn ;   //  int8_t  indgradtn ;
int8_t  p_kotla;   // float   indp_kotla ;
int8_t  regim  ;  // int8_t  indregim  ;
int8_t  ftzad  ;  // int8_t  indtzad   ;
byte    summ   ;  // byte    oldsumm   ;
int8_t rleto   ;  // int8_t indrleto   ;

////////////////////////////////////////////////// работа с памятью еепром

byte timeras ;//  int ftimeras  ;    //Корректор времени разморозки.
byte timeoff ; // int ftimeoff  ;    //Время наработки при плюсовой температуре.
byte dtrazm  ; // int fdtrazm   ;    //Разница температур сработки разморозки.
byte mintprod; // int fmintprod ;    //Минимальная температура оттайки продувкой
byte theat   ; // int ftheat    ;    //Температура подогрева картера
byte summ2   ;

///////////////////////////////////////////////////ошибки

byte i10 = 0;         // счетчик ошибок
byte i11 = 0;         // счетчик ошибок
byte err = 0;         // ошибка счетчик перезагрузки
byte err_tul = 0;
byte err_tdom = 0;
byte err_tpod = 0;
byte err_thlad = 0;
byte err_tul_2 = 0;
byte err_tdom_2 = 0;
byte err_tpod_2 = 0;
byte err_thlad_2 = 0;
byte err_tul_3 = 0;
byte err_tdom_3 = 0;
byte err_tpod_3 = 0;
byte err_tpod1 = 0;
byte err_thlad_3 = 0;
byte err_difhlad = 0;
byte err_diful = 0;
byte err_eeprom = 0;
byte termos = 0;
// int  fer=0;
String stroka = "LOAD ";
String stroka_2 = " E";

//   String stroka_3 = "_l";
String stroka_4 = " error";
int Esum = 0;
bool readee = true;


///////////////////////////////////////////////////флаги

byte i25=0;          // каждые 60 секунд отправка данных о настройках
byte x1 = 0;         // таймер для строки состояния
byte fglob = 0;      // флаг глобальных настроек
byte vflag = 0;      // флаг для экрана
byte fs = 0;         // флаг шага настройки
byte fsm = 0;        // флаг шаг сервис мод
byte fsm1 = 0;       // флаг шаг сервис мод
byte fserv = 0;      // флаг для экрана сервис мод
byte fservice = 0;   // предыдущее состояние  servis mode
byte freset = 0;     // предыдущее состояние кнопки reset
byte fset = 0;       // флаг перелистывание дисп
byte fdop = 0;       // флаг дополнительного подогрева
byte pdop = 0;       // флаг дополнительного подогрева
word flag_disp = 0;  // флаг первого таймера
word flag_obhod = 0; // флаг таймера обходчика программы
byte flag_source = 1; // флаг выбора источника тепла 1-тепловой насос, 2 газ, 3 - тэн
byte started = true; // флаг глобального отключения
byte compzad = 0;   // флаг задержки включения
byte compprev = 0;   // флаг задержки включения
bool nagrev = false; // флаг включить отопление
byte ten_power = 0;  // флаг мощности тенов
bool ten_start = false; // флаг сервис мода тен вкл
bool ten_2_on = false; // флаг сервис мода тен 2 кВт
bool ten_4_on = false; // флаг сервис мода тен 4 кВт
///////////////////////////////////////////переменные газовый котел
bool gaz = false;
//        byte zadgasoff=18;    //задержка включения газового котла х*10 сек
//        byte zadgason=90;     //задержка включения газового котла х*10 сек
byte tikgason = 0;
byte tikgasoff = 0;

/////////////////////////////////////продувка разморозка пауза

byte i = 0;                // тэн автоматический режим
byte i1 = 0;               // счетчик 2 для вентилятора
byte produvka = 0;         // счетчик 3 вентилятора
byte dprod = 0;
byte drazm = 0;
byte i3 = 0;               // тэн автоматический режим
byte razm_steep = 0;       // счетчик 3 вентилятора
byte i6 = 0;               // только при запуске
//      byte i7=0;                 // цикл включения
int comp_work = 0;        // счетчик продувки теплообменника
//byte i9=0;               // счетчик перезаписи еепром
byte pauza = 1;
byte ipauza = 0;


void setup()
{
  wdt_disable(); // бесполезная строка до которой не доходит выполнение при bootloop
  ////////////////////////////////////////////////////////////////прием передача по uart
  Serial.begin(115200);
  //Serial.setTimeout(50);
  //////////////////////////////////////////////////////////////////создаем объекты реле

  Comp.    pin = pin_Comp    ;
  Valve.   pin = pin_Valve   ;
  Wentil.  pin = pin_Wentil  ;
  Podogrev.pin = pin_Podogrev;
  Ten2.    pin = pin_Ten2    ;
  Ten4.    pin = pin_Ten4    ;
  Pomp.    pin = pin_Pomp    ;
  Gas.     pin = pin_Gas     ;
  proverka ();

  ////////////////////////////////////////////////////////////////////// порты реле
  /////////////////////////////////////////////////////////////////////////////////

  pinMode(pin_Comp,    OUTPUT); //Comp.signalon=0;  //настройка портов реле
  pinMode(pin_Valve,   OUTPUT);// Valve.signalon=0;    //настройка портов реле
  pinMode(pin_Wentil,  OUTPUT);// Wentil.signalon=0;   //настройка портов реле
  pinMode(pin_Podogrev, OUTPUT); //Podogrev.signalon=0;    //настройка портов реле
  pinMode(pin_Ten2,    OUTPUT); //Ten2.signalon=0;   //настройка портов реле
  pinMode(pin_Ten4,    OUTPUT); //Ten4.signalon=0;    //настройка портов реле
  pinMode(pin_Pomp,    OUTPUT); //Pomp.signalon=0;   //настройка портов реле
  pinMode(pin_Gas,     OUTPUT); //Gas.signalon=0;   //настройка портов реле
  proverka ();

  ////////////////////////////////////////////////////////////////инициализация дисплея

  lcd.init();                       // инициализация дисплея
  lcd.backlight();                  // подсветка включить
  lcdset(0);                        //курсор на первую строку
  lcd.print(stroka);                // приветствие
  lcd.createChar(0, man);

  //////////////////////////////////////////////////////////////////////////////// кнопки
  left.setDebounce(50);        // настройка антидребезга (по умолчанию 80 мс)
  left.setTimeout(2000);        // настройка таймаута на удержание (по умолчанию 500 мс)
  left.setClickTimeout(600);   // настройка таймаута между кликами (по умолчанию 300 мс)
  enter.setDebounce(50);        // настройка антидребезга (по умолчанию 80 мс)
  enter.setTimeout(2000);        // настройка таймаута на удержание (по умолчанию 500 мс)
  enter.setClickTimeout(600);   // настройка таймаута между кликами (по умолчанию 300 мс)
  rite.setDebounce(50);        // настройка антидребезга (по умолчанию 80 мс)
  rite.setTimeout(2000);        // настройка таймаута на удержание (по умолчанию 500 мс)
  rite.setClickTimeout(600);   // настройка таймаута между кликами (по умолчанию 300 мс)

  //
  //      pinMode(left   , INPUT_PULLUP);     //14й – вход  кнопка, замыкающая на землю
  //      pinMode(enter  , INPUT_PULLUP);     //15й – вход  кнопка, замыкающая на землю
  //      pinMode(rite   , INPUT_PULLUP);     //16й – вход  кнопка, замыкающая на землю
  pinMode(pin_termost   , INPUT);     //16й – вход  кнопка, замыкающая на землю

  pinMode( tempPin0, INPUT );
  pinMode( tempPin1, INPUT );
  pinMode( tempPin2, INPUT );
  pinMode( tempPin3, INPUT );
  /////////////////////////////////////////////////////////////////// чтение значения переменных сохраненных в еепром.
  koeffb   = EEPROM.read(1);
  vspom    = EEPROM.read(2);
  gradtn   = EEPROM.read(3);
  p_kotla  = EEPROM.read(4);
  regim    = EEPROM.read(5);  // флаг переключения на внешний источник
  ftzad    = EEPROM.read(6);
  summ     = EEPROM.read(7);
  rleto    = EEPROM.read(8);
  all_stop = EEPROM.read(9);
  if  (summ != koeffb + vspom + gradtn + p_kotla + regim + ftzad)
  {
    err_eeprom = 1;
    readee = false;
    koeffb = 40;
    vspom = 0;
    gradtn = 20;
    p_kotla = 2;
    regim = 2;
    ftzad = 10;
    rleto = 6;
  }
  /////////////////////////////////////////////////////////////////////////глобальные настройки
  timeras = EEPROM.read(11);     //Корректор времени разморозки.
  timeoff = EEPROM.read(12);     //Время наработки при плюсовой температуре.
  dtrazm  = EEPROM.read(13);     //Разница температур сработки разморозки.
  mintprod = EEPROM.read(14);     //Минимальная температура оттайки продувкой
  theat   = EEPROM.read(15);      //Температура подогрева картера
  summ2   = EEPROM.read(16);      //Температура подогрева картера
  //////////////////////////////////////////////////////////переменные тэнов
  EEPROM.get(adrPtn,  Ptn );       //Счетчик мощности
  EEPROM.get(adrPten, Pten);       //Счетчик мощности
  prevPten = Pten;
  prevPtn = Ptn;
  if ( summ2 != timeras + timeoff + dtrazm + mintprod + theat && summ2 > 0 )
  {
    err_eeprom = 1;
    readee = false;
    timeras = 6;
    timeoff = 3;
    dtrazm = 10;
    mintprod = 2;
    theat = 2;
  }

  //      ftimeras = timeras*10 ;    //Корректор времени разморозки.
  //      ftimeoff = timeoff*10 ;    //Время наработки при плюсовой температуре.
  //      fdtrazm  = dtrazm     ;    //Разница температур сработки разморозки.
  //      fmintprod= mintprod   ;    //Минимальная температура оттайки продувкой
  //      ftheat   = theat-1    ;    //Температура подогрева картера

  /////////////////////////////////////////////версия ПО

  /////////////////////////////////////////////////////чтение текущего значения температур
  readsensor ();

  /////////////////////////////////////////////////////таймер вступительный

  //    lcdset(0);lcd.print("> to NM");
  //    lcdset(1);lcd.print("E to TM");         // приветствие
  lcdset(1); lcd.print(nomer);
  if (readee == false) {
    lcdset(2);
    lcd.print("E9");
  }
  lcd.setCursor(0, 3); lcd.print("GS"); lcd.setCursor(9, 3); lcd.print("TM"); lcd.setCursor(17, 3); lcd.print("NM"); // приветствие
  currentTime  = millis() - 1000;
  for (;;) {
    left.tick(); enter.tick(); rite.tick();
    if ( left.isClick()) {
      fglob = 1;
      vflag = 1;
      fs = 1;
      break;
    };
    if (enter.isClick()) {
      fserv = 1;
      fsm = 2;
      break;
    };
    if ( rite.isClick()) {
      fserv = 0;
      break;
    };
    if (i6 >= 60) {
      break;
    }

    if (millis() > currentTime + 1000) {
      i6++;
      lcdset(0);      //курсор на строку 4
      lcd.print("NM :");
      lcd.print((60 - i6));
      lcd.print(" sec");   // приветствие
      currentTime  = millis();
    }

  }
  wifisend1(); wifisend2(); wifisend3();
  wdt_enable (WDTO_8S);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////основной цикл//////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void loop()
{ left.tick(); enter.tick(); rite.tick();
  wdt_reset();
  if (millis() > 4000000000) {
    asm volatile("jmp 0x00");
  }

  if (fglob == 1)  {
    globalsettings ();
  }
  else {
    if (fserv == 1) {
      servicemode ();
    }
    else {   // нормальный режим

      currentTime  = millis(); // считываем время, прошедшее с момента запуска программы
      currentTime1 = millis(); // считываем время, прошедшее с момента запуска программы
      if (currentTime  < loopTime ) {
        loopTime  = currentTime;
      }
      if (currentTime1 < loopTime1) {
        loopTime1 = currentTime1;
      }
      knopki  ();
      parsing ();                   // функция парсинга
      if (currentTime1 - loopTime1  > flag_obhod)
      {
        readsensor ();           // чтение датчиков
        logika     ();           // логика работы
        proverka   ();           // проверка состояния реле



        send1 = 0; send2 = 0; 
        i25++; if(i25==6){send3=0;i25=0;}
        flag_obhod = 10000;
        flag_disp = 0  ;         // обновить экран
        loopTime1 = currentTime1;// флаг  обхода
      }
      ////////////////////////////////////////////////////////конец flag_obhod таймера///////////////////////////////////////////////////////////////////
      ////////////////////////////////////////////////////////Дисплей////////////////////////////////////////////////////////////////////////////////
      ////////////////////////////////////////////////////////проход раз в 10 сек (flag_disp)////////////////////////////////////////////////////////////
      if (currentTime1 - loopTime1  >  1600) {
        if (send1 == 0) {
          wifisend1  ();
        }
      }
      if (currentTime1 - loopTime1  >  5000) {
        if (send2 == 0) {
          wifisend2  ();
        }
      }
      if (currentTime1 - loopTime1  >  8300) {
        if (send3 == 0) {
          wifisend3  ();
        }
      }
      if (currentTime - loopTime  >  flag_disp)
      { displey ();          // вывод информации на дисплей
        loopTime = currentTime;
        flag_disp = 10000;        // флаг таймера   дисплея
      }
    }
  }
}
////////////////////////////////////////////////// конец основного цикла

void ochist () {
  lcd.clear();
}
void lcdset(byte stroka) {
  lcd.setCursor(0, stroka);
}
void displey ()
{

      tzad=ftzad*0.5+15;

   // Главный экран
     
  if (vflag==0)
     {
      ochist (); //очистка экрана
      lcdset(0);lcd.print("tvul:");lcd.print(tul, 1 );if(tul>=0){if(tul<10){lcd.print(" ");}}lcd.setCursor(9, 0);lcd.print(char(0));lcd.print("  ");lcd.print(razm );lcd.setCursor(15, 0); lcd.print(char(0));lcd.print("K4WH");
      lcdset(1);lcd.print("tbud:");if (ftzad==1){lcd.print("off ");}else{lcd.print(tdom,1);if(tdom<10){lcd.print(" ");}}lcd.setCursor(9, 1);lcd.print(char(0));if (Pten < 10000){lcd.print(" ");}if (Pten < 1000){lcd.print(" ");}if (Pten < 100){lcd.print(" ");}if (Pten < 10){lcd.print(" ");}lcd.print(Pten,0 );lcd.setCursor(15, 1);lcd.print(char(0)); lcd.print(Comp.sost2);lcd.print(Valve.sost2);lcd.print(Wentil.sost2);lcd.print(Podogrev.sost2);
      lcdset(2);lcd.print("tpod:");lcd.print(tpod,1);if(tpod<10){lcd.print(" ");}lcd.setCursor(9, 2);lcd.print(char(0));if (Ptn  < 10000){lcd.print(" ");}if (Ptn  < 1000){lcd.print(" ");}if (Ptn  < 100){lcd.print(" ");} if (Ptn < 10){lcd.print(" ");}lcd.print(Ptn ,0 );lcd.setCursor(15,2);lcd.print(char(0));lcd.print("TTGP");
      lcdset(3);lcd.print("Ttn :");lcd.print(ttepl,1);lcd.setCursor(9, 3);lcd.print(char(0)); lcd.setCursor(10, 3);  lcd.print(stroka); if (produvka>=1  ){lcd.print(30-produvka );}if (razm_steep>=1){lcd.print(timeras+45-razm_steep);}lcd.setCursor(15, 3);lcd.print(char(0)); lcd.print(Ten2.sost2);lcd.print(Ten4.sost2);lcd.print(Gas.sost2);lcd.print(Pomp.sost2);
      }
//////////////////////////////////////////////////////////////////////////// Экран настроек 1

      if (vflag==1)
      {
        ochist ();
        if (fs<=3){fset = 0;}if (fs==4){fset = -1;}if (fs>=5){fset = -2;} if (fs>=6){fset = -3;}
        if (fs  <=3) {   lcdset(fset)  ; if(fs==1){lcd.print(">");}else{lcd.print(" ");} lcd.print("tzad   : "); if(ftzad==1)    {lcd.print("pump on") ;}else{lcd.print(tzad,1      );}}
        if (fs  <=4) {   lcdset(fset+1); if(fs==2){lcd.print(">");}else{lcd.print(" ");} lcd.print("Power  : "); if(p_kotla==0){lcd.print("auto")   ;}else{lcd.print(p_kotla*powerten,1);}}
        if (fs  <=5) {   lcdset(fset+2); if(fs==3){lcd.print(">");}else{lcd.print(" ");} lcd.print("Ttn    : "); lcd.print(gradtn-20);}
                         lcdset(fset+3); if(fs==4){lcd.print(">");}else{lcd.print(" ");} lcd.print("Pdop   : "); lcd.print(vspom*powerten,1);
        if (fs  >=4)  {  lcdset(fset+4); if(fs==5){lcd.print(">");}else{lcd.print(" ");} lcd.print("Regim  : "); if(regim==1){lcd.print("TN");}   ;if(regim==2) {lcd.print("TN+EK");}if(regim==3){lcd.print("EK");}if(regim==4){lcd.print("TN+GAZ");}if(regim==5){lcd.print("GAZ"); };}
        if (fs  >=5)  {  lcdset(fset+5); if(fs==6){lcd.print(">");}else{lcd.print(" ");} lcd.print("koeffb : "); lcd.print(koeffb); }
        if (fs  >=6)  {  lcdset(fset+6); if(fs==7){lcd.print(">");}else{lcd.print(" ");} lcd.print("hol/tep: "); if(rleto==5){lcd.print("Zima_h");} if(rleto==6){lcd.print("Zima");}if(rleto>=7){lcd.print("Leto "); lcd.print(rleto);lcd.print(" C");} }
      }
//////////////////////////////////////////////////////////////////////////////// Экран настроек 2
      if (vflag==2)
      {       switch (fs){
               case 1: ochist ();lcdset(fset);  lcd.print(" tzad   : ");if(ftzad==1     ){lcd.print("pump on");}else{lcd.print(tzad,1);}; break;
               case 2: ochist ();lcdset(fset+1);lcd.print(" Power  : ");if(p_kotla==0){lcd.print("auto");}else {lcd.print(p_kotla*powerten,1);} break;
               case 3: ochist ();lcdset(fset+2);lcd.print(" Ttn    : ");                 lcd.print(gradtn-20) ; break;
               case 4: ochist ();lcdset(fset+3);lcd.print(" Pdop   : ");lcd.print(vspom*powerten,1); break;
               case 5: ochist ();lcdset(fset+4);lcd.print(" Regim  : ");if(regim==1     ){lcd.print("TN");};  if(regim==2) {lcd.print("TN+EK");}if(regim==3){lcd.print("EK"  );} if(regim==4){lcd.print("TN+GAZ");}if(regim==5){lcd.print("GAZ"); };break; 
               case 6: ochist ();lcdset(fset+5);lcd.print(" koeffb : ");                 lcd.print(koeffb) ;break;
               case 7: ochist ();lcdset(fset+6);lcd.print(" hol/tep: ");if(rleto==5){lcd.print("Zima_h");}if(rleto==6     ){lcd.print("Zima");}if(rleto>=7){lcd.print("Leto "); lcd.print(rleto);lcd.print(" C");} break;
      }}

       
       
}

///////////строка индикации
void strokasost ()
{ if (rleto<=6)     {
  switch (flag_source){
                case 1: stroka = "TN"; break;
                case 3: stroka = "EK"; break;
                case 2: stroka = "GAZ"; break;}
if (tpod>=ttepl+out)   {stroka = "OUT  ";}
}
else                  {stroka = "LITO";}
 if (razm_steep>=1)   {stroka = "RZM";lcd.print(timeras+45-razm_steep);}
 if (produvka>=1  )   {stroka = "PRD";lcd.print(30+dprod-produvka );}
if (started==false)   {stroka = "STOP";}
if (termos==1     )   {stroka = "TERMO";}
if (all_stop==0   )   {stroka = "OFF";}
if (err>0 )           {stroka = "ERROR";}
}
//////////// инидикация ошибок
  void errordisp()
{
 for ( int itest = 0; itest < 10; itest++) {
 ochist (); 
 lcdset(0);lcd.print("STATUS: ");lcd.print(stroka);
 lcdset(1); 
 if (err_tul      >0){lcd.print(stroka_2);lcd.print("vul" ); }
 if (err_tdom     >0){lcd.print(stroka_2);lcd.print("bud" );}
 if (err_tpod     >0){lcd.print(stroka_2);lcd.print("pod" );}
 if (err_thlad    >0){lcd.print(stroka_2);lcd.print("roz" );}
 if (err_eeprom   >0){lcd.print(stroka_2);lcd.print("eprom");}
 if (err_tpod1    >0){lcd.print("pod<5" );}
 if (err_tul_2 +err_tpod_2+err_thlad_2   >0)
 {lcdset(2); lcd.print("old error: ");
 lcdset(3);
 if (err_tul_2    >0){lcd.print(stroka_2);lcd.print("vul" );}
  if (err_tpod_2   >0){lcd.print(stroka_2);lcd.print("pod" );}
   if (err_thlad_2  >0){lcd.print(stroka_2);lcd.print("roz");}
 }
 
// lcdset(3); 
// for (int i2 = 1; i < 12; i2++) {errlog[i2]
// if (errlog[i2]>0){lcd.print("E");lcd.print(i2);lcd.print(" ");lcd.print(errlog[i2]);} // тело цикла
//}
 delay (1000);
 wdt_reset();
  }
}
///////////////////////Действия при ошибках

//  void errorlog()
//{
////  if (tdom  < -10  ) {err_tdom    = 1;tdom=0;}else{
////  if (tdom  > 40   ) {err_tdom    = 2;tdom=0;}err_tdom = 0;}
////  if (ftzad  == 1  ) {err_tdom    = 0;}
////  if (tul   < -35  ) {err_tul     = 1;tul=0;}else{
////  if (tul   > 50   ) {err_tul     = 2;tul=0; }err_tul = 0;}
////  if (thlad < -35  ) {err_thlad   = 1;thlad=0;}else{
////  if (thlad > 120  ) {err_thlad   = 2;thlad=0;}err_thlad = 0;}
////  if (flag_source!=1){err_tul     = 0;err_thlad = 0;}
////  if (tpod  <  5   ) {err_tpod    = 1;tpod=0; }else{
////  if (tpod  >  84  ) {err_tpod    = 2;tpod=0;}err_thlad = 0;}
//
//
////  if (Valve.signalon  ){
////  if (comp_work==20   ){
//////  if (thlad  > tul+7    ){err_difhlad=1;}else{err_difhlad=0;}
//////  if (tul    > thlad+7  ){err_diful  =1;}else{err_diful  =0;}
////  }}
// 
//  
//  Esum = err ;
//
////if (i10>10){err = 0;fer = 0; i10=11;} // если 10 обнулить индикацию ошибок
//strokasost ();
//  }
////глобальные настройки

void globalsettings ()
{
  
  currentTime  = millis(); // считываем время, прошедшее с момента запуска программы
if ( rite.isClick()) 
{    flag_disp=50; 
         if (vflag==1){fs++;if(fs>7){fs=7;}}
         if (vflag==2){   
                  if(fs==1){timeras++ ;if(timeras>30 ){timeras =30;}} 
                  if(fs==2){timeoff++ ;if(timeoff>9  ){timeoff=9;  }} 
                  if(fs==3){dtrazm++  ;if(dtrazm>15  ){dtrazm=15;  }} 
                  if(fs==4){mintprod++;if(mintprod>5 ){mintprod=5; }} 
                  if(fs==5){theat++   ;if(theat<1    ){theat=1;    }}
                  if(fs==6){timeras=6 ;timeoff=3;dtrazm=10;mintprod=2;theat=2;summ2=timeras+timeoff+dtrazm+mintprod+theat;} 
                  if(fs==7){ 
                              EEPROM.write(11, timeras    );
                              EEPROM.write(12, timeoff    );
                              EEPROM.write(13, dtrazm     );
                              EEPROM.write(14, mintprod   );
                              EEPROM.write(15, theat      );
                              summ2=timeras+ timeoff + dtrazm+ mintprod+ theat;
                              EEPROM.write(16, summ2     ); 
                              lcdset(fset+6);lcd.print("save ok reboting");
                              delay (2000);  
                              asm volatile("jmp 0x00");} 
                           }
      }


if (enter.isClick()) // если кнопка ентер нажата
       {  flag_disp=50; 
       if (vflag==1){vflag=2;}else{vflag=1;}
     }

if (left.isClick()) // если кнопка ентер нажата 

    {  flag_disp=50;
        if (vflag==1){fs--;if(fs<1){fs=1;}}
        if (vflag==2){   
                  if(fs==1){timeras-- ;if(timeras <3){timeras =3;}} 
                  if(fs==2){timeoff-- ;if(timeoff<2 ){timeoff=2 ;}} 
                  if(fs==3){dtrazm--  ;if(dtrazm<3  ){dtrazm=3  ;}} 
                  if(fs==4){mintprod--;if(mintprod<1){mintprod=1;}} 
                  if(fs==5){theat--   ;if(theat>10  ){theat=10  ;}}
                    }
    }

  
if(currentTime > (loopTime + flag_disp))
 {   
//////////////////////////////////////////////////////////////////////////// Экран настроек глобальных
//       ftimeras = timeras*10;     //Корректор времени разморозки. 3-30 (30-300)
//       ftimeoff = timeoff*10 ;    //Время наработки при плюсовой температуре.2-9 (20-90)
//       fdtrazm  = dtrazm;         //Разница температур сработки разморозки.3-15 (3-15)
//       fmintprod= mintprod ;      //Минимальная температура оттайки продувкой 1-5 ()
//       ftheat   = theat-1 ;       //Температура подогрева картера1-10  
     
      if (vflag==1)
      {
               ochist ();
        if (fs<=3){fset = 0;}if (fs==4){fset = -1;}if (fs>=5){fset = -2;}if (fs>=6){fset = -3;}
               
        if (fs  <=3)  {  lcdset(fset  ); if(fs==1){lcd.print(">");}else{lcd.print(" ");} lcd.print("timeras : ");lcd.print(timeras*10  );lcd.print(" sek");}
        if (fs  <=4)  {  lcdset(fset+1); if(fs==2){lcd.print(">");}else{lcd.print(" ");} lcd.print("timeoff : ");lcd.print(timeoff*10  );lcd.print(" min");}
        if (fs  <=5)  {  lcdset(fset+2); if(fs==3){lcd.print(">");}else{lcd.print(" ");} lcd.print("dtrazm  : ");lcd.print(dtrazm   );lcd.print(" *C");}
                         lcdset(fset+3); if(fs==4){lcd.print(">");}else{lcd.print(" ");} lcd.print("mintprod: ");lcd.print(mintprod );lcd.print(" *C");
        if (fs  >=4)  {  lcdset(fset+4); if(fs==5){lcd.print(">");}else{lcd.print(" ");} lcd.print("T heat  : ");if(theat==1) {lcd.print("AUTO");}else{lcd.print(theat-1);lcd.print(" *C");}}
        if (fs  >=5)  {  lcdset(fset+5); if(fs==6){lcd.print(">");}else{lcd.print(" ");} lcd.print("zavodskie nastroiki")               ;}
        if (fs  >=6)  {  lcdset(fset+6); if(fs==7){lcd.print(">");}else{lcd.print(" ");} lcd.print("save & exit")                       ;}
      }
//////////////////////////////////////////////////////////////////////////////// Экран настроек 2
      if (vflag==2)
      {
               if(fs==1){ochist ();lcdset(fset);  lcd.print("timeras : ");lcd.print(timeras*10  );lcd.print(" sek");} 
               if(fs==2){ochist ();lcdset(fset+1);lcd.print("timeoff : ");lcd.print(timeoff*10 );lcd.print(" min");}
               if(fs==3){ochist ();lcdset(fset+2);lcd.print("dtrazm  : ");lcd.print(dtrazm  );lcd.print(" *C");if(fs!=10){lcd.print("!!!");}} 
               if(fs==4){ochist ();lcdset(fset+3);lcd.print("mintprod: ");lcd.print(mintprod);lcd.print(" *C");}
               if(fs==5){ochist ();lcdset(fset+4);lcd.print("T heat  : ");if(theat==1) {lcd.print("AUTO");}else{lcd.print(theat-1);lcd.print(" *C");}} 
               if(fs==6){ochist ();lcdset(fset+5);lcd.print("zav. nastr. press >");}
               if(fs==7){ochist ();lcdset(fset+6);lcd.print("save & exit press >");}
    }

 
       
loopTime = currentTime;
flag_disp=10000; // флаг первого таймера   
}
}
void knopki()
{
  //////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// действия при нажатии кнопок//////////////////////////// 
//////////////////////////////////////////////////////////////////////////////////////

if ( rite.isClick())              
     {    flag_disp=50; 
         if (vflag==0){ errordisp();} 
         if (vflag==1){fs++;if(fs>7){fs=7;}}
         if (vflag==2){ 
          switch (fs) { 
                        case 1: ftzad++  ;    if(ftzad >20){ftzad  =20; }break;
                        case 2: p_kotla++;    if(p_kotla>3){p_kotla=3;  }break;
                        case 3: gradtn++ ;    if(gradtn>40){gradtn=40;  }break; 
                        case 4: vspom++  ;    if(vspom>2  ){vspom=2;    }break; 
                        case 5: regim++  ;    if(regim>5  ){regim=5;    }break;
                        case 6: koeffb++ ;    if(koeffb>50){koeffb=50;  }break;  
                        case 7: rleto++  ;    if(rleto>20 ){rleto=20;   }break;
                        } 
      }
     }


 if (enter.isClick()) // если кнопка ентер нажата
 {
      flag_disp=50;send3=0; 
       if (vflag==0){vflag=1;}else {if (vflag==1){vflag=2;if(fs==0){vflag=0;}}else{readeeprom ();vflag=1; fs=0;}}
  }

if ( left.isClick())
    {  flag_disp=50;
        if (vflag==1){fs--;if(fs<1){fs=1;}}
        if (vflag==2){switch (fs) { 
                      case 1:ftzad--  ;      if(ftzad<1   ){ftzad =1;  } break;
                      case 2:p_kotla--;      if(p_kotla<0 ){p_kotla=0; } break;
                      case 3:gradtn-- ;      if(gradtn<5  ){gradtn=5;  } break;
                      case 4:vspom--  ;      if(vspom<0   ){vspom=0;   } break;
                      case 5:regim--  ;      if(regim<1   ){regim=1;   } break;
                      case 6:koeffb-- ;      if(koeffb<30 ){koeffb=30; } break;
                      case 7:rleto--  ;      if(rleto<5   ){rleto=5;   } break;
                               }
                     } 
    }
  
  
  if (rite.isHolded()&& vflag==0) // если кнопка вправо удерживается на главном экране
      {freset=1;  flag_disp=50;tester();}
     
   if (left.isHolded()&& vflag==0) // если кнопка влево удерживается на главном экране 
    { flag_disp=50;  poread();}

         if (enter.isHolded()&& vflag==0) // если кнопка центр
    { flag_disp=50;  
    if (all_stop==0){all_stop=1;flag_disp=50;flag_obhod = 50; EEPROM.write(9, all_stop    );}
                else{all_stop=0;flag_disp=50;flag_obhod = 50; EEPROM.write(9, all_stop    );} readeeprom (); void logika ();}
      
   
      
  }
void logika ()
{
 
////////////////////////////////////////////////условия для безусловного отключения теплового насоса
    started=true;
    if (all_stop==0){started=false;}                          /// отключение веб интерфейсом.
    if (digitalRead(pin_termost ) == LOW ){started=false; termos=1;}else{termos=0;}    /// если на пине 13 минус отрубить все если +5В  то ок.
    if (err_tpod>0){started=false;}                           /// если на пине 13 минус отрубить все если +5В  то ок.
 
  if (rleto<=6) {//////////////////////////////////////////////РЕЖИМ ЗИМА

/////////////////////////////////////////////////включение, режим, условия низкого приоритета, ошибки
        
    //if (tul>=tzad&&tdom>=tzad+0.5){started=false;}else{started=true;}           // выключить если на улице больше 18 и в доме тепло.    
    if (regim==1){if (tul>(gradtn-20)+1)      flag_source=1;
                  if (tul<(gradtn-20)-1)     {started=false;}}                    // только тепловой насос 
    if (regim==2){if (tul>(gradtn-20)+1)     {flag_source=1;}
                  if (tul<(gradtn-20)-1)     {flag_source=3;}}                    // тепловой насос и электрокотел
    if (regim==3){                            flag_source=3;}                     // только электрокотел
    if (regim==4){if (tul>(gradtn-20)+1)     {flag_source=1;}  
                  if (tul<(gradtn-20)-1)     {flag_source=2;}}                    // ТН + газовый
    if (regim==5){                            flag_source=2;}                     // только газовый
   
    ttepl =  koeffb-tul;                                    // расчет температуры теплоносителя
    if (rleto==5){ttepl =  koeffb; 
    if (ttepl>(50-tul)){ ttepl=50-tul;
    if (ttepl>40){ ttepl=40;}
    if (ttepl<30){ ttepl=30;}}
    }

    if (flag_source!=1){if(err_thlad>30||err_tul>30){ttepl=koeffb;}}
    if (ttepl >50            ) {ttepl=50;}                  // максимальная температура работы 50 С
    if (ttepl <25            ) {ttepl=25;}                  // минимальная  температура с включенным тепловым насосом 30 С
    if (flag_source==1&&ttepl>40){ttepl=40;}                // максимальная температура с включенным тепловым насосом 40 С
    if (flag_source==2&&ttepl>45){ttepl=45;} 
  
    if (tpod >= (ttepl+1)){nagrev=false; }                  // условие выключения
    if (tpod <= (ttepl-1)){nagrev=true ; }                  // условие включеня


    
//////////////////////////////////////////////////////////режим тепловой насос

    if (flag_source==1){if(err_thlad>30||err_tul>30||err_tul_2>30||err_thlad_2>30){started=false;}}
    
///////////////////////////////////////////////////////////проверка на ошибки

    if (started){

//////////////////////////////////////////насос циркуляции
  
  if (tdom<(tzad-0.3)){Pomp.signalon=true;}
  if (tdom>(tzad+0.3)){Pomp.signalon=false;} 
  if (ftzad==1)       {Pomp.signalon=true;} 
  
 
  switch (flag_source){

 ///////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////// режим тепловой насос    
 /////////////////////////////////////////////////////////////////////
    case 1:
    if (tpod <  5|| err_tpod1==1){nagrev=false;err_tpod1=1;} /// строка защиты завис открытым 4-х ходовой клапан
    Gas.signalon=false;  
    if(nagrev&&compzad>18){ Comp.signalon=1;compprev=1;}else {Comp.signalon=0;}
    /// задержку включения компрессора
    if(Comp.signalon==0&&compprev==1){compzad=0;compprev=0;}
    if(compzad<18){compzad++;}else {compzad=50;}
    ////////////////////////////////////////////////////////4-х ходовой
    Valve.signalon=true;
    ////////////////////////////////////////////////////////подогрев картера компрессора
    
    if (theat ==1){                                                                           ////если включен режи авто
    if (tul  <= 3 ) {                                                                         ////если на улице холоднее 3-х
      if ( thlad+dtrazm+3<=tul  ) {Podogrev.signalon=true ;}else{Podogrev.signalon=false;}}}  ////включить когда процент разморозки +3
                                                                                              ////если режим авто не включен
    else {if (tul  <= theat     ) {Podogrev.signalon=true ; }                                 ////включить когда меньше чем температура включения подогрева
          if (tul  > theat+1    ) {Podogrev.signalon=false; }}                                ////выключить когда  температура включения подогрева больше уличной +1
          if (  tpod >= ttepl+2 ) {Podogrev.signalon=false;}                                  //// отключить при тепловом выбеге
     
    //////////////////////////////////////////////////////Продувка размомрозка
          if (Comp.signalon){ comp_work++;
          Wentil.signalon=true ;   /// вентилятор включить
                if(comp_work>500){comp_work=500;}
                
                // Включить продувку по времени нароботки
                if(comp_work>timeoff*10*6 && tul>mintprod){produvka=1;compzad=0;}

               // Включить разморозку или продувку по переохлаждению
                if(thlad+dtrazm<=tul){if(tul>mintprod){produvka=1;}else{razm_steep=1;}compzad=0;}
               
                }
             
             else///////////////////////если компрессор встал после нагрева
             {if(comp_work>30&&tul>=mintprod){produvka=1;compzad=0;} /// продувку включит если нагрел и остановился
             Wentil.signalon=false;                        /// остановить вентилятор
             comp_work=0;                                 }/// обнулить время работы компрессора

            // продувка розморозка запустяться если больше 1
          produv();razmorozka ();
///////////////////////////////////////////////////////////////догрев тенами       

        if (vspom >= 1 && regim==2      ){
        if (tdom>=tzad                  ){pdop=0;            }
        if (tdom<(tzad)-0.5||ftzad==1   ){pdop=1;            }
        if (tpod < ttepl-3              ){fdop=1;            }
        if (tpod > ttepl                ){fdop=0;ten_power=0;}
        if (tpod > 40                   ){fdop=0;ten_power=0;}
        if (vspom == 1&&fdop==1&&pdop==1){ ten_power=1;      } 
        if (vspom == 2&&fdop==1&&pdop==1){ ten_power=2;      }
                                    }else{ ten_power=0;      }
                 

  break;
  ///////////////////////////////////////////// режим газовый котел
  case 2:
  ten_power=0; compzad=0;
    Ten2.signalon    =false;   Ten4.signalon    =false;   Comp.signalon    =false;
    Wentil.signalon  =false;   Valve.signalon   =false;   Podogrev.signalon=false;

      if (nagrev==true  && tikgasoff>=18){Gas.signalon=true ;}
      if (nagrev==false || tikgason >=90){Gas.signalon=false;}
      if (Gas.signalon==true ) { tikgason++ ;if(tikgason >90){tikgason =90;}tikgasoff=0;}
                          else { tikgasoff++;if(tikgasoff>18){tikgasoff=18;}tikgason =0;}

  break; 

///////////////////////////////////////////// режим электрокотел
  case 3:
    compzad=0;
    Comp.signalon    =false;
    Gas.signalon     =false;
    Wentil.signalon  =false;
    Valve.signalon   =false;
    Podogrev.signalon=false;
    
    if (p_kotla==0    ){ i++;
    if (nagrev        ){    
    if (ten_power==0  ){ten_power=1;}
    if (i >= 4)           {if (tpod <= ptpod && tpod < (ttepl-1) ){i3++;  i=0;}else {i3=0;}
    if (i3 > 3)           {ten_power++; i3=0; i=0;}
    if (tpod  > (ttepl+1)){ten_power--; i3=0; i=0;} ptpod=tpod;}
                        }else {ten_power=0;}
                      
  ////////////////////////////////////тэн ручной режим  
    }else{ 
    if(p_kotla==1){if(nagrev){ten_power=1;}else  {ten_power=0;}}
    if(p_kotla==2){if(nagrev){ten_power=2;}else  {ten_power=0;}}
    if(p_kotla==3){if(nagrev){ten_power=3;}else  {ten_power=0;}}}
//   }else {ten_power=0;} 
  /////////////////////////////////////доп подогрев тенами
  break;
 

//////////////////////////////////////////////////////////отключить все если нет сигнала старт

}
 ////////////////////////////////////////////////////включение тенов
 switch (ten_power){
 case 0: Ten2.signalon=false; Ten4.signalon=false;  break;
 case 1: Ten2.signalon=true ; Ten4.signalon=false;  break;
 case 2: Ten2.signalon=false; Ten4.signalon=true ;  break;
 case 3: Ten2.signalon=true ; Ten4.signalon=true ;  break;  }     
       
////////////////////////////////////////////////////////счетчик мощности

if (Comp.signalon==1               ){Ptn  = Ptn + powertn *0.00278;}
if ((Ten2.signalon+Ten4.signalon)>0){Pten = Pten + (Ten2.signalon+Ten4.signalon)*powerten*2*0.00278;}
if (prevPten<Pten+2){prevPten=prevPten+2; EEPROM.put(adrPten,  Pten);}
if (prevPtn<Ptn+2  ){prevPtn =prevPtn +2; EEPROM.put(adrPtn ,  Ptn );}

///////////////////////////////////////////////////// Сигналы отключения самый высокий приоритет/
////////////////////////////////////////////////////          Тепловой выбег
if (tpod >= ttepl+out ){
  ten_power=0;Ten2.signalon=false; Ten4.signalon=false;
  Pomp.signalon     =true;
  Wentil.signalon   =false;
  Podogrev.signalon =false; 
  Valve.signalon    =false; 
  Ten2.signalon     =false; 
  Ten4.signalon     =false;  
  Comp.signalon     =false; 
  Gas.signalon      =false;}   // когда греет внешний котел все кроме насоса выключить
  
}else {Comp.signalon=false ; Wentil.signalon=false; Podogrev.signalon=false; Valve.signalon=false;
       Ten2.signalon=false ; Ten4.signalon=false  ; Gas.signalon=false     ;Pomp.signalon=false  ;
       if (tpod >= 60 ){ Pomp.signalon=true;} compzad=0;compprev=0;}
}else{
//////////////////////////////////////////////РЕЖИМ ЛЕТО
if (started){
Podogrev.signalon=false;
Valve.signalon   =false;
Ten2.signalon    =false;
Ten4.signalon    =false;
Gas.signalon     =false;
Pomp.signalon    =true;
ttepl = rleto;
if (tpod   >= ttepl+2) {Comp.signalon=true ; Wentil.signalon=true ;}
if (tpod   <= ttepl  ) {Comp.signalon=false; Wentil.signalon=false;pauza=1;}
if ( thlad >=98      ) {pauza=1;}


  if (pauza>=1){ Wentil.signalon=true; Comp.signalon  =false;
  pauza++; if (pauza > 30) {Wentil.signalon=true; pauza=0;}}
  
}else {Comp.signalon=false ; Wentil.signalon=false; Podogrev.signalon=false; Valve.signalon=false;
       Ten2.signalon=false ; Ten4.signalon=false  ; Gas.signalon=false     ; Pomp.signalon=false ;}
}
}

/*
   Данный алгоритм позволяет получить через Serial пачку значений, и раскидать
   их в целочисленный массив. Использовать можно банально для управления
   ЧЕМ УГОДНО через bluetooth, так как bluetooth модули есть UART интерфейс связи.
   Либо управлять через Serial с какой-то программы с ПК
   Как использовать:
   1) В PARSE_AMOUNT указывается, какое количество значений мы хотим принять.
   От этого значения напрямую зависит размер массива принятых данных, всё просто
   2) Пакет данных на приём должен иметь вид:
   Начало - символ $
   Разделитель - пробел
   Завершающий символ - ;
   Пример пакета: $110 25 600 920;  будет раскидан в массив intData согласно порядку слева направо
   Что делает данный скетч:
   Принимает пакет данных указанного выше вида, раскидывает его в массив intData, затем выводит обратно в порт.
   Отличие от предыдущего примера: написан мной, не используя никаких хитрых функций. Предельно просто и понятно работает
*/

void parsing() {
  if (Serial.available() > 0) {
    char incomingByte = Serial.read();        // обязательно ЧИТАЕМ входящий символ
    if (getStarted) {                         // если приняли начальный символ (парсинг разрешён)
      if (incomingByte != ' ' && incomingByte != ';') {   // если это не пробел И не конец
        string_convert += incomingByte;       // складываем в строку
      } else {                                // если это пробел или ; конец пакета
        intData[index] = string_convert.toInt();  // преобразуем строку в int и кладём в массив
        string_convert = "";                  // очищаем строку
        index++;                              // переходим к парсингу следующего элемента массива
      }
    }
    if (incomingByte == '$') {                // если это $
      getStarted = true;                      // поднимаем флаг, что можно парсить
      index = 0;                              // сбрасываем индекс
      string_convert = "";                    // очищаем строку
    }
    if (incomingByte == ';') {                // если таки приняли ; - конец парсинга
      getStarted = false;                     // сброс
      recievedFlag = true;                    // флаг на принятие
      while (Serial.available()) Serial.read();
    }

    }

  
  if (recievedFlag) {          // если получены данные
       recievedFlag = false; 
       if (intData[0]==1){
        ftzad   = intData[1];if(ftzad  <1 ){ftzad =1;  }if(ftzad >20 ){ftzad= 20; }
        p_kotla = intData[2];if(p_kotla<0 ){p_kotla=0; }if(p_kotla>3 ){p_kotla=3;  }
        gradtn  = intData[3];if(gradtn<5  ){gradtn=5;  }if(gradtn>40 ){gradtn=40;  }
        vspom   = intData[4];if(vspom<0   ){vspom=0;   }if(vspom>2   ){vspom=2;    }
        regim   = intData[5];if(regim<1   ){regim=1;   }if(regim>5   ){regim=5;    }
        koeffb  = intData[6];if(koeffb<30 ){koeffb=30; }if(koeffb>50 ){koeffb=50;  }
        rleto   = intData[7];if(rleto<6   ){rleto=6;   }if(rleto>20  ){rleto=20;   }
        all_stop= intData[8];if(all_stop<0){all_stop=0;}if(all_stop>1){all_stop=1; }
        Serial.println("save");
        }
        if (intData[0]==2){
        all_stop= intData[1];if(all_stop<0){all_stop=0;}if(all_stop>1){all_stop=1; }
        Serial.println("on/off");
        }
        if (intData[0]==3){
        regim   = intData[1];if(regim<1   ){regim=1;   }if(regim>5   ){regim=5;    }
        Serial.println("regim ok");
        }

   }
  
}
void wifisend1() {
   
      Serial.print("$");
      Serial.print("1")  ;Serial.print(" ");
      Serial.print(Comp.signalon)  ;Serial.print(" ");
      Serial.print(Valve.signalon)   ;Serial.print(" ");
      Serial.print(Wentil.signalon);Serial.print(" ");
      Serial.print(Podogrev.signalon);Serial.print(" ");
      Serial.print(Ten2.signalon)  ;Serial.print(" ");
      Serial.print(Ten4.signalon)    ;Serial.print(" ");
      Serial.print(Gas.signalon)   ;Serial.print(" ");
      Serial.print(Pomp.signalon)    ;
      Serial.println(";");
       send1=1;
}
void wifisend2() {
      Serial.print("$"); 
      Serial.print("2")       ;Serial.print(" ");
      Serial.print(tul*10,0  );Serial.print(" ");
      Serial.print(tdom*10,0 );Serial.print(" ");
      Serial.print(tpod*10,0 );Serial.print(" ");
      Serial.print(thlad*10,0);Serial.print(" ");
      Serial.print(ttepl*10,0);
      Serial.println(";");
       send2=1;
}
void wifisend3() {
      Serial.print("$")    ; 
      Serial.print("3")    ;Serial.print(" ");
      Serial.print(ftzad)  ;Serial.print(" ");
      Serial.print(p_kotla);Serial.print(" ");
      Serial.print(gradtn) ;Serial.print(" ");
      Serial.print(vspom)  ;Serial.print(" ");
      Serial.print(regim)  ;Serial.print(" ");
      Serial.print(koeffb) ;Serial.print(" ");
      Serial.print(rleto)  ;Serial.print(" ");
      Serial.print(all_stop);
      Serial.println(";");
      send3=1;

  }
void razmorozka()
{
  if (razm_steep>=1){                                               // цикл продувки теплообменника при низких температурах
          Comp.signalon=0; Ten2.signalon=0;
          Ten4.signalon=0;Podogrev.signalon=1;                      // пока цикл разморозки компрессор выключен а так-же задержка повторного запуска
          razm_steep++; 
          if (tul+1>=0  )  {drazm=3;}else{drazm=0;}
          if (razm_steep>1 )              {Wentil.signalon=0;  }    // выключить вентилятор.
          if (razm_steep>12)              {Valve.signalon=0;   }    // через минуту после стопа выкл 4 ходовой
          if (razm_steep>13)              {Comp.signalon=1;    }    // через 5 минуты включить компрессор.
          if (razm_steep>(13+timeras-drazm   )) {Comp.signalon=false;}    //if (razm_steep>19) {Comp.signalon=0;}                           // через 1 минуту выключить компрессор.
          if (razm_steep>(13+timeras+6       )) {Comp.signalon=true ;}    //if (razm_steep>25) {Comp.signalon=1;}                           // включить компрессор.
          if (razm_steep>(13+timeras+7       )) {Comp.signalon=false;}    //if (razm_steep>26) {Comp.signalon=0;}                           // выключить компрессор.
          if (razm_steep>(13+timeras+13      )) {Comp.signalon=true ;}    //if (razm_steep>32) {Comp.signalon=1;}                           // включить компрессор.
          if (razm_steep>(13+timeras+14      )) {Comp.signalon=false;}    //if (razm_steep>33) {Comp.signalon=0;}                           // выключить компрессор.
          if (razm_steep>(13+timeras+20      )) {Comp.signalon=true ;}    //if (razm_steep>32) {Comp.signalon=1;}                           // включить компрессор.
          if (razm_steep>(13+timeras+21      )) {Comp.signalon=false;}    //if (razm_steep>33) {Comp.signalon=0;}                           // выключить компрессор.
          if (razm_steep>(13+timeras+27      )) {Comp.signalon=true ;}    //if (razm_steep>32) {Comp.signalon=1;}                           // включить компрессор.
          if (razm_steep>(13+timeras+28      )) {Comp.signalon=false;}    //if (razm_steep>33) {Comp.signalon=0;}                           // выключить компрессор.
          
          }
if (razm_steep>(13+timeras+32)) {razm_steep=0;}                // всего цикрл разморозки 6 минут 

 }
void produv ()
{
  if (produvka>=1){
           Wentil.signalon=false;                                 // цикл продувки теплообменника при низких температурах
           Comp.signalon=false;                                  // пока цикл разморозки компрессор выключен а так-же задержка повторного запуска
           produvka++; 
           if (produvka>6 ) {Wentil.signalon=true;}                     // через минуту после стопа включить вентилятор
           if (tul<4){dprod=10;}else{dprod=0;}
           if (produvka>(30+dprod)) {Wentil.signalon=false; produvka=0;}               // подождать 4 минуты и выйти из цикла, разрешить запуск компрессора, выключить вентилятор
           }
}
void pauz ()
{
  if (pauza>=1){
           Wentil.signalon=true;                                       // цикл продувки теплообменника при перегреве компрессора
           Comp.signalon  =false;                                      // пока цикл разморозки компрессор выключен а так-же задержка повторного запуска
           pauza++; 
           if (pauza > 30) {Wentil.signalon=true; pauza=0;}            // подождать 4 минуты и выйти из цикла, разрешить запуск компрессора, выключить вентилятор
           }
}
void readeeprom ()
{
      EEPROM.write(1, koeffb   );
      EEPROM.write(2, vspom    );
      EEPROM.write(3, gradtn   );
      EEPROM.write(4, p_kotla  );
      EEPROM.write(5, regim    );
      EEPROM.write(6, ftzad    );
      summ=koeffb+ vspom+ gradtn+ p_kotla+ regim+ ftzad;
      EEPROM.write(7, summ     );
      EEPROM.write(8, rleto    );
      EEPROM.write(9, all_stop );
 //     Serial.println("save eeprom");
 } 

void proverka ()
{
if (Comp.signalon    ){digitalWrite(pin_Comp,0);Comp.sost2="+";          if (!Comp.prevsost){delay (300);}Comp.prevsost=true;}  
                  else{digitalWrite(pin_Comp,1);Comp.sost2="-";          if (Comp.prevsost ){delay (300);}Comp.prevsost=false;}  

if (Valve.signalon   ){digitalWrite(pin_Valve,0);Valve.sost2="+";        if (!Valve.prevsost){delay (300);}Valve.prevsost=true;}  
                  else{digitalWrite(pin_Valve,1);Valve.sost2="-";        if (Valve.prevsost) {delay (300);}Valve.prevsost=false;}   

if (Wentil.signalon  ){digitalWrite(pin_Wentil,0);Wentil.sost2="+";      if (!Wentil.prevsost){delay (300);}Wentil.prevsost=true;}  
                  else{digitalWrite(pin_Wentil,1);Wentil.sost2="-";      if (Wentil.prevsost ){delay (300);}Wentil.prevsost=false;}  

if (Podogrev.signalon){digitalWrite(pin_Podogrev,0);Podogrev.sost2="+";  if (!Podogrev.prevsost){delay (300);}Podogrev.prevsost=true;}  
                  else{digitalWrite(pin_Podogrev,1);Podogrev.sost2="-";  if (Podogrev.prevsost ){delay (300);}Podogrev.prevsost=false;}   

if (Ten2.signalon    ){digitalWrite(pin_Ten2,0);Ten2.sost2="+";          if (!Ten2.prevsost){delay (300);}Ten2.prevsost=true;} 
                  else{digitalWrite(pin_Ten2,1);Ten2.sost2="-";          if (Ten2.prevsost ){delay (300);}Ten2.prevsost=false;}   

if (Ten4.signalon    ){digitalWrite(pin_Ten4,0);Ten4.sost2="+";          if (!Ten4.prevsost){delay (300);}Ten4.prevsost=true;} 
                  else{digitalWrite(pin_Ten4,1);Ten4.sost2="-";          if (Ten4.prevsost ){delay (300);}Ten4.prevsost=false;}   

if (Gas.signalon     ){digitalWrite(pin_Gas,0);Gas.sost2="+";            if (!Gas.prevsost){delay (300);}Gas.prevsost=true;} 
                  else{digitalWrite(pin_Gas,1);Gas.sost2="-";            if (Gas.prevsost ){delay (300);}Gas.prevsost=false;}   

if (Pomp.signalon    ){digitalWrite(pin_Pomp,0);Pomp.sost2="+";          if (!Pomp.prevsost){delay (300);}Pomp.prevsost=true;}  
                  else{digitalWrite(pin_Pomp,1);Pomp.sost2="-";          if (Pomp.prevsost ){delay (300);}Pomp.prevsost=false;}  



}
/////////////////////////////// чтение датчиков показаний

void readsensor ()

{  
  t0 = analogRead( tempPin0 );
if ( t0>1010||t0<50){err_tul++;}
    v0 = t0*0.0048828125;
     tr0 = ((5/v0)*SERIAL_R)-SERIAL_R;
      etul = 0.00335570+ 0.0002531645*log(tr0/THERMISTOR_R);
       etul =  (1.0 /etul)-273;
 if (ftzad >1 ) 
 { 
   t1 = analogRead( tempPin1 );
   if ( t1>1010||t1<50){err_tdom++;}
     v1 = t1*0.0048828125;
     tr1 = ((5/v1)*SERIAL_R)-SERIAL_R;
      etdom = 0.00335570+ 0.0002531645*log(tr1/THERMISTOR_R);
       etdom =  (1.0 / etdom)-273;
       }
   t2 = analogRead( tempPin2 );
   if ( t2>1010||t2<50){err_tpod++;}
    v2= t2*0.0048828125;
     tr2 = ((5/v2)*SERIAL_R)-SERIAL_R;
      etpod = 0.00335570+ 0.0002531645*log(tr2/THERMISTOR_R);
       etpod =  (1.0 / etpod)-273;
       
   t3 = analogRead( tempPin3 );
   if ( t3>1010||t0<50){err_thlad++;}
     v3 = t3*0.0048828125;
     tr3 = ((5/v3)*SERIAL_R)-SERIAL_R;
      ethlad = 0.00335570+ 0.0002531645*log(tr3/THERMISTOR_R);
       ethlad =  (1.0 / ethlad)-273;
  
  /////////////////////////////тут записываем данные если они не выходят за пределы
  if (ftzad  == 1                 ) {err_tdom = 0;}else{ 
  if (etdom  > -20 && etdom  < 40 ) {tdom=etdom;  err_tdom   = 0;}}
  if (etul   > -30 && etul   < 50 ) {tul=etul;    err_tul    = 0;}else{err_tul++;}
  if (etpod  > -5  && etpod  < 120) {tpod=etpod;  err_tpod   = 0;}else{err_tpod++;}
  if (ethlad >-35  && ethlad < 120) {thlad=ethlad;err_thlad  = 0;}else{err_thlad++;}
 
////////////////////////////////////переменная процент обмерзания
if(err_thlad==0){
razm =  tul*10 - thlad*10 ;
if ( razm <= 0 ){razm=0; }
}
/////////////////////////////////тут ограничиваем максимальное значение переменной
if(err_tul>30    ){tul  =0;  err = 1;  err_tul_2= 1 ;   err_tul= 61 ;}  
if(err_tdom>30   ){tdom =0; ftzad= 1;                   err_tdom=61;} /// отключает датчик температуры домашний
if(err_tpod>30   ){tpod =0;  err = 1;  err_tpod_2=1 ;   err_tpod=61 ;}
if(err_thlad>30  ){thlad=0;  err = 1;  err_thlad_2=1;   err_thlad=61;}
 

/////сбрасывает ошибку когда датчик прочитан
if ((err_thlad+err_tpod+err_tul)==0){i10++;}else {i10=0;}
if (i10>30){err = 0;}

////////часть кода которая останавливает работу когда зарегестрирована ошибка
if (err>=1){i11++;}else {i11=0;}
if (i11>180){started=false;}

// errorlog   ();           // действия при ошибках
//Esum = err ;
//if (i10>10){err = 0;fer = 0; i10=11;} // если 10 обнулить индикацию ошибок
strokasost ();
  //////  переменная для индикации уровня обмерзания
//if(err_thlad_2==0){
//razm =  tul*10 - thlad*10 ;
//if ( razm <= 0 ){razm=0; }
//}
 
}
void servicemode ()
{ 
  /////////////////////////////////////////////////////////////////////////// быстрая часть программы
 
 currentTime = millis();// считываем время, прошедшее с момента запуска программы
  
  ///////////////////////////// действия при нажатии кнопок////////////////////////////
      
if ( rite.isClick())// если кнопка вправо нажата
     {  
         flag_disp=50;
              if(fsm1==0) {fsm  ++; if (fsm>10) {fsm=1;}}
              if(fsm1==1) {ttepl++;}

     }  

  if ( enter.isClick())  // если кнопка ентер нажата
          {  flag_disp=50; switch (fsm) {
             case 1 : if(Comp.signalon    ) {Comp.signalon=false;}     else{Comp.signalon=true;}     break;
             case 2 : if(Valve.signalon   ) {Valve.signalon=false;}    else{Valve.signalon=true;}    break;
             case 3 : if(Wentil.signalon  ) {Wentil.signalon=false;}   else{Wentil.signalon=true;}   break;
             case 4 : if(Podogrev.signalon) {Podogrev.signalon=false;} else{Podogrev.signalon=true;} break;
             case 5 : if(ten_2_on         ) {ten_2_on=false;}          else{ten_2_on=true;}          break;
             case 6 : if(ten_4_on         ) {ten_4_on=false;}          else{ten_4_on=true;}          break;
             case 7 : if(Gas.signalon     ) {Gas.signalon=false;}      else{Gas.signalon=true;}      break;
             case 8 : if(Pomp.signalon    ) {Pomp.signalon=false;}     else{Pomp.signalon=true;}     break;
             case 9 :tester();                                                                      break;
             case 10:if(fsm1==1)  {fsm1=0;}  else{fsm1=1;}                                          break;
           }
           }
 
 
 if ( left.isClick())// если кнопка влево нажата
    {  flag_disp=50;
       if(fsm1==0) {fsm --; if (fsm<1) {fsm=10;}}
       if(fsm1==1) {ttepl--;} 
    }
  
  
  ///////////////////////////////////////////////////////////////////медленная часть 
     currentTime2 = millis();
    if(currentTime2 - loopTime2 > 5000){
    readsensor (); 
    loopTime2 = currentTime2;
    }
   if(currentTime - loopTime > flag_disp){
     
     if (tpod<=(ttepl-1)){ten_start=true;}
     if (tpod>=(ttepl+1)){ten_start=false;}
     if (ten_start && ten_2_on ) { Ten2.signalon=true; } else {Ten2.signalon=false;}
     if (ten_start && ten_4_on ) { Ten4.signalon=true; } else {Ten4.signalon=false;}
    /// проверка включения реле.        
     proverka ();
     
  ///////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////Дисплей сервисмод
  ////////////////////////////////////////////////////////////////////////////////////
     
     
               ochist ();
               lcdset(0); lcd.print("      Test mode     ");
               lcdset(1); if (fsm!=10){lcd.setCursor((fsm-1), 1);lcd.print(char(0));}
                          lcd.setCursor(10, 1);lcd.print("tzad=");lcd.print(ttepl,1);
                          if (fsm==10){lcd.setCursor(19, 1);if (fsm1==1){lcd.print("+");}else{lcd.print("-");}}
                          
               lcdset(2); lcd.print("K4WHTTGPt"); lcd.print(" tpod=");lcd.print(tpod,1);
               lcdset(3); lcd.print(Comp.sost2);lcd.print(Valve.sost2);lcd.print(Wentil.sost2);lcd.print(Podogrev.sost2);lcd.print(Ten2.sost2);lcd.print(Ten4.sost2);lcd.print(Gas.sost2);lcd.print(Pomp.sost2);lcd.print("e");

     loopTime = currentTime;
     flag_disp=10000; // флаг первого таймера   
    
}
  
}
void tester()
{
 for ( int itest = 0; itest < 10; itest++) {
 ochist ();   
 lcdset(0);lcd.print("tvul :"); lcd.print(tul , 1); if(err_tul  >0){lcd.print(stroka_4);}
 lcdset(1);lcd.print("tbud :"); lcd.print(tdom ,1); if(err_tdom >0){lcd.print(stroka_4);}
 lcdset(2);lcd.print("tpod :"); lcd.print(tpod ,1); if(err_tpod >0){lcd.print(stroka_4);} 
 lcdset(3);lcd.print("trozm:"); lcd.print(thlad,1);  if(err_thlad>0){lcd.print(stroka_4);} 
 readsensor (); 
 delay (1000);
 wdt_reset();
  }
  
  }
  void poread()
{
  Ptn=1;Pten=1;  EEPROM.put(adrPtn,  Ptn); EEPROM.put(adrPten,  Pten);
  }
  

Дозволено використання у особистих цілях.
Заборонено використання у комерційних цілях.

Остання редакція daniil (2025-01-19 15:34:25)

Неактивний

#2 2025-01-18 22:59:51

jokeer
Гість

Re: Створення чи ремонт теплового насосу STEEL на базі Arduino

Єдине питання: теплообмінник не обмерзає?

#3 2025-01-18 23:05:50

Hanter83
Гість

Re: Створення чи ремонт теплового насосу STEEL на базі Arduino

У всіх теплових насосів теплообмінник обмерзає бо він холодний. Він сам розморожуватись повинен коли обмерзне. Так само і в кондиціонерах вода конденсується у всіх бо теплообмінних холодний. smile

#4 2025-01-18 23:59:05

jokeer
Гість

Re: Створення чи ремонт теплового насосу STEEL на базі Arduino

Я так зрозумів, що пропонується перепиляти кондиціонер на тепловий насос. Він не дуже годиться для саморозморожування.

#5 2025-01-19 00:21:37

Daniil83
Гість

Re: Створення чи ремонт теплового насосу STEEL на базі Arduino

8 років вже розморожується.  smile.
Звичайна теплоова машина.
Не зовсім підходе у криворуких майстрів.

#6 2025-01-19 00:29:38

Daniil83
Гість

Re: Створення чи ремонт теплового насосу STEEL на базі Arduino

Слушне зауваження завтра доповню опис. Розморожується нормально.

#7 2025-01-19 01:39:17

jokeer
Гість

Re: Створення чи ремонт теплового насосу STEEL на базі Arduino

Я теплотехнік не настоящий. Але в школі нас учили що лід - теплоізолятор. Яка магія його розморожує? Конденсат в вигляді води - він просто витікає. А лід в холодильнику наприклад розморожується пів дня.

#8 2025-01-19 10:21:46

Daniil83
Гість

Re: Створення чи ремонт теплового насосу STEEL на базі Arduino

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

#9 2025-01-19 10:23:53

Daniil83
Гість

Re: Створення чи ремонт теплового насосу STEEL на базі Arduino

Ось наприклад наглядно показано.
https://youtu.be/O2mDQ80PYXM?si=y_85VTF5cpSGU-0i

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму