Тепличка, понимаю что непервая на форуме :)

Thorn
Offline
Зарегистрирован: 07.11.2014

Парни, в выходные испробовал контроллер для теплички - всё супер НО провода для измерения влажности почвы брал медные а электроды в грунт решил использовать длиннные сатрые сварочные, и неповреите даже на глубине в 3 см !!!! влажность почвы была 98% - оказалось разность металлов всему виной :) пришлось электроды делать из медной проволки и глубиной не более 7 см :).

И второй косяк с вольтметром, когда подключен USИ и батарея напряжение ИДЕАЛЬНО отображается но без USB ровно на 0,9....1,0 вольт БОЛЬШЕ. Как победить такой косяк, пока просто минусую но нужно понять ЛОГИКУ процесса, выручайте у кого есть идейки пожалста:)

Thorn
Offline
Зарегистрирован: 07.11.2014

Господа - подскажите, в чём дело то, про опорноя напряжение читал., его непользую несильно точность нужна. Но 0,9 вольт всеже не АЙС ... Почему-же подключение по USB в дополнение к батарее так себя ведёт...

art100
Offline
Зарегистрирован: 09.03.2014

Без схемы? А самому слабо телепатическими способностями угадать? Включаем хрустальный шар. Начинаем гудеть. Уууууууууууууууууууууууууууууууу.

 

Не. Неудается схему угадать.

Thorn
Offline
Зарегистрирован: 07.11.2014

Сначала повёлся - начал читать и на третьей схеме понял что развод :(.

Счас будет схема :)

Thorn
Offline
Зарегистрирован: 07.11.2014

Вот, скетчик для измерения:



//=====VoltMeter*
int voltInput=A2;                    //Определяем Аналоговый вход A2 для измерения напряжения
float vout=0.0;
float vin=0.0;
float R1=32140.0;                    //Resistance of R1 (22K) - see text!
float R2=11520.0;                    //Resistance of R2 (12K) - see text!
int valueVo=0;

void setup() {
  Wire.begin();
    tone(BeepPin, 5040, 1000);
  Serial.begin(9600);                                //Инициализация Serial-порта
    pinMode(voltInput,INPUT);                        //Определяем вход вольтметра
}

//========== Считывание напряжения АКБ
void voltM(){
  valueVo=analogRead(voltInput);                         //Само собой считываем Аналоговый вход (с делителя)
    vout=(valueVo*5.00)/1023.0;                          //Делим именно на 1023, а 5.00 - это опроное "стабилизированное" питание
    vin=vout/0.263857;                                   //vin=vout/(R2/(R1+R2));
      if (vin<0.09) {vin=0.0;}                           //Округляем с высокой точностью
    if (EEPROM.read(18)==1){                             //Если установен флаг необходимости контроля напряжения батареи (в меню)
    if (vin<EEPROM.read(17)){
      bLinkLed();
    tone(BeepPin, 3040, 100);}                           //Пищщим как угорелые и просим заменить батарейку!!!
  }
//    Serial.println(vin);  
}



Thorn
Offline
Зарегистрирован: 07.11.2014

А вот схемка:

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

делить на float это жестоко, да и смысл когда можно сразу в формуле нужное напряжение вписать

Thorn
Offline
Зарегистрирован: 07.11.2014

эммм непонял, я же вписал в формулу мое "опорное" пятивольтовое 5,05В если точно. По формуле вроде нет ошибок, вроде...

Thorn
Offline
Зарегистрирован: 07.11.2014

Пошагово: 

Сначала читаем аналоговый вход, он от 0 до 1023.

Далее "промежуточное" vout 

Далее получаем выходное с делителя vin

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

Мне непонятно откуда при подклчении по этой схеме и этому коду берется почти вольт сверху, если в ардуинку воткнуть USB 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

узнаешь во сколько раз уменьшается напряжение на делителе, например три. и в формуле пишешь 15 (5*3=15), а не 5 . и никакого деления на флоат дополнительного

Thorn
Offline
Зарегистрирован: 07.11.2014

Ага, а по вольтику что скжите? ПО лишнему? 

Счас сделал эксперимент, воткнул поделку свою в РАЗНЫЕ устройства с USB, начиная от прикуривателя авто :) и заканчивая ноубуками и зарядками. Результат суко плачевный. напряжение МЕНЯЕТСЯ (замеряемое) от +1,2В до -0,3В !!!! Занижение было при подключении к стааарому ноуту а завышение ко всем зарядкам. Видимо там чуток побольше vcc (на usb имеется ввиду).

Так мне придется  пересчитывать формулу всёже, так как работать то приблуда будет ВСЕГДА без подключенного usb-шнурка, обновляться часто непланирую :)

Жалка ардуинка уже на термоклей посажена в коробочку - может нужно подавать СТАБИЛИЗИРОВАННЫЕ +5,05В не на 30-ую ножку VIN которая а на 27 ножку (где чЁткие) только 5В подаются?

 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

что тут сказать. проблема с питанием

Thorn
Offline
Зарегистрирован: 07.11.2014

Думаю надо подъитожить и выложить окончательные фотки и видео :) ну и сам скетчик.

Вот кодик:









#include <EEPROM.h>                  //Подключаем библиотеку для работы с энергонезависимой памятью
#include <Wire.h>                    //Подключаем библиотеку для использования I2C                                     
#include <OneWire.h>                 //Подключаем библиотеку для температурного датчика DS18B20
#include <DHT.h>                     //Подключаем библиотеку для датчика влажности и температуры

//=====Tft*
#include <Adafruit_GFX.h>            //Core graphics library
#include <Adafruit_ST7735.h>         //Hardware-specific library
#include <SPI.h>
#define sclk 13
#define mosi 11
#define cs   8
#define dc   7
#define rst  9                       //You can also connect this to the Arduino reset
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, mosi, sclk, rst);

//=====Button PS*
#define axis_X A0                    //Ось Х подключена к Analog 0
#define axis_Y A1                    //Ось Y подключена к Analog 1
#define axis_Z 6                     //Ось Z (кнопка джойстика) подключена к Digital 6
#define pushLED 10                   //Индикаторный светик нахожения в меню и нажатия кнопки (мигает при авариях)
unsigned  long pressTime=0;          //Запоминаем, когда произошло нажатие кнопки
bool prevButtonState;
int val_X, val_Y, val_Z=0;           //Переменные для хранения значений осей
byte buttonState=0;                  //Флаг состояния нажатия кнопки
byte butLongState=0;                 //Флаг "удержания" кнопки, longClick

//=====Blink led*
#define BeepPin 12                   //Пищалка

//=====Moisture*
#define moistIn A2                   //Определяем Аналоговый вход А2 датчика влажности почвы (вилочка такая)
int moistAO=EEPROM.read(9);          //Переменная влажности в % (итоговая), приравниваем, чтобы при старте неполивать :(
int moistTmp=0;                      //Переменная влажности в "попугаях" 0-1023 (промежуточная)
byte autoIrrig=0;                    //Флаг состояния автополива(необходимо поднять при включении помпы)
byte tIrrig=0;                       //Переменная интервала влючения датчика влажности грунта

//=====VoltMeter*
int voltInput=A3;                    //Определяем Аналоговый вход A3 для измерения напряжения
float vout=0.0;
float vin=0.0;
float R1=32140.0;                    //Номинал первого резистора, тот которй ПОСЛЕДОВАТЕЛЬНО в цепи измерения
float R2=12810.0;                    //А тут номинал второго резистора, что ПАРАЛЕЛЬНО измерению и к земле
int valueVo=0;

//=====Led_Relay*
#define OUT0 2                       //Используем цифровой ПОРТ 2 включения датчика измернеия влажности почвы
#define OUT1 3                       //Используем цифровой ПОРТ 3 помпочки автополива
//#define OUT2 A6                      //Используем аналоговый ПОРТ A6 включения реле вентиляции теплички

//=====Humidity*
#define dhtPin 5                    //Определяем цифровой ПОРТ 5 датчика влажности воздуха в тепличке (хреновая)
#define dhtType DHT11               //Ранее был А6 (он РАСПАЯН и обрезан, красный короткий)
DHT dht(dhtPin, dhtType);
float hmdt;

//=====Termo_Sensor*
int tempPin=4;                      //Определяем порт шины OneWire (IC) для температурного датчика DS18B20                               
OneWire ds(tempPin);                 //Создаем объект для работы с термометром
byte flagDallas=0;                   //Флаг для обработки показаний с датчиков Dallas
byte data[12];
byte addr1[8]={0x28, 0x33, 0x4B, 0xEA, 0x05, 0x00, 0x00, 0x54};     //адрес датчика DS18B20_в парничке
byte addr2[8]={0x28, 0xFF, 0xB5, 0x24, 0x54, 0x14, 0x01, 0xC7};     //адрес датчика DS18B20_на улице
unsigned int raw;                    //Если экранированный кабель, можно подключать до 32 термо-датчиков DS18B20
float temp[2];                       //Температура на уличке \ в парничке

//=====Rtc_Clock*
#define DS1307_I2C_ADDRESS 0x68
byte seconds, minutes, hours, day, date, month, year;
byte decToBcd (byte val){return((val/10*16)+(val%10));}

//=====Timer*
byte IrrigStat=0;                   //Флаг полива, если включена, то 1 конечное-жеж
byte TempStat=0;                    //Флаг вентиляции, если включена, то 1 конечное-жеж
byte isIrrigt=0;                    //Флаг для обработки необходимости включить автополив (по таймеру менюшному)
byte isTemp=0;                      //Флаг для обработки необходимости включить вентиляцию (по томуже таймеру)
byte isNight=0;                     //Если включаем на ночь, т.е. начальное время больше конечного

//=====Menu*
byte winMe;                         //Номер экрана меню
byte setHorClockOn;                 //Часы включения Таймера
byte setMinClockOn;                 //Минуты включения Таймера
byte setHorClockOff;                //Часы вЫключения Таймера
byte setMinClockOff;                //Минуты вЫключения Таймера

byte setTemptGist;                  //Гистерезис температур (по 1/2 в каждую сторону)
byte setTemptIn;                    //Максимальная температура воздуха в парничке для вентиляции
byte setTemptInOnOff;               //Флаг Включения/Выключения НЕОЬХОДИМОСТИ "контроля" температуры воздуха в тепличке

byte setMoistIn;                    //Максимальная влажность воздуха в тепличке для вентиляции
byte setMoistInOnOff;               //Флаг Включения/Выключения НЕОЬХОДИМОСТИ контроля влажности воздуха

byte setSoiltIn;                    //Минимальная влажность почвы в парничке для полива
byte setSoiltTime;                  //Интервал работы датчика влажности грунта
byte setSoiltIrrig;                 //Интервал работы помпочки автополива
byte setSoiltInOnOff;               //Флаг Включения/Выключения НЕОЬХОДИМОСТИ контроля влажности грунта

byte setVoltCt;                     //Минимальная напряжение на батарее для замены
byte setVoltCtOnOff;                //Флаг Включения/Выключения НЕОЬХОДИМОСТИ контрорля напряжения батареечки ценной

//=====Delays*
unsigned long prvMlsTm=0;           //Предыдущее показание миллисекунд для обновления показания часов
unsigned long prvMlsVo=0;           //Предыдущее показание обновления показания вольтметра
unsigned long prvMlsMoist=0;        //Предыдущее показание обновления показания влажности почвы
unsigned long prvMlsIrrig=0;        //Предыдущее показание обновления показания автополива
unsigned long prvMlsTemp=0;         //Предыдущее показание обновления температур
unsigned long prvMlsTimer=0;        //Предыдущее показание обновления таймера
unsigned long prvMlsbLink=0;        //Предыдущее показание миллисекунд для обновления "blink led"
unsigned long tzad=millis();        //Переменная задержки (пока для ds18b20, ds.write)

unsigned long zadM[4];              //Массив для задержек
const long zadTime[]={100,500,750,1000,2000,3000,5000,10000,60000};

const char menuTxt[6][17]={"set Timer Soil >","set Timer Temp >",
                           "set Irrigation >","set TermoRele >>",
                           "set VoltControl>","set Clock >>>>>>"};      //Массив с наименованиями для экрана

void setup(){
  Wire.begin();
    tone(BeepPin, 5040, 1000);
  Serial.begin(9600);                                //Инициализация Serial-порта
  dht.begin();                                       //Инициализация датчика влажности DHT-11
    pinMode(voltInput,INPUT);                        //Определяем вход вольтметра
    pinMode(moistIn, INPUT);                         //Определяем вход измерителя влажности почвы
    pinMode(axis_Z, INPUT);                          //Задаем как вход нажатия кнопки джойстика
    digitalWrite(axis_Z,HIGH);                       //ПОдтягиваем внутреннее сопротивнление ардуинки
    pinMode(pushLED,OUTPUT);                         //Определяем светик нажатия и нахождения в меню
    pinMode(OUT0,OUTPUT);                            //Определяем инверсные выходы реле датчика влажности почвы
    pinMode(OUT1,OUTPUT);                            //Определяем инверсные выходы реле помпы автополива
//    pinMode(bLink,OUTPUT);
    digitalWrite(OUT0,HIGH);                         //Определяем инверсный выход в HIGH реле сенсора почвы
    digitalWrite(OUT1,HIGH);                         //Определяем инверсный выход в HIGH реле помпы полива
    digitalWrite(pushLED,LOW);                       //Определяем инверсный выход в HIGH реле помпы полива
//    digitalWrite(bLink,HIGH);
    tft.initR(INITR_BLACKTAB);                       //Initialize a ST7735S chip, black tab
    tft.fillScreen(ST7735_BLACK);                    //Clear screen
}  

//========== Обработка нажатия кнопки и джойстика PS
void buttonPS(){
  val_X=analogRead(axis_X);                         //Считываем аналоговое значение оси Х
  val_Y=analogRead(axis_Y);                         //Считываем аналоговое значение оси Y
  val_Z=digitalRead(axis_Z);                        //Считываем цифровое значение оси Z (кнопка)
  val_Z=val_Z^1;                                    //Инвертируем значение
bool buttonState;                                   //Читаем кнопку
buttonState=(digitalRead(axis_Z)==LOW);
    if (buttonState==HIGH){
      digitalWrite(pushLED,HIGH);
  } else {
      digitalWrite(pushLED,LOW);}
    if(!prevButtonState && buttonState){            //Была не нажата, стала нажата
     pressTime=millis();}
    if(!buttonState)pressTime=0;                    //При отпускании кнопки - сразу останавливаем осчет
    if(pressTime&&(millis()-pressTime>1000)){       //Если с момента нажатия прошло более 1- секунды
    butLongState=1;                                 //Поднимаем флаг "удержания" кнопки
    tone(BeepPin, 240, 100);                        //Попискиваем при этом
    pressTime=0;}                                   //Останавливаем отсчет что-бы не переключить несколько раз по одному нажатию 
      prevButtonState=buttonState;                  //Запомнили "прошлое" состояние кнопки
}
 
//========== Обработка Входа в Меню
void setUp(){
    if (butLongState==1){                            //ВХОД В МЕНЮ и проверка блокировки от возврата. Принимаем код клавиши
    digitalWrite(OUT0,HIGH); digitalWrite(OUT1,HIGH);//Отключаем датчик измерения влажности почвы и работу помпы !!!!
        menu();}                                     //Если флаг longClick идем в меню
}
                           
//=========== Обработка Меню, выбор экрана
void menu(){
  tft.fillScreen(ST7735_BLUE);                                  //Clear screen
  tft.setTextSize(1);
  tft.setTextColor(ST7735_WHITE, ST7735_BLUE);
  byte pos=0;
  while(1){                                                     //Бесконечный цикл
//      bLinkLed();
      butLongState=0;
      buttonPS();
      digitalWrite(pushLED,HIGH);
    tft.setCursor(5,55);
    tft.print(pos+1);                                           //Печатаем номер
    tft.print(". ");
    tft.print(menuTxt[pos]);                                    //Печатаем название
      if (val_Y>923 && pos<5) {pos++;}
  else if (pos==5 && val_Y>923) {pos=0;}
      if (val_Y<123 && pos>0) {pos--;}                          //Уменьшить/увеличить позицию окна меню
  else if (pos==0 && val_Y<123) {pos=5;}                        //Уменьшить/увеличить (циклично)      
      winMe=pos;                                                //Переменная номера таймера
    if (butLongState==1 && pos==0) setOnOff();        //"set Timer Soil >" 0
    if (butLongState==1 && pos==1) setOnOff();        //"set Timer Temp >" 1
    if (butLongState==1 && pos==2) setIrrigation();   //"set Irrigation >" 2
    if (butLongState==1 && pos==3) setTermoRele();    //"set TermoRele >>" 3
    if (butLongState==1 && pos==4) setVoltControl();  //"set VoltControl>" 4
    if (butLongState==1 && pos==5) setClock();        //"set Clock >>>>>>" 5
    if (val_X>923){                                              //Выход из меню с проверкой и установкой блокировки от возврата       
      tft.fillScreen(ST7735_BLACK);                              //Clear screen
    tone(BeepPin, 540, 200); break;} 
  }
} 

//=========== Обработка Меню, параметры и настройка таймеров
void setOnOff(){
  byte pos=0;   
  setHorClockOn=  EEPROM.read(winMe*4+1);                //Считываем записанные значения таймеров
  setMinClockOn=  EEPROM.read(winMe*4+2);                //Адрес определяется как номер таймера*4 + четыре ячейки
  setHorClockOff= EEPROM.read(winMe*4+3);
  setMinClockOff= EEPROM.read(winMe*4+4);
    tft.fillScreen(ST7735_RED);                          //Clear screen
  while(1){                                              //Бесконечный цикл
//    while(buttonState==LOW){
      butLongState=0;                                    //Обнуляем флаг longClick
      buttonPS();
      digitalWrite(pushLED,HIGH);
      if (millis()-prvMlsTimer>zadTime[7]){                 //Проверяем интервал для обновления 
     prvMlsTimer=millis();
      tft.setTextSize(1);
    tft.setCursor(45,40);
    tft.setTextColor(ST7735_YELLOW,ST7735_RED);
    tft.print("  On   Off"); 
    tft.setCursor(5,150);
    tft.setTextColor(ST7735_GREEN, ST7735_RED);
    tft.print("=== push to save ===");}
    tft.setCursor(5,55);
    tft.print(winMe+1,DEC);                                //Печатаем номер программы таймера
    tft.print("|");
    tft.print(pos/3,DEC);                                  //Печатаем позицию настройки параметра (замена blink)
    tft.print(" ->");  
    tft.setCursor(45,55);                                  //Выводим инфу о часах и минутах
     if (setHorClockOn<10) tft.print("0");
    tft.print(setHorClockOn,DEC);
    tft.print(":");
     if (setMinClockOn<10) tft.print("0"); 
    tft.print(setMinClockOn,DEC);  
    tft.print(" ");     
     if (setHorClockOff<10) tft.print("0");
    tft.print(setHorClockOff,DEC);
    tft.print(":");
     if (setMinClockOff<10) tft.print("0");
    tft.print(setMinClockOff,DEC); 

    tft.setCursor(pos,0);                                   //Устанавливаем курсор согласно позиции

    if (val_X>923 && pos==3){                                //Выход из подменю без сохранения       
      tft.fillScreen(ST7735_BLACK);                          //Clear screen
    return; winMe=pos;} 

    if (pos<3) pos=3;
    if (val_X<123 && pos<11) pos += 3;                       //Крутим позицию право-лево
    else if (val_X>923 && pos>3) pos -= 3;

    else if (pos==3 && val_Y>1020) setHorClockOn++;          //Крутим значения
    else if (pos==3 && val_Y<10) setHorClockOn--;
    else if (pos==6 && val_Y>1020) setMinClockOn++;
    else if (pos==6 && val_Y<10) setMinClockOn--;    
    else if (pos==9 && val_Y>1020) setHorClockOff++;
    else if (pos==9 && val_Y<10) setHorClockOff--;    
    else if (pos==12 && val_Y>1020) setMinClockOff++;
    else if (pos==12 && val_Y<10) setMinClockOff--; 
    
    if (setHorClockOn>23) setHorClockOn=0;                   //Ограничиваем значения
    else if (setMinClockOn>59) setMinClockOn=0;
    else if (setHorClockOff>23) setHorClockOff=0;
    else if (setMinClockOff>59) setMinClockOff=0;

    if (butLongState==1){                                    //Выход из меню с проверкой и установкой блокировки от возврата
    tft.fillScreen(ST7735_BLACK);                            //Clear screen
    break;} 
}                                                            //Конец цикла
   tft.fillScreen(ST7735_BLACK);                             //Clear screen
   EEPROM.write(winMe*4+1, setHorClockOn);                   //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, setMinClockOn); 
   EEPROM.write(winMe*4+3, setHorClockOff);
   EEPROM.write(winMe*4+4, setMinClockOff);
   
   tft.setCursor(25,105);
   tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
   tft.setTextSize(1);
   tft.print("== Saved =="); tone(BeepPin, 3040, 500); 
   delay(zadTime[4]);
}

//=========== Обработка Меню, параметры и настройка автополива (влажность грунта)
void setIrrigation(){
  byte pos=0;   
  setSoiltIn=       EEPROM.read(winMe*4+1);              //Считываем записанные значения 
  setSoiltTime=     EEPROM.read(winMe*4+2);              //Адрес определяется как номер *2 + две ячейки
  setSoiltIrrig=    EEPROM.read(winMe*4+3);
  setSoiltInOnOff=  EEPROM.read(winMe*4+4);
    tft.fillScreen(ST7735_RED);                          //Clear screen
  while(1){                                              //Бесконечный цикл
      butLongState=0;                                    //Обнуляем флаг longClick
      buttonPS();
      digitalWrite(pushLED,HIGH);
      tft.setTextSize(1);
      if (millis()-prvMlsTimer>zadTime[7]){                 //Проверяем интервал для обновления 
     prvMlsTimer=millis();
    tft.setCursor(45,40);
    tft.setTextColor(ST7735_YELLOW,ST7735_RED);
    tft.print("Soil%  Tsens"); 
      tft.setCursor(45,70);
    tft.setTextColor(ST7735_YELLOW,ST7735_RED);
    tft.print("Tpomp  On/Of"); 
    tft.setCursor(5,150);
    tft.setTextColor(ST7735_GREEN, ST7735_RED);
    tft.print("=== push to save ===");}
      tft.setCursor(5,55);
    tft.print(winMe+1,DEC);                                //Печатаем номер программы 
    tft.print("|");
    tft.print(pos/3,DEC);                                  //Печатаем позицию настройки параметра (замена blink)
    tft.print(" ->");  
    tft.setCursor(45,55);                                  //Выводим инфу 
     if (setSoiltIn<10) tft.print("0");
    tft.print(setSoiltIn,DEC);
    tft.print(" : ");
     if (setSoiltTime<10) tft.print("0");
    tft.print(setSoiltTime,DEC);
    tft.setCursor(45,85);
     if (setSoiltIrrig<10) tft.print("0");
    tft.print(setSoiltIrrig,DEC);
    tft.print(" : ");
    tft.print(setSoiltInOnOff,DEC);  
    
    tft.setCursor(pos,0);                                   //Устанавливаем курсор согласно позиции

    if (val_X>923 && pos==3){                                //Выход из подменю без сохранения       
      tft.fillScreen(ST7735_BLACK);                          //Clear screen
    return;} 

    if (pos<3) pos=3;
    if (val_X<123 && pos<11) pos += 3;                       //Крутим позицию право-лево
    else if (val_X>923 && pos>3) pos -= 3;

    else if (pos==3 && val_Y>1020) setSoiltIn++;            //Крутим значения
    else if (pos==3 && val_Y<10) setSoiltIn--;
    else if (pos==6 && val_Y>1020) setSoiltTime++;
    else if (pos==6 && val_Y<10) setSoiltTime--; 
    else if (pos==9 && val_Y>1020) setSoiltIrrig++;
    else if (pos==9 && val_Y<10) setSoiltIrrig--; 
    else if (pos==12 && val_Y>1020) setSoiltInOnOff++;
    else if (pos==12 && val_Y<10) setSoiltInOnOff--;    
    
    if (setSoiltIn>99) setSoiltIn=0;                        //Ограничиваем значения
    if (setSoiltTime>59) setSoiltTime=0;
    if (setSoiltIrrig>19) setSoiltIrrig=0;
    if (setSoiltInOnOff>1) setSoiltInOnOff=0;

    if (butLongState==1){                                    //Выход из меню с проверкой и установкой блокировки от возврата
    tft.fillScreen(ST7735_BLACK);                            //Clear screen
    break;} 
}                                                            //Конец цикла
   tft.fillScreen(ST7735_BLACK);                             //Clear screen
   EEPROM.write(winMe*4+1, setSoiltIn);                      //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, setSoiltTime);
   EEPROM.write(winMe*4+3, setSoiltIrrig);
   EEPROM.write(winMe*4+4, setSoiltInOnOff); 
   
   tft.setCursor(25,105);
   tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
   tft.setTextSize(1);
   tft.print("== Saved =="); tone(BeepPin, 3040, 500);
   delay(zadTime[4]);
}

//=========== Обработка Меню, параметры и настройка термореле (вентиляция)
void setTermoRele(){
  byte pos=0;   
  setTemptIn=       EEPROM.read(winMe*4+1);              //Считываем записанные значения 
  setTemptGist=     EEPROM.read(winMe*4+2);              //Адрес определяется как номер *4 + четыре ячейки
  setTemptInOnOff=  EEPROM.read(winMe*4+3);
    tft.fillScreen(ST7735_RED);                          //Clear screen
  while(1){                                              //Бесконечный цикл
//    while(buttonState==LOW){
      butLongState=0;                                    //Обнуляем флаг longClick
      buttonPS();
      digitalWrite(pushLED,HIGH);
    if (millis()-prvMlsTimer>zadTime[7]){                 //Проверяем интервал для обновления 
     prvMlsTimer=millis();
      tft.setTextSize(1);
    tft.setCursor(45,40);
    tft.setTextColor(ST7735_YELLOW,ST7735_RED);
    tft.print("Temp Gst On/f"); 
    tft.setCursor(5,150);
    tft.setTextColor(ST7735_GREEN, ST7735_RED);
    tft.print("=== push to save ===");}
    tft.setCursor(5,55);
    tft.print(winMe+1,DEC);                                //Печатаем номер программы 
    tft.print("|");
    tft.print(pos/3,DEC);                                  //Печатаем позицию настройки параметра (замена blink)
    tft.print(" ->");  
    tft.setCursor(45,55);                                  //Выводим инфу о часах и минутах
     if (setTemptIn<10) tft.print("0");
    tft.print(setTemptIn,DEC);
    tft.print("  : ");
    tft.print(setTemptGist,DEC);
    tft.print("  : ");
    tft.print(setTemptInOnOff,DEC);  
    
    tft.setCursor(pos,0);                                   //Устанавливаем курсор согласно позиции

    if (val_X>923 && pos==3){                                //Выход из подменю без сохранения       
      tft.fillScreen(ST7735_BLACK);                          //Clear screen
    return;} 

    if (pos<3) pos=3;
    if (val_X<123 && pos<8) pos += 3;                       //Крутим позицию право-лево
    else if (val_X>923 && pos>3) pos -= 3;

    else if (pos==3 && val_Y>1020) setTemptIn++;            //Крутим значения
    else if (pos==3 && val_Y<10) setTemptIn--;
    else if (pos==6 && val_Y>1020) setTemptGist++;
    else if (pos==6 && val_Y<10) setTemptGist--;    
    else if (pos==9 && val_Y>1020) setTemptInOnOff++;
    else if (pos==9 && val_Y<10) setTemptInOnOff--;  
    
    if (setTemptIn>50) setTemptIn=0;                        //Ограничиваем значения
    if (setTemptGist>9) setTemptGist=0;
    if (setTemptInOnOff>1) setTemptInOnOff=0;

    if (butLongState==1){                                    //Выход из меню с проверкой и установкой блокировки от возврата
    tft.fillScreen(ST7735_BLACK);                            //Clear screen
    break;} 
}                                                            //Конец цикла
   tft.fillScreen(ST7735_BLACK);                             //Clear screen
   EEPROM.write(winMe*4+1, setTemptIn);                      //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, setTemptGist); 
   EEPROM.write(winMe*4+3, setTemptInOnOff);
     
   tft.setCursor(25,105);
   tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
   tft.setTextSize(1);
   tft.print("== Saved =="); tone(BeepPin, 3040, 500);
   delay(zadTime[4]);
}

//=========== Обработка Меню, параметры и настройка ВольтКонтроля (замена батареи)
void setVoltControl(){
  byte pos=0;   
  setVoltCt=          EEPROM.read(winMe*4+1);              //Считываем записанные значения 
  setVoltCtOnOff=     EEPROM.read(winMe*4+2);              //Адрес определяется как номер *4 + четыре ячейки
     tft.fillScreen(ST7735_RED);                          //Clear screen
  while(1){                                              //Бесконечный цикл
//    while(buttonState==LOW){
      butLongState=0;                                    //Обнуляем флаг longClick
      buttonPS();
      digitalWrite(pushLED,HIGH);
    if (millis()-prvMlsTimer>zadTime[7]){                 //Проверяем интервал для обновления 
     prvMlsTimer=millis();
      tft.setTextSize(1);
    tft.setCursor(40,40);
    tft.setTextColor(ST7735_YELLOW,ST7735_RED);
    tft.print("volt  On/Off"); 
    tft.setCursor(5,150);
    tft.setTextColor(ST7735_GREEN, ST7735_RED);
    tft.print("=== push to save ===");}
    tft.setCursor(5,55);
    tft.print(winMe+1,DEC);                                //Печатаем номер программы 
    tft.print("|");
    tft.print(pos/3,DEC);                                  //Печатаем позицию настройки параметра (замена blink)
    tft.print(" ->");  
    tft.setCursor(45,55);                                  //Выводим инфу о часах и минутах
     if (setVoltCt<10) tft.print("0");
    tft.print(setVoltCt,DEC);
    tft.print("  :  ");
    tft.print(setVoltCtOnOff,DEC);
    
    tft.setCursor(pos,0);                                   //Устанавливаем курсор согласно позиции

    if (val_X>923 && pos==3){                                //Выход из подменю без сохранения       
      tft.fillScreen(ST7735_BLACK);                          //Clear screen
    return;} 

    if (pos<3) pos=3;
    if (val_X<123 && pos<5) pos += 3;                       //Крутим позицию право-лево
    else if (val_X>923 && pos>3) pos -= 3;

    else if (pos==3 && val_Y>1020) setVoltCt++;            //Крутим значения
    else if (pos==3 && val_Y<10) setVoltCt--;
    else if (pos==6 && val_Y>1020) setVoltCtOnOff++;
    else if (pos==6 && val_Y<10) setVoltCtOnOff--;    
    
    if (setVoltCt>15) setVoltCt=7;                        //Ограничиваем значения
    else if (setVoltCt<7) setVoltCt=15;
    if (setVoltCtOnOff>1) setVoltCtOnOff=0;

    if (butLongState==1){                                    //Выход из меню с проверкой и установкой блокировки от возврата
    tft.fillScreen(ST7735_BLACK);                            //Clear screen
    break;} 
}                                                            //Конец цикла
   tft.fillScreen(ST7735_BLACK);                             //Clear screen
   EEPROM.write(winMe*4+1, setVoltCt);                      //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, setVoltCtOnOff); 
     
   tft.setCursor(25,105);
   tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
   tft.setTextSize(1);
   tft.print("== Saved =="); tone(BeepPin, 3040, 500);
   delay(zadTime[4]);
}

//=========== Обработка Меню, параметры установки времени
void setClock(){
  byte pos=0;
    tft.fillScreen(ST7735_RED);                            //Clear screen
  while(1){                                              //Бесконечный цикл
//    while(buttonState==LOW){
      butLongState=0;                                    //Обнуляем флаг longClick
      buttonPS();
      digitalWrite(pushLED,HIGH);
    if (millis()-prvMlsTimer>zadTime[7]){                 //Проверяем интервал для обновления 
     prvMlsTimer=millis();
      tft.setTextSize(1);
    tft.setCursor(5,150);
    tft.setTextColor(ST7735_GREEN, ST7735_RED);
    tft.print("=== push to save ===");}
    tft.setCursor(5,55);
    tft.print(winMe+1,DEC);                                //Печатаем номер программы 
    tft.print("|");
    tft.print(pos/3,DEC);                                  //Печатаем позицию настройки параметра (замена blink)
    tft.print(" ->");  
    tft.setCursor(45,55); 
     if (hours<10) tft.print("0");
    tft.print(hours);
    tft.print(":");
     if (minutes<10) tft.print("0"); 
    tft.print(minutes);
      tft.print(":");
     if (seconds<10) tft.print("0"); 
    tft.print(seconds);  
    tft.setCursor(5,75);
      if (day<10) tft.print("0");
    tft.print(day);
      tft.print(" | ");
      if (date<10) tft.print("0");
    tft.print(date);
    tft.print("/");
     if (month<10) tft.print("0");
    tft.print(month);
    tft.print("/");
     if (year<10) tft.print("0");
    tft.print(year);
    tft.setCursor(pos,0);
    
    if (val_X>923 && pos==3){                                //Выход из подменю без сохранения       
      tft.fillScreen(ST7735_BLACK);                          //Clear screen
    return;}
    
    if (pos<3) pos=3;
    if (val_X<123 && pos<21) pos += 3;                       //Крутим позицию право-лево
    else if (val_X>923 && pos>3) pos -= 3;
    
    else if (pos==3 && val_Y>1020) hours++;                   //Крутим значения
    else if (pos==3 && val_Y<10) hours--;
    else if (pos==6 && val_Y>1020) minutes++;
    else if (pos==6 && val_Y<10) minutes--;
    else if (pos==9 && val_Y>1020) seconds++;
    else if (pos==9 && val_Y<10) seconds--;
    else if (pos==12 && val_Y>1020) day++;
    else if (pos==12 && val_Y<10) day--;     
    else if (pos==15 && val_Y>1020) date++;
    else if (pos==15 && val_Y<10) date--;    
    else if (pos==18 && val_Y>1020) month++;
    else if (pos==18 && val_Y<10) month--;    
    else if (pos==21 && val_Y>1020) year++;
    else if (pos==21 && val_Y<10) year--;  
    
    if (hours>23) hours=0;
    else if (minutes>59) minutes=0;
    else if (seconds>59) seconds=0;
    else if (day>7) day=1;
    else if (date>31) date=1;
    else if (month>12) month=1;
    else if (year>99) year=0;
        
    if (butLongState==1){                                    //Выход из меню с проверкой и установкой блокировки от возврата
    tft.fillScreen(ST7735_BLACK);                            //Clear screen
    break;}
}
   tft.fillScreen(ST7735_BLACK);   
   setRtc(seconds, minutes, hours, day, date, month, year); 
   tft.setCursor(25,105);
   tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
   tft.setTextSize(1);
   tft.print("== Saved =="); tone(BeepPin, 3040, 500);
   delay(zadTime[4]);
}

//========== Обработка таймера включения датчика Влажности почвы, измерение и автополив
void irrigation(){
  if (EEPROM.read(12)==1){                      //Если установен флаг необходимости проверки датчика влажности почвы (в меню)
  if (seconds<EEPROM.read(10)){                 //Сверяем значение текущего времени с интервалом вклчюения датчика
    digitalWrite(OUT0,LOW); tIrrig=1;}          //Включаем реле датчика измерения влажности почвы, поднимаем флаг интервала
  else if (seconds>EEPROM.read(10)){            //Ежели время непришло, реле разомкнуто и некорродирует :) флаг низкий
    digitalWrite(OUT0,HIGH); tIrrig=0;}

//========== Считывание Влажности почвы
  if (tIrrig==1){                                        //Если датчик влажности включен
  if (millis()-prvMlsIrrig>zadTime[1]){                  //Проверяем интервал для обновления 
     prvMlsIrrig=millis();
  moistTmp=analogRead(moistIn);                          //Считываем показатели влажности почвы
  moistAO=map(moistTmp,0,1023,99.9,0);}                  //Преобразуя в процентное соотношение :)
  }
}
//========== Обработка помпы автополива
    if (IrrigStat==1){                                    //Если таймер необходимости автополива в меню (день) задан и
    if (moistAO<EEPROM.read(9)&&tIrrig==0){autoIrrig=1;}  //Если показания влажности почвы МЕНЬШЕ сохраненных 
//  tone(BeepPin, 9040, 100);                             //И датчик влажности отключен, поднимаем флаг необходимости полива
    else if (moistAO>EEPROM.read(9)){autoIrrig=0;}        //Ежели показания ВЫШЕ то ничего неделаем и флаг держим низким
    
    if (autoIrrig==1){                                    //Если флажок необходимости автополива поднят
  digitalWrite(OUT1,LOW); //tone(BeepPin, 5040, 800);     //Включаем помпочку на время из заданного в меню и попискиваем
      if (millis()-prvMlsIrrig>EEPROM.read(11)*1000){     //Проверяем интервал для обновления 
     prvMlsIrrig=millis();
     autoIrrig=0; moistAO=EEPROM.read(9);}}
    if (autoIrrig==0){
  digitalWrite(OUT1,HIGH);}
  }
}

//========== Считывание Влажности воздуха
void humiDity(){
  hmdt=(dht.readHumidity()+11);                           //Reading temperature or humidity takes about 250 milliseconds!
}

//========== Считывание напряжения АКБ
void voltM(){
  valueVo=analogRead(voltInput);                         //Само собой считываем Аналоговый вход (с делителя)
    vout=(valueVo*5.00)/1023.0;                          //Делим именно на 1023, а 5.00 - это опроное "стабилизированное" питание
    vin=vout/0.284983;                                   //vin=vout/(R2/(R1+R2));
    if (vin<0.09) {vin=0.0;}                             //Округляем с высокой точностью
    if (EEPROM.read(18)==1){                             //Если установен флаг необходимости контроля напряжения батареи (в меню)
    if (vin<EEPROM.read(17)){
      bLinkLed();
    tone(BeepPin, 3040, 100);}                           //Пищщим как угорелые и просим заменить батарейку!!!
  }
//    Serial.println(vin);  
}

//=========== Считывание температур
void dallas(){
  ds.reset();
  ds.write(0xCC);                                      //Команда инициации  
  ds.write(0x44);                                      //Start conversion, with parasite power on at the end
    tzad=millis()+750; flagDallas=1;}
  float DS18B20(byte *adres){
  ds.reset();
  ds.select(adres);
  ds.write(0xBE);                                      //Read Scratchpad
    for (byte i=0; i<9; i++) data[i]=ds.read();        //We need 9 bytes
    int raw=(data[1]<<8) | data[0];                    //Переводим в температуру   
    float celsius=(float)raw/16.0;                     //Для ds18b20 делим на "16", для ds18s20 на "2"
    return celsius;
}

//=========== Обработка Термо-Реле
void tempDallas(){
      if (tzad<millis()&&flagDallas==1){  
    temp[0]=DS18B20(addr1);
    temp[1]=DS18B20(addr2);
    prvMlsTemp=millis();
      flagDallas=0;}
//  if (TempStat==1){                                          //Если таймер необходимости вентиляции в меню (день) задан и
//      if (temp[1]>EEPROM.read(13)-(EEPROM.read(14)/2)){      //Если температура в тепличке выше сохранённой в ЕПРОМ и гистерезис пополам
//    digitalWrite(OUT2,LOW);}                                 //Реле вентиляции включается
//      else if (temp[1]<EEPROM.read(13)+(EEPROM.read(14)/2)){ //Если температура в тепличке ниже сохранённой в ЕПРОМ и гистерезис пополам
//    digitalWrite(OUT2,HIGH);}                                //Реле вентиляции включается
//  }
}

//=========== Обработка установки RTC часов
void setRtc(byte seconds, byte minutes, byte hours, byte day, byte date, byte month, byte year){
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0x00);
  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(DS1307_I2C_ADDRESS);       //104 is DS3231 device address
  Wire.write(0x00);                                 //Start at register 0
  Wire.endTransmission();
  Wire.requestFrom(DS1307_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));
  }
}

//=========== Обработка Таймеров
void timer(){
  int fulMin=hours*60+minutes;                                 //Переводим часы + минуты к полным минутам
  int fulMinOn1=    EEPROM.read(1)*60+EEPROM.read(2);          //Переводим часы + минуты включения Soil реле к полным минутам
  int fulMinOff1=   EEPROM.read(3)*60+EEPROM.read(4);          //Переводим часы + минуты выключения Soil реле к полным минутам
  int fulMinOn2=    EEPROM.read(5)*60+EEPROM.read(6);          //Переводим часы + минуты включения Temp реле к полным минутам
  int fulMinOff2=   EEPROM.read(7)*60+EEPROM.read(8);          //Переводим часы + минуты выключения Temp реле к полным минутам
 
 //========== Таймер №1 (автополивалочка)        
    if (fulMinOn1>fulMinOff1) {isNight=1;}                   //Если ночное время
    if (isNight==0) {                                        //Если день
    if (fulMin>=fulMinOn1&&fulMin<fulMinOff1) {isIrrigt=1;}  //Проверяем интервал
   else {isIrrigt=0;}                                        //Если необходимо включить автополив
  } else {                                                   //Если ночь
      if(fulMin-fulMinOn1>=0) {isIrrigt=1;}                  //Если больше или равно верхнему значению, то необходимо включить автополив
   else {                                                    //Если необходимо включить автополив
      if(fulMin<fulMinOff1) {isIrrigt=1;}                    //Если меньше нижнего значения, то необходимо включить автополив
   else {isIrrigt=0;}                                        //Если необходимо включить автополив
    }
  }  
    if((isIrrigt==1)&&(IrrigStat==0)){                       //Если автополив еще не включен и выставлен флаг необходимости включить
      {IrrigStat=1;}
  } else {
      if(isIrrigt==0&&IrrigStat==1){
      {IrrigStat=0;}
  }
}

//========== Таймер №2 (вентиялция парничковых газов)
      if (fulMinOn2>fulMinOff2) {isNight=1;}                //Если ночное время
    if (isNight==0){                                        //Если день
    if (fulMin>=fulMinOn2&&fulMin<fulMinOff2) {isTemp=1;}  //Проверяем интервал
   else {isTemp=0;}                                        //Если необходимо включить вентиляцию
  } else {                                                  //Если ночь
      if(fulMin-fulMinOn2>=0) {isTemp=1;}                  //Если больше или равно верхнему значению, то необходимо включить вентиляцию
   else {                                                   //Если необходимо включить вентиляцию
      if(fulMin<fulMinOff2) {isTemp=1;}                    //Если меньше нижнего значения, то необходимо включить вентиляцию
   else {isTemp=0;}                                        //Если необходимо включить вентиляцию
    }
  }  
     if((isTemp==1)&&(TempStat==0)){                      //Если вентиляция еще не включена и выставлен флаг необходимости включить
        {TempStat=1;}
  } else {
      if(isTemp==0&&TempStat==1){
        {TempStat=0;}
    }
  }
}

//=========== Обработка Аврийного индикатора
void bLinkLed(){
  if (millis()-prvMlsbLink>zadTime[1]){               //Проверяем интервал для обновления 
    prvMlsbLink=millis();                             //Установка задержки
      digitalWrite(pushLED,!digitalRead(pushLED));}   //Инверсия значения
}

//=========== Обработки печати и вывода на дисплейчик (часы)
void printTime() {
      if (millis()-prvMlsTm>zadTime[3]){                     //Проверяем интервал для обновления часов
      prvMlsTm=millis();                                     //Вызываем ф-цию вывода времени на экран
    tft.setTextSize(2);
      tft.setCursor(15,2);
    tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
        if (hours<10) {tft.print(0);tft.print(hours);} else {tft.print(hours);} 
    tft.print(":"); 
      if (minutes<10) {tft.print(0);tft.print(minutes);} else {tft.print(minutes);} 
    tft.print(":"); 
      if (seconds<10) {tft.print(0);tft.print(seconds);} else {tft.print(seconds);}
  }
}

//=========== Обработки печати и вывода на дисплейчик (напряжения, температуры, давление)
void printDin(){
      if (millis()-prvMlsVo>zadTime[6]){                     //Проверяем интервал для обновления показателй динамичных
    prvMlsVo=millis();
    tft.setTextSize(2);
      tft.setCursor(0,40);
    tft.setTextColor(ST7735_YELLOW, ST7735_BLACK);
    tft.print(temp[0],1);
      tft.setTextSize(3);
    tft.setCursor(55,40);
    tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
    tft.print(temp[1],1);
    tft.setTextColor(ST7735_YELLOW, ST7735_BLACK);
      tft.setCursor(55,70);
    tft.print(hmdt,1);
    tft.setTextColor(ST7735_RED, ST7735_BLACK);
      tft.setCursor(55,100);
    tft.print((moistAO*1.001),1);
    tft.setTextColor(ST7735_BLUE, ST7735_BLACK);
      tft.setCursor(55,130);
    tft.print(vin,1);
  } 
}

//=========== Обработки печати и вывода на дисплейчик СТАТИКИ
void printStat(){
        if (millis()-prvMlsTimer>zadTime[8]){                 //Проверяем интервал для обновления 
     prvMlsTimer=millis();
    tft.setTextSize(1);
//      tft.setCursor(0,45);
//    tft.setTextColor(ST7735_YELLOW);
//    tft.print("Temp C: ");
      tft.setCursor(0,75);
    tft.setTextColor(ST7735_YELLOW);
    tft.print("Atmo %: ");
      tft.setCursor(0,105);
    tft.setTextColor(ST7735_YELLOW);
    tft.print("Soil %: ");
      tft.setCursor(0,135);
    tft.setTextColor(ST7735_YELLOW);
    tft.print("Volt V: ");
    tft.drawLine(0,35, tft.width()-1, 35, ST7735_WHITE);
    tft.drawLine(0,65, tft.width()-1, 65, ST7735_WHITE);
    tft.drawLine(0,95, tft.width()-1, 95, ST7735_WHITE);
    tft.drawLine(0,125, tft.width()-1, 125, ST7735_WHITE); 
    tft.drawLine(0,155, tft.width()-1, 155, ST7735_WHITE);    
    tft.setTextColor(ST7735_YELLOW, ST7735_BLACK);
      tft.setTextSize(1);
      tft.setCursor(15,22);
    tft.setTextColor(ST7735_GREEN,ST7735_BLACK);
    if (date<10) {tft.print(0);tft.print(date);} else {tft.print(date);} 
    tft.print("/");
    if (month==1){tft.print ("Jan");} 
    if (month==2){tft.print ("Feb");} 
    if (month==3){tft.print ("Mar");} 
    if (month==4){tft.print ("Apr");} 
    if (month==5){tft.print ("May");} 
    if (month==6){tft.print ("Jun");} 
    if (month==7){tft.print ("Jul");} 
    if (month==8){tft.print ("Aug");} 
    if (month==9){tft.print ("Sep");} 
    if (month==10){tft.print ("Oct");} 
    if (month==11){tft.print ("Nov");} 
    if (month==12){tft.print ("Dec");} 
    tft.print("/"); 
    tft.print(year+2000); 
    if (day==1){tft.print (" Sun.");} 
    if (day==2){tft.print (" Mon.");} 
    if (day==3){tft.print (" Tue.");} 
    if (day==4){tft.print (" Wed.");} 
    if (day==5){tft.print (" Thu.");} 
    if (day==6){tft.print (" Fri.");} 
    if (day==7){tft.print (" Sat.");}
  }
}

void loop(){
    timeRtc();
    timer();
    buttonPS();
    setUp();
      if (millis()-prvMlsTemp>zadTime[6]&&flagDallas!=1){dallas();}
    tempDallas();
    irrigation();
    voltM();
    humiDity();
    printTime();
    printDin();
    printStat();
}

Код делал как "конструктор", старался каждую функцию сделать отдельно, чтобы чего ненужно закомментил в loop и непаришся пока отлаживаеш имеющееся. Это совет ув. bwn с форума :)

Вот, что получаем:

-измерение температур на уличке и в тепличке (ну чтоб разницу видеть просто);

Исходя из измеренных темперетур и гистерезиса вентилировать тепличку (пока неиспользуется).

-измерение влажности воздуха в тепличке (очень условно ибо датчик и врёт и погрешность велика), ну да показания имеем.

-измерение влажности грунта;

Эти показания используются для автополива.

-измерение напряжения;

Сигнализирует о необходимости заменить батареечку.

-часы и календарик;

ПО ним в меню настраиваем, а когда собственно нужно поливать и проветривать, два таймера суточных.

Вот как выглядит коробочка "изнутри":

 и 

А вот "снаружи":

 и 

Вот в тепличке уже:

 и 

А это бочка для воды, литров 60-70, вода в неё неплохо нагревается. Внутри заборный шланг и на нём "фильтр" средней :) очистки:

 и 

Качество видео "хромает" снимал утром, телефон ещё видимо непроснулся.

И кусочки видео, первый с общим видом и менюшками: http://www.youtube.com/watch?v=YGat6qNseD8

Второй, коротенький совсем с бочкой: http://www.youtube.com/watch?v=9DUedxoqGos

 

Итог: делал как "пробный" полёт, если взлетит и оправдает, в следующем сезоне и тепличку сварю\обошью поликарбонатом нормальную, квадратов на 25 кв.м и полив через "распылители" форсунки или дождевалки.  Всё делалось из того что было. втом числе и тепличка сама :)

Аккумулятора хватает ровно на 4 дня :( и это печалька. Хорошо их у меня штуки три. Может они просто старые уже (некоторые 2009-2010) года от старых ИБП, новый жалко пока.

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

Ничего так себе. По результатам испытаний, интересно, как себя ведет DHT в такой влажности и вызывает сомнения экран с тачем.
Насчет сварного варианта поддерживаю, вчера закончил. Ждем испытания снегом))). Первый вариант из ППР труб, под снегом скис.

По энергосбережению, на сварном варианте оптимальней использовать гравитацию (бочка наверх, клапан, полив капельный) ИМХО.
 

Thorn
Offline
Зарегистрирован: 07.11.2014

Доброго утречка. Про самополив - само собой метра даже на 2-2,5 от земли уже 0,2Атм давление :) можно и капельно а клапанов полно в Ali... 

Экранчик БЕЗ тача -  и на самом деле цифорки и данные читаются лучьше чем видео кажет, хотя ежели солнышко яркое то неочень, ну да они лиш для настроек в меню и Епром нужны. 

А вот DHT по утру показывает 100% :) это без шуток, конденсат сильный, влёнка изнутри вся в нём. Ну я же и думал что просто поставлю его в приблуду потестить, стоит то 50 рублей :) и валялся всеравно.

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

Закупаю почуть 20*20*1,5мм профтрубу (за 6 метров у нас она 235 руб) плюс 8мм поликарбонат думаю, 6-ка тонковата будет, по подсчётам более 8 тыщ выйдет тепличка в 25кв.м - это дорого, и надо там растить чтото полезное :))

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

Цены на трубу у вас сладкие, карбонат нормально держит и 4мм (просвет примерно 1м х 1,7м угол градусов 30). Листом зашил крышу и фасады, стены пленка армированная (побюджетней и санитария лучше). В итоге у меня получилось 6х3 в районе 12тыров.
По DHT не ерничал, самому интересно как он живет при 100% влажности и как долго. Модуль управления наверно лучше все таки выносить наружу, на сквознячок и много много лака.
По экрану, не рассмотрел, что без тача. Для тех влага - смерть. Из ППР делать реально, но надо усилить центральной хребтовой балкой, прогибает в центре (карбонат 4мм). Моя устояла, но чистил после каждого снегопада (прогибается, потом встает обратно)

uragan
Offline
Зарегистрирован: 23.02.2015

По разности показаний. Пробовали уже подключить стаб. Питание на клемму 5 v? Если подключаешься на vin , сама аурдина еще откусывает.

Thorn
Offline
Зарегистрирован: 07.11.2014

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

А я как ж..й чуял что дело именно в подключении СТАБИЛИЗИРОВАННОГО питания на vin а не на vcc. ну да пбудет уроком иликогда переделку задумаю.

ПО рабочте все нормуль, но подбешивает необходимость замены аккумов каждый  дня :( Старый автомобильный вообще издох за время лежания....

Вот по DHT-11, этот товарищ по утрам при охрененном конденсате (проветривания то НЕТ :( пока плёнка ) он кажет и 102 и 104% влажности, не ну я неудивлён однако такой режим работы для него будет скоротечен наверное.

Корпус приблуды кстати действительно СВЕРХ-герметичен и туда ничего нини....

Вот, есчо увеличил время полива, ранее оно было ограничено строками:

343	    if (setSoiltIrrig>19) setSoiltIrrig=0;
344	    if (setSoiltInOnOff>1) setSoiltInOnOff=0;

- увеличил до 59 сек :). Бывает водичка уходит за время стояния и потом помпа за раз неможет стартануть за 19 сек и набить трубку водой до середины....

Писчалка\буззер стоит ВНУТРИ корпуса и потому звук неочень слышен. Жду когда приедет десяток АКТИВНЫХ за 50 руб с Ali и вынесу наружу, чтоб слышать про аварии и батарею более ЯВНО :)

uragan
Offline
Зарегистрирован: 23.02.2015

Есть вариант определения влажности классическим способом: сухой влажный термометр. DS18b20 справятся. И неубиваемый.

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

uragan пишет:

Есть вариант определения влажности классическим способом: сухой влажный термометр. DS18b20 справятся. И неубиваемый.

А стабильный ток воздуха как вокруг них обеспечить? Не вентилятор же ставить.

uragan
Offline
Зарегистрирован: 23.02.2015

А как же другие датчики без этого обходятся?

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

uragan пишет:

А как же другие датчики без этого обходятся?

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

uragan
Offline
Зарегистрирован: 23.02.2015

Влажность же не самоцель. Получается два термометра лучше отвечают требованиям растений. Дует ветер - им плохо. Нет ветра - замечательно.

ViNt.77
Offline
Зарегистрирован: 31.01.2016

Здравствуйте можно скетч в виде файла выложить?

Лёвчег
Offline
Зарегистрирован: 07.02.2016

Интересная тема. Тоже заказал себе ардуино поюзать. И первая мысль "ленивая теплица". Так-как "туп как дерево",думаю, дайка пошарю в инете, полюбой умные люди уже всё сделали. И какаво-же было моё удивление, когда оказалось, что инфы про это почти нЭма. Уж растроился... И тут напоролся на вашу ветку. Страсть как интересно. Вот только жаль, что мой ещё не дошел. Буду внимательно следить)

Лёвчег
Offline
Зарегистрирован: 07.02.2016
Arduino: 1.6.8 Hourly Build 2016/02/02 09:41 (Windows 7), Плата:"Arduino/Genuino Uno"
 
C:\Users\Лёвчег\Documents\Arduino\sketch1\sketch1.ino:4:148: fatal error: DHT.h: No such file or directory
 
compilation terminated.
 
Несколько библиотек найдено для "OneWire.h"
 Используется: C:\Users\Лёвчег\Documents\Arduino\libraries\OneWire
Не используется: C:\Users\Лёвчег\Documents\Arduino\libraries\MAX31850_OneWire
exit status 1
Ошибка компиляции.
 
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
 
Народ! Отзовитесь! Как исправить эту ошибку? Я знаю, что для вас это не сложно.
nevkon
Offline
Зарегистрирован: 20.01.2015

Вам ведь по русски пишут: хочу файл DHT.h

Лёвчег
Offline
Зарегистрирован: 07.02.2016

Это как? Я тулько учусь понимать что такое ардуино. Мне бы желательно пальцем ткнуть.

nevkon
Offline
Зарегистрирован: 20.01.2015

У вас нет библиотеки для работы с датчиками DHT, вам ее надо скачать/скопировать в каталог библиотек или с вашей программой.

Travmatolog
Offline
Зарегистрирован: 13.04.2016

Очень интересная система, сам хочу такую собрать

Travmatolog
Offline
Зарегистрирован: 13.04.2016

Подскажите датчик влажности почвы на какую длину можно вынести от ардуины?

DIYMan
DIYMan аватар
Онлайн
Зарегистрирован: 23.11.2015

Travmatolog пишет:

Подскажите датчик влажности почвы на какую длину можно вынести от ардуины?

До 20 км, если использовать мощный радиопередатчик.

lexssazo
Offline
Зарегистрирован: 05.05.2016

Скажите  собрали такой уже . Работает ? Хочу приобрести для своей теплицы . Какая цена ? lexs.sazo@mail.ru +79183570057

sir_kimas
Offline
Зарегистрирован: 01.08.2016

Подскажите на каких модулей все собрано? Схему можно в студию.

Dimoooon
Offline
Зарегистрирован: 09.03.2018

Можно целый скетч?