РУКОДЕЛКИ не корректная совместная работа BME280, arduino, ватметра и "прямых" рук

vivatgm

✩✩✩✩✩✩✩
26 Янв 2021
23
0
Доброго времени суток дамы и господа! Вы моя наверное последняя инстанция, не знаю куда дальше рыть, так как не понимаю в какую сторону. И так, имеется: солнечная на панель, аккумулятор наверное от трактора (12в, 190А/ч), UPS от компа, переделанный как инвертор на 600 вт, ну и ардуино с модулями. В итоге планировалось получить некое устройство в коробочке из губки для обуви, которое бы находилось у меня в гараже и имело следующий функционал:

- измерения напряжения аккумулятора и отключение всей нагрузки кроме ардуино при падении уровня заряда батареи ниже критического;

- ватметр (некий электросчетчик, чисто для меня чтобы знать сколько потратил «чистого» электричества);

- 3 задаваемого таймера на включение и выключение инвертора (включение насоса бассейна летом и новогодней иллюминации зимой)

- датчик bme280 для отображения сведений о температуре и влажности на дисплее и для отправки сведений на esp8266 с последующим предоставлением сведений в телеграмм канале.

Данные ватметра и таймеры записываются в EEprom c целью защиты от утери при зависании и перезагрузок.

Управление непосредственно на устройстве осуществляется с помощью 3х сенсорных кнопок используя долгое нажатие, клик и удержание, так же с помощью телеграмм канала, только для меня (сверка по id пользователя) предоставляются дополнительные кнопки на принудительное включение и выключение инвертора. Для остальных пользователей только выводится информация с датчика BME280.

И вроде схема работает, но по отдельности. Так к примеру, при подключении бме280 и дисплея я могу видеть на дисплее данные из бме280, при подключении ватметра и дисплея я могу видеть данные ватметра, но все вместе работать отказывается. При включении дисплей черный или с артефактами, перезагрузка не помогает. Почему так происходит не понимаю, так как ватметр подключается не по I2C и перехлест адресов не может быть в принципе.

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

Схема:
схема.jpg

Распиновка площадки на схеме: 1) +5V; 2) gnd; 3) Tx ардуины; 4) Rx ардуины; 5) 3,3В для питания esp; 6) пин снятия данных с шунта; 7) SDA; 8) SCL; 9) пин вкл/выкл инвертора; 10) пин защиты аккумулятора от переразряда; 11) GND; 12) +12V.

Пин 7 и 8 используется для подключения датчика bme280 так как он выносится за пределы помещения для снятия уличных данных.

Получившаяся плата:
1.png
2.png
ну и на всякий случай выкладываю скетч проекта ардуины:
C++:
#include <EEPROM.h>
#include <microDS3231.h>
MicroDS3231 rtc;
#define OLED_SOFT_BUFFER_64   // Буфер на стороне МК
#include <GyverOLED.h>        // Библиотека дисплея
#include <GyverBME280.h>      // библиотека датчика BME280
#include <GyverButton.h>      // библиотека кнопок
#include <GyverUART.h>
GyverOLED<SSD1306_128x64, OLED_BUFFER> oled;
GyverBME280 bme;
GButton up(4, LOW_PULL);     // Кнопки
GButton down(5, LOW_PULL);
GButton ok(3, LOW_PULL);

#define ITEMS 3               // Общее кол во пунктов (больше 8 - нужно несколько страниц)
#define Check220 6            // пин включения инвертора 220В
#define Health 7              // пин сохранения жизни аккумулятора панели и переключение при низком заряде на сеть 220В
#define PARSE_AMOUNT 4        // число значений в массиве, который хотим получить
#define INPUT_AMOUNT 80       // максимальное количество символов в пакете, который идёт в сериал
#define Volt A0               // пин измерения напряжения сети
#define Amp A1                // пин измерения падения напряжения, для измерения ампеража потребления

const char week_1[] PROGMEM = "Пн"; const char week_2[] PROGMEM = "Вт"; const char week_3[] PROGMEM = "Ср"; const char week_4[] PROGMEM = "Чт"; const char week_5[] PROGMEM = "Пт"; const char week_6[] PROGMEM = "Сб"; const char week_0[] PROGMEM = "Вс";
const char* const week[] PROGMEM = {week_1, week_2, week_3, week_4, week_5, week_6, week_0};

const char mesyac_1[] PROGMEM = "января"; const char mesyac_2[] PROGMEM = "февраля"; const char mesyac_3[] PROGMEM = "марта"; const char mesyac_4[] PROGMEM = "апреля"; const char mesyac_5[] PROGMEM = "мая"; const char mesyac_6[] PROGMEM = "июня";
const char mesyac_7[] PROGMEM = "июля"; const char mesyac_8[] PROGMEM = "августа"; const char mesyac_9[] PROGMEM = "сентября"; const char mesyac_10[] PROGMEM = "октября"; const char mesyac_11[] PROGMEM = "ноября"; const char mesyac_12[] PROGMEM = "декабря";
const char* const mesyac[] PROGMEM = {mesyac_1, mesyac_2, mesyac_3, mesyac_4, mesyac_5, mesyac_6, mesyac_7, mesyac_8, mesyac_9, mesyac_10, mesyac_11, mesyac_12};

bool flagTimer[] = {0, 0, 0};       //флаг был ли включен будильник
uint8_t timerminuk[] = {0, 0, 0};    //конец работы таймера (минуты)
uint8_t timerchask[] = {0, 0, 0};    //конец работы таймера (час)
uint8_t timerchasn[] = {0, 0, 0};    //начало работы таймера (час)
uint8_t timerminun[] = {0, 0, 0};    //начало работы таймера (минуты)
uint8_t addr = 0;                 // начальный адрес считывания с EEPROM
bool vkl = 0;                      //флаг включен таймер или нет
bool faccum = 0;                   //флаг сработала ли безопастность отключение источников от батарей
uint8_t cont = 255;                // начальная яркость экрана
bool contr = 0;                    // флаг включено ли меню настройки яркости
uint32_t bmeup = 0;               // опрос датчика bme раз в 2 секунды
uint32_t Wh = 0;                  // время для счетчика ватт*час
float Watt = 0;                   // переменная хранящая ватт*час
float temp;                       //переменная хранящая значение температуры
int Humidity;                   //переменная хранящая значение влажности
uint16_t davlen;                  //переменная хранящая значение атмосферного давления
bool disp = 0;                    //режим отображения дисплея
int16_t savedate = 0;
bool n=1;                       // может быть не нужна


void setup() {
  uart.begin(9600);
  bme.setMode(FORCED_MODE);       //БМЕ будет работать в спящем режиме и просыпаться по запросу
  bme.begin();                    // Инциализация БМЕ
  oled.init();                    // Инциализация дисплея
  oled.setContrast(cont);         // Макс. яркость
  pinMode(Check220, OUTPUT);      // подключается паралельно к кнопке инвертора для вкл/выкл его по таймеру
  pinMode(Health, OUTPUT);        // подключается реле 220 аакума и сети по умолчанию открыт питание от аккума
  digitalWrite(Check220, n);
  digitalWrite(Health, HIGH);
  bme.oneMeasurement();                               // Просим датчик проснуться и сделать одно преобразование
  while (bme.isMeasuring());
  temp = bme.readTemperature();
  Humidity = int(bme.readHumidity());
  davlen = int(pressureToMmHg((bme.readPressure())));
  ok.setTickMode(AUTO);           //
  up.setTickMode(AUTO);           // кнопки опрашиваются автоматически
  down.setTickMode(AUTO);         //
  ok.setTimeout(500);
  recovery ();
  savedate = rtc.getDate();

}

void loop() {
  if (ok.isHolded()) {        //вход в меню при удержании кнопки ок
    menu();
  }
  if (up.isClick() || down.isClick()) {
    disp = !disp;
  }
   if (down.isHolded()) {        //потом удалить для проверки срабатывания безопастности
    n=!n;
    digitalWrite(Check220, n);
  }
  ammetr();

  printTime();                //вывод инфы на дисплей
  provBudil();                //проверка исполнения таймеров
  saveAccum();                //проверка сохранения жизни аккумулятора панели и переключение при низком заряде на сеть 220В
  peredacha ();               //отправка данных на esp

}

void printTime() {                                      // вывод главное экрана с временем и значениями
  switch (disp) {
    case 0: {
        if (millis() - bmeup >= 2000) {

          bme.oneMeasurement();                               // Просим датчик проснуться и сделать одно преобразование
          while (bme.isMeasuring());
          temp = bme.readTemperature();
          Humidity = int(bme.readHumidity());
          davlen = int(pressureToMmHg((bme.readPressure())));
          bmeup = millis();
        }
        DateTime now = rtc.getTime();
        bool ftimer[3]; EEPROM.get(12, ftimer);
        oled.clear();           // Очищаем буфер
        oled.home();
        oled.setScale(2);
        if (now.hour < 10) oled.print(F("0"));
        oled.print(now.hour);
        oled.print(F(":"));
        if (now.minute < 10) oled.print(F("0"));
        oled.print(now.minute);
        oled.print(F(":"));
        if (now.second < 10) oled.print(F("0"));
        oled.print(now.second);
        printFromPGM(&week[now.day - 1]);
        oled.println();
        oled.setScale(1);
        oled.print(F(" "));
        oled.print(now.date);
        oled.print(F(" "));
        printFromPGM(&mesyac[now.month - 1]); //oled.print(now.month);
        oled.print(F(" "));
        oled.print(now.year);
        oled.println(F("г."));
        oled.setCursor(0, 4);
        oled.print(F("Темп = "));
        oled.print(temp, 1);
        oled.println(F("*C"));
        oled.print(F("Влажность = "));
        oled.print(Humidity);
        oled.println(F("%"));
        oled.print(F("Давлен = "));
        oled.print(davlen);
        oled.println(F("mmHg"));
        oled.print(F("сменить вид нажми +-"));
        if (contr) {
          oled.setCursor(0, 3);
          oled.print(F("Яркость: "));
          oled.invertText(true);
          oled.print(cont / 10);
          oled.invertText(false);
        }
        for (byte i = 0; i < 3; i++) {
          if (flagTimer[i]) {
            oled.setCursor(110, 3); oled.invertText(true); oled.print(F(" T ")); oled.invertText(false);
          }
        }
        if(!n) {
          oled.setCursor(85, 3); oled.invertText(true); oled.print(F(" Ин ")); oled.invertText(false);
          }
        oled.update();
        if(faccum) {
          oled.setCursor(70, 3); oled.invertText(true); oled.print(F(" ! ")); oled.invertText(false);
          }
        oled.update();
        break;
      }
    case 1: {
        oled.clear();           // Очищаем буфер
        oled.home();
        oled.setScale(1);
        oled.print(F("Напряжение: "));                             //напряжение сети
        oled.print(analogRead(Volt) * 0.01464, 1);
        oled.println(F("V"));
        oled.print(F("потреб = "));
        if (Watt > 1000) {
          oled.print (Watt / 1000, 3);
          oled.println(F(" kВт"));
        }
        else {
          oled.print (Watt, 2);
          oled.println(F(" Вт"));
        }
        oled.print(F("сила тока= "));
        oled.print((analogRead(Amp) * 0.05922));
        oled.println(F(" А"));
        oled.print(F("сменить вид нажми +-"));
        oled.update();
        break;
      }
  }

}

void printFromPGM(int charMap) {                                  //чтение данных из массивов progmem и вывод на экран
  char buffer[24];                                                // буфер для хранения строки
  uint16_t ptr = pgm_read_word(charMap);                          // получаем адрес из таблицы ссылок
  uint8_t i = 0;                                                  // переменная - индекс массива буфера
  do {
    buffer[i] = (char)(pgm_read_byte(ptr++));                     // прочитать символ из PGM в ячейку буфера, подвинуть указатель
  } while (buffer[i++] != NULL);                                  // повторять пока прочитанный символ не нулевой, подвинуть индекс буфера
  oled.print(buffer);
} // печатаем готовую строку

void menu() {                                                     //меню настроек устройства
  while (1) {                                                     //меню настроек при удержании кнопки ок
    static int8_t pointer = 0;                                    // Переменная указатель

    /* Кнопки */

    if (up.isClick() or up.isHold()) {                            // Если кнопку нажали или удерживают
      pointer = constrain(pointer - 1, 0, ITEMS - 1);             // Двигаем указатель в пределах дисплея
    }

    if (down.isClick() or down.isHold()) {
      pointer = constrain(pointer + 1, 0, ITEMS - 1);
    }

    if (ok.isClick()) {                                           // Нажатие на ОК - переход в пункт меню
      switch (pointer) {                                          // По номеру указателей располагаем вложенные функции (можно вложенные меню)
        case 0: Budilnic(); break;                                // По нажатию на ОК при наведении на 0й пункт вызвать функцию
        case 1: setVremya(); break;
        case 2: Yarkoct(); break;
      }
    }

    /* меню */
    oled.clear();           // Очищаем буфер
    oled.home();            // Курсор в левый верхний угол

    oled.println (F("  SET таймер 220В"));
    oled.println (F("  SET дата и время"));
    oled.println (F("  Яркость экрана"));

    printPointer(pointer);                                        // Вывод указателя
    oled.update();                                                // Выводим кадр на дисплей
    provBudil();                                                  //проверка исполнения таймеров
    saveAccum();                                                 //проверка сохранения жизни аккумулятора панели и переключение при низком заряде на сеть 220В
    peredacha ();
    ammetr();
    if (ok.isHolded()) return;
  }
}

void printPointer(uint8_t pointer) {                              //отображеие курсора в меню

  oled.setCursor(0, pointer);
  oled.print(">");

}

void setVremya (void) {                                           //раздел меню Set дата и время, установка текущей даты и времени
  DateTime now = rtc.getTime();
  int8_t sec = now.second; int8_t minu = now.minute; int8_t chas = now.hour; int8_t den = now.date; int8_t mes = now.month; int16_t god = now.year;
  int8_t fmesto = 0; bool save = 0;
  while (1) {
    provBudil();                                                  //проверка исполнения таймеров
    saveAccum();                                                  //проверка сохранения жизни аккумулятора панели и переключение при низком заряде на сеть 220В
    peredacha ();
    ammetr();
    if (ok.isHolded()) {                                          //при удержании кнопки ок выход с сохранением если настройка времени в сохраняется или без сохранения
      if (save) {
        rtc.setTime(sec, minu, chas, den, mes, god);
        return;
      } else {
        return;
      }
    }
    if (ok.isClick()) {                                           // при клике ок меняется что будет изменяться
      fmesto++;
    }
    if (fmesto >= 6) {                                            //при клике ок на последнем настраиваемом пункте возвращается на первый
      fmesto = 0;
    }
    if (up.isClick() or up.isHold()) {                            // клик или удержание кнопки вверх увеличивает значение с проверкой предотвращающей неправильные значения
      switch (fmesto) {
        case 0: {
            chas++;
            if (chas >= 24) {
              chas = 0;
            };
            break;
          }
        case 1: {
            minu++;
            if (minu >= 60) {
              minu = 0;
            };
            break;
          }
        case 2: {
            den++;
            if (den >= provdate(mes, god) + 1) {
              den = 1;
            };
            break;
          }
        case 3: {
            mes++;
            if (mes >= 13) {
              mes = 1;
            };
            break;
          }
        case 4: {
            god++;
            if (god >= 2101) {
              god = 2020;
            };
            break;
          }
        case 5: {
            save = !save;
            break;
          }
      }
    }
    if (down.isClick() or down.isHold()) {                        // клик или удержание кнопки вниз уменьшает значение значение с проверкой предотвращающей неправильные значения
      switch (fmesto) {
        case 0: {
            if (chas == 0) {
              chas = 23;
            } else {
              chas--;
            } break;
          }
        case 1: {
            if (minu == 0) {
              minu = 59;
            } else {
              minu--;
            } break;
          }
        case 2: {
            if (den == 1) {
              den = provdate(mes, god);
            } else {
              den--;
            } break;
          }
        case 3: {
            if (mes == 1) {
              mes = 12;
            } else {
              mes--;
            } break;
          }
        case 5: {
            save = !save;
            break;
          }
      }
    }
    oled.clear();                                                 // далее до конца функции код вывода инфы на дисплей
    oled.home();
    oled.println(F(" установка времени"));
    oled.setCursor (7, 2);
    if (fmesto == 0) oled.invertText(true);
    if (chas < 10) oled.print(F("0"));
    oled.print(chas);
    oled.invertText(false);
    oled.print(F(":"));
    if (fmesto == 1) oled.invertText(true);
    if (minu < 10) oled.print(F("0"));
    oled.print(minu);
    oled.invertText(false);
    oled.print(F(":0"));
    oled.print(sec);
    oled.setCursor (2, 4);
    if (fmesto == 2) oled.invertText(true);
    oled.print(den);
    oled.invertText(false);
    oled.print(F(" "));
    if (fmesto == 3) oled.invertText(true);
    printFromPGM(&mesyac[mes - 1]);
    oled.invertText(false);
    oled.print(F(" "));
    if (fmesto == 4) oled.invertText(true);
    oled.print(god);
    oled.invertText(false);
    oled.print(F("г."));
    if (fmesto == 5) oled.invertText(true);
    if (save) {
      oled.setCursor(5, 6);
      oled.print(F("Сохранить"));
    } else {
      oled.setCursor(4, 6);
      oled.print(F("не сохранять"));
    }
    oled.invertText(false);
    oled.update();
  }
}

int provdate(int mes, int god) {                                  //проверка в каком месяце сколько дней
  byte den;
  switch (mes) {
    case 1: {
        den = 31;
        break;
      }
    case 2: {
        if (god % 4 == 0) {
          den = 29;
        } else {
          den = 28;
        } break;
      }
    case 3: {
        den = 31;
        break;
      }
    case 4: {
        den = 30;
        break;
      }
    case 5: {
        den = 31;
        break;
      }
    case 6: {
        den = 30;
        break;
      }
    case 7: {
        den = 31;
        break;
      }
    case 8: {
        den = 31;
        break;
      }
    case 9: {
        den = 30;
        break;
      }
    case 10: {
        den = 31;
        break;
      }
    case 11: {
        den = 30;
        break;
      }
    case 12: {
        den = 31;
        break;
      }
  }
  return den;
}

void Budilnic() {                                                 //раздел меню SET таймер 220В, установка таймеров на включение и выключение 220В
  int8_t minu[] = {timerminun[0], timerminun[1], timerminun[2]}; int8_t chas[] = {timerchasn[0], timerchasn[1], timerchasn[2]}; //проставляем текущее время во время включения таймера
  int8_t timinu[] = {timerminuk[0], timerminuk[1], timerminuk[2]}; int8_t tichas[] = {timerchask[0], timerchask[1], timerchask[2]}; //инициализируем временной интервал таймера (сколько работать)
  int8_t fmesto = 0; bool save[] = {0, 0, 0}; int8_t timnomer = 0; bool fTimer[] = {flagTimer[0], flagTimer[1], flagTimer[2]};
  while (1) {
    provBudil();                                                  //проверка исполнения таймеров
    saveAccum();                                                 //проверка сохранения жизни аккумулятора панели и переключение при низком заряде на сеть 220В
    peredacha ();
    ammetr();

    if (ok.isHolded()) {
      for (byte i = 0; i < 3; i++) {                             // сохранение и выход на меню вверх
        flagTimer[i] = fTimer[i];
        timerminuk[i] = timinu[i];
        timerchask[i] = tichas[i];
        timerchasn[i] = chas[i];
        timerminun[i] = minu[i];
      }
      EEPROM.put(addr, timerminuk); addr += sizeof(timerminuk);
      EEPROM.put(addr, timerchask); addr += sizeof(timerchask);
      EEPROM.put(addr, timerchasn); addr += sizeof(timerchasn);
      EEPROM.put(addr, timerminun); addr += sizeof(timerminun);
      EEPROM.put(addr, flagTimer); addr = 0; return;

    }

    if (ok.isClick()) {
      fmesto++;
    }
    if (fmesto >= 7) {
      fmesto = 0;
    }
    if (up.isClick() or up.isHold()) {
      switch (fmesto) {
        case 0: {
            timnomer++;
            if (timnomer >= 3) {
              timnomer = 0;
            };
            break;
          }
        case 1: {
            fTimer[timnomer] = !fTimer[timnomer];
            break;
          }
        case 2: {
            chas[timnomer]++;
            if (chas[timnomer] >= 24) {
              chas[timnomer] = 0;
            };
            break;
          }
        case 3: {
            minu[timnomer]++;
            if (minu[timnomer] >= 60) {
              minu[timnomer] = 0;
            };
            break;
          }
        case 4: {
            tichas[timnomer]++;
            if (tichas[timnomer] >= 24) {
              tichas[timnomer] = 0;
            };
            break;
          }
        case 5: {
            timinu[timnomer]++;
            if (timinu[timnomer] >= 60) {
              timinu[timnomer] = 0;
            };
            break;
          }
        case 6: {
            save[timnomer] = !save[timnomer];
            break;
          }
      }
    }
    if (down.isClick() or down.isHold()) {
      switch (fmesto) {
        case 0: {
            if (timnomer == 0) {
              timnomer = 2;
            } else {
              timnomer--;
            } break;
          }
        case 1: {
            fTimer[timnomer] = !fTimer[timnomer];
            break;
          }
        case 2: {
            if (chas[timnomer] == 0) {
              chas[timnomer] = 23;
            } else {
              chas[timnomer]--;
            } break;
          }
        case 3: {
            if (minu[timnomer] == 0) {
              minu[timnomer] = 59;
            } else {
              minu[timnomer]--;
            } break;
          }
        case 4: {
            if (tichas[timnomer] == 0) {
              tichas[timnomer] = 23;
            } else {
              tichas[timnomer]--;
            } break;
          }
        case 5: {
            if (timinu[timnomer] == 0) {
              timinu[timnomer] = 59;
            } else {
              timinu[timnomer]--;
            } break;
          }
        case 6: {
            save[timnomer] = !save[timnomer];
            break;
          }
      }
    }
    oled.clear();      // очистить
    oled.home();
    oled.println(F("     установка"));
    oled.println(F("   электротаймера"));
    oled.print(F("таймер N. "));
    if (fmesto == 0) oled.invertText(true);
    oled.println(timnomer + 1);
    oled.invertText(false);
    oled.print(F("Таймер: "));
    if (fmesto == 1) oled.invertText(true);
    if (fTimer[timnomer]) {
      oled.println("ВКЛ!");
    }
    else {
      oled.println("ВЫКЛ");
    }
    oled.invertText(false);
    oled.print(F("Вкл. в: "));
    if (fmesto == 2) oled.invertText(true);
    if (chas[timnomer] < 10) oled.print(F("0"));
    oled.print(chas[timnomer]);
    oled.invertText(false);
    oled.print(F("ч."));
    if (fmesto == 3) oled.invertText(true);
    if (minu[timnomer] < 10) oled.print(F("0"));
    oled.print(minu[timnomer]);
    oled.invertText(false);
    oled.println(F("м."));
    oled.print(F("Выкл. в: "));
    if (fmesto == 4) oled.invertText(true);
    if (tichas[timnomer] < 10) oled.print(F("0"));
    oled.print(tichas[timnomer]);
    oled.invertText(false);
    oled.print(F("ч."));
    if (fmesto == 5) oled.invertText(true);
    if (timinu[timnomer] < 10) oled.print(F("0"));
    oled.print(timinu[timnomer]);
    oled.invertText(false);
    oled.println(F("м."));
    if (fmesto == 6) oled.invertText(true);
    if (save[timnomer]) {
      oled.setCursor(5, 7);
      oled.print(F("Сохранить"));
    } else {
      oled.setCursor(4, 7);
      oled.print(F("не сохранять"));
    }
    oled.invertText(false);
    oled.update();
  }
}

void provBudil() {                                                //проверка не наступило ли время включенных таймеров и исполнение их
DateTime now = rtc.getTime();
  int8_t minu = now.minute; int8_t chas = now.hour;
  EEPROM.get(addr, timerminuk); addr += sizeof(timerminuk);
  EEPROM.get(addr, timerchask); addr += sizeof(timerchask);
  EEPROM.get(addr, timerchasn); addr += sizeof(timerchasn);
  EEPROM.get(addr, timerminun); addr += sizeof(timerminun);
  EEPROM.get(addr, flagTimer); addr = 0;
  for (byte i = 0; i < 3; i++) {
    if (flagTimer[i] && chas == timerchasn[i] && minu == timerminun[i] && !vkl) {
      n=0;
      digitalWrite(Check220, n);
      vkl = !vkl;
    }
    if (flagTimer[i] && chas == timerchask[i] && minu == timerminuk[i] && vkl) {
      n=1;
      digitalWrite(Check220, n);
      vkl = !vkl;
    }
  }
}

void Yarkoct() {                                                  //изменение яркости экрана
  contr = 1;
  while (1) {
    oled.setContrast(cont);
    printTime();
    provBudil();                //проверка исполнения таймеров
    saveAccum();                //проверка сохранения жизни аккумулятора панели и переключение при низком заряде на сеть 220В
    peredacha ();
    ammetr();
    if (ok.isHolded()) {
      contr = 0;
      return;
    }
    if (up.isClick() or up.isHold()) {
      if (cont > 245) {
        cont = 255;
      }
      else cont += 10;
    }
    if (down.isClick() or down.isHold()) {
      if (cont < 10) {}
      else cont -= 10;
    }
  }
}
void peredacha () {                                               //передача данных в ESP8266
  int dataArray[1];
  String dacha;
  int bigwatt=0;
  int minwatt=0;
  if (uart.parsePacket((int*)dataArray)) {
    switch (dataArray[0]) {
      case 0:  {                                                  //0 инвертор включен потому что открывает ключ земля
        n=0;
          digitalWrite(Check220, n);
          break;
        }
      case 1: {                                                  //1 инвертор выключен на пине питание
        n=1;
          digitalWrite(Check220, n);
          break;
        }
    }
    if (Watt>32767){
      bigwatt= Watt/32767;
      minwatt=Watt-(long)(32767*bigwatt);
    }
    else {minwatt=(int)Watt;}
    String dacha = "$"+ String(int(temp* 10)) + " " +  String(int(Humidity)) + " " + String(int(davlen)) + " " + String(int(analogRead(Volt) * 0.01464*10))+" "+ String(int(analogRead(Amp) * 0.05922 * 100)) +  " " +String(int(minwatt))  +  " " + String(int(bigwatt))+ " "+  String(n) + " "+String(faccum)+";";
    saveznach ();
    uart.print(dacha); //вернуть на просто принт
  }
}
void saveAccum() {                                                //проверка сохранения жизни аккумулятора панели и переключение при низком заряде на сеть 220В
  if ((analogRead(Volt) * 0.01464)  < 11 && !faccum) {
    digitalWrite(Health, LOW);
    faccum = !faccum;
  }
  if ((analogRead(Volt) * 0.01464) > 12.5 && faccum) {
    digitalWrite(Health, HIGH);
    faccum = !faccum;
  }
}
void ammetr() {                                                   //расчет ватт * час
  Watt = Watt + (((analogRead(Volt) * 0.01464) * (analogRead(Amp) * 0.05922)) * (millis() - Wh) / 3600000);
  Wh = millis();
  saveznach ();
}
void saveznach () {                                               //сохраняет в EEPROM значение ватт*час и количество запросов при смене даты
  float vremwatt;
  uint32_t schetzapr;
  if (rtc.getDate() != savedate) {
    EEPROM.get(15, vremwatt);
    if (vremwatt > Watt) {
      Watt = vremwatt + Watt;
      EEPROM.put(15, Watt);
    }
    else {
      EEPROM.put(15, Watt);
    }
  }
}

void recovery () {                    //проверка целостности данных EEPROM
  uint8_t recovery[] = {0, 0, 0};     // если в EEPROM некорректные данные переменная для сохранения в EEPROM значений по умолчанию
  bool recflagTimer[] = {0, 0, 0};   // если в EEPROM некорректные данные переменная для сохранения в EEPROM значений по умолчанию (флаги)
  float watik = 0;
  EEPROM.get(addr, timerminuk);
  for (byte i = 0; i < 3; i++) {
    if (timerminuk[i] < 0 || timerminuk[i] > 59) {
      EEPROM.put(addr, recovery);
    }
  }
  addr += sizeof(timerminuk);
  EEPROM.get(addr, timerchask);
  for (byte i = 0; i < 3; i++) {
    if (timerchask[i] < 0 || timerchask[i] > 23) {
      EEPROM.put(addr, recovery);
    }
  }
  addr += sizeof(timerchask);
  EEPROM.get(addr, timerchasn);
  for (byte i = 0; i < 3; i++) {
    if (timerchasn[i] < 0 || timerchasn[i] > 23) {
      EEPROM.put(addr, recovery);
    }
  }
  addr += sizeof(timerchasn);
  EEPROM.get(addr, timerminun);
  for (byte i = 0; i < 3; i++) {
    if (timerminun[i] < 0 || timerminun[i] > 59) {
      EEPROM.put(addr, recovery);
    }
  }
  addr += sizeof(timerminun);
  EEPROM.get(addr, flagTimer);
  for (byte i = 0; i < 3; i++) {
    if (flagTimer[i] < 0 || flagTimer[i] > 1) {
      EEPROM.put(addr, recflagTimer);
    }
  }
  addr += sizeof(flagTimer);
  EEPROM.get(addr, watik);
  if (watik < 0) {
    EEPROM.put(addr, 0);
  }
  addr += sizeof(watik);
  addr = 0;
}