Перезагрузка при подаче сигнала .

MakcuMyM
MakcuMyM аватар
Offline
Зарегистрирован: 27.04.2017


Доброго времени суток форумчане. Возник вопрос по питанию arduino nano . Делаю автополив растений используя  стандартный   набор (дисплей 2004 ,реле на 4 канала ,3 мосфета irlz44n ,  часы реального времени . датчик температуры)

Для питания  был взят стабилизатор напряжения на 5В такого типа :

Все работает ,но при подаче сигнала на мосфеты  ардуинка уходит в ребут .  

схема  устройства 

И переделанный скетч (оригинал )  

//================================== Правка кода 05.02.2020.г */
#include <EEPROM.h>
#include <Wire.h>                   //Подключаем библиотеку для использования однопроводного интерфейса                                     
#include <OneWire.h>                //Подключаем библиотеку для температурного датчика DS18B20
#include <LiquidCrystal_I2C.h>      //Подключаем I2C библиотеку экрана
LiquidCrystal_I2C lcd(0x27,20,4);   //Устанавливаем LCD-адрес 0x27 для отображения 20 символов и 4 линии
#define LAMP_PIN 6                  //Используем цифровой ПОРТ D6 для реле светодиодных ламп (LED1)
#define FITOLAMP_PIN 7              //Используем цифровой ПОРТ D7 для реле светодиодных фитоламп (LED2)
#define RELAY3_PIN 8                //Используем цифровой ПОРТ D8 для реле (пока не задействован) 
#define RELAY4_PIN 9                //Используем цифровой ПОРТ D9 для реле (пока не задействован)
#define WATERING_POMP_1_PIN 2       //Используем цифровой ПОРТ D2 для полива линия №1  
#define WATERING_POMP_2_PIN 3       //Используем цифровой ПОРТ D3 для полива линия №2
#define WATERING_POMP_3_PIN 4       //Используем цифровой ПОРТ D4 для полива линия №3
#define TEMP_PIN 5                  //Используем цифровой ПОРТ D5 для подключения датчика температуры DS18B20
#define BUTTONS_PIN A0              //Используем аналоговый ПОРТ A0 для подключения кнопок управления контроллером
#define LED_PIN 10                  //Используем цифровой ПОРТ D10 для индикации светодиода (пока не задействован)
//================================== Rtc_Clock часы реального времени*
#define DS3231_I2C_ADDRESS 104 
byte seconds, minutes, hours, day, date, month, year;
byte decToBcd (byte val){return((val/10*16)+(val%10));}
//================================== Температурный датчик*
OneWire ds(TEMP_PIN);               //Создаем объект для работы с термометром
float temp, temp_pred;              //Температура текущая и предыдущая
unsigned long lastUpdateTime = 0;   // Переменная для хранения времени последнего считывания с датчика
const int TEMP_UPDATE_TIME = 5000;  // Определяем периодичность проверок

const bool OFF    = false;
const bool ON     = true;

// Пользовательский символ градуса 
byte degree[8] = { 
0b00110, 
0b01001, 
0b01001, 
0b00110, 
0b00000, 
0b00000, 
0b00000, 
0b00000, 
}; 

// Пользовательский символ "черный прямоугольник"
byte progressbar[8] = { 
0b00000, 
0b00000, 
0b11111, 
0b11111, 
0b11111, 
0b11111, 
0b00000, 
0b00000, 
};
byte termometru[8] = //Пользовательский символ "Термометр"
{
B00100,
B01010,
B01010,
B01110,
B01110,
B11111,
B11111,
B01110
};
byte kran[8] =  //Пользовательский символ крантика (подпитки)
 {
 B01110,
 B00100,
 B11110,
 B11111,
 B00011,
 B00000,
 B00001,
 B00000
 };
 byte bak_0[8] =  //Пользовательский символ пустого бака 
 {
 B00010,
 B11111,
 B10001,
 B10001,
 B11001,
 B11101,
 B11111,
 B00000
 };
 byte bak_full[8] =   //Пользовательский символ полного бака 
 {
 B00010,
 B11111,
 B11111,
 B11111,
 B11111,
 B11111,
 B11111,
 B00000
 };
//================================== Метод отображающий версию ПО и разработчика
void ShowVersion() {
  lcd.clear();
  lcd.setCursor(0,1);
  lcd.print("  AVTOPOLIV v.1.0b");   //Выводим версию и прочее
  lcd.setCursor(0,2);
  lcd.print("        "); // 20
  delay(5000);  
}

void setup() {
  Wire.begin();                        //Инициируем I2C интерфейс
   pinMode(LAMP_PIN, OUTPUT);          // устанавливает режим работы - выход
  // digitalWrite(LAMP_PIN, HIGH);     // выключает
  setLAMP(OFF);
   pinMode(FITOLAMP_PIN, OUTPUT);      // устанавливает режим работы - выход
  //digitalWrite(FITOLAMP_PIN, HIGH) ; // выключает
  setFITOLAMP(OFF);
  pinMode(RELAY3_PIN, OUTPUT);         // устанавливает режим работы - выход
  digitalWrite(RELAY3_PIN, HIGH);      // выключает
  pinMode(RELAY4_PIN, OUTPUT);         // устанавливает режим работы - выход
  digitalWrite(RELAY4_PIN, HIGH);      // выключает
  
  pinMode(WATERING_POMP_1_PIN, OUTPUT);   // устанавливает режим работы - выход
  digitalWrite(WATERING_POMP_1_PIN, LOW); // выключает
  pinMode(WATERING_POMP_2_PIN, OUTPUT);   // устанавливает режим работы - выход
  digitalWrite(WATERING_POMP_2_PIN, LOW); // выключает
  pinMode(WATERING_POMP_3_PIN, OUTPUT);   // устанавливает режим работы - выход
  digitalWrite(WATERING_POMP_3_PIN, LOW); // выключает

  
  pinMode(LED_PIN, OUTPUT);   // устанавливает режим работы - выход
  digitalWrite(LED_PIN, LOW); // выключает
  
  pinMode(TEMP_PIN, INPUT);         // устанавливает режим работы - вход
  pinMode(BUTTONS_PIN, INPUT);      // устанавливает режим работы - вход
  
  
  lcd.init();                       // запускаем библиотеку экрана 
  lcd.backlight();
  lcd.clear();                      // Очищаем на всякий случай дисплей
  lcd.createChar(1, degree);        // символ градуса
  lcd.createChar(2, progressbar);   // символ ProgressBar
  lcd.createChar(3, termometru);    // символ термометра
  lcd.createChar(4, kran);          // символ крана
  lcd.createChar(5, bak_0);         // символ пустого бака
  lcd.createChar(6, bak_full);      // символ полного бака
  LoadSettings();                   // ЗАГРУЖАЕМ ЗНАЧЕНИЯ ПЕРЕМЕННЫХ ИЗ ЭНЕРГОНЕЗАВИСИМОЙ ПАМЯТИ
  ShowVersion();
  lcd.clear();                      //Очистка дисплея
}
//================================== Функция переводит число в строку и дополняет ее ведущими нулями
String ByteToStrFormat(byte val, byte digits = 1) {
  String result;
  result = val;
  while (result.length()<digits) result = "0"+result;
  return (String)result;
}

//-----------------------------------------------------------------------------------
// Нажатые кнопки
const byte BUTTON_NONE   = 0;
const byte BUTTON_UP     = 1;
const byte BUTTON_DOWN   = 2;
const byte BUTTON_OK     = 3;
const byte BUTTON_MENU   = 4;

int getPressedButton()
{
 byte KeyNum=0;
 int KeyValue1=0;
 int KeyValue2=0;
 
//Читаем в цикле аналоговый вход, для подавления дребезга и нестабильности читаем по два раза подряд, пока значения не будут равны.
//Если значения равны 1023 – значит не была нажата ни одна кнопка.
do {
 // считываем значения с аналогового входа (A0)  
 KeyValue1=analogRead(BUTTONS_PIN);
 delay(10);
 KeyValue2=analogRead(BUTTONS_PIN);
 delay(5);
 } while (KeyValue1!=KeyValue2);

//Интерпретируем полученное значение и определяем код нажатой клавиши
 if (KeyValue2 > 900) 
  {KeyNum = BUTTON_NONE;}
 else if (KeyValue2 > 450) 
       {KeyNum = BUTTON_MENU;}
      else if (KeyValue2 > 250) 
            {KeyNum = BUTTON_OK;}
           else if (KeyValue2 > 100) 
                 {KeyNum = BUTTON_UP;}
                else {KeyNum = BUTTON_DOWN;}
return KeyNum;    //Возвращаем код нажатой клавиши
}

//================================== Считывание температуры
int detectTemperature(){
  byte data[2];
  ds.reset();// Начинаем взаимодействие со сброса всех предыдущих команд и параметров
  ds.write(0xCC);// Даем датчику DS18b20 команду пропустить поиск по адресу. В нашем случае только одно устрйоство 
  ds.write(0x44);// Даем датчику DS18b20 команду измерить температуру. Само значение температуры мы еще не получаем - датчик его положит во внутреннюю память
  if ((abs(millis() - lastUpdateTime)) > TEMP_UPDATE_TIME) {
    lastUpdateTime = millis();
    ds.reset();// Теперь готовимся получить значение измеренной температуры
    ds.write(0xCC);
    ds.write(0xBE);// Просим передать нам значение регистров со значением температуры
    // Получаем и считываем ответ
    data[0] = ds.read(); // Читаем младший байт значения температуры
    data[1] = ds.read(); // А теперь старший
    // Формируем итоговое значение: 
    //    - сперва "склеиваем" значение, 
    //    - затем умножаем его на коэффициент, соответсвующий разрешающей способности (для 12 бит по умолчанию - это 0,0625)
    temp_pred = temp; // Запоминаем предыдущую температуру.
    temp =  ((data[1] << 8) | data[0]) * 0.0625;  // и вычисляем текущую.
  }
}

//================================== Обработка установки RTC часов
void setRtc(byte seconds, byte minutes, byte hours, byte day, byte date, byte month, byte year){
  Wire.beginTransmission(DS3231_I2C_ADDRESS);        //104 is DS3231 device address
  Wire.write(0x00);                                  //Start at register 0
  Wire.write(decToBcd(seconds));
  Wire.write(decToBcd(minutes));
  Wire.write(decToBcd(hours));
  Wire.write(decToBcd(day));
  Wire.write(decToBcd(date));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

//================================== Обработка RTC часов
void timeRtc(){
  Wire.beginTransmission(DS3231_I2C_ADDRESS);        //104 is DS3231 device address
  Wire.write(0x00);                                  //Start at register 0
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);           //Request seven bytes
  if(Wire.available()){ 
    seconds = Wire.read();                           //Get second
    minutes = Wire.read();                           //Get minute
    hours   = Wire.read();                           //Get hour
    day     = Wire.read();
    date    = Wire.read();
    month   = Wire.read();                           //Get month
    year    = Wire.read();
       
    seconds = (((seconds & B11110000)>>4)*10 + (seconds & B00001111));   //Convert BCD to decimal
    minutes = (((minutes & B11110000)>>4)*10 + (minutes & B00001111));
    hours   = (((hours & B00110000)>>4)*10 + (hours & B00001111));       //Convert BCD to decimal (assume 24 hour mode)
    day     = (day & B00000111);                                         // 1-7
    date    = (((date & B00110000)>>4)*10 + (date & B00001111));         //Convert BCD to decimal  1-31
    month   = (((month & B00010000)>>4)*10 + (month & B00001111));       //msb7 is century overflow
    year    = (((year & B11110000)>>4)*10 + (year & B00001111));
  }
}

//=============================== Переменные таймера для светодиодных ламп (LAMP)
bool LAMP_ON;                     // флаг состояния ламп, true - включены, false - выключены
byte hours_ON1_LAMP;              // час начала  рассвета 
byte minutes_ON1_LAMP;            // минута начала  рассвета 
byte hours_OFF1_LAMP;             // час начала заката 
byte minutes_OFF1_LAMP;           // минута начала  заката 
//=============================== Переменные таймера для светодиодных фитоламп (FITOLAMP) 
bool FITOLAMP_ON;                 // флаг состояния, true - включен, false - выключен
byte hours_ON1_FITOLAMP;          // час начала  рассвета 
byte minutes_ON1_FITOLAMP;        // минута начала  рассвета 
byte hours_OFF1_FITOLAMP;         // час начала  заката 
byte minutes_OFF1_FITOLAMP;       // минута начала  заката 

#define mn 60UL         // Дополнительные константы для удобства 
#define hr 3600UL       // Отражают соответствующие количества секунд 
#define d 86400UL       // в минуте, в часе, в сутках (дне)

//======== Метод производящий включение-выключение светодиодных ламп (LAMP)
void setLAMP(bool state) {
  if (state == OFF) {                 // если OFF
    digitalWrite(LAMP_PIN, HIGH);     // то выключаем лампы
    LAMP_ON = false;                  // и сбрасываем флаг включенных ламп в false
  }
  else {                              // если ON
    digitalWrite(LAMP_PIN, LOW);      // то включаем лампы
    LAMP_ON = true;                   // и устанавливаем флаг включенных ламп в true
  }
}
//======== Метод производящий включение-выключение светодиодных фитоламп (FITOLAMP) 
void setFITOLAMP(bool state) {
  if (state == OFF) {                      // если OFF
    digitalWrite(FITOLAMP_PIN, HIGH);     // то выключаем FITOLAMP
    FITOLAMP_ON = false;                  // и сбрасываем флаг включения в false
  }
  else {                                  // если ON
    digitalWrite(FITOLAMP_PIN, LOW);      // то включаем FITOLAMP
    FITOLAMP_ON = true;                   // и устанавливаем флаг включения в true
  }
}
//============================== Таймер для светодиодных ламп (LAMP)
void timerLAMP()
{
  //----- Обрабатываем интервал включения-выключения.
  // Если час и минута включения равны часу и минуте выключения, значит этот интервал обрабатываться не будет.
  if ((hours_ON1_LAMP != hours_OFF1_LAMP) || (minutes_ON1_LAMP != minutes_OFF1_LAMP)) {
    if ((hours == hours_ON1_LAMP)&&(minutes == minutes_ON1_LAMP)) { 
      if (!LAMP_ON) setLAMP(ON);   // Если наступило время включения ламп, то включаем и устанавливаем флаг включения
    }
    if ((hours == hours_OFF1_LAMP)&&(minutes == minutes_OFF1_LAMP)) { 
      if (LAMP_ON) setLAMP(OFF); // Если наступило время выключения ламп, то выключаем и устанавливаем флаг выключения
    }
  }
  }
//============================== Таймер светодиодных фитоламп (FITOLAMP)
void timerFITOLAMP()
{
  //----- Обрабатываем  интервал включения-выключения.
  // Если час и минута включения равны часу и минуте выключения, значит этот интервал обрабатываться не будет.
  if ((hours_ON1_FITOLAMP != hours_OFF1_FITOLAMP) || (minutes_ON1_FITOLAMP != minutes_OFF1_FITOLAMP)) {
    if ((hours == hours_ON1_FITOLAMP)&&(minutes == minutes_ON1_FITOLAMP)) { 
      if (!FITOLAMP_ON) setFITOLAMP(ON);   // Если наступило время включения FITOLAMP, то включаем и устанавливаем флаг включения
    }
    if ((hours == hours_OFF1_FITOLAMP)&&(minutes == minutes_OFF1_FITOLAMP)) { 
      if (FITOLAMP_ON) setFITOLAMP(OFF); // Если наступило время выключения FITOLAMP, то выключаем и устанавливаем флаг выключения
    }
  }
  
}
//=============================== Переменные системы полива 
bool feed_WATERING_POMP_1;                // флаг полива (WATERING_POMP_1)
bool feed_WATERING_POMP_2;                // флаг полива (WATERING_POMP_2)
bool feed_WATERING_POMP_3;                // флаг полива (WATERING_POMP_3)

byte days_WATERING_POMP_1;                 // день полива (WATERING_POMP_1)
byte hours_WATERING_POMP_1;               // час начала полива (WATERING_POMP_1)
byte minutes_WATERING_POMP_1;             // минута полива (WATERING_POMP_1)
byte duration_WATERING_POMP_1;            // длительность полива (WATERING_POMP_1 в секундах)

byte days_WATERING_POMP_2;                 // день  полива (WATERING_POMP_2)
byte hours_WATERING_POMP_2;               // час начала полива (WATERING_POMP_2)
byte minutes_WATERING_POMP_2;             // минута началаполива (WATERING_POMP_2)
byte duration_WATERING_POMP_2;            // длительность полива (WATERING_POMP_2 в секундах)

byte days_WATERING_POMP_3;                 // день  полива (WATERING_POMP_3)
byte hours_WATERING_POMP_3;               // час начала полива (WATERING_POMP_3)
byte minutes_WATERING_POMP_3;             // минута начала полива (WATERING_POMP_3)
byte duration_WATERING_POMP_3;            // длительность полива (WATERING_POMP_3 в секундах)

//=============================== Таймер Линии полива №1 (WATERING_POMP_1)
void timerWATERING_POMP_1() {
  if (hours_WATERING_POMP_1 != 0) {  // Если час  полива  равен 0, то полива растений  не будет (выкл)
    if ((day == days_WATERING_POMP_1)&&(hours == hours_WATERING_POMP_1)&&(minutes == minutes_WATERING_POMP_1)) { 
      if (!feed_WATERING_POMP_1) {
        digitalWrite(WATERING_POMP_1_PIN, HIGH);  // Если наступило время полива растений, то подаём его
        delay(duration_WATERING_POMP_1*100);      // в течении заданного количества секунд,
        digitalWrite(WATERING_POMP_1_PIN, LOW);   // затем отключаем подачу
        feed_WATERING_POMP_1 = true;              // и устанавливаем флаг подачи в true
      }
    }
    else {
      if (feed_WATERING_POMP_1) {
        feed_WATERING_POMP_1 = false;       // если время полива растений, тогда сбрасываем флаг подачи
      }
    }
  }
}
//=============================== Таймер Линии полива №2 (WATERING_POMP_2)
void timerWATERING_POMP_2() {
  if (hours_WATERING_POMP_2 != 0) {  // Если час  полива  равен 0, то полива растений  не будет (выкл)
    if ((day == days_WATERING_POMP_2)&&(hours == hours_WATERING_POMP_2)&&(minutes == minutes_WATERING_POMP_2)) { 
      if (!feed_WATERING_POMP_2) {
        digitalWrite(WATERING_POMP_2_PIN, HIGH);  // Если наступило время полива растений, то подаём его
        delay(duration_WATERING_POMP_2*100);      // в течении заданного количества секунд,
        digitalWrite(WATERING_POMP_2_PIN, LOW);   // затем отключаем подачу
        feed_WATERING_POMP_2 = true;              // и устанавливаем флаг подачи в true
      }
    }
    else {
      if (feed_WATERING_POMP_2) {
        feed_WATERING_POMP_2 = false;       // если время полива растений, тогда сбрасываем флаг подачи
      }
    }
  }
}
//=============================== Таймер Линии полива №3 (WATERING_POMP_3)
void timerWATERING_POMP_3() {
  if (hours_WATERING_POMP_3 != 0) {  // Если час  полива  равен 0, то полива растений  не будет (выкл)
    if ((day == days_WATERING_POMP_3)&&(hours == hours_WATERING_POMP_3)&&(minutes == minutes_WATERING_POMP_3)) { 
      if (!feed_WATERING_POMP_3) {
        digitalWrite(WATERING_POMP_3_PIN, HIGH);  // Если наступило время полива растений, то подаём его
        delay(duration_WATERING_POMP_3*100);      // в течении заданного количества секунд,
        digitalWrite(WATERING_POMP_3_PIN, LOW);   // затем отключаем подачу
        feed_WATERING_POMP_3 = true;              // и устанавливаем флаг подачи в true
      }
    }
    else {
      if (feed_WATERING_POMP_3) {
        feed_WATERING_POMP_3 = false;       // если время полива растений, тогда сбрасываем флаг подачи
      }
    }
  }
}
//=============================== Переменные для навигации по меню и выводу на дисплей информации
byte buttonPressed;               // Код нажатой кнопки
byte pMenu;                       // Пункт меню (номер меню)
byte pos;                         // Позиция текущего изменяемого значения в этом пункте меню
String display0;                  // Первая строка дисплея
String display1;                  // Вторая строка дисплея
String display2;                  // Третья строка дисплея
String display3;                  // Четвертая строка дисплея

//=============================== Метод отвечающий за очистку дисплея и переменных дисплея
void ClearDisplay() {
  lcd.clear();                                    // Очищаем дисплей
  display0 = display1 = display2 = display3 = ""; // Стираем строки дисплея (переменные)
  pos = 0;                                        // Сбрасываем позицию изменяемого значения на начальную
}
//=============================== Метод отвечающий за вывод информации на дисплей.
void PrintDisplay(String mdisp0, String mdisp1, String mdisp2, String mdisp3) {
   if (display0 != mdisp0) {          // Если содержимое строки изменилось, то выводим ее на дисплей
    display0 = mdisp0;
    lcd.setCursor(0,0);
    lcd.print(display0);
  }
  if (display1 != mdisp1) {
    display1 = mdisp1;
    lcd.setCursor(0,1);
    lcd.print(display1);
  }
  if (display2 != mdisp2) {
    display2 = mdisp2;
    lcd.setCursor(0,2);
    lcd.print(display2);
  }
  if (display3 != mdisp3) {
    display3 = mdisp3;
    lcd.setCursor(0,3);
    lcd.print(display3);
  }
}
//=============================== Метод отвечающий за установку часов реального времени
void SetTime() {
  int plus_minus;         // Инкремент или декремент (+1 или -1)
  String msg;             // Сообщение редактируемого параметра
  String mdisplay1;       // Вторая строка дисплея
  String mdisplay2;       // Третья строка дисплея
  delay(500);
  while(buttonPressed != BUTTON_MENU) {
    buttonPressed = getPressedButton();               // Считываем нажатую кнопку
    plus_minus = 0;
    switch(buttonPressed){
      case BUTTON_UP:   plus_minus = 1;  break;
      case BUTTON_DOWN: plus_minus = -1; break;
      case BUTTON_OK:
        pos++;              // Переходим к следующему изменяемому значению
        if (pos>7) pos = 0; // и по кругу
      break;    
    }
    switch (pos) {
      case 0:
        date += plus_minus;              // Крутим значения длительности
        if (date > 31) date = 1;         // Ограничиваем значения
        msg = "    "; msg += "<<Set"; msg += " Date"; msg += ">>"; msg += "    "; // 20
        //msg = "    <<Set Date>>    ";
      break;
      case 1:
        month += plus_minus;             // Крутим значения длительности
        if (month > 12) month = 1;       // Ограничиваем значения
        msg = "   "; msg += "<<Set"; msg += " Month"; msg += ">>"; msg += "    "; // 20
        //msg = "   <<Set Month>>    ";
      break;
      case 2:
        year += plus_minus;              // Крутим значения длительности
        if (year > 99) year = 0;         // Ограничиваем значения
        msg = "    "; msg += "<<Set"; msg += " Year"; msg += ">>"; msg += "    "; // 20
        //msg = "    <<Set Year>>    ";
      break;
      case 3:
        day += plus_minus;               // Крутим значения длительности
        if (day > 7) day = 1;            // Ограничиваем значения
        if (day < 1) day = 7;            // Ограничиваем значения
        msg = "    "; msg += "<<Set"; msg += " Day"; msg += ">>"; msg += "    "; // 19
        //msg = "    <<Set Day>>     ";
      break;
      case 4:
        hours += plus_minus;             // Крутим значения часов
        if (hours > 23) hours = 0;       // Ограничиваем значения
        msg = "   "; msg += "<<Set"; msg += " Hours"; msg += ">>"; msg += "    "; // 20
        //msg = "   <<Set Hours>>    ";
      break;
      case 5:
        minutes += plus_minus;           // Крутим значения минут
        if (minutes > 59) minutes = 0;   // Ограничиваем значения
        msg = "  "; msg += "<<Set"; msg += " Minutes"; msg += ">>"; msg += "   "; // 20
        //msg = "  <<Set Minutes>>   ";
      break;
      case 6:
        seconds += plus_minus;           // Крутим значения длительности
        if (seconds > 59) seconds = 0;   // Ограничиваем значения
        msg = "  "; msg += "<<Set"; msg += " Seconds"; msg += ">>"; msg += "   "; // 20
        //msg = "  <<Set Seconds>>   ";
      break;
      case 7:
        setRtc(seconds, minutes, hours, day, date, month, year);  // Устанавливаем часы и дату
        lcd.clear();
        lcd.setCursor(0,2);
        lcd.print("      -=Save"); lcd.print("d"); lcd.print("=- "); // lcd.print("    ");
        lcd.setCursor(0,3);
        lcd.print("      -=Save"); lcd.print("d"); lcd.print("=- "); // lcd.print("    ");
        buttonPressed = BUTTON_MENU;
        delay(2000);
        continue;
      break;   
    }
    lcd.setCursor(0,0);
    lcd.print("Set Date  / Set Time");   //20                 // Формируем строки с информацией для вывода на дисплей
    mdisplay1 = ByteToStrFormat(date, 2) + "/" + ByteToStrFormat(month, 2) + "/20" +  ByteToStrFormat(year, 2) + "  ";  //12
    mdisplay1 +=  ByteToStrFormat(hours, 2) + ":" + ByteToStrFormat(minutes, 2) + ":" + ByteToStrFormat(seconds, 2);  //8
    mdisplay2 = "Day=" + ByteToStrFormat(day, 1) + "      -=Save" + "=- ";
    lcd.setCursor(0,1);       // Выводим строки на дисплей
    lcd.print(mdisplay1);
    lcd.setCursor(0,2);
    lcd.print(mdisplay2);
    lcd.setCursor(0,3);
    lcd.print(msg);
    //PrintDisplay(mdisplay0, mdisplay1, mdisplay2, mdisplay3); // Выводим строки на дисплей
  } 
}
//=============================== Метод отвечающий за тестирование системы полива (POMPS)
void Menu_POMP_Test() {
  int plus_minus;         // Инкремент или декремент (+1 или -1)
  String msg;             // Сообщение редактируемого параметра
  String mdisplay0;       // Первая строка дисплея
  String mdisplay1;       // Вторая строка дисплея
  String mdisplay2;       // Третья строка дисплея
  String mdisplay3;       // Четвертая строка дисплея
  byte Duration_WATERING_POMP_1 = 1;
  byte Duration_WATERING_POMP_2 = 1;
  byte Duration_WATERING_POMP_3 = 1;
  
  delay(500);
  mdisplay1 = "    "; mdisplay1 += "-=POMP TEST=-"; mdisplay1 += "    ";   //20
  lcd.setCursor(0,1);       // Выводим строки на дисплей
  lcd.print(mdisplay1);
  delay(3000);
  ClearDisplay();       // Очищаем дисплей и переменные дисплея
  
  while(buttonPressed != BUTTON_MENU) {
    buttonPressed = getPressedButton();               // Считываем нажатую кнопку
    plus_minus = 0;
    switch(buttonPressed){
      case BUTTON_UP:   plus_minus = 1;  break;
      case BUTTON_DOWN: 
        switch (pos) {
          case 0:
            digitalWrite(WATERING_POMP_1_PIN, HIGH);  // то подаём его
            delay(Duration_WATERING_POMP_1*100);      // в течении заданного количества секунд,
            digitalWrite(WATERING_POMP_1_PIN, LOW);   // затем отключаем подачу
          break;
          case 1:
            digitalWrite(WATERING_POMP_2_PIN, HIGH);  // то подаём его
            delay(Duration_WATERING_POMP_2*100);      // в течении заданного количества секунд,
            digitalWrite(WATERING_POMP_2_PIN, LOW);   // затем отключаем подачу
          break;
          case 2:
            digitalWrite(WATERING_POMP_3_PIN, HIGH);      // то подаём его
            delay(Duration_WATERING_POMP_3*100);      // в течении заданного количества секунд,
            digitalWrite(WATERING_POMP_3_PIN, LOW);   // затем отключаем подачу
          break;
        }
      break;
      case BUTTON_OK:
        pos++;              // Переходим к следующему изменяемому значению
        if (pos>2) pos = 0; // и по кругу
      break;    
    }
    switch (pos) {
      case 0:
        Duration_WATERING_POMP_1 += plus_minus;              // Крутим значения длительности
        if (Duration_WATERING_POMP_1 > 250) Duration_WATERING_POMP_1 = 1;         // Ограничиваем значения
        msg = "<<Set"; msg += "Duration_P1"; msg += ">>"; // 20
      break;
      case 1:
        Duration_WATERING_POMP_2 += plus_minus;              // Крутим значения длительности
        if (Duration_WATERING_POMP_2 > 250) Duration_WATERING_POMP_2 = 1;         // Ограничиваем значения
        msg = "<<Set"; msg += "Duration_P2"; msg += ">>"; // 20
      break;
      case 2:
        Duration_WATERING_POMP_3 += plus_minus;              // Крутим значения длительности
        if (Duration_WATERING_POMP_3 > 250) Duration_WATERING_POMP_3 = 1;         // Ограничиваем значения
        msg = "<<Set"; msg += " Duration_P3 "; msg += ">>"; // 20
      break;   
    }
    mdisplay0 = "POMP1 " + ByteToStrFormat(Duration_WATERING_POMP_1, 2) + " Sec/10"; //20
    mdisplay1 = "POMP2 " + ByteToStrFormat(Duration_WATERING_POMP_2, 2) + " Sec/10"; //20
    mdisplay2 = "POMP3 " + ByteToStrFormat(Duration_WATERING_POMP_3, 2) + " Sec/10"; //17
    mdisplay3 = msg;
    PrintDisplay(mdisplay0, mdisplay1, mdisplay2, mdisplay3); // Выводим строки на дисплей
    delay(100);
  }
  ClearDisplay();       // Очищаем дисплей и переменные дисплея
  mdisplay1 = "    "; mdisplay1 += "-=POMP TEST=-"; mdisplay1 += "    ";   //20
  mdisplay2 = "    "; mdisplay2 += "    "; mdisplay2 += "EXIT"; mdisplay2 += "    "; mdisplay2 += "    ";   //20
  lcd.setCursor(0,1);       // Выводим строки на дисплей
  lcd.print(mdisplay1);
  lcd.setCursor(0,2);       // Выводим строки на дисплей
  lcd.print(mdisplay2);
  delay(3000);
  pMenu = 0;
}

//=============================== Метод отвечающий за режим профилактики (ручная настройка выходов реле 220В)
void SetProfilactika() {
  int plus_minus;     // Инкремент или декремент (+1 или -1)
  String msg;             // Сообщение редактируемого параметра
  String mdisplay0;       // Первая строка дисплея
  String mdisplay1;       // Вторая строка дисплея
  String mdisplay2;       // Третья строка дисплея
  String mdisplay3;       // Четвертая строка дисплея
  
  mdisplay1 = "    "; mdisplay1 += "-=RELAY TEST=-"; mdisplay1 += "    ";   //20
  lcd.setCursor(0,1);       // Выводим строки на дисплей
  lcd.print(mdisplay1);
  delay(3000);
  ClearDisplay();       // Очищаем дисплей и переменные дисплея
  while(buttonPressed != BUTTON_MENU) {
    buttonPressed = getPressedButton();               // Считываем нажатую кнопку
    plus_minus = 0;
    switch(buttonPressed){
      case BUTTON_UP:   plus_minus = 1;  break;
      case BUTTON_DOWN: plus_minus = -1; break;
      case BUTTON_OK:
        pos++;              // Переходим к следующему изменяемому значению
        if (pos>5) pos = 0; // и по кругу
      break;    
    }
    switch (pos) {
     case 0:
        if (plus_minus == 1) {
          if (!LAMP_ON) setLAMP(ON);
        }
        else if (plus_minus == -1) {
          if (LAMP_ON) setLAMP(OFF);
        }
        msg = "  "; msg += "<<  Set"; msg += " LED_1"; msg += " >>"; msg += "  "; // 20
      break;
      case 1:
          if (plus_minus == 1) {
          if (!FITOLAMP_ON) setFITOLAMP(ON);
        }
        else if (plus_minus == -1) {
          if (FITOLAMP_ON) setFITOLAMP(OFF);
        }
       msg = "  "; msg += "<<  Set"; msg += " LED_2"; msg += " >>"; msg += "  "; // 20
      break;   
    }
    mdisplay1 = (LAMP_ON == true) ? "LED_1=ON  " : "LED_1=OFF ";  //9
    mdisplay1 += (FITOLAMP_ON == true) ? "LED_2=ON  " : "LED_2=OFF "; //9
    //mdisplay2 = (RELAY3_ON == true) ? "RELAY3=ON  " : "RELAY3=OFF "; //10
    //mdisplay2 += (RELAY4_ON == true) ? "RELAY4=ON  " : "RELAY4=OFF "; //10
    mdisplay3 = msg;
    PrintDisplay(mdisplay0, mdisplay1, mdisplay2, mdisplay3); // Выводим строки на дисплей
    delay(100);
  }
  ClearDisplay();       // Очищаем дисплей и переменные дисплея
  mdisplay1 = "    "; mdisplay1 += "-=POMP TEST=-"; mdisplay1 += "    ";   //20
  mdisplay2 = "    "; mdisplay2 += "    "; mdisplay2 += "EXIT"; mdisplay2 += "    "; mdisplay2 += "    ";   //20
  lcd.setCursor(0,1);       // Выводим строки на дисплей
  lcd.print(mdisplay1);
  lcd.setCursor(0,2);       // Выводим строки на дисплей
  lcd.print(mdisplay2);
  delay(3000);
  pMenu = 0; 
}
//=============================== Метод отвечающий за навигацию по меню контроллера
void Menu() {
  buttonPressed = getPressedButton();               // Считываем нажатую кнопку
  if ((pMenu == 0)&&(buttonPressed != BUTTON_NONE)) // Нулевое меню - вывод информации о работе контроллера
    switch(buttonPressed){
        case BUTTON_MENU:
          pMenu++;              // Переходим к следующему меню
          ClearDisplay();       // Очищаем дисплей и переменные дисплея
          ShowSetMenu();
        break;
        case BUTTON_UP:
          ClearDisplay();       // Очищаем дисплей и переменные дисплея
          SetTime();            // Установка часов реального времени
        break;
        case BUTTON_DOWN:
          ClearDisplay();       // Очищаем дисплей и переменные дисплея
          SetProfilactika();    // Переходим в режим профилактики 
        break;
        case BUTTON_OK:
          ShowVersion();
          ClearDisplay();       // Очищаем дисплей и переменные дисплея
          Menu_POMP_Test();
          ShowSetMenu();
        break;
  }
  else if (buttonPressed == BUTTON_MENU) {
    pMenu++;                    // Переходим к следующему меню
    if (pMenu > 6) pMenu = 0;   // Если прошлись по всем меню, то пререходим в информационное меню 
    ClearDisplay();             // Очищаем дисплей и переменные дисплея
    ShowSetMenu();
  }
  else if (buttonPressed == BUTTON_NONE) {
    ShowSetMenu();
    return;
  }
  else
    ShowSetMenu();
  if (pMenu>0) delay(100);
}

void ShowSetMenu() {
    String s;
    switch (pMenu) {
      case 0:  Menu_INFO();
      break;
      case 1: 
        s = "Menu"; s += "0"; s += "1"; s += " LED_1"; s += " Period"; s += ""; // "Menu11 LAMP Period"
        Menu_LAMP_FITOLAMP(s, hours_ON1_LAMP, minutes_ON1_LAMP, hours_OFF1_LAMP, minutes_OFF1_LAMP);
      break;
       case 2: 
        s = "Menu"; s += "0"; s += "2"; s += " LED_2"; s += " Period"; s += ""; // "Menu13 FITOLAMP Period"
        Menu_LAMP_FITOLAMP(s, hours_ON1_FITOLAMP, minutes_ON1_FITOLAMP, hours_OFF1_FITOLAMP, minutes_OFF1_FITOLAMP);
      break;
      case 3: 
        s = "Menu"; s += "0"; s += "3"; s += " "; s += " p1"; s += " "; //WATERING_POMP_1
        Menu_WATERING(s, days_WATERING_POMP_1, hours_WATERING_POMP_1, minutes_WATERING_POMP_1, duration_WATERING_POMP_1, " Sec/10");
      break;
      case 4: 
        s = "Menu"; s += "0"; s += "4"; s += " "; s += " p2"; s += " "; // "WATERING_POMP_2"
        Menu_WATERING(s, days_WATERING_POMP_2, hours_WATERING_POMP_2, minutes_WATERING_POMP_2, duration_WATERING_POMP_2, " Sec/10");
      break;
      case 5: 
        s = "Menu"; s += "0"; s += "5"; s += " "; s += " p3"; s += " " ; // "WATERING_POMP_3"
        Menu_WATERING(s, days_WATERING_POMP_3, hours_WATERING_POMP_3, minutes_WATERING_POMP_3, duration_WATERING_POMP_3, " Sec/10");
      break;
      case 6: 
        s = "Menu"; s += "0"; s += "6"; s += " SAVE"; s += " NOW"; // "SAVE NOW"
        Menu_Save(s);
      break;
     
    } 
}
//=============================== Метод отвечающий за вывод Информационного меню (часы, дата, свет, температура)
void Menu_INFO() {
  String mdisplay0;       // Первая строка дисплея
  String mdisplay1;       // Вторая строка дисплея
  String mdisplay2;       // Третья строка дисплея
  String mdisplay3;       // Четвертая строка дисплея
  String t;
  mdisplay0 = ByteToStrFormat(hours, 2) + ":" + ByteToStrFormat(minutes, 2) + ":" + ByteToStrFormat(seconds, 2) + "  ";  //часы
  mdisplay0 += ByteToStrFormat(date, 2) + "/" + ByteToStrFormat(month, 2) + "/20" +  ByteToStrFormat(year, 2);  //дата
  mdisplay1 = (LAMP_ON == true) ? "LED_1=ON  " : "LED_1=OFF "; //Информация освещение №1
  mdisplay1 += (FITOLAMP_ON == true) ? "LED_2=ON  " : "LED_2=OFF ";//Информация освещение №2
  t = (String)temp;
  //t = t.substring(0,t.indexOf('.')+2);
  t = t.substring(0, 4);
  mdisplay2 = "\3 " + t + "\1C"; //температура 
  mdisplay2 += " " ; //Тестовая информация
  mdisplay3 = (feed_WATERING_POMP_1 == true) ? "p1=ON " : "p1=OFF ";      // состояние таймера линии полива №1
  mdisplay3 += (feed_WATERING_POMP_2 == true) ? "p2=ON " : "p2=OFF ";     // состояние таймера линии полива №2
  mdisplay3 += (feed_WATERING_POMP_3 == true) ? "p3=ON " : "p3=OFF ";     // состояние таймера линии полива №3
  PrintDisplay(mdisplay0, mdisplay1, mdisplay2, mdisplay3); // Выводим строки на дисплей
}
//============ Метод отвечающий за вывод меню настроек системы полива 
void Menu_WATERING(String mName, byte &mDays, byte &mHours, byte &mMinutes, byte &mDuration, String ed) {
  int plus_minus = 0;     // Инкремент или декремент (+1 или -1)
  String msg;             // Сообщение редактируемого параметра
  String mdisplay0;       // Первая строка дисплея
  String mdisplay1;       // Вторая строка дисплея
  String mdisplay2;       // Третья строка дисплея
  String mdisplay3;       // Четвертая строка дисплея
  //Serial.print(mName);
  switch(buttonPressed){
    case BUTTON_UP:   plus_minus = 1;  break;
    case BUTTON_DOWN: plus_minus = -1; break;
    case BUTTON_OK:
      pos++;              // Переходим к следующему изменяемому значению
      if (pos>3) pos = 0; // и по кругу
    break;    
  }
  switch (pos) {
    case 0:
      mDays += plus_minus;             // Крутим значения часов
        if (mDays > 7) mDays = 1;            // Ограничиваем значения
        if (mDays < 1) mDays = 7;            // Ограничиваем значения
         msg = "    "; msg += "<<Set"; msg += " Day"; msg += ">>"; msg += "    "; // 19
        //msg = "    <<Set Day>>     ";
    break;
    case 1:
      mHours += plus_minus;             // Крутим значения часов
      if (mHours > 23) mHours = 0;      // Ограничиваем значения
      msg = "   "; msg += "<<Set"; msg += " Hours"; msg += ">>"; msg += "    "; // 20
    break;
    case 2:
      mMinutes += plus_minus;           // Крутим значения минут
      if (mMinutes > 59) mMinutes = 0;  // Ограничиваем значения
      msg = "  "; msg += "<<Set"; msg += " Minutes"; msg += ">>"; msg += "   "; // 20
    break;
    case 3:
      mDuration += plus_minus;          // Крутим значения длительности
      //if (mDuration > 59) mDuration = 0;// Ограничиваем значения
      msg = "  "; msg += "<<Set"; msg += " "; msg += "Duration"; msg += ">>"; msg += "  "; // 20
    break;   
  }
  mdisplay0 = mName;                    // Формируем строки с информацией для вывода на дисплей
  mdisplay0 += " Day: " + ByteToStrFormat(mDays, 2) + " ";;
  mdisplay1 = "Start Time: " + ByteToStrFormat(mHours, 2) + ":" + ByteToStrFormat(mMinutes, 2) + " ";
  mdisplay2 = "Duration"; mdisplay2 += " " + ByteToStrFormat(mDuration, 2) + ed;
  mdisplay3 = msg;
  PrintDisplay(mdisplay0, mdisplay1, mdisplay2, mdisplay3); // Выводим строки на дисплей
}
//=============================== Метод отвечающий за вывод меню настроек светодтодных и фитоламп
void Menu_LAMP_FITOLAMP(String menuName, byte &mHoursON, byte &mMinutesON, byte &mHoursOFF, byte &mMinutesOFF) {
  int plus_minus = 0;     // Инкремент или декремент (+1 или -1)
  String msg;             // Сообщение редактируемого параметра
  String mdisplay0;       // Первая строка дисплея
  String mdisplay1;       // Вторая строка дисплея
  String mdisplay2;       // Третья строка дисплея
  String mdisplay3;       // Четвертая строка дисплея
  switch(buttonPressed){
    case BUTTON_UP:   plus_minus = 1;  break;
    case BUTTON_DOWN: plus_minus = -1; break;
    case BUTTON_OK:
      pos++;              // Переходим к следующему изменяемому значению
      if (pos>3) pos = 0; // и по кругу
    break;    
  }
  switch (pos) {
    case 0:
      mHoursON += plus_minus;             // Крутим значения часов
      if (mHoursON > 23) mHoursON = 0;      // Ограничиваем значения
      msg = "  "; msg += "<<Set"; msg += " Hours"; msg += "ON"; msg += ">>"; msg += "   "; // 20
    break;
    case 1:
      mMinutesON += plus_minus;           // Крутим значения минут
      if (mMinutesON > 59) mMinutesON = 0;  // Ограничиваем значения
      msg = " "; msg += "<<Set"; msg += " Minutes"; msg += "ON"; msg += ">>"; msg += "  "; // 20
    break;
    case 2:
      mHoursOFF += plus_minus;             // Крутим значения часов
      if (mHoursOFF > 23) mHoursOFF = 0;      // Ограничиваем значения
      msg = "  "; msg += "<<Set"; msg += " Hours"; msg += "OFF"; msg += ">>"; msg += "  "; // 20
    break;
    case 3:
      mMinutesOFF += plus_minus;           // Крутим значения минут
      if (mMinutesOFF > 59) mMinutesOFF = 0;  // Ограничиваем значения
      msg = " "; msg += "<<Set"; msg += " Minutes"; msg += "OFF"; msg += ">>"; msg += " "; // 20
    break;   
  }
  mdisplay0 = menuName;                 // Формируем строки с информацией для вывода на дисплей
  mdisplay1 = "ON"; mdisplay1 += " Time"; mdisplay1 += " "; mdisplay1 += ":"; mdisplay1 += " "; // 10 
  mdisplay1 += ByteToStrFormat(mHoursON, 2) + ":" + ByteToStrFormat(mMinutesON, 2) + "   "; // 8-10
  mdisplay2 = "OFF"; mdisplay2 += " Time"; mdisplay2 += ":"; mdisplay2 += " "; // 10
  mdisplay2 += ByteToStrFormat(mHoursOFF, 2) + ":" + ByteToStrFormat(mMinutesOFF, 2) + "   "; // 8-10
  mdisplay3 = msg;
  PrintDisplay(mdisplay0, mdisplay1, mdisplay2, mdisplay3); // Выводим строки на дисплей
}

//=============================== Метод отвечающий за вывод меню Сохранения настроек
void Menu_Save(String menuName) {
  String msg;             // Сообщение редактируемого параметра
  String mdisplay0;       // Первая строка дисплея
  String mdisplay1;       // Вторая строка дисплея
  String mdisplay2;       // Третья строка дисплея
  String mdisplay3;       // Четвертая строка дисплея
  switch(buttonPressed){
    case BUTTON_UP:   SaveSettings(); return; break;
    case BUTTON_DOWN: CancelSettings(); return; break;
    case BUTTON_OK: break;    
  }
  mdisplay0 = menuName;                    // Формируем строки с информацией для вывода на дисплей
  mdisplay1 = "Press \""; mdisplay1 += "+"; mdisplay1 += "\" to"; mdisplay1 += " save";
  mdisplay2 = "Press \""; mdisplay2 += "-"; mdisplay2 += "\" to"; mdisplay2 += " cancel";
  mdisplay3 = msg;
  PrintDisplay(mdisplay0, mdisplay1, mdisplay2, mdisplay3); // Выводим строки на дисплей
}

void LoadSettings() {
  // ЗАГРУЖАЕМ ЗНАЧЕНИЯ ПЕРЕМЕННЫХ ИЗ ЭНЕРГОНЕЗАВИСИМОЙ ПАМЯТИ
  //=============================== Переменные третьего таймера для LAMP 
  hours_ON1_LAMP = EEPROM.read(0x20);             // час начала первого периода
  minutes_ON1_LAMP = EEPROM.read(0x21);           // минута начала первого периода

  hours_OFF1_LAMP = EEPROM.read(0x22);            // час конца первого периода
  minutes_OFF1_LAMP = EEPROM.read(0x23);          // минута конца первого периода
  //=============================== Переменные четвертого таймера для FITOLAMP 
  hours_ON1_FITOLAMP = EEPROM.read(0x30);             // час начала первого периода
  minutes_ON1_FITOLAMP = EEPROM.read(0x31);           // минута начала первого периода

  hours_OFF1_FITOLAMP = EEPROM.read(0x32);            // час конца первого периода
  minutes_OFF1_FITOLAMP = EEPROM.read(0x33);          // минута конца первого периода
 
  //=============================== Переменные системы полива
  days_WATERING_POMP_1 = EEPROM.read(0x37);                 // день полива линия №1
  hours_WATERING_POMP_1 = EEPROM.read(0x40);               // час начала для полива линия №1
  minutes_WATERING_POMP_1 = EEPROM.read(0x41);             // минута начала для полива линия №1
  duration_WATERING_POMP_1 = EEPROM.read(0x42);            // длительность для полива линия №1 в секундах

  days_WATERING_POMP_2 = EEPROM.read(0x38);                 // день полива линия №2
  hours_WATERING_POMP_2 = EEPROM.read(0x43);               // час начала для полива линия №2
  minutes_WATERING_POMP_2 = EEPROM.read(0x44);             // минута начала для полива линия №2
  duration_WATERING_POMP_2 = EEPROM.read(0x45);            // длительность для полива линия №2 в секундах

  days_WATERING_POMP_3 = EEPROM.read(0x39);                 // день начала для полива линия №3
  hours_WATERING_POMP_3 = EEPROM.read(0x46);               // час началадля полива линия №3
  minutes_WATERING_POMP_3 = EEPROM.read(0x47);             // минута начала для полива линия №3
  duration_WATERING_POMP_3 = EEPROM.read(0x48);            // длительность для полива линия №3 в секундах
  
}

void SaveSettings() {
  //String mdisplay0;        // Первая строка дисплея
  String mdisplay1;          // Вторая строка дисплея
  String mdisplay2;          // Третья строка дисплея
  //String mdisplay3;        // Четвертая строка дисплея
  //mdisplay0 = mdisplay3 = "";
  lcd.clear();
  mdisplay1 = "   "; mdisplay1 += "-"; mdisplay1 += "="; mdisplay1 += " SAVE"; mdisplay1 += " NOW"; 
  mdisplay1 += "="; mdisplay1 += "-"; mdisplay1 += "   ";
  lcd.setCursor(0,1);
  lcd.print(mdisplay1);
  for (int i=0; i<21; i++) {            // Формируем Прогресс Бар и выводим его
    mdisplay2 = "";
    for (int j=0; j<i; j++)
      mdisplay2.concat("\2");
    lcd.setCursor(0,2);
    lcd.print(mdisplay2);
    //PrintDisplay(mdisplay0, mdisplay1, mdisplay2, mdisplay3); // Выводим строки на дисплей
    delay(250);
  }
  // СОХРАНЯЕМ ВСЕ ПЕРЕМЕННЫЕ В ЭНЕРГОНЕЗАВИСИМУЮ ПАМЯТЬ!
   //=============================== Переменные таймера для светодиодных ламп (LAMP)
  EEPROM.write(0x20, hours_ON1_LAMP);             // час начала периода
  EEPROM.write(0x21, minutes_ON1_LAMP);           // минута начала периода
  EEPROM.write(0x22, hours_OFF1_LAMP);            // час конца периода
  EEPROM.write(0x23, minutes_OFF1_LAMP);          // минута конца периода

  //=============================== Переменные таймера для светодиодных фитоламп (FITOLAMP)
  EEPROM.write(0x30, hours_ON1_FITOLAMP);             // час начала периода
  EEPROM.write(0x31, minutes_ON1_FITOLAMP);           // минута начала периода
  EEPROM.write(0x32, hours_OFF1_FITOLAMP);            // час конца периода
  EEPROM.write(0x33, minutes_OFF1_FITOLAMP);          // минута конца периода
 
  //=============================== Переменные системы полива
  EEPROM.write(0x37, days_WATERING_POMP_1);                 // день полива линия №1
  EEPROM.write(0x40, hours_WATERING_POMP_1);               // час начала полива линия №1
  EEPROM.write(0x41, minutes_WATERING_POMP_1);             // минута начала полива линия №1
  EEPROM.write(0x42, duration_WATERING_POMP_1);            // длительность полива линия №1 в секундах

  EEPROM.write(0x38, days_WATERING_POMP_2);                 // день полива линия №2
  EEPROM.write(0x43, hours_WATERING_POMP_2);               // час начала полива линия №2
  EEPROM.write(0x44, minutes_WATERING_POMP_2);             // минута начала полива линия №2
  EEPROM.write(0x45, duration_WATERING_POMP_2);            // длительность полива линия №2 в секундах

  EEPROM.write(0x39, days_WATERING_POMP_3);                 // день полива линия №3
  EEPROM.write(0x46, hours_WATERING_POMP_3);               // час начала полива линия №3
  EEPROM.write(0x47, minutes_WATERING_POMP_3);             // минута начала полива линия №3
  EEPROM.write(0x48, duration_WATERING_POMP_3);            // длительность пполива линия №3 в секундах
  
  pMenu = 0;              // После сохраниния попадаем в информационное меню
  ClearDisplay();
}

void CancelSettings() {
  //String mdisplay0;         // Первая строка дисплея
  String mdisplay1;           // Вторая строка дисплея
  String mdisplay2;          // Третья строка дисплея
  //String mdisplay3;        // Четвертая строка дисплея
  //mdisplay0 = mdisplay3 = "";
  lcd.clear();
  //mdisplay1 = "  -= Cancelling =-  ";
  mdisplay1 = "  "; mdisplay1 += "-"; mdisplay1 += "="; mdisplay1 += " Cancel"; mdisplay1 += " NOW "; 
  mdisplay1 += "="; mdisplay1 += "-"; mdisplay1 += "  ";
  lcd.setCursor(0,1);
  lcd.print(mdisplay1);
  for (int i=19; i>-1; i--) {            // Формируем Прогресс Бар и выводим его
    mdisplay2 = "";
    for (int j=0; j<i; j++) {
      mdisplay2.concat("\2");
    }
    lcd.setCursor(0,2);
    lcd.print(mdisplay2);
    //PrintDisplay(mdisplay0, mdisplay1, mdisplay2, mdisplay3); // Выводим строки на дисплей
    lcd.setCursor(i, 2);
    lcd.print(" ");
    delay(250);
  }
  pMenu = 0;              // После отмены изменений попадаем в информационное меню
  LoadSettings();         // ЗАГРУЖАЕМ ЗНАЧЕНИЯ ПЕРЕМЕННЫХ ИЗ ЭНЕРГОНЕЗАВИСИМОЙ ПАМЯТИ
  ClearDisplay();
}

//=================================== ГЛАВНЫЙ ЦИКЛ ПРОГРАММЫ ===============================
void loop() {
  timeRtc();
  timerLAMP();
  timerFITOLAMP();
  timerWATERING_POMP_1();
  timerWATERING_POMP_2();
  timerWATERING_POMP_3();
  Menu();
  detectTemperature();
  }

Пробывал подключать различные источники питания от 6-12в результат тот же -перезагрузка . Читал что питание датчиков и силовую нагрузку лучще разделять , но имеем что имеем  .К тому же паралельно я их не планирую использовать.

Radiokrot
Offline
Зарегистрирован: 30.12.2019

А что подключено к мосфетам?

bwn
Offline
Зарегистрирован: 25.08.2014

А после мосфетов что идет? Вот не верю, что затвор так просаживает.

Да и чтобы голову не ломать. Выкиньте всю программу, для начала, и просто погоняйте их digitalWrite с делеями. ИМХО.

Radiokrot
Offline
Зарегистрирован: 30.12.2019

bwn пишет:

 не верю, что затвор так просаживает.

Тоже не верю. Как затвор с резистором может так просадить?

MakcuMyM
MakcuMyM аватар
Offline
Зарегистрирован: 27.04.2017

Radiokrot пишет:

А что подключено к мосфетам?

 Помпа 5в  максимальный ток 200мА.

Тестовый скетч:

int outPin = 2;                 // цифровой вывод 8

void setup()
{
  pinMode(outPin, OUTPUT);      // настроить цифровой вывод на выход
}

void loop()
{
  digitalWrite(outPin, HIGH);   // включить вывод
   delay(10000);                 
  digitalWrite(outPin, LOW);    // выключить вывод
   delay(10000);                  
}

Без  нагрузки все работает.Подаю нагрузку ардуинка глючит.

Походу где то с разводкой платы начудил....

_https://easyeda.com/irk.nikitin/av_poliv

 

 

bwn
Offline
Зарегистрирован: 25.08.2014

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

ВН
Offline
Зарегистрирован: 25.02.2016

MakcuMyM пишет:
Помпа 5в  максимальный ток 200мА.
помпа это мотор, мотор при пуске потребляет тока  в 3-6 раз больше номинального, т.е. может вообще вышибать выход вашего бп. Цифровым тестером можно это увидеть , а можно и нет. 

подайте с бп питание 5в на ардуину через  диод. (диод уже стоит в цепи +5 которая идет от усби разъема.)

Если одного диода не хватит, можно поле него пробовать добавить электролит. 

 

MakcuMyM
MakcuMyM аватар
Offline
Зарегистрирован: 27.04.2017

bwn пишет:

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

Да их я не предусмотрел  ....

ВН пишет:

MakcuMyM пишет:
Помпа 5в  максимальный ток 200мА.
помпа это мотор, мотор при пуске потребляет тока  в 3-6 раз больше номинального, т.е. может вообще вышибать выход вашего бп. Цифровым тестером можно это увидеть , а можно и нет. 

подайте с бп питание 5в на ардуину через  диод. (диод уже стоит в цепи +5 которая идет от усби разъема.)

Если одного диода не хватит, можно поле него пробовать добавить электролит. 

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

 

PS Проблема как оказалась в диодах которые стоят в паралель  + _ на помпу выпаял их все заработало.

bwn
Offline
Зарегистрирован: 25.08.2014

MakcuMyM пишет:

PS Проблема как оказалась в диодах которые стоят в паралель  + _ на помпу выпаял их все заработало.

Так вы их в прямом включении впаяли?)))) Коротыш называется.))))

MakcuMyM
MakcuMyM аватар
Offline
Зарегистрирован: 27.04.2017

bwn пишет:

MakcuMyM пишет:

PS Проблема как оказалась в диодах которые стоят в паралель  + _ на помпу выпаял их все заработало.

Так вы их в прямом включении впаяли?)))) Коротыш называется.))))

bwn  ну  глянул как на схемах   ....так и сделал =)

 

bwn
Offline
Зарегистрирован: 25.08.2014

MakcuMyM пишет:

bwn  ну  глянул как на схемах   ....так и сделал =)

 

Боюсь, что диоды были наоборот, анодом к плюсу. Иначе эффект необъясним.

P/S Ну и варисторов конечно не было.

rkit
Offline
Зарегистрирован: 23.11.2016

MakcuMyM пишет:

bwn пишет:

MakcuMyM пишет:

PS Проблема как оказалась в диодах которые стоят в паралель  + _ на помпу выпаял их все заработало.

Так вы их в прямом включении впаяли?)))) Коротыш называется.))))

bwn  ну  глянул как на схемах   ....так и сделал =)

 

А какое отношение эта схема имеет к помпе?

ВН
Offline
Зарегистрирован: 25.02.2016

там нарисована схема для быстрого размагничивания электромагнитного замка. т.е. у нее сугубо специальное назначение.

Если бы цель была просто ограничить напряжение диод в ней не требуется.

ВН
Offline
Зарегистрирован: 25.02.2016

MakcuMyM пишет:

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

PS Проблема как оказалась в диодах которые стоят в паралель  + _ на помпу выпаял их все заработало.

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

MakcuMyM
MakcuMyM аватар
Offline
Зарегистрирован: 27.04.2017

ВН пишет:

там нарисована схема для быстрого размагничивания электромагнитного замка. т.е. у нее сугубо специальное назначение.

Если бы цель была просто ограничить напряжение диод в ней не требуется.

Любая помпа как вы  и писали выше является мотором ,поэтому я поставил диод. Схема взята 1 попавшиеся из интернета  чтоб понять что я сделал .

 

ВН пишет:

MakcuMyM пишет:

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

PS Проблема как оказалась в диодах которые стоят в паралель  + _ на помпу выпаял их все заработало.

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

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

 

P.S Не ошибается тот кто ничего не делает . 

ВН
Offline
Зарегистрирован: 25.02.2016

MakcuMyM пишет:
P.S Не ошибается тот кто ничего не делает .

это верно, и что обо всем рассказали, тоже хорошо. Успехов!

kesha47
Offline
Зарегистрирован: 26.05.2020

Здравствуйте. При попытке залить код а врдуино выдает

//================================== Функция переводит число в строку и дополняет ее ведущими нулями
String ByteToStrFormat(byte val, byte digits = 1) {
  String result;
  result = val;
  while (result.length()<digits) result = "0"+result;
  return (String)result;
}
 
ambiguous overload for 'operator=' (operand types are 'String' and 'byte {aka unsigned char}')
 
Как лечить?
 

 

Radiokrot
Offline
Зарегистрирован: 30.12.2019

Вы складываете "0" (тоесть тип данных bute) с result (это строка). Поэтому и вылазит ошибка.

rkit
Offline
Зарегистрирован: 23.11.2016

kesha47 пишет:

Функция переводит число в строку

Нет, не переводит. И в этом ошибка.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Си это не питон. Он такого не позволяет.

kesha47
Offline
Зарегистрирован: 26.05.2020

я в этом не разбираюсь. Что и куда надо вставить, чтоб залилось нормально?

Это не я придумал, а у автора поста так.