Gроект для аквариума (акваконтроллер для led, temp, time, co2)

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

Ну тогда наверно все таки делать блокировку клавиш. Это проще по исполнению, чем все экранами обвешивать. На остальное я так понял не влияет, только IR колбасит.

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

Доброго утречка!

Взял свой стаарый код, где обработка кнопок была по:



#define KEY1 0x41BEC03F           //setup
#define KEY2 0x41BE40BF           //left
#define KEY3 0x41BED02F           //up
#define KEY4 0x41BE609F           //down
#define KEY5 0x41BEB04F           //right
#define KEY6 0x41BEF00F           //exit 
#define KEY7 0x41BE708F           //vol_down
#define KEY8 0x41BE10EF           //vol_up
#define KEY9 0x41BE20DF           //slide
#define KEY10 0x41BEA05F          //stop

Вкорячил его назад, все как и было, нажато - возвращает, ненажато - тишина. :)

Теперь работа в таком виде с меню и параметрами.

Хочу сам попробовать победить и вот чтовыходит, меню: 



void menu(){
  tft.fillScreen(ST7735_BLUE); // Clear screen
  tft.setTextSize(1);
  tft.setTextColor(ST7735_WHITE, ST7735_BLUE);
  char menuTxt[5][17] = {"set Timer 1 >>>>", "set Timer 2 >>>>","set Timer Lcd >>","set MoonLight >>","set Timer Co2 >>"};  //Массив с наименованиями для экрана
  byte pos=0;
  while(1) {                                                    //Бесконечный цикл
    tft.setCursor(5,55);
    tft.print(pos+1);                                           //Печатаем номер.
    tft.print(". ");
    tft.print(menuTxt[pos]);                                    //Печатаем название
    if (val==KEY3 && pos>0) {pos--;}                               //Уменьшить увеличить + блокировка кнопки
    if (val==KEY4 && pos<4) {pos++;}
    winMe=pos;                                                  //Переменная номера таймера
/* Здесь переходим на подменю. Если останется как сейчас, то достаточно. Сейчас можно перейти на разные подменю.
    if (KEY==5) setOnOff(); */
    if (val==KEY5 && pos==0) setOnOff();
    if (val==KEY5 && pos==1) setOnOff();
    if (val==KEY5 && pos==2) setOnOff();
    if (val==KEY5 && pos==3) setOnOff();
    if (val==KEY5 && pos==4) setOnOff();
    if (val==KEY1){         //Выход из меню с проверкой и установкой блокировки от возврата       
    tft.fillScreen(ST7735_BLACK); // Clear screen
         break; } 
    }
}

(снова tft имхо тестово) .В таком виде по нажатию KEY1 я попадаю в меню и ТУТ-же из него вылетаю, мгновенно. Хочу спросить строка while(1) { //Бесконечный цикл это не нажатие-ли кнопки 1 из нашего старого кода работы с кнопками?

И фукнкция настройки параметров в меню:



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);
//    lcd.blink();
    tft.fillScreen(ST7735_RED);                           //Clear screen
    while(val!=KEY1) {                                   //Крутим цикл пока не будет Setup
//      delay(200);                                       //Если убрать, не работает подсветка уст.позиции
    tft.setCursor(45,40);
    tft.setTextColor(ST7735_YELLOW,ST7735_RED);
    tft.setTextSize(1);

Правильно-ли описал здесь работу   while(val!=KEY1) { //Крутим цикл пока не будет Setup

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

Добрый день. По первому коду, вас выбрасывает 22 строка. Я когда писал пример, там была блокировка этой клавиши на какое-то время. Ее надо вводить при входе и также при возврате из подменю. В подменю возврат из while вроде правильный.

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

Ок, поменял 22 строку на:



if (val==1 && zadM[0]<millis()) {                   //Выход из меню с проверкой и установкой блокировки от возврата       
         zadM[0]=millis()+600;

где: 



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

объявлены в переменных.

В меню попал и там пока повис (снова кнопки надо правильно прописывать :)  ) Ну это уже лучьше...

Так что есть: 

 while(1) {                                                    //Бесконечный цикл

в 7 строке? Кнопка KEY1 может её иначе описать?

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

Только вторая строка первого кода должна быть в loop-е и setTimeOn (вроде правильно функцию назвал) и применятся в момент перехода в основной экран меню, иначе вы там и будете висеть, т.к. условия выхода никогда не достигнете.

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

О, первая прическа, попробуйте если все работает, будем дальше чесать. Я свои варианты по currentMillis пока закомментил в коде, смотрите сами, что использовать. Тайминги опросов датчиков пока не трогал.

#include <EEPROM.h>
#include <Wire.h>                     //Подключаем библиотеку для использования однопроводного интерфейса                                     
#include <LiquidCrystal_I2C.h>        //Подключаем библиотеку для использования I2C интерфейса
#include <OneWire.h>                  //Подключаем библиотеку для температурного датчика DS18B20
#include <BMP085.h>                   //Подключаем библиотеку для маленького барометра
#include <IRremote.h>                 //Подключаем библиотеку для IR сенсора
LiquidCrystal_I2C lcd(0x27,20,4);     //Устанавливаем LCD-адрес 0x27 для отображения 20 символов и 4 линии
byte currentLight=0;                  //Переменная включения подсветки LCD 

//=====BT*
char inByte;                          //Ввходящие данные BT (Bluetooth модуля)

//=====IR_Sensor*
#define recvPin 3                    //Вход IR-приемника и кнопки пульта
uint32_t val; 
IRrecv irrecv(recvPin);
decode_results results;

//=====IR_Dimmer*
byte angData1, angData2=0;        //Переменная выходов диммирования (из двух половинок :))
byte maxDimm=255;                 //Переменная определяет МАКСИМАЛЬНОЕ значение диммирования
byte upR2=210;                    //Переменная включения 2 свето-релейного канала
byte upR3=240;                    //Переменная включения 3 свето-релейного канала
byte downR2=205;                  //Переменная выключения 2 свето-релейного канала
byte downR3=235;                  //Переменная выключения 3 свето-релейного канала
int pManDimmUp=800;               //Период увеличения яркости 
int pManDimmDown=500;             //Период уменьшения яркости
byte flagDimm=0;                  //Флаг для обработки "НЕОБРАТИМОГО" выключения Power_Off
unsigned long tDimm=millis();     //Переменная задержки auto_dimmer

//=====Termo_Relay*
const int RelayChn1=4;             //Используем цифровой ПОРТ 4 для ПЕРВОГО канала термо-реле (вода) 
const int RelayChn2=A1;            //Используем цифровой ПОРТ A1 для ВТОРОГО канала термо-реле (радиатор)

//=====Led_Relay*
#define OUT1 7                      //Используем цифровой ПОРТ 7 для 1 свето-релейного канала Dimm
#define OUT2 8                      //Используем цифровой ПОРТ 8 для 2 свето-релейного канала
#define OUT3 9                      //Используем цифровой ПОРТ 9 для 3 свето-релейного канала

//=====Other_Relay*
#define OUT0 10                     //Используем цифровой ПОРТ 10 для ATX (включение ATX (зелёный + черный))
//#define OUT6 31                     //Используем цифровой ПОРТ 11 для CO2
//#define OUT7 32                     //Используем цифровой ПОРТ 12 для другое

//=====Dimmer_Out*
#define OUT4 5                      //Используем цифровой ПОРТ 5 для 1/2 SunSet канала (dimmer)
#define OUT5 6                      //Используем цифровой ПОРТ 6 для 1/2 SunSet канала (dimmer)

//=====VoltMeter*
int voltInput=A7;                   //Используем аналоговый вход A7 для измерения напряжения
float vout=0.0;
float vin=0.0;
float R1=21700.0;                   //Resistance of R1 (22K) - see text!
float R2=12770.0;                   //Resistance of R2 (12K) - see text!
int valueVo=0;

//=====Pressure*
BMP085 dps=BMP085();                // Digital Pressure Sensor 
long Pressure=0;
unsigned long timeDps=0;

//=====Termo_Sensor*
int tempPin=2;                      //Определяем порт шины OneWire (IC) для температурного датчика DS18B20                               
OneWire ds(tempPin);                //Создаем объект для работы с термометром
byte flagDallas=0;                  //Флаг для обработки показаний с датчиков Dallas
byte data[12];
byte addr1[8] = {0x28, 0xC5, 0x3B, 0x5C, 0x06, 0x00, 0x00, 0x85};     //адрес датчика DS18B20_Вода в аквариуме
byte addr2[8] = {0x28, 0x86, 0x48, 0xEA, 0x05, 0x00, 0x00, 0xF6};     //адрес датчика DS18B20_Радиатор (2-ой канал, центр)
byte addr3[8] = {0x28, 0xF2, 0x29, 0xEB, 0x05, 0x00, 0x00, 0xE1};     //адрес датчика DS18B20_Блок реле
unsigned int raw;                  //Если экранированный кабель, можно подключать до 32 термо-датчиков DS18B20
//float temp1, temp2, temp3;         //Температура аквариума \ радиаторов Led \ блока реле
float temp[3];
//float t1=25.0;                     //Переменная предела срабатывания реле RelayChn1
//float t2=47.0;                     //Переменная предела срабатывания реле RelayChn2
//float t3=55.0;                     //Переменная предела срабатывания реле RelayChn3
float t[]={25.0, 47.0, 55.0};
float tGistrsis=1.0;               //Гистерезис температур (по 0,25 в каждую сторону)

//=====Rtc_Clock*
#define DS3231_I2C_ADDRESS 104 
byte seconds, minutes, hours, day, date, month, year;

//=====Timer*
//    long lghtIntv=60000;            //Интервал для проверки вкл./выкл. освещения аквариума, 1 минута
byte lcdStat=0;                //Флаг подсветки Lcd если включена, то в 1
//byte lghtStat1=0;              //Флаг освещения, если включена, то в 1 в первом таймере
//byte lghtStat2=0;              //Флаг освещения, если включена, то в 1 во втором таймере
byte lghtStat[2];
byte co2Stat=0;                //Флаг Co2, если включена, то в 1
byte isLcdt=0;                 //Флаг для обработки необходимости включить подсветку Lcd
//byte isLght1=0;                //Флаг для обработки необходимости включить реле освещения в первом таймере
//byte isLght2=0;                //Флаг для обработки необходимости включить реле освещения во втором таймере
byte isLght[2];
byte isCo2t=0;                 //Флаг для обработки необходимости включить реле Co2
byte isNight=0;                //Если включаем на ночь, т.е. начальное время больше конечного

//=====Menu*
byte setHorClockOn;                 //Часы включения
byte setMinClockOn;                 //Минуты включения
byte setHorClockOff;                //Часы вЫключения
byte setMinClockOff;                //Минуты вЫключения  
//byte setTempt1;                     //Максимальная температура t1 (вода в аквариуме)
//byte setTempt2;                     //Максимальная температура t2 (радиатор Led)
//byte setTempt3;                     //Максимальная температура t3 (блок коммутации, реле)
byte setTempt[3];
byte winMe;                         //Номер экрана меню

//=====Delays*
//unsigned long tmIntv=1000;          //Интервал для обновления времени на экране каждую секунду
//unsigned long razdIntv=2000;        //Интервал для обновления ":" на экране каждые 2 секунды
unsigned long prvMlsTm=0;           //Предыдущее показание миллисекунд для обновления показания часов
unsigned long prvMlsRazd=0;         //Предыдущее показание миллисекунд для обновления ":"
//unsigned long prvMlsLght=0;         //Предыдущее показание проверки временного интервала
unsigned long prvMlsVo=0;           //Предыдущее показание обновления показания вольтметра
//unsigned long voIntv=5000;          //Интервал для обновления напряжения
unsigned long prvMlsOut=0;          //Предыдущее показание обновления показания OUT
//unsigned long outIntv=1000;         //Интервал для обновления OUT
unsigned long prvMlsBar=0;          //Предыдущее показание обновления показания барометра
//unsigned long barIntv=10000;        //Интервал для обновления барометра
unsigned long prvMlsTemp=0;         //Предыдущее показание обновления температур
//unsigned long tempIntv=5000;        //Интервал для обновления температур
unsigned long prvMlsTimer=0;        //Предыдущее показание обновления таймера
//unsigned long timerIntv=10000;      //Интервал для обновления таймера
unsigned long tzad=millis();        //Переменная задержки (пока для ds18b20, ds.write) и непользую....

// Все ваши переменные, которые мог, перевел в массив zadTime[]. Которые использовались в коде заменил.
//Те которые для дальнейшего развития, только предусмотрел значения в массиве.

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

const char menuTxt[5][17] = {"set Timer 1 >>>>", "set Timer 2 >>>>","set Timer Lcd >>","set MoonLight >>","set Timer Co2 >>"};  //Массив с наименованиями для экрана

//=====Byte_Symbol*
byte equ[8] =                    //Символ "=" но КОРОТКИЙ :)
{
  B00000,
  B00000,
  B01110,
  B00000,
  B01110,
  B00000,
  B00000,
}; 

//Здесь чуть поизвращался
void relayHigh()
{
  digitalWrite(OUT0,HIGH);                            //Определяем инверсный выход в HIGH реле ATX
  digitalWrite(OUT1,HIGH);                            //Определяем инверсный выход в HIGH реле 1 канала Led
  digitalWrite(OUT2,HIGH);                            //Определяем инверсный выход в HIGH реле 2 канала Led
  digitalWrite(OUT3,HIGH);                            //Определяем инверсный выход в HIGH реле 3 канала Led
}


void setup() {
  Wire.begin();
//  Serial.begin(9600);
  irrecv.enableIRIn();                                //Включаем IR-сенсор
  dps.init(MODE_STANDARD, 25000, true);               //250 meters, true = using meter units
     pinMode(voltInput,INPUT);                        //Определяем вход вольтметра  
//    pinMode(RelayChn1,OUTPUT);                      //Определяем выход 1-термореле охлаждения воды аквариума 
//    pinMode(RelayChn2,OUTPUT);                      //Определяем выход 2-термореле охлаждения радиаторов Led
//  digitalWrite(RelayChn1,HIGH);                     //Определяем инверсный выход в HIGH охлаждения воды аквариума
//  digitalWrite(RelayChn2,HIGH);                     //Определяем инверсный выход в HIGH охлаждения радиаторов Led
     pinMode(OUT0,OUTPUT);                            //Определяем инверсный выход реле ATX 
     pinMode(OUT1,OUTPUT);                            //Определяем инверсные выходы реле 1 канала Led
     pinMode(OUT2,OUTPUT);                            //Определяем инверсные выходы реле 2 канала Led
     pinMode(OUT3,OUTPUT);                            //Определяем инверсные выходы реле 3 канала Led
 //    pinMode(OUT6,OUTPUT);
 //    pinMode(OUT7,OUTPUT);
  
  //digitalWrite(OUT0,HIGH);                            //Определяем инверсный выход в HIGH реле ATX
  //digitalWrite(OUT1,HIGH);                            //Определяем инверсный выход в HIGH реле 1 канала Led
  //digitalWrite(OUT2,HIGH);                            //Определяем инверсный выход в HIGH реле 2 канала Led
  //digitalWrite(OUT3,HIGH);                            //Определяем инверсный выход в HIGH реле 3 канала Led

     relayHigh();


//  digitalWrite(OUT6,HIGH);
//  digitalWrite(OUT7,HIGH);
  analogWrite(OUT4,angData2);                      //Инициация выхода 1/2 диммера
  analogWrite(OUT5,angData1);                      //Инициация выхода 1/2 диммера
      lcd.init();                                     //Инициализируем дисплейчик
      lcd.setBacklight(1);  
      lcd.clear();                                    //Очищаем на всякий случай дисплейчик
      lcd.setCursor(2,0);
      lcd.print("Aqua  Controller");                  //Выводим версию и прочее
      lcd.setCursor(2,1);
      lcd.print("      v1.1      ");
      lcd.setCursor(1,3);
      lcd.print("_0802_menu_NoEp_Dim_");
  delay(zadTime[3]);
      lcd.clear();                                    //Очистка дисплея и void (printTime, printDin, printStat)
}

//========== Обработка IR-сенсора, определение кнопок
byte keyIr(){
  if (irrecv.decode(&results)) {      //Если пришел пакет и этот пакет не FF сохраняем правильный пакет в переменную
//  if (results.value!=0xFFFFFFFF) {  //Если пришел FF, соответственно пропускаем.
    val=results.value; //}            //Сверяем значение из переменной val.. если пришла команда повтора (пакет с FF)    
    irrecv.resume(); }                //В переменной останется прошлый, правильный, пакет и код выполнится повторно.
//  Serial.println(val,HEX);
//  Serial.println(" ");
  if (val==0x41BEB04F) return 5;    //right      KEY5
  if (val==0x41BE609F) return 4;    //down       KEY4
  if (val==0x41BED02F) return 3;    //up         KEY3
  if (val==0x41BE40BF) return 2;    //left       KEY2
  if (val==0x41BEC03F) return 1;    //setup      KEY1
  if (val==0x41BEA05F) return 10;   //stop       KEY10
  if (val==0x41BE20DF) return 9;    //slide      KEY9
  if (val==0x41BE10EF) return 8;    //vol_up     KEY8
  if (val==0x41BE708F) return 7;    //vol_down   KEY9
  if (val==0x41BEF00F) return 6;    //exit       POWER_KEY
     else return 0;
}

//========== Обработка IR-кнопок
void keyI()
{
  byte KEY=keyIr();            

//========== Обработка Входа в Меню
     if (KEY==1)
{                          //***ВХОД В МЕНЮ и проверка блокировки от возврата. Принимаем код клавиши
        val=0;
        menu(); 
}                          //Если setup идем в меню
    
//========== Отключение LCD с кнопки
  if (KEY==9)
{   val=0;
    lcd.setBacklight(currentLight);
    currentLight = !currentLight; 
}

//========== Увеличение яркости (удержание кнопки)
      if (KEY==5)
{       val=0;
      //Данная конструкция неработоспособна. Контролирует только второй параметр.
      //if (angData1, angData2<255) angData1++, angData2++;   //Начало увеличения диммирования
         if (angData1<255) angData1++, angData2=angData1;
         analogWrite(OUT4, angData2);
         analogWrite(OUT5, angData1);
      //if (angData1, angData2>0) {            //Включаем реле ATX и диммера на первом шаге (начало диммирования)
         if (angData1>0) 
       {
         digitalWrite(OUT0,LOW);             //Включаем реле ATX
         digitalWrite(OUT1,LOW); 
       }
}

//========== Уменьшение яркости (удержание кнопки)
      if (KEY==2)
{        val=0;
      //if (angData1, angData2!=0) angData1--, angData2--;  //Начало снижения диммирования 
         if (angData1!=0) angData1--, angData2=angData1;
         analogWrite(OUT4, angData2);
         analogWrite(OUT5, angData1);
      //if (angData1, angData2==0) {           //Выключаем реле диммера (по окончании диммирования)
         if (angData1==0) 
       {
         relayHigh();
         
         //digitalWrite(OUT1,HIGH);
         //digitalWrite(OUT2,HIGH);
         //digitalWrite(OUT3,HIGH);
         //digitalWrite(OUT0,HIGH); 
       }           //Выключаем реле ATX
}

//========== Обработка "одного" нажатия   
      if (KEY==8 & flagDimm==0)
{              //Если нажата кнопка УВЕЛИЧЕНИЯ диммирования
      if (tDimm<millis())
      {                    //и не дана команда на полное выключение
  pManDimmUp; dimmUp(); 
      }                     //Интервал УВЕЛИЧЕНИЯ диммирования
}
      if (KEY==7 & flagDimm==0)
{              //Здесь аналогично увеличению яркости
      if (tDimm<millis()) 
      {
  pManDimmDown; dimmDown(); 
      }                 //Интервал Снижения диммирования
}
      if (KEY==6 & angData2!=0)
{              //Power_Off. Если диммер включен, устанавливаем флаг
    flagDimm=1; 
}
      if (flagDimm==1) 
{                      //Если флаг установлен, продолжаем уменьшение яркости
      if (angData2==0) 
      {                      //Яркость на 0, флаг сбросили.
      flagDimm=0;
    
    relayHigh();
    //digitalWrite(OUT1,HIGH);
    //digitalWrite(OUT2,HIGH);
    //digitalWrite(OUT3,HIGH);
    //digitalWrite(OUT0,HIGH); 
       }
      if (tDimm<millis())
       {                     //Последовательно уменьшаем яркость, кнопки заблокированы
  pManDimmDown=300; dimmDown(); 
       }              //Интервал СНИЖЕНИЯ диммирования (по Power_Off)
  val=0; 
}  

//========== Обработка ATX, НЕдиммируемых реле
//     if (KEY == 6) digitalWrite(OUT0, !digitalRead(OUT0));      //Power_KEY, ON/OFF_KEY, включение ATX
//   else if (KEY == 6) digitalWrite(OUT0, !digitalRead(OUT0));
 if (KEY==3) 
     {
     val=0; if (!digitalRead(OUT1)!=0 && angData2 >=1) digitalWrite(OUT2,!digitalRead(OUT2));
     }
 if (KEY==3) 
     { 
     val=0; if (!digitalRead(OUT1)!=0 && angData2!=0) digitalWrite(OUT2,digitalRead(OUT2));
     }
 if (KEY==4) 
     { 
     val=0; if (digitalRead(OUT1)==0 && angData2>=1) digitalWrite(OUT3,!digitalRead(OUT3));
     }
 if (KEY==4) 
     { 
     val=0; if (digitalRead(OUT1)==0 && angData2!=0) digitalWrite(OUT3,digitalRead(OUT3));
     }
}

//========== Увеличение яркости (auto)
void dimmUp() 
{
      if (angData2<maxDimm)
      {                //Ограничение верхнего значения диммирования, (0-255)
    angData2++;                             //Начало подъёма диммирования
    //angData1++;
    angData1=angData2;
    analogWrite(OUT4,angData2);             //Пишем в порт
    analogWrite(OUT5,angData1);
      if (angData2>0)
           {                      //Включаем реле ATX и диммера на первом шаге (начало диммирования)
    digitalWrite(OUT0,LOW);
    digitalWrite(OUT1,LOW); 
           }
      if (angData2==upR2) 
           {                  //Включаем Второе реле при upR2
    digitalWrite(OUT2,LOW); 
           }
      if (angData2==upR3) 
           {                  //Включаем Третье реле при upR3
    digitalWrite(OUT3,LOW); 
           }
    tDimm=millis()+pManDimmUp; 
      }             //Устанавливаем время следующего шага
    if (angData2==maxDimm)    {val=0;}
}

//========== Уменьшение яркости (auto)
void dimmDown() {
      if (angData2>0) {
    angData2--;                            //Начало снижения диммирования 
    //angData1--;
    angData1=angData2;
    analogWrite(OUT4,angData2);
    analogWrite(OUT5,angData1);
      if (angData2==downR3){               //Выключаем Третье реле при downR3
    digitalWrite(OUT3,HIGH); }
      if (angData2==downR2){               //Выключаем Втором реле при downR2
    digitalWrite(OUT2,HIGH); }
      if (angData2 == 0){                  //Выключаем реле диммера (по окончании диммирования)
    
    relayHigh();
    //digitalWrite(OUT0,HIGH);
    //digitalWrite(OUT1,HIGH);
    //digitalWrite(OUT2,HIGH);
    //digitalWrite(OUT3,HIGH); }
    tDimm=millis()+pManDimmDown; }         //Устанавливаем время следующего шага
    if (angData2==0){val=0;}
}

//=========== Обработка Меню, выбор экрана
void menu(){
  lcd.clear();                                    //Очищаем на всякий случай дисплейчик
  // Переместил в блок начальной инициализации, здесь это лишнее.
  //char menuTxt[5][17] = {"set Timer 1 >>>>", "set Timer 2 >>>>","set Timer Lcd >>","set MoonLight >>","set Timer Co2 >>"};  //Массив с наименованиями для экрана
  byte pos=0;
  while(1) {                                                    //Бесконечный цикл
    byte KEY=keyIr();
      val=0;  
    lcd.setCursor(0,1);
    lcd.print(pos+1);                                           //Печатаем номер.
    lcd.print(". ");
    lcd.print(menuTxt[pos]);                                    //Печатаем название
    if (KEY==3 && pos>0) {pos--;}                               //Уменьшить увеличить + блокировка кнопки
    if (KEY==4 && pos<4) {pos++;}
    winMe=pos;                                                  //Переменная номера таймера
/* 
    Здесь переходим на подменю. Если останется как сейчас, то достаточно. Сейчас можно перейти на разные подменю.
    if (KEY == 5) setOnOff();
*/
    if (KEY == 5) setOnOff();
    //Подменю вы неиспользуете, поэтому выбросил
    //if (KEY==5 && pos==0) setOnOff();
    //if (KEY==5 && pos==1) setOnOff();
    //if (KEY==5 && pos==2) setOnOff();
    //if (KEY==5 && pos==3) setOnOff();
    //if (KEY==5 && pos==4) setOnOff();
    if (KEY==1) {                                   //Выход из меню с проверкой и установкой блокировки от возврата       
    lcd.clear();                                    //Очищаем на всякий случай дисплейчик
      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);
      lcd.clear();                                       //Очищаем на всякий случай дисплейчик
      lcd.blink();
    while(keyIr()!=1) {                                  //Крутим цикл пока не будет Setup
    byte KEY=keyIr();                                    //Читаем состояние кнопок
    val=0;
//      delay(200);                                      //Если убрать, не работает подсветка уст.позиции
    lcd.setCursor(7,0);
    lcd.print("-On-  -Off-"); 
    lcd.setCursor(0,3);
    lcd.print("=== push to save ===");
    lcd.setCursor(1, 1);
    lcd.print(winMe+1,DEC);                              //Печатаем номер программы таймера
    lcd.print("|");
    lcd.print(pos/3,DEC);                                //Печатаем позицию настройки параметра (замена blink)
    lcd.print("->");  
    lcd.setCursor(7,1);                                  //Выводим инфу о часах и минутах
     if (setHorClockOn<10) lcd.print("0");
    lcd.print(setHorClockOn,DEC);
    lcd.print(":");
     if (setMinClockOn<10) lcd.print("0"); 
    lcd.print(setMinClockOn,DEC);  
    lcd.print(" ");     
     if (setHorClockOff<10) lcd.print("0");
    lcd.print(setHorClockOff,DEC);
    lcd.print(":");
     if (setMinClockOff<10) lcd.print("0");
    lcd.print(setMinClockOff,DEC); 
    //  Здесь подправил, вроде должно правильно мигать блинком
    //lcd.setCursor(pos, 0);                                //Устанавливаем курсор согласно позиции
    lcd.setCursor(pos, 1); //Это если время устанавливаемое в первой строке (строки считаем 0-1-2-3)
    
    if (pos<3) pos=3;
    if (KEY==5 && pos<11) pos += 3;                       //Крутим позицию право-лево
    else if (KEY==2 && pos>3) pos -= 3;
    
    else if (pos==3 && KEY==3) setHorClockOn++;           //Крутим значения
    else if (pos==3 && KEY==4) setHorClockOn--;
    else if (pos==6 && KEY==3) setMinClockOn++;
    else if (pos==6 && KEY==4) setMinClockOn--;    
    else if (pos==9 && KEY==3) setHorClockOff++;
    else if (pos==9 && KEY==4) setHorClockOff--;    
    else if (pos==12 && KEY==3) setMinClockOff++;
    else if (pos==12 && KEY==4) setMinClockOff--; 
    
    if (setHorClockOn>23) setHorClockOn=0;                //Ограничиваем значения
    else if (setMinClockOn>59) setMinClockOn=0;
    else if (setHorClockOff>23) setHorClockOff=0;
    else if (setMinClockOff>59) setMinClockOff=0;
}                                                         //Конец цикла
      lcd.noBlink(); 
      lcd.clear();                                        //Очищаем на всякий случай дисплейчик
   EEPROM.write(winMe*4+1, setHorClockOn);                //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, setMinClockOn); 
   EEPROM.write(winMe*4+3, setHorClockOff);
   EEPROM.write(winMe*4+4, setMinClockOff);
   lcd.setCursor(4,2);
   lcd.print("== Saved ==");
   delay(zadTime[3]);
}

//========== Считывание напряжения
void voltM() {
  valueVo=analogRead(voltInput);               //Read the value at analog input
  vout=(valueVo*5.0)/1024.0;               //See text
  vin=vout/(R2/(R1+R2)); 
      if (vin<0.09) {
  vin=0.0; }                                  //Statement to quash undesired reading
}

//========== Считывание Давления
void bar() {
  if (((millis()-timeDps)/1000.0)>=1.0) //Конструкция жуткая и жрущая море ресурсов при расчете вещественных чисел.
  //if (timeDps<millis())    //Я бы закомментил ваши и попробовал так
  {     
     dps.calcTrueTemperature();
     timeDps=millis(); 
     // timeDps=millis()+1000;
  }
     dps.getPressure(&Pressure);
}

//=========== Считывание температур
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){ //flagDallas=0;
  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;
    return celsius;
}

//=========== Обработка Термо-Реле
void tempRelay(){
    temp[0] = DS18B20(addr1);
    temp[1] = DS18B20(addr2);
    temp[2] = DS18B20(addr3);
      if (temp[0]>t[0]-tGistrsis/2){
    digitalWrite(RelayChn1,LOW);                 //Термо-реле 1-включается
//        lcd.setCursor(8, 2);
//        lcd.print("*");
  }     
      else if (temp[0]<t[0]+tGistrsis/2){
    digitalWrite(RelayChn1,HIGH);                //Термо-реле 1-выключается
//        lcd.setCursor(8, 2);
//        lcd.print("-");
  } 
      if (temp[1]>t[1]-tGistrsis/2){
    digitalWrite(RelayChn2,LOW);                 //Термо-реле 2-включается
//        lcd.setCursor(18, 2);
//        lcd.print("*");
  }     
      else if (temp[1]<t[1]+tGistrsis/2){
    digitalWrite(RelayChn2,HIGH);                //Термо-реле 2-выключается
//        lcd.setCursor(18, 2);
//        lcd.print("-");
  } 
} 

//=========== Обработка 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));
  }
}

//=========== Обработка Таймеров
void timer(){

//========== Таймер №1 
  int fullMinutes=hours*60+minutes;                                 //Переводим часы + минуты к полным минутам
  int fullMinutesOn1=EEPROM.read(1)*60+EEPROM.read(2);              //Переводим часы + минуты включения 1 реле к полным минутам
  int fullMinutesOff1=EEPROM.read(3)*60+EEPROM.read(4);             //Переводим часы + минуты выключения 1 реле к полным минутам
  int fullMinutesOn2=EEPROM.read(5)*60+EEPROM.read(6);              //Переводим часы + минуты включения 2 реле к полным минутам
  int fullMinutesOff2=EEPROM.read(7)*60+EEPROM.read(8);             //Переводим часы + минуты выключения 2 реле к полным минутам
  int fullMinutesOnLcd=EEPROM.read(9)*60+EEPROM.read(10);           //Переводим часы + минуты включения Lcd к полным минутам
  int fullMinutesOffLcd=EEPROM.read(11)*60+EEPROM.read(12);         //Переводим часы + минуты выключения Lcd к полным минутам
  int fullMinutesOffOut3=EEPROM.read(13)*60+EEPROM.read(14);        //Переводим часы + минуты включения OUT3 к полным минутам
  int fullMinutesOffOut2=EEPROM.read(15)*60+EEPROM.read(16);        //Переводим часы + минуты выключения OUT2 к полным минутам
          
    if (fullMinutesOn1>fullMinutesOff1) {isNight=1;}                //Если ночное время
    if (isNight==0) {                          //Если день
    if (fullMinutes>=fullMinutesOn1&&fullMinutes<fullMinutesOff1) {isLght[0]=1;}        //Проверяем интервал
   else {isLght[0]=0;}                           //Если необходимо включить свет
  } else {                                       //Если ночь
      if(fullMinutes-fullMinutesOn1>=0) {isLght[0]=1;}        //Если больше или равно верхнему значению, то необходимо включить свет
   else {                                        //Если необходимо включить свет
      if(fullMinutes<fullMinutesOff1) {isLght[0]=1;}            //Если меньше нижнего значения, то необходимо включить свет
   else {isLght[0]=0;}                           //Если необходимо включить свет
    }
  }  
    if((isLght[0]==1)&&(lghtStat[0]==0)){      //Если свет еще не включен и выставлен флаг необходимости включить
    if (tDimm < millis()) {                //И не дана команда на полное выключение
  pManDimmUp; dimmUp(); } 
      if (angData2==maxDimm) {lghtStat[0]=1;}
  } else {
      if(isLght[0]==0&&lghtStat[0]==1){
    if (tDimm < millis()) {
  pManDimmDown; dimmDown(); } 
      if (angData2==0){lghtStat[0]=0;}
  }
}
//========== Таймер №2
      if (fullMinutesOn2>fullMinutesOff2) {isNight=1;}                  //Если ночное время
    if (isNight==0) {                          //Если день
    if (fullMinutes>=fullMinutesOn2&&fullMinutes<fullMinutesOff2) {isLght[1]=1;}        //Проверяем интервал
   else {isLght[1]=0; }                           //Если необходимо включить свет
  } else {                                       //Если ночь
      if(fullMinutes-fullMinutesOn2>=0) {isLght[1]=1;}        //Если больше или равно верхнему значению, то необходимо включить свет
   else {                                        //Если необходимо включить свет
      if(fullMinutes<fullMinutesOff2) {isLght[1]=1;}            //Если меньше нижнего значения, то необходимо включить свет
   else {isLght[1]=0; }                           //Если необходимо включить свет
    }
  }  
    if((isLght[1]==1)&&(lghtStat[1]==0)){      //Если свет еще не включен и выставлен флаг необходимости включить
    if (tDimm < millis()) {                //И не дана команда на полное выключение
  pManDimmUp; dimmUp(); }
      if (angData2==maxDimm) {lghtStat[1]=1;}
  } else {
      if(isLght[1]==0&&lghtStat[1]==1){
    if (tDimm < millis()) {
  pManDimmDown; dimmDown(); }
      if (angData2==0){lghtStat[1]=0;}
  }
}
//========== Таймер Lcd-подсветки  
      if (fullMinutesOnLcd>fullMinutesOffLcd) {isNight=1;}        //Если ночное время
    if (isNight==0) {                          //Если день
    if (fullMinutes>=fullMinutesOnLcd&&fullMinutes<fullMinutesOffLcd) {isLcdt=1;}        //Проверяем интервал
   else {isLcdt=0;}                           //Если необходимо включить подсветку Lcd
  } else {                                       //Если ночь
      if(fullMinutes-fullMinutesOnLcd>=0) {isLcdt=1;}        //Если больше или равно верхнему значению, то необходимо включить подсветку Lcd
   else {                                        //Если необходимо включить подсветку Lcd
      if(fullMinutes<fullMinutesOffLcd) {isLcdt=1;}            //Если меньше нижнего значения, то необходимо включить подсветку Lcd
   else {isLcdt=0;}                           //Если необходимо включить подсветку Lcd
    }
  }  
    if((isLcdt==1)&&(lcdStat==0)){        //Если подсветка Lcd еще не включена и выставлен флаг необходимости включить
    lcd.backlight(); lcdStat=1;
  } else {
      if(isLcdt==0&&lcdStat==1){
    lcd.noBacklight(); lcdStat=0;
  }
}
//========== Таймер "Лунного света"  
    if (fullMinutes>=fullMinutesOffOut3) {
       digitalWrite(OUT3,HIGH);}
    if (fullMinutes>=fullMinutesOffOut2) {
       digitalWrite(OUT2,HIGH);
} 
//========== Таймер СО2
}
//=========== Обработка Bluetooth

//=========== Обработки печати и вывода на дисплейчик (часы)
void printTime() {
  // Зачем создавать лишнюю переменную? 
  unsigned long currentMillis=millis();
       //if (millis()- prvMlsTm>zadTime[2]) {
       if(currentMillis-prvMlsTm>zadTime[2]) {   //Проверяем интервал для обновления часов
  prvMlsTm=currentMillis;                    //Вызываем ф-цию вывода времени на экран
      //prvMlsTm=millis();                   // В этом случае currentMillis становится ненужным.
  lcd.setCursor(0,0);
      if (hours<10) {lcd.print(0);lcd.print(hours);} else {lcd.print(hours);} 
  lcd.print(":"); 
      if (minutes<10) {lcd.print(0);lcd.print(minutes);} else {lcd.print(minutes);} 
  lcd.print(":"); 
      if (seconds<10) {lcd.print(0);lcd.print(seconds);} else {lcd.print(seconds);}
  } 
        //Здесь аналогичный вопрос по целесообразности.
        // if (millis()- prvMlsRazd > zadTime[3]) {
        if(currentMillis - prvMlsRazd > zadTime[3]) {  //Проверяем интервал для обновления ":"
  
  //prvMlsRazd=millis();
  prvMlsRazd=currentMillis;
    lcd.setCursor(2,0);
    lcd.print(" ");
    lcd.setCursor(5,0);
    lcd.print(" ");
    lcd.setCursor(8,0);
    lcd.print(" ");
  }
}
//=========== Обработки печати и вывода на дисплейчик (напряжения, температуры, давление)
void printDin() {
  unsigned long currentMillis=millis();
        //if (millis()- prvMlsVo>zadTime[5]){
        if(currentMillis-prvMlsVo>zadTime[5]){   //Проверяем интервал для обновления напряжения
  //prvMlsVo=millis();
  prvMlsVo=currentMillis;
  lcd.setCursor(2,2);                        //Вывод значений температур на LCD                     
  lcd.print((temp[0]),1);
  lcd.setCursor(9,2);                          
  lcd.print((temp[1]),1);  
  lcd.setCursor(16,2);                          
  lcd.print((temp[2]),1);
  lcd.setCursor(9,3);
  lcd.print(vin);
  lcd.setCursor(4,1);
  lcd.print(Pressure/133.3,1);                //Выводим на экранчик показания атм.давления в мм.
  } 
}

//=========== Обработки печати и вывода на дисплейчик СТАТИКИ
void printStat() {
  unsigned long currentMillis=millis();
        //if (millis()- prvMlsTimer>zadTime[6]){
        if(currentMillis-prvMlsTimer>zadTime[6]){   //Проверяем интервал для обновления 
      //prvMlsTimer=millis();
      prvMlsTimer=currentMillis;
      lcd.setCursor(16,1);
      lcd.print("pw\1");
      lcd.setCursor(0,1);
      lcd.print("bar\1");
      lcd.setCursor(0,2);
      lcd.print("a\1");
      lcd.setCursor(7,2);
      lcd.print("b\1");
      lcd.setCursor(14,2);
      lcd.print("c\1");
      lcd.setCursor(0,3);
      lcd.print("~");
      lcd.setCursor(2,3);
      lcd.print(":");
      lcd.setCursor(4,3);
      lcd.print(":");
      lcd.setCursor(7,3);
      lcd.print("v\1");
      lcd.setCursor(15,3);
      lcd.print("%\1");
      lcd.setCursor(9,0);
      if (date<10) {lcd.print(0);lcd.print(date);} else {lcd.print(date);} 
      lcd.print("/");
   if (month==1){lcd.print ("Jan");} 
   if (month==2){lcd.print ("Feb");} 
   if (month==3){lcd.print ("Mar");} 
   if (month==4){lcd.print ("Apr");} 
   if (month==5){lcd.print ("May");} 
   if (month==6){lcd.print ("Jun");} 
   if (month==7){lcd.print ("Jul");} 
   if (month==8){lcd.print ("Aug");} 
   if (month==9){lcd.print ("Sep");} 
   if (month==10){lcd.print ("Oct");} 
   if (month==11){lcd.print ("Nov");} 
   if (month==12){lcd.print ("Dec");} 
     lcd.print("/"); 
     lcd.print(year+zadTime[3]); 
     lcd.setCursor(12,1);
   if (day==1){lcd.print ("Sun");} 
   if (day==2){lcd.print ("Mon");} 
   if (day==3){lcd.print ("Tue");} 
   if (day==4){lcd.print ("Wed");} 
   if (day==5){lcd.print ("Thu");} 
   if (day==6){lcd.print ("Fri");} 
   if (day==7){lcd.print ("Sat");}
   lcd.setCursor(19,1);                  //Вывод состояния ATX (Power ON\OFF)
   lcd.print(!digitalRead(OUT0));
   lcd.setCursor(1,3);                   //Вывод состояния выходов реле освещения
   lcd.print(!digitalRead(OUT1));
   lcd.setCursor(3,3);
   lcd.print(!digitalRead(OUT2));
   lcd.setCursor(5,3);
   lcd.print(!digitalRead(OUT3));
    }
    lcd.setCursor(17,3);                 //Вывод состояния аналогового выхода диммирования
    lcd.print(angData2);
    lcd.setCursor(18,3);
    lcd.print("  ");
    lcd.setCursor(17,3);
    lcd.print(angData2);
}

void loop(){
    timeRtc();
    timer();
    keyI();
    dallas();
    tempRelay();
    voltM();
    bar();
//    bluetooth();
    printTime();
    printDin();
    printStat();
}

 

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

Отличненько работает, вы объединили релюшки в одну функцию - здорово и строк сразу меньшеи массиввам иопределили температуры и задержки - это как пример будет для будующих переделок. Вход и выход из меню и функции параметров void setOnOff() теперь корректно и без задержек.

Единственноя вынес ЗА пределы работы функции кнопок keyI(); функцию //========== Обработка "одного" нажатия  

если оставить как есть ТО любое условие прерывает её и диммирование ++ или -- прерывается и останавливается на последней комманде, если вынести её в отдельную к примеру в auto_key_dimmer() { и лупить в loop то после выполнения комманды (даже после выхода из меню) диммирование ++ или -- продолжится.

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

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

Сбрасывайте рабочий вариант скетча, буду дальше чесать. Кнопки не трогаю, у вас в динамике их проще проверить. Теперь задержки на опрос датчиков.

Сбросьте мне на почту вашу библу BMP085, у меня что то на нее фыркает.

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

Так, сейчас логика работы не требует второй переменной angData2, будем ее убирать? Если захотите два независимых канала, функции управления придется переделывать серьезно. Которые сейчас, точно не подойдут.

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

bwn пишет:

Так, сейчас логика работы не требует второй переменной angData2, будем ее убирать? Если захотите два независимых канала, функции управления придется переделывать серьезно. Которые сейчас, точно не подойдут.

Это я понимал в самом начале, а для чего разделил? Да просто два канала по 5-ть драйверов и на них сигнал PWM с ардуинки, подумал, ВДРУГ незватит токовой нагрузки и подстраховался, так как подключение напрямую без транзистров и прочей лабуды (драйвер хорошо защищен и нетребует высоких токов) - сделать ДВА канала но СИММЕТРИЧНЫХ. На самом деле драйвера пищат хоть и несильно но пищат и просто оставлять их в "не краних" положениях ( между 0 и 255) ненужно - главное ПЛАВНО поднять освещение на angData2 канале (предварительно задав там 0 и включив реле на  OUT1) - что сейчас шикарно делается.

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

Упс, вот и неувидел её....сорри счас всё упакую.

Вот, вчера после работы залил дома скетчик вми проработанный. Сразу скажу - никаких граблей пока на IR-нет. Дополнительно я пищевой фольгой и на "минус" монтажную схемку с распайкой всех выводов отгородил, надо было сразу. Всеже драйвера фонят и фонят некисло. По скетчу... пост: http://arduino.ru/forum/proekty/groekt-dlya-akvariuma-akvakontroller-dlya-led-temp-time-co2?page=5#comment-99500

вернул строки 338 и 364 без них при увеличении яркости (автодиммировании) по таймеру только ОДИН канал работал. При ручном - оба. Сначала невкурил даже что то неочень ряко + свист легкий на angData2=255 (а н легкий фон пропадает уже после 200) так что их нужно приравнивать с angData1 ранее.

Библиотеки свои ВСЕ выслал.

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

Скетч который сейчас рабочий, тоже сбросьте, а то накодим в разных вариантах))). Потом три года не разберешся.

angData я вообще одну оставлю.

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

Добавил есчо одно на мой взляд НЕЛИШНЮЮ настройку диммирования, 21 -25 строки (надо бы ещё и 26, 27 вкорячить) (пост #256)

Добавил в строку меню: 



const char menuTxt[6][17] = {"set Timer 1 >>>>", "set Timer 2 >>>>","set Timer Lcd >>","set MoonLight >>","set Timer Co2 >>","set Dimmer >>>>"};  //Массив с наименованиями для экрана

Также новую функцию (пока коряво НО уже работает):



//=========== Обработка Меню, параметры диммирования
void setDimmer(){    
  byte pos=0;   
  maxDimm=  EEPROM.read(winMe*5+1);                //Считываем записанные значения таймеров
  upR2=     EEPROM.read(winMe*5+2);                //Адрес определяется как номер таймера*5 + пять ячейки          
  downR2=   EEPROM.read(winMe*5+3);
  upR3=     EEPROM.read(winMe*5+4);                          
  downR3=   EEPROM.read(winMe*5+5);

    tft.fillScreen(ST7735_RED);                           //Clear screen
    while(keyIr()!=1) {                                  //Крутим цикл пока не будет Setup
    byte KEY=keyIr();                                    //Читаем состояние кнопок
    val=0;
    tft.setTextSize(1);
    tft.setCursor(5,90);
    tft.setTextColor(ST7735_GREEN, ST7735_RED);
    tft.print("=== set 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 (maxDimm < 10) tft.print("0");
    tft.print(maxDimm,DEC);
    tft.print(" dim");
    tft.setCursor(5,75);
    tft.setTextColor(ST7735_YELLOW,ST7735_RED);
    tft.setTextSize(1);
     if (upR2 < 10) tft.print("0"); 
    tft.print(upR2,DEC);  
    tft.print(" | ");     
     if (downR2 < 10) tft.print("0");
    tft.print(downR2,DEC);
    tft.print(" || ");
     if (upR3 < 10) tft.print("0");
    tft.print(upR3,DEC);
    tft.print(" | ");     
     if (downR3 < 10) tft.print("0");
    tft.print(downR3,DEC); 
    
    tft.setCursor(pos, 0);                                //Устанавливаем курсор согласно позиции
    
    if (pos<3) pos=3;
    if (KEY==5 && pos<15) pos += 3;                       //Крутим позицию право-лево
    else if (KEY==2 && pos>3) pos -= 3;
    
    else if (pos==3 && KEY==3) maxDimm++;           //Крутим значения
    else if (pos==3 && KEY==4) maxDimm--;
    else if (pos==6 && KEY==3) upR2++;
    else if (pos==6 && KEY==4) upR2--;    
    else if (pos==9 && KEY==3) downR2++;
    else if (pos==9 && KEY==4) downR2--;    
    else if (pos==12 && KEY==3) upR3++;
    else if (pos==12 && KEY==4) upR3--;
    else if (pos==15 && KEY==3) downR3++;
    else if (pos==15 && KEY==4) downR3--;  
}                                                         // конец цикла
//   lcd.noBlink(); 
   tft.fillScreen(ST7735_BLACK);                          // Clear screen
   EEPROM.write(winMe*5+1, maxDimm);                //Записываем НОВЫЕ значения
   EEPROM.write(winMe*5+2, upR2); 
   EEPROM.write(winMe*5+3, downR2);
   EEPROM.write(winMe*5+4, upR3);
   EEPROM.write(winMe*5+5, downR3);
   tft.setCursor(25,105);
   tft.setTextColor(ST7735_WHITE,ST7735_BLACK);
   tft.setTextSize(1);
   tft.print("== Saved ==");
   delay(zadTime[3]);
}

Ну и в саму функцию меню строчки заменил на:

   tft.print(menuTxt[pos]);                                    //Печатаем название
    if (KEY==3 && pos>0) {pos--;}                               //Уменьшить увеличить + блокировка кнопки
    if (KEY==4 && pos<5) {pos++;}
    winMe=pos;                                                  //Переменная номера таймера
if (KEY==5 && pos==0) setOnOff();
if (KEY==5 && pos==1) setOnOff();
if (KEY==5 && pos==2) setOnOff();
if (KEY==5 && pos==3) setMoonLgh();
if (KEY==5 && pos==4) setOnOff();
if (KEY==5 && pos==5) setDimmer();
if (KEY==1) { //Выход из меню с проверкой и установкой блокировки от возврата
tft.fillScreen(ST7735_BLACK); // Clear screen
break; }

- это часть из кода. Коненчое в функции таймера заменил чтение присвоенных переменных (в объявлении переменных они у меня были заданы "=") на чтение из ЕПРОМ. 

Это меню действительно "находка" и памяти увеличилсоь чуть более на 1кб всего :)

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

Последний код, 8 строка будет работать некорректно. второе условие наверно  pos<=4 (знаки сравнения, не уверен правильно ли поставил, может =<)

А у вас при выходе из первого экрана меню в loop, обратно не шмыгает в меню?

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

Нене, всё отличненько и входит и выходит. Нмогу понять почему у меня свободные ячеки ЕПРОМ правда образовались между 9 и 10 строкой последнего кода, тоетсь заканчиваются настройки pos==4 далее (5 пустых ячеек) и pos==5 с её пятью ячейками. Проверал, загружая стандартный скетч чтения:



/*
 * EEPROM Read
 *
 * Reads the value of each byte of the EEPROM and prints it 
 * to the computer.
 * This example code is in the public domain.
 */

#include <EEPROM.h>

// start reading from the first byte (address 0) of the EEPROM
int address = 0;
byte value;

void setup()
{
  // initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
}

void loop()
{
  // read a byte from the current address of the EEPROM
  value = EEPROM.read(address);
  
  Serial.print(address);
  Serial.print("\t");
  Serial.print(value, DEC);
  Serial.println();
  
  // advance to the next address of the EEPROM
  address = address + 1;
  
  // there are only 512 bytes of EEPROM, from 0 to 511, so if we're
  // on address 512, wrap around to address 0
  if (address == 512)
    address = 0;
    
  delay(500);
}

 

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

А я не пересчитывал. Считаем: winMe принимает от 0 до 5 значит

winMe=0 поля 0*4+1 (1) до 0*4+4(4);        =1 1*4+1(5) до 1*4+4(8);    =2 (9) до (12);   =3 (13) до (16);    =4 (17) до (20)

а дальше вы изменили формулу winMe*5+1(5) и получили winMe=5  5*5+1(26) до 5*5+5(30). Вот они 5 недостающих. Здесь либо алгоритм адресации менять либо мирится.

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

Либо убрать один самый первый параметр maxDimm= EEPROM.read(winMe*5+1); из этой функции и перенести, но получится уже нетак красиво,Хотя у мнея же ещё НЕОБРАБОТАНЫ два настраиваемых: пост #256

026 int pManDimmUp=800; //Период увеличения яркости
027 int pManDimmDown=500; //Период уменьшения яркости

Вот попробую к ним, тогда останется один незадействован.

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

Так зачем, второй экран меню можете спокойно использовать для всего где нужны пять ячеек. Ну будет этот разрыв, какая беда? Периоды поделите на 10 и тоже можете в меню забить, только при использовании не забывать умножать обратно. В экранчике написать сек/100*255

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

Добавил вход в даллас из loop + отработка температурных реле по таймингу (они завязаны с далласом) и изменил, где вы реле через функцию releHigh() не сделали. Все angData1,2 заменил на одну переменную angData.

Больше ничего не трогал.


#include <EEPROM.h>
#include <Wire.h>                     //Подключаем библиотеку для использования однопроводного интерфейса                                     
#include <LiquidCrystal_I2C.h>        //Подключаем библиотеку для использования I2C интерфейса
#include <OneWire.h>                  //Подключаем библиотеку для температурного датчика DS18B20
#include <BMP085.h>                   //Подключаем библиотеку для маленького барометра
#include <IRremote.h>                 //Подключаем библиотеку для IR сенсора
LiquidCrystal_I2C lcd(0x27,20,4);     //Устанавливаем LCD-адрес 0x27 для отображения 20 символов и 4 линии
byte currentLight=0;                  //Переменная включения подсветки LCD 


//=====BT*
char inByte;                          //Ввходящие данные BT (Bluetooth модуля)

//=====IR_Sensor*
#define recvPin 3                    //Вход IR-приемника и кнопки пульта
uint32_t val; 
IRrecv irrecv(recvPin);
decode_results results;

//=====IR_Dimmer*
byte angData=0;                   //Переменная выходов диммирования (из двух половинок :))
byte maxDimm=255;                 //Переменная определяет МАКСИМАЛЬНОЕ значение диммирования
byte upR2=210;                    //Переменная включения 2 свето-релейного канала
byte upR3=240;                    //Переменная включения 3 свето-релейного канала
byte downR2=205;                  //Переменная выключения 2 свето-релейного канала
byte downR3=235;                  //Переменная выключения 3 свето-релейного канала
int pManDimmUp=500;               //Период увеличения яркости 
int pManDimmDown=400;             //Период уменьшения яркости
byte flagDimm=0;                  //Флаг для обработки "НЕОБРАТИМОГО" выключения Power_Off
unsigned long tDimm=millis();     //Переменная задержки auto_dimmer

//=====Termo_Relay*
const int RelayChn1=4;             //Используем цифровой ПОРТ 4 для ПЕРВОГО канала термо-реле (вода) 
const int RelayChn2=A1;            //Используем цифровой ПОРТ A1 для ВТОРОГО канала термо-реле (радиатор)

//=====Led_Relay*
#define OUT1 7                      //Используем цифровой ПОРТ 7 для 1 свето-релейного канала Dimm
#define OUT2 8                      //Используем цифровой ПОРТ 8 для 2 свето-релейного канала
#define OUT3 9                      //Используем цифровой ПОРТ 9 для 3 свето-релейного канала

//=====Other_Relay*
#define OUT0 10                     //Используем цифровой ПОРТ 10 для ATX (включение ATX (зелёный + черный))
//#define OUT6 11                     //Используем цифровой ПОРТ 11 для CO2
//#define OUT7 12                     //Используем цифровой ПОРТ 12 для другое

//=====Dimmer_Out*
#define OUT4 5                      //Используем цифровой ПОРТ 5 для 1/2 SunSet канала (dimmer)
#define OUT5 6                      //Используем цифровой ПОРТ 6 для 1/2 SunSet канала (dimmer)

//=====VoltMeter*
int voltInput=A7;                   //Используем аналоговый вход A7 для измерения напряжения
float vout=0.0;
float vin=0.0;
float R1=21700.0;                   //Resistance of R1 (22K) - see text!
float R2=12770.0;                   //Resistance of R2 (12K) - see text!
int valueVo=0;

//=====Pressure*
BMP085 dps=BMP085();                // Digital Pressure Sensor 
long Pressure=0;
unsigned long timeDps=0;

//=====Termo_Sensor*
int tempPin=2;                      //Определяем порт шины OneWire (IC) для температурного датчика DS18B20                               
OneWire ds(tempPin);                //Создаем объект для работы с термометром
byte flagDallas=0;                  //Флаг для обработки показаний с датчиков Dallas
byte data[12];
byte addr1[8] = {0x28, 0xC5, 0x3B, 0x5C, 0x06, 0x00, 0x00, 0x85};     //адрес датчика DS18B20_Вода в аквариуме
byte addr2[8] = {0x28, 0x86, 0x48, 0xEA, 0x05, 0x00, 0x00, 0xF6};     //адрес датчика DS18B20_Радиатор (2-ой канал, центр)
byte addr3[8] = {0x28, 0xF2, 0x29, 0xEB, 0x05, 0x00, 0x00, 0xE1};     //адрес датчика DS18B20_Блок реле
unsigned int raw;                   //Если экранированный кабель, можно подключать до 32 термо-датчиков DS18B20
float temp[3];                      //Температура аквариума \ радиаторов Led \ блока реле
float t[]={25.0, 47.0, 55.0};       //Переменная предела срабатывания реле RelayChn1, RelayChn1, RelayChn1
float tGistrsis=1.0;                //Гистерезис температур (по 0,5 в каждую сторону)

//=====Rtc_Clock*
#define DS3231_I2C_ADDRESS 104 
byte seconds, minutes, hours, day, date, month, year;

//=====Timer*
//    long lghtIntv=60000;            //Интервал для проверки вкл./выкл. освещения аквариума, 1 минута
byte lcdStat=0;                //Флаг подсветки Lcd если включена, то в 1
byte lghtStat[2];              //Флаг освещения, если включена, то в 1 в первом и втором таймере
byte co2Stat=0;                //Флаг Co2, если включена, то в 1
byte isLcdt=0;                 //Флаг для обработки необходимости включить подсветку Lcd
byte isLght[2];                //Флаг для обработки необходимости включить реле освещения в первом и втором таймере
byte isCo2t=0;                 //Флаг для обработки необходимости включить реле Co2
byte isNight=0;                //Если включаем на ночь, т.е. начальное время больше конечного

//=====Menu*
byte setHorClockOn;                 //Часы включения
byte setMinClockOn;                 //Минуты включения
byte setHorClockOff;                //Часы вЫключения
byte setMinClockOff;                //Минуты вЫключения  
byte setTempt1;                     //Максимальная температура t1 (вода в аквариуме)
byte setTempt2;                     //Максимальная температура t2 (радиатор Led)
byte setTempt3;                     //Максимальная температура t3 (блок коммутации, реле)
byte winMe;                         //Номер экрана меню

//=====Delays*
//unsigned long tmIntv=1000;          //Интервал для обновления времени на экране каждую секунду
//unsigned long razdIntv=2000;        //Интервал для обновления ":" на экране каждые 2 секунды
unsigned long prvMlsTm=0;           //Предыдущее показание миллисекунд для обновления показания часов
unsigned long prvMlsRazd=0;         //Предыдущее показание миллисекунд для обновления ":"
//unsigned long prvMlsLght=0;         //Предыдущее показание проверки временного интервала
unsigned long prvMlsVo=0;           //Предыдущее показание обновления показания вольтметра
//unsigned long voIntv=5000;          //Интервал для обновления напряжения
unsigned long prvMlsOut=0;          //Предыдущее показание обновления показания OUT
//unsigned long outIntv=1000;         //Интервал для обновления OUT
unsigned long prvMlsBar=0;          //Предыдущее показание обновления показания барометра
//unsigned long barIntv=10000;        //Интервал для обновления барометра
unsigned long prvMlsTemp=0;         //Предыдущее показание обновления температур
//unsigned long tempIntv=5000;        //Интервал для обновления температур
unsigned long prvMlsTimer=0;        //Предыдущее показание обновления таймера
//unsigned long timerIntv=10000;      //Интервал для обновления таймера
unsigned long tzad=millis();        //Переменная задержки (пока для ds18b20, ds.write) и непользую....

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

const char menuTxt[5][17] = {"set Timer 1 >>>>", "set Timer 2 >>>>","set Timer Lcd >>","set MoonLight >>","set Timer Co2 >>"};  //Массив с наименованиями для экрана

//=====Byte_Symbol*
byte equ[8] =                      //Символ "=" но КОРОТКИЙ :)
{
  B00000,
  B00000,
  B01110,
  B00000,
  B01110,
  B00000,
  B00000,
}; 


void setup() {
  Wire.begin();
//  Serial.begin(9600);
  irrecv.enableIRIn();                                //Включаем IR-сенсор
//                            dps.init(MODE_STANDARD, 25000, true);               //250 meters, true = using meter units
     pinMode(voltInput,INPUT);                        //Определяем вход вольтметра  
//    pinMode(RelayChn1,OUTPUT);                      //Определяем выход 1-термореле охлаждения воды аквариума 
//    pinMode(RelayChn2,OUTPUT);                      //Определяем выход 2-термореле охлаждения радиаторов Led
//  digitalWrite(RelayChn1,HIGH);                     //Определяем инверсный выход в HIGH охлаждения воды аквариума
//  digitalWrite(RelayChn2,HIGH);                     //Определяем инверсный выход в HIGH охлаждения радиаторов Led
     pinMode(OUT0,OUTPUT);                            //Определяем инверсный выход реле ATX 
     pinMode(OUT1,OUTPUT);                            //Определяем инверсные выходы реле 1 канала Led
     pinMode(OUT2,OUTPUT);                            //Определяем инверсные выходы реле 2 канала Led
     pinMode(OUT3,OUTPUT);                            //Определяем инверсные выходы реле 3 канала Led
 //    pinMode(OUT6,OUTPUT);
 //    pinMode(OUT7,OUTPUT);
    relayHigh();                                      //Определяем инверсный выход в HIGH реле ATX, OUT1,2,3
//  digitalWrite(OUT6,HIGH);
//  digitalWrite(OUT7,HIGH);
  analogWrite(OUT4,angData);                         //Инициация выхода 1/2 диммера
  analogWrite(OUT5,angData);                         //Инициация выхода 1/2 диммера
      lcd.init();                                     //Инициализируем дисплейчик
      lcd.setBacklight(1);  
      lcd.clear();                                    //Очищаем на всякий случай дисплейчик
      lcd.setCursor(2,0);
      lcd.print("Aqua  Controller");                  //Выводим версию и прочее
      lcd.setCursor(2,1);
      lcd.print("      v1.1      ");
      lcd.setCursor(0,3);
      lcd.print("_0902_menu_NoEp_Dim_");
  delay(2000);
      lcd.clear();                                    //Очистка дисплея и void (printTime, printDin, printStat)
}

//========== Обработка IR-сенсора, определение кнопок
byte keyIr(){
  if (irrecv.decode(&results)) {      //Если пришел пакет и этот пакет не FF сохраняем правильный пакет в переменную
//  if (results.value!=0xFFFFFFFF) {  //Если пришел FF, соответственно пропускаем.
    val=results.value; //}            //Сверяем значение из переменной val.. если пришла команда повтора (пакет с FF)    
    irrecv.resume(); }                //В переменной останется прошлый, правильный, пакет и код выполнится повторно.
//  Serial.println(val,HEX);
//  Serial.println(" ");
  if (val==0x41BEC03F) return 1;    //setup      KEY1
  if (val==0x41BE40BF) return 2;    //left       KEY2
  if (val==0x41BED02F) return 3;    //up         KEY3
  if (val==0x41BE609F) return 4;    //down       KEY4 
  if (val==0x41BEB04F) return 5;    //right      KEY5
  if (val==0x41BEF00F) return 6;    //exit       POWER_KEY
  if (val==0x41BE708F) return 7;    //vol_down   KEY9
  if (val==0x41BE10EF) return 8;    //vol_up     KEY8
  if (val==0x41BE20DF) return 9;    //slide      KEY9
  if (val==0x41BEA05F) return 10;   //stop       KEY10
    else return 0;
}

//========== Обработка IR-кнопок
void keyI(){
  byte KEY=keyIr();            

//========== Обработка Входа в Меню
     if (KEY==1){                          //***ВХОД В МЕНЮ и проверка блокировки от возврата. Принимаем код клавиши
        val=0;
        menu(); }                          //Если setup идем в меню
    
//========== Отключение LCD с кнопки
  if (KEY==9){ val=0;
    lcd.setBacklight(currentLight);
    currentLight = !currentLight; }

//========== Увеличение яркости (удержание кнопки)
      if (KEY==5){ val=0;
      if (angData<255) angData++;   //Начало увеличения диммирования
         analogWrite(OUT4, angData);
         analogWrite(OUT5, angData);
      if (angData>0){                                  //Включаем реле ATX и диммера на первом шаге (начало диммирования)
         digitalWrite(OUT0,LOW);                        //Включаем реле ATX
         digitalWrite(OUT1,LOW); }
}

//========== Уменьшение яркости (удержание кнопки)
      if (KEY==2){ val=0;
      if (angData!=0) angData--;  //Начало снижения диммирования 
         analogWrite(OUT4, angData);
         analogWrite(OUT5, angData);
      if (angData==0) {                      //Выключаем реле диммера (по окончании диммирования)
         
          relayHigh();
         //digitalWrite(OUT1,HIGH);
         //digitalWrite(OUT2,HIGH);
         //digitalWrite(OUT3,HIGH);
         //digitalWrite(OUT0,HIGH); }         //Выключаем реле ATX
      }
}

//========== Обработка "одного" нажатия   
      if (KEY==8 & flagDimm==0){              //Если нажата кнопка УВЕЛИЧЕНИЯ диммирования
      if (tDimm<millis()){                    //и не дана команда на полное выключение
  pManDimmUp; dimmUp(); }                     //Интервал УВЕЛИЧЕНИЯ диммирования
}
      if (KEY==7 & flagDimm==0){              //Здесь аналогично увеличению яркости
      if (tDimm<millis()) {
  pManDimmDown; dimmDown(); }                 //Интервал Снижения диммирования
}
      if (KEY==6 & angData!=0){              //Power_Off. Если диммер включен, устанавливаем флаг
    flagDimm=1; }
      if (flagDimm==1) {                      //Если флаг установлен, продолжаем уменьшение яркости
      if (angData==0) {                      //Яркость на 0, флаг сбросили.
      flagDimm=0;
    relayHigh(); }
      if (tDimm<millis()){                    //Последовательно уменьшаем яркость, кнопки заблокированы
  pManDimmDown=200; dimmDown(); }             //Интервал СНИЖЕНИЯ диммирования (по Power_Off)
  val=0; 
}  

//========== Обработка ATX, НЕдиммируемых реле
//if (KEY==6) {
//     val=0; if (digitalWrite(OUT0, !digitalRead(OUT0)));      //Power_KEY, ON/OFF_KEY, включение ATX
//if (KEY==6) {
//     val=0; if (digitalWrite(OUT0, !digitalRead(OUT0)));
 if (KEY==3) {
     val=0; if (!digitalRead(OUT1)!=0 && angData >=1) digitalWrite(OUT2,!digitalRead(OUT2));}
 if (KEY==3) { 
     val=0; if (!digitalRead(OUT1)!=0 && angData!=0) digitalWrite(OUT2,digitalRead(OUT2));}
 if (KEY==4) { 
     val=0; if (digitalRead(OUT1)==0 && angData>=1) digitalWrite(OUT3,!digitalRead(OUT3));}
 if (KEY==4) { 
     val=0; if (digitalRead(OUT1)==0 && angData!=0) digitalWrite(OUT3,digitalRead(OUT3));}
}

//========== Увеличение яркости (auto)
void dimmUp() {
      if (angData<maxDimm){                 //Ограничение верхнего значения диммирования, (0-255)
    angData++;                              //Начало подъёма диммирования
    analogWrite(OUT4,angData);              //Пишем в порт
    analogWrite(OUT5,angData);
      if (angData>0){                       //Включаем реле ATX и диммера на первом шаге (начало диммирования)
    digitalWrite(OUT0,LOW);
    digitalWrite(OUT1,LOW); }
      if (angData==upR2) {                  //Включаем Второе реле при upR2
    digitalWrite(OUT2,LOW); }
      if (angData==upR3) {                  //Включаем Третье реле при upR3
    digitalWrite(OUT3,LOW); }
    tDimm=millis()+pManDimmUp; }             //Устанавливаем время следующего шага
    if (angData==maxDimm){val=0;}
}

//========== Уменьшение яркости (auto)
void dimmDown() {
      if (angData>0) {
    angData--;                              //Начало снижения диммирования 
    analogWrite(OUT4,angData);
    analogWrite(OUT5,angData);
      if (angData==downR3){                 //Выключаем Третье реле при downR3
    digitalWrite(OUT3,HIGH); }
      if (angData==downR2){                 //Выключаем Втором реле при downR2
    digitalWrite(OUT2,HIGH); }
      if (angData == 0){                    //Выключаем реле диммера (по окончании диммирования)
     relayHigh();
    //digitalWrite(OUT0,HIGH);
    //digitalWrite(OUT1,HIGH);
    //digitalWrite(OUT2,HIGH);
    //digitalWrite(OUT3,HIGH); }
      }
    tDimm=millis()+pManDimmDown; }           //Устанавливаем время следующего шага
    if (angData==0){val=0;}
}

//=========== Обработка Меню, выбор экрана
void menu(){
  lcd.clear();                                                  //Очищаем на всякий случай дисплейчик
  byte pos=0;
  while(1) {                                                    //Бесконечный цикл
    byte KEY=keyIr();
      val=0;  
    lcd.setCursor(0,1);
    lcd.print(pos+1);                                           //Печатаем номер.
    lcd.print(". ");
    lcd.print(menuTxt[pos]);                                    //Печатаем название
    if (KEY==3 && pos>0) {pos--;}                               //Уменьшить увеличить + блокировка кнопки
    if (KEY==4 && pos<4) {pos++;}
    winMe=pos;                                                  //Переменная номера таймера
// Здесь переходим на подменю. Если останется как сейчас, то достаточно. Сейчас можно перейти на разные подменю.
    if (KEY==5) setOnOff();
                                                                //Подменю вы неиспользуете, поэтому выбросил
    //if (KEY==5 && pos==0) setOnOff();
    //if (KEY==5 && pos==1) setOnOff();
    //if (KEY==5 && pos==2) setOnOff();
    //if (KEY==5 && pos==3) setOnOff();
    //if (KEY==5 && pos==4) setOnOff();
    if (KEY==1) {                                   //Выход из меню с проверкой и установкой блокировки от возврата       
    lcd.clear();                                    //Очищаем на всякий случай дисплейчик
      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);
      lcd.clear();                                       //Очищаем на всякий случай дисплейчик
      lcd.blink();
    while(keyIr()!=1) {                                  //Крутим цикл пока не будет Setup
    byte KEY=keyIr();                                    //Читаем состояние кнопок
    val=0;
     delay(300);                                        //Если убрать, не работает подсветка уст.позиции
    lcd.setCursor(7,0);
    lcd.print("-On-  -Off-"); 
    lcd.setCursor(0,3);
    lcd.print("=== push to save ===");
    lcd.setCursor(1, 1);
    lcd.print(winMe+1,DEC);                              //Печатаем номер программы таймера
    lcd.print("|");
    lcd.print(pos/3,DEC);                                //Печатаем позицию настройки параметра (замена blink)
    lcd.print("->");  
    lcd.setCursor(7,1);                                  //Выводим инфу о часах и минутах
     if (setHorClockOn<10) lcd.print("0");
    lcd.print(setHorClockOn,DEC);
    lcd.print(":");
     if (setMinClockOn<10) lcd.print("0"); 
    lcd.print(setMinClockOn,DEC);  
    lcd.print(" ");     
     if (setHorClockOff<10) lcd.print("0");
    lcd.print(setHorClockOff,DEC);
    lcd.print(":");
     if (setMinClockOff<10) lcd.print("0");
    lcd.print(setMinClockOff,DEC); 
    lcd.setCursor(pos,1);                                 //Устанавливаем курсор согласно позиции
    
    if (pos<3) pos=3;
    if (KEY==5 && pos<11) pos += 3;                       //Крутим позицию право-лево
    else if (KEY==2 && pos>3) pos -= 3;
    
    else if (pos==3 && KEY==3) setHorClockOn++;           //Крутим значения
    else if (pos==3 && KEY==4) setHorClockOn--;
    else if (pos==6 && KEY==3) setMinClockOn++;
    else if (pos==6 && KEY==4) setMinClockOn--;    
    else if (pos==9 && KEY==3) setHorClockOff++;
    else if (pos==9 && KEY==4) setHorClockOff--;    
    else if (pos==12 && KEY==3) setMinClockOff++;
    else if (pos==12 && KEY==4) setMinClockOff--; 
    
    if (setHorClockOn>23) setHorClockOn=0;                //Ограничиваем значения
    else if (setMinClockOn>59) setMinClockOn=0;
    else if (setHorClockOff>23) setHorClockOff=0;
    else if (setMinClockOff>59) setMinClockOff=0;
}                                                         //Конец цикла
      lcd.noBlink(); 
      lcd.clear();                                        //Очищаем на всякий случай дисплейчик
   EEPROM.write(winMe*4+1, setHorClockOn);                //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, setMinClockOn); 
   EEPROM.write(winMe*4+3, setHorClockOff);
   EEPROM.write(winMe*4+4, setMinClockOff);
   lcd.setCursor(4,2);
   lcd.print("== Saved ==");
   delay(zadTime[3]);
}

//========== Считывание напряжения
void voltM() {
  valueVo=analogRead(voltInput);               //Read the value at analog input
  vout=(valueVo*5.0)/1024.0;                   //See text
  vin=vout/(R2/(R1+R2)); 
      if (vin<0.09) {
  vin=0.0; }                                   //Statement to quash undesired reading
}

//========== Считывание Давления
void bar() {
  if (((millis()-timeDps)/1000.0)>=1.0) {  //Конструкция жуткая и жрущая море ресурсов при расчете вещественных чисел.     
//if (timeDps<millis())                    //Я бы закомментил ваши и попробовал так   
    //                  dps.calcTrueTemperature();
     timeDps=millis(); }
  // timeDps=millis()+1000;
  //                    dps.getPressure(&Pressure);
}

//=========== Считывание температур
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){ //flagDallas=0;
  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;
    return celsius;
}

//=========== Обработка Термо-Реле
void tempRelay(){
    
    if (tzad<millis()&&flagDallas==1){
    temp[0] = DS18B20(addr1);
    temp[1] = DS18B20(addr2);
    temp[2] = DS18B20(addr3);
    prvMlsTemp=millis();
    flagDallas=0;
    }
 if (temp[0]>t[0]-tGistrsis/2){
    digitalWrite(RelayChn1,LOW);                 //Термо-реле 1-включается
//        lcd.setCursor(8, 2);
//        lcd.print("*");
  }     
      else if (temp[0]<t[0]+tGistrsis/2){
    digitalWrite(RelayChn1,HIGH);                //Термо-реле 1-выключается
//        lcd.setCursor(8, 2);
//        lcd.print("-");
  } 
      if (temp[1]>t[1]-tGistrsis/2){
    digitalWrite(RelayChn2,LOW);                 //Термо-реле 2-включается
//        lcd.setCursor(18, 2);
//        lcd.print("*");
  }     
      else if (temp[1]<t[1]+tGistrsis/2){
    digitalWrite(RelayChn2,HIGH);                //Термо-реле 2-выключается
//        lcd.setCursor(18, 2);
//        lcd.print("-");
  } 
} 

//=========== Обработка 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));
  }
}

//=========== Обработка Таймеров
void timer(){

//========== Таймер №1 
  int fulMin=hours*60+minutes;                                 //Переводим часы + минуты к полным минутам
  int fulMinOn1=EEPROM.read(1)*60+EEPROM.read(2);              //Переводим часы + минуты включения 1 реле к полным минутам
  int fulMinOff1=EEPROM.read(3)*60+EEPROM.read(4);             //Переводим часы + минуты выключения 1 реле к полным минутам
  int fulMinOn2=EEPROM.read(5)*60+EEPROM.read(6);              //Переводим часы + минуты включения 2 реле к полным минутам
  int fulMinOff2=EEPROM.read(7)*60+EEPROM.read(8);             //Переводим часы + минуты выключения 2 реле к полным минутам
  int fulMinOnLcd=EEPROM.read(9)*60+EEPROM.read(10);           //Переводим часы + минуты включения Lcd к полным минутам
  int fulMinOffLcd=EEPROM.read(11)*60+EEPROM.read(12);         //Переводим часы + минуты выключения Lcd к полным минутам
  int fulMinOffOut3=EEPROM.read(13)*60+EEPROM.read(14);        //Переводим часы + минуты выключения OUT3 к полным минутам
  int fulMinOffOut2=EEPROM.read(15)*60+EEPROM.read(16);        //Переводим часы + минуты выключения OUT2 к полным минутам
          
    if (fulMinOn1>fulMinOff1) {isNight=1;}                     //Если ночное время
    if (isNight==0) {                                          //Если день
    if (fulMin>=fulMinOn1&&fulMin<fulMinOff1) {isLght[0]=1;}        //Проверяем интервал
   else {isLght[0]=0;}                                         //Если необходимо включить свет
  } else {                                                     //Если ночь
      if(fulMin-fulMinOn1>=0) {isLght[0]=1;}                   //Если больше или равно верхнему значению, то необходимо включить свет
   else {                                                      //Если необходимо включить свет
      if(fulMin<fulMinOff1) {isLght[0]=1;}                     //Если меньше нижнего значения, то необходимо включить свет
   else {isLght[0]=0;}                                         //Если необходимо включить свет
    }
  }  
    if((isLght[0]==1)&&(lghtStat[0]==0)){                      //Если свет еще не включен и выставлен флаг необходимости включить
    if (tDimm < millis()) {                                    //И не дана команда на полное выключение
  pManDimmUp; dimmUp(); } 
      if (angData==maxDimm) {lghtStat[0]=1;}
  } else {
      if(isLght[0]==0&&lghtStat[0]==1){
    if (tDimm < millis()) {
  pManDimmDown; dimmDown(); } 
      if (angData==0){lghtStat[0]=0;}
  }
}
//========== Таймер №2
      if (fulMinOn2>fulMinOff2) {isNight=1;}                  //Если ночное время
    if (isNight==0) {                                         //Если день
    if (fulMin>=fulMinOn2&&fulMin<fulMinOff2) {isLght[1]=1;}        //Проверяем интервал
   else {isLght[1]=0; }                                       //Если необходимо включить свет
  } else {                                                    //Если ночь
      if(fulMin-fulMinOn2>=0) {isLght[1]=1;}                  //Если больше или равно верхнему значению, то необходимо включить свет
   else {                                                     //Если необходимо включить свет
      if(fulMin<fulMinOff2) {isLght[1]=1;}                    //Если меньше нижнего значения, то необходимо включить свет
   else {isLght[1]=0; }                                       //Если необходимо включить свет
    }
  }  
    if((isLght[1]==1)&&(lghtStat[1]==0)){                     //Если свет еще не включен и выставлен флаг необходимости включить
    if (tDimm < millis()) {                                   //И не дана команда на полное выключение
  pManDimmUp; dimmUp(); }
      if (angData==maxDimm) {lghtStat[1]=1;}
  } else {
      if(isLght[1]==0&&lghtStat[1]==1){
    if (tDimm < millis()) {
  pManDimmDown; dimmDown(); }
      if (angData==0){lghtStat[1]=0;}
  }
}
//========== Таймер Lcd-подсветки  
      if (fulMinOnLcd>fulMinOffLcd) {isNight=1;}              //Если ночное время
    if (isNight==0) {                                         //Если день
    if (fulMin>=fulMinOnLcd&&fulMin<fulMinOffLcd) {isLcdt=1;}        //Проверяем интервал
   else {isLcdt=0;}                                           //Если необходимо включить подсветку Lcd
  } else {                                                    //Если ночь
      if(fulMin-fulMinOnLcd>=0) {isLcdt=1;}                   //Если больше или равно верхнему значению, то необходимо включить подсветку Lcd
   else {                                                     //Если необходимо включить подсветку Lcd
      if(fulMin<fulMinOffLcd) {isLcdt=1;}                     //Если меньше нижнего значения, то необходимо включить подсветку Lcd
   else {isLcdt=0;}                                           //Если необходимо включить подсветку Lcd
    }
  }  
    if((isLcdt==1)&&(lcdStat==0)){                            //Если подсветка Lcd еще не включена и выставлен флаг необходимости включить
    lcd.backlight(); lcdStat=1;
  } else {
      if(isLcdt==0&&lcdStat==1){
    lcd.noBacklight(); lcdStat=0;
  }
}
//========== Таймер "Лунного света"  
    if (fulMin>=fulMinOffOut3) {
       digitalWrite(OUT3,HIGH);}
    if (fulMin>=fulMinOffOut2) {
       digitalWrite(OUT2,HIGH);
} 
//========== Таймер СО2
}

//=========== Обработка (групповая реле) в ВЫКЛ.
void relayHigh(){
  digitalWrite(OUT0,HIGH);                            //Определяем инверсный выход в HIGH реле ATX
  digitalWrite(OUT1,HIGH);                            //Определяем инверсный выход в HIGH реле 1 канала Led
  digitalWrite(OUT2,HIGH);                            //Определяем инверсный выход в HIGH реле 2 канала Led
  digitalWrite(OUT3,HIGH);                            //Определяем инверсный выход в HIGH реле 3 канала Led
}

//=========== Обработка Bluetooth
void bluetooth() {
}

//=========== Обработки печати и вывода на дисплейчик (часы)
void printTime() {
  unsigned long currentMillis=millis();
      if(currentMillis-prvMlsTm>zadTime[2]){           //Проверяем интервал для обновления часов
  prvMlsTm=currentMillis;                              //Вызываем ф-цию вывода времени на экран
  lcd.setCursor(0,0);
      if (hours<10) {lcd.print(0);lcd.print(hours);} else {lcd.print(hours);} 
  lcd.print(":"); 
      if (minutes<10) {lcd.print(0);lcd.print(minutes);} else {lcd.print(minutes);} 
  lcd.print(":"); 
      if (seconds<10) {lcd.print(0);lcd.print(seconds);} else {lcd.print(seconds);}
  } 
      if(currentMillis - prvMlsRazd > zadTime[3]){    //Проверяем интервал для обновления ":"
    prvMlsRazd=currentMillis;
    lcd.setCursor(2,0);
    lcd.print(" ");
    lcd.setCursor(5,0);
    lcd.print(" ");
    lcd.setCursor(8,0);
    lcd.print(" ");
  }
}
//=========== Обработки печати и вывода на дисплейчик (напряжения, температуры, давление)
void printDin() {
  unsigned long currentMillis=millis();
    if(currentMillis-prvMlsVo>zadTime[5]){           //Проверяем интервал для обновления напряжения
  prvMlsVo=currentMillis;
  lcd.setCursor(2,2);                                //Вывод значений температур на LCD                     
  lcd.print((temp[0]),1);
  lcd.setCursor(9,2);                          
  lcd.print((temp[1]),1);  
  lcd.setCursor(16,2);                          
  lcd.print((temp[2]),1);
  lcd.setCursor(9,3);
  lcd.print(vin);
  lcd.setCursor(4,1);
  lcd.print(Pressure/133.3,1);                      //Выводим на экранчик показания атм.давления в мм.рт.столба
  } 
}

//=========== Обработки печати и вывода на дисплейчик СТАТИКИ
void printStat() {
  unsigned long currentMillis=millis();
        if(currentMillis-prvMlsTimer>zadTime[6]){   //Проверяем интервал для обновления 
      prvMlsTimer=currentMillis;
      lcd.setCursor(16,1);
      lcd.print("pw\1");
      lcd.setCursor(0,1);
      lcd.print("bar\1");
      lcd.setCursor(0,2);
      lcd.print("a\1");
      lcd.setCursor(7,2);
      lcd.print("b\1");
      lcd.setCursor(14,2);
      lcd.print("c\1");
      lcd.setCursor(0,3);
      lcd.print("~");
      lcd.setCursor(2,3);
      lcd.print(":");
      lcd.setCursor(4,3);
      lcd.print(":");
      lcd.setCursor(7,3);
      lcd.print("v\1");
      lcd.setCursor(15,3);
      lcd.print("%\1");
      lcd.setCursor(9,0);
      if (date<10) {lcd.print(0);lcd.print(date);} else {lcd.print(date);} 
      lcd.print("/");
   if (month==1){lcd.print ("Jan");} 
   if (month==2){lcd.print ("Feb");} 
   if (month==3){lcd.print ("Mar");} 
   if (month==4){lcd.print ("Apr");} 
   if (month==5){lcd.print ("May");} 
   if (month==6){lcd.print ("Jun");} 
   if (month==7){lcd.print ("Jul");} 
   if (month==8){lcd.print ("Aug");} 
   if (month==9){lcd.print ("Sep");} 
   if (month==10){lcd.print ("Oct");} 
   if (month==11){lcd.print ("Nov");} 
   if (month==12){lcd.print ("Dec");} 
     lcd.print("/"); 
     lcd.print(year+2000); 
     lcd.setCursor(12,1);
   if (day==1){lcd.print ("Sun");} 
   if (day==2){lcd.print ("Mon");} 
   if (day==3){lcd.print ("Tue");} 
   if (day==4){lcd.print ("Wed");} 
   if (day==5){lcd.print ("Thu");} 
   if (day==6){lcd.print ("Fri");} 
   if (day==7){lcd.print ("Sat");}
   lcd.setCursor(19,1);                            //Вывод состояния ATX (Power ON\OFF)
   lcd.print(!digitalRead(OUT0));
   lcd.setCursor(1,3);                             //Вывод состояния выходов реле освещения
   lcd.print(!digitalRead(OUT1));
   lcd.setCursor(3,3);
   lcd.print(!digitalRead(OUT2));
   lcd.setCursor(5,3);
   lcd.print(!digitalRead(OUT3));
    }
//ПОка для быстрого мониторинга прорисовка диммирования "постоянная"
    lcd.setCursor(17,3);                           //Вывод состояния аналогового выхода диммирования
    lcd.print(angData);
    lcd.setCursor(18,3);
    lcd.print("  ");
    lcd.setCursor(17,3);
    lcd.print(angData);
}

void loop(){
    timeRtc();
    timer();
    keyI();
       if (millis()-prvMlsTemp>zadTime[6]&&flagDallas!=1){
          dallas();}
    tempRelay();
    voltM();
    bar();
//    bluetooth();
    printTime();
    printDin();
    printStat();
}

 

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

Шикарненько, ну вот недумал никогда что можно как высделали в строках 155 и 156 - потому и делал из двух частей на два "пина" :(

ПО термореле, теперечи начал понимать, что вы мне в самом начале толковали про флаги замер\флаг - сравнили с заданным\флаг- ну и вывод на на дисплейчик (строки 421 и 443, и условие в 703 - всё верно? :) )

С каждым разом все меньше размер и строк, ваша коррекция (без моих доп. окошек меню и неубранных currentMillis :) всего 22,5кб - эдак и до AtMegи рукой подать, шутка конечное. Счас главное стабильность и скорость выросла. Я ваши правкив свой кусок с менюшками и на ночь.... теститься.

 

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

Thorn пишет:

Шикарненько, ну вот недумал никогда что можно как высделали в строках 155 и 156 - потому и делал из двух частей на два "пина" :(

ПО термореле, теперечи начал понимать, что вы мне в самом начале толковали про флаги замер\флаг - сравнили с заданным\флаг- ну и вывод на на дисплейчик (строки 421 и 443, и условие в 703 - всё верно? :) )

С каждым разом все меньше размер и строк, ваша коррекция (без моих доп. окошек меню и неубранных currentMillis :) всего 22,5кб - эдак и до AtMegи рукой подать, шутка конечное. Счас главное стабильность и скорость выросла. Я ваши правкив свой кусок с менюшками и на ночь.... теститься.

 

Так я вам сразу говорил, что если всякими tft не баловатся, наны за глаза хватит.

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

Доброго l@yz! :)

Ну что... все работает стабильно и шустро. ПО меню его счас облизываю. Утомляет "невозможность" менять позиции winMe (окон меню) в "цикличной последовательности". Ваш код и строки 314 -315 описал так:

    tft.print(menuTxt[pos]);                                    //Печатаем название
    if (KEY==3 && pos>0) {pos--;}                               //Уменьшить/увеличить позицию окна меню
  else if (pos==0 && KEY==3) {pos=5;}                           //Уменьшить/увеличить (циклично)
    if (KEY==4 && pos<5) {pos++;}
  else if (pos==5 && KEY==4) {pos=0;}

стало нааамного веселее, зная что окошек меню может теперь быть и не 6 а много больше :) (ну и на будущее вдруг понадобится).

Попытался с часами тоже сделать (ну чтобы не начинать с 0 до 23 часов в одну строноу а потмо вдругую) решил также "зациклить" получилось но как т осмешновато. минуты дошли до 59 пытаемся перейти в 00 и тутже меняются и часы (вроде и удобно но ненужно) а назад вообще в мгновение возврат с 0 в 255 !!! и в 0, в 59 никак. Вот какой у меня рисунок кода:

    if (setHorClockOn>23) setHorClockOn=0;                //Ограничиваем значения
    if (setHorClockOn==0 && KEY==4) {setHorClockOn--;}
    else if (setHorClockOn==23 && KEY==3) {setHorClockOn++;}
    if (setMinClockOn>59) setMinClockOn=0;
    if (setMinClockOn==0 && KEY==4) {setMinClockOn--;}
    else if (setMinClockOn==59 && KEY==3) {setHorClockOn++;}
    if (setHorClockOff>23) setHorClockOff=0;
    if (setHorClockOff==0 && KEY==4) {setHorClockOff--;}
    else if (setHorClockOff==23 && KEY==3) {setHorClockOff++;}
    if (setMinClockOff>59) setMinClockOff=0;
    if (setMinClockOff==0 && KEY==4) {setMinClockOff--;}
    else if (setMinClockOff==59 && KEY==3) {setHorClockOff++;}

это строки 380 -383 из поста #270

мне кажется будет прощще и короче на switch \ case (может на данном примере покажите как) при возможности.

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

А второй код если так?

if (pos<3) pos=3;
    if (KEY==5 && pos<11) pos += 3;                       //Крутим позицию право-лево
    if (KEY==2 && pos>3) pos -= 3;
	     
    else if (pos==3 && KEY==3) setHorClockOn++;           //Крутим значения
    else if (pos==3 && KEY==4) setHorClockOn--;
    else if (pos==6 && KEY==3) setMinClockOn++;
    else if (pos==6 && KEY==4) setMinClockOn--;   
    else if (pos==9 && KEY==3) setHorClockOff++;
    else if (pos==9 && KEY==4) setHorClockOff--;   
    else if (pos==12 && KEY==3) setMinClockOff++;
    else if (pos==12 && KEY==4) setMinClockOff--;
	     
    if (setHorClockOn>23) setHorClockOn=0;    //Ограничиваем значения
    else if (setHorClockOn<0)   setHorClockOn=23   
    else if (setMinClockOn>59)  setMinClockOn=0;
    else if (setMinClockOn<0)   setMinClockOn=59;
    else if (setHorClockOff>23) setHorClockOff=0;
    else if (setHorClockOff<0)  setHorClockOff=23;
    else if (setMinClockOff>59) setMinClockOff=0;
    else if (setMinClockOff<0)  setMinClockOff=59;

 

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

Работает толко "++" с 23 на 0 далее 1 2 3 . А вот в "--" неа. тоетсь 2 1 0 и всё, нули. Счас поколдую над вашим, может надо чередовать if else для промежуточныйх значнеи >23 и <0

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

Я если честно, вообще здесь else  не очень понимаю, но не экспериментировал.

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

Здравствуйте. БЛИН блин ....блин.

У меня кончается "свободное место". Немного переделал подменю, теперь их уже семь (пара таймеров на свет, один на со2, один на досветку "луна" типа, диммирование  и установка часов), чуток поправил переменные. В итоге размер уже 29,4кб - на свооде почти ничего. А впереди есчо должна была быть блютусина или wi-fi, неговорю уже про влажность и уровень воды в банке - хотел добавить :)

Что делать relg оптимизироват md первую голову. Библиотек то и нету почти (за исключением IR и барометра - остальные стандартно и без них нельзя. Вотон скетчик - всё работает и стабильно, всё настраивается. Кстати заметил что всё чт ов епром запихивается после сохранения в подменю вступает в силу после RESSET на ардуинке. Код:

#include <EEPROM.h>
#include <Wire.h>                    //Подключаем библиотеку для использования однопроводного интерфейса                                     
#include <LiquidCrystal_I2C.h>       //Подключаем библиотеку для использования I2C интерфейса
#include <OneWire.h>                 //Подключаем библиотеку для температурного датчика DS18B20
#include <BMP085.h>                  //Подключаем библиотеку для маленького барометра
#include <IRremote.h>                //Подключаем библиотеку для IR сенсора
LiquidCrystal_I2C lcd(0x27,20,4);    //Устанавливаем LCD-адрес 0x27 для отображения 20 символов и 4 линии
byte currentLight=0;                 //Переменная включения подсветки LCD 

//=====BT*
char inByte;                         //Ввходящие данные BT (Bluetooth модуля)

//=====IR_Sensor*
#define recvPin 3                    //Вход IR-приемника и кнопки пульта
uint32_t val; 
IRrecv irrecv(recvPin);
decode_results results;

//=====IR_Dimmer*
byte angData=0;                     //Переменная выходов диммирования (из двух половинок :))
byte flagDimm=0;                    //Флаг для обработки "НЕОБРАТИМОГО" выключения Power_Off
unsigned long tDimm=millis();       //Переменная задержки auto_dimmer

//=====Termo_Relay*
const int RelayChn1=4;              //Используем цифровой ПОРТ 4 для ПЕРВОГО канала термо-реле (вода) 
const int RelayChn2=A1;             //Используем цифровой ПОРТ A1 для ВТОРОГО канала термо-реле (радиатор)

//=====Led_Relay*
#define OUT1 7                      //Используем цифровой ПОРТ 7 для 1 свето-релейного канала Dimm
#define OUT2 8                      //Используем цифровой ПОРТ 8 для 2 свето-релейного канала
#define OUT3 9                      //Используем цифровой ПОРТ 9 для 3 свето-релейного канала

//=====Other_Relay*
#define OUT0 10                     //Используем цифровой ПОРТ 10 для ATX (включение ATX (зелёный + черный))
//#define OUT6 11                     //Используем цифровой ПОРТ 11 для CO2
//#define OUT7 12                     //Используем цифровой ПОРТ 12 для другое

//=====Dimmer_Out*
#define OUT4 5                      //Используем цифровой ПОРТ 5 для 1/2 SunSet канала (dimmer)
#define OUT5 6                      //Используем цифровой ПОРТ 6 для 1/2 SunSet канала (dimmer)

//=====Blink led*
#define bLink 13                    //Индикатор и аварийный сброс

//=====VoltMeter*
int voltInput=A7;                   //Используем аналоговый вход A7 для измерения напряжения
float vout=0.0;
float vin=0.0;
float R1=21700.0;                   //Resistance of R1 (22K) - see text!
float R2=12770.0;                   //Resistance of R2 (12K) - see text!
int valueVo=0;

//=====Pressure*
BMP085 dps=BMP085();                // Digital Pressure Sensor 
long Pressure=0;
unsigned long timeDps=0;

//=====Termo_Sensor*
int tempPin=2;                      //Определяем порт шины OneWire (IC) для температурного датчика DS18B20                               
OneWire ds(tempPin);                //Создаем объект для работы с термометром
byte flagDallas=0;                  //Флаг для обработки показаний с датчиков Dallas
byte data[12];
byte addr1[8]={0x28,0xC5,0x3B,0x5C,0x06,0x00,0x00,0x85};     //адрес датчика DS18B20_Вода в аквариуме
byte addr2[8]={0x28,0x86,0x48,0xEA,0x05,0x00,0x00,0xF6};     //адрес датчика DS18B20_Радиатор (2-ой канал, центр)
byte addr3[8]={0x28,0xF2,0x29,0xEB,0x05,0x00,0x00,0xE1};     //адрес датчика DS18B20_Блок реле
unsigned int raw;                   //Если экранированный кабель, можно подключать до 32 термо-датчиков DS18B20
float temp[3];                      //Температура аквариума \ радиаторов Led \ блока реле
float t[]={25.0, 47.0, 55.0};       //Переменная предела срабатывания реле RelayChn1, RelayChn1, RelayChn1
float tGistrsis=1.0;                //Гистерезис температур (по 0,5 в каждую сторону)

//=====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));}

//=====Timer*
//    long lghtIntv=60000;            //Интервал для проверки вкл./выкл. освещения аквариума, 1 минута
byte lcdStat=0;                //Флаг подсветки Lcd если включена, то в 1
byte lghtStat[2];              //Флаг освещения, если включена, то в 1 в первом и втором таймере
byte co2Stat=0;                //Флаг Co2, если включена, то в 1
byte isLcdt=0;                 //Флаг для обработки необходимости включить подсветку Lcd
byte isLght[2];                //Флаг для обработки необходимости включить реле освещения в первом и втором таймере
byte isCo2t=0;                 //Флаг для обработки необходимости включить реле Co2
byte isNight=0;                //Если включаем на ночь, т.е. начальное время больше конечного

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

byte setHorClockOffR3;              //Часы вЫключения OUT3, (R3)
byte setMinClockOffR3;              //Минуты вЫключения OUT3, (R3)
byte setHorClockOffR2;              //Часы вЫключения OUT2, (R2)
byte setMinClockOffR2;              //Минуты вЫключения OUT2, (R2)

byte setTempt1;                     //Максимальная температура t1 (вода в аквариуме)
byte setTempt2;                     //Максимальная температура t2 (радиатор Led)
byte setTempt3;                     //Максимальная температура t3 (блок коммутации, реле)

byte maxDimm;                       //Переменная определяет МАКСИМАЛЬНОЕ значение диммирования
byte upR2;                          //Переменная включения OUT2
byte downR2;                        //Переменная вЫключения OUT2
byte upR3;                          //Переменная включения OUT3
byte downR3;                        //Переменная вЫключения OUT3

byte pManDimmUp;                    //Период увеличения яркости 
byte pManDimmDown;                  //Период уменьшения яркости

//=====Delays*
//unsigned long tmIntv=1000;          //Интервал для обновления времени на экране каждую секунду
unsigned long prvMlsTm=0;           //Предыдущее показание миллисекунд для обновления показания часов
unsigned long prvMlsRazd=0;         //Предыдущее показание миллисекунд для обновления ":"
unsigned long prvMlsVo=0;           //Предыдущее показание обновления показания вольтметра
unsigned long prvMlsOut=0;          //Предыдущее показание обновления показания OUT
unsigned long prvMlsBar=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[7][17]={"set Timer 1 >>>>","set Timer 2 >>>>","set Timer Lcd >>","set MoonLight >>","set Timer Co2 >>","set Dimmer >>>>>","set Clock >>>>>>"};  //Массив с наименованиями для экрана

//=====Byte_Symbol*
byte equ[8]={B00000,B00000,B01110,B00000,B01110,B00000,B00000};  //Символ "=" но КОРОТКИЙ :) 

void setup() {
  Wire.begin();
//  Serial.begin(9600);
  irrecv.enableIRIn();                                //Включаем IR-сенсор
  dps.init(MODE_STANDARD, 25000, true);               //250 meters, true = using meter units
     pinMode(voltInput,INPUT);                        //Определяем вход вольтметра  
//    pinMode(RelayChn1,OUTPUT);                      //Определяем выход 1-термореле охлаждения воды аквариума 
//    pinMode(RelayChn2,OUTPUT);                      //Определяем выход 2-термореле охлаждения радиаторов Led
//  digitalWrite(RelayChn1,HIGH);                     //Определяем инверсный выход в HIGH охлаждения воды аквариума
//  digitalWrite(RelayChn2,HIGH);                     //Определяем инверсный выход в HIGH охлаждения радиаторов Led
     pinMode(OUT0,OUTPUT);                            //Определяем инверсный выход реле ATX 
     pinMode(OUT1,OUTPUT);                            //Определяем инверсные выходы реле 1 канала Led
     pinMode(OUT2,OUTPUT);                            //Определяем инверсные выходы реле 2 канала Led
     pinMode(OUT3,OUTPUT);                            //Определяем инверсные выходы реле 3 канала Led
     pinMode(bLink,OUTPUT);                           //Определяем аварийный "blink led"
 //    pinMode(OUT6,OUTPUT);
 //    pinMode(OUT7,OUTPUT);
//  digitalWrite(OUT0,HIGH);                            //Определяем инверсный выход в HIGH реле ATX
//  digitalWrite(OUT1,HIGH);                            //Определяем инверсный выход в HIGH реле 1 канала Led
//  digitalWrite(OUT2,HIGH);                            //Определяем инверсный выход в HIGH реле 2 канала Led
//  digitalWrite(OUT3,HIGH);                            //Определяем инверсный выход в HIGH реле 3 канала Led
    relayHigh();                                      //Определяем инверсный выход в HIGH реле ATX, OUT1,2,3
  digitalWrite(bLink,HIGH);                           //Определяем аварийный "blink led" в HIGH
//  digitalWrite(OUT6,HIGH);
//  digitalWrite(OUT7,HIGH);
  analogWrite(OUT4,angData);                          //Инициация выхода 1/2 диммера
  analogWrite(OUT5,angData);                          //Инициация выхода 1/2 диммера
      lcd.init();                                     //Инициализируем дисплейчик
      lcd.setBacklight(1);  
      lcd.createChar(1,equ);                          //Создаем символ под номером 1     
      lcd.clear();                                    //Очищаем на всякий случай дисплейчик
      lcd.setCursor(2,0);
      lcd.print("Aqua  Controller");                  //Выводим версию и прочее
      lcd.setCursor(2,1);
      lcd.print("      v3.1      ");
      lcd.setCursor(0,3);
      lcd.print("_1702_menu_setRtc_");
  delay(2000);
      lcd.clear();                                    //Очистка дисплея и void (printTime, printDin, printStat)
}

//========== Обработка IR-сенсора, определение кнопок
byte keyIr(){
  if (irrecv.decode(&results)){       //Если пришел пакет и этот пакет не FF сохраняем правильный пакет в переменную
//  if (results.value!=0xFFFFFFFF){   //Если пришел FF, соответственно пропускаем.
    val=results.value; //}            //Сверяем значение из переменной val.. если пришла команда повтора (пакет с FF)    
    irrecv.resume();}                 //В переменной останется прошлый, правильный, пакет и код выполнится повторно.
//  Serial.println(val,HEX);
//  Serial.println(" ");
  if (val==0x41BEC03F) return 1;    //setup      KEY1
  if (val==0x41BE40BF) return 2;    //left       KEY2
  if (val==0x41BED02F) return 3;    //up         KEY3
  if (val==0x41BE609F) return 4;    //down       KEY4 
  if (val==0x41BEB04F) return 5;    //right      KEY5
  if (val==0x41BEF00F) return 6;    //exit       POWER_KEY
  if (val==0x41BE708F) return 7;    //vol_down   KEY9
  if (val==0x41BE10EF) return 8;    //vol_up     KEY8
  if (val==0x41BE20DF) return 9;    //slide      KEY9
  if (val==0x41BEA05F) return 10;   //stop       KEY10
    else return 0;
}

//========== Обработка IR-кнопок
void keyI(){
  byte KEY=keyIr();            

//========== Обработка Входа в Меню
     if (KEY==1){                          //ВХОД В МЕНЮ и проверка блокировки от возврата. Принимаем код клавиши
        val=0;
        menu();}                           //Если setup идем в меню
    
//========== Отключение LCD с кнопки
  if (KEY==9){ val=0;
    lcd.setBacklight(currentLight);
    currentLight=!currentLight;}

//========== Увеличение яркости (удержание кнопки)
      if (KEY==5){ val=0;
      if (angData<255) angData;                        //Начало увеличения диммирования
         analogWrite(OUT4,angData);
         analogWrite(OUT5,angData);
      if (angData>0){                                  //Включаем реле ATX и диммера на первом шаге (начало диммирования)
         digitalWrite(OUT0,LOW);                       //Включаем реле ATX
         digitalWrite(OUT1,LOW);}
}

//========== Уменьшение яркости (удержание кнопки)
      if (KEY==2){ val=0;
      if (angData!=0) angData--;                        //Начало снижения диммирования 
         analogWrite(OUT4, angData);
         analogWrite(OUT5, angData);
      if (angData==0){                                 //Выключаем реле диммера (по окончании диммирования)
//         digitalWrite(OUT1,HIGH);
//        digitalWrite(OUT2,HIGH);
//         digitalWrite(OUT3,HIGH);
//         digitalWrite(OUT0,HIGH);
        relayHigh();}                     //Выключаем реле ATX
}

//========== Обработка "одного" нажатия   
      if (KEY==8 & flagDimm==0){              //Если нажата кнопка УВЕЛИЧЕНИЯ диммирования
      if (tDimm<millis()){                    //и не дана команда на полное выключение
    (EEPROM.read(26)*50); dimmUp();}          //Интервал УВЕЛИЧЕНИЯ диммирования
}
      if (KEY==7 & flagDimm==0){              //Здесь аналогично увеличению яркости
      if (tDimm<millis()){
    (EEPROM.read(27)*50); dimmDown();}        //Интервал Снижения диммирования
}
      if (KEY==6 & angData!=0){               //Power_Off. Если диммер включен, устанавливаем флаг
    flagDimm=1; }
      if (flagDimm==1){                       //Если флаг установлен, продолжаем уменьшение яркости
      if (angData==0){                        //Яркость на 0, флаг сбросили.
      flagDimm=0;
//    digitalWrite(OUT1,HIGH);
//    digitalWrite(OUT2,HIGH);
//    digitalWrite(OUT3,HIGH);
//    digitalWrite(OUT0,HIGH);
    relayHigh();}
      if (tDimm<millis()){                    //Последовательно уменьшаем яркость, кнопки заблокированы
    (EEPROM.read(27)*50)/2; dimmDown();}      //Интервал СНИЖЕНИЯ диммирования (по Power_Off)
  val=0; 
}  

//========== Обработка ATX, НЕдиммируемых реле
//if (KEY==6){
//     val=0; if (digitalWrite(OUT0, !digitalRead(OUT0)));      //Power_KEY, ON/OFF_KEY, включение ATX
//if (KEY==6){
//     val=0; if (digitalWrite(OUT0, !digitalRead(OUT0)));
 if (KEY==3){
     val=0; if (!digitalRead(OUT1)!=0 && angData>=1) digitalWrite(OUT2,!digitalRead(OUT2));}
 if (KEY==3){ 
     val=0; if (!digitalRead(OUT1)!=0 && angData!=0) digitalWrite(OUT2,digitalRead(OUT2));}
 if (KEY==4){ 
     val=0; if (digitalRead(OUT1)==0 && angData>=1) digitalWrite(OUT3,!digitalRead(OUT3));}
 if (KEY==4){ 
     val=0; if (digitalRead(OUT1)==0 && angData!=0) digitalWrite(OUT3,digitalRead(OUT3));}
}

//========== Увеличение яркости (auto)
void dimmUp(){
      if (angData<EEPROM.read(21)){                 //Ограничение верхнего значения диммирования, (0-255)
    angData++;                                     //Начало подъёма диммирования
    analogWrite(OUT4,angData);                     //Пишем в порт
    analogWrite(OUT5,angData);
      if (angData>0){                              //Включаем реле ATX и диммера на первом шаге (начало диммирования)
    digitalWrite(OUT0,LOW);
    digitalWrite(OUT1,LOW);}
      if (angData==EEPROM.read(22)){               //Включаем Второе реле при upR2
    digitalWrite(OUT2,LOW);}
      if (angData==EEPROM.read(24)){               //Включаем Третье реле при upR3
    digitalWrite(OUT3,LOW);}
    tDimm=millis()+(EEPROM.read(26)*50);}          //Устанавливаем время следующего шага
    if (angData==EEPROM.read(21)){val=0;}
}

//========== Уменьшение яркости (auto)
void dimmDown(){
      if (angData>0){
    angData--;                                    //Начало снижения диммирования 
    analogWrite(OUT4,angData);
    analogWrite(OUT5,angData);
      if (angData==EEPROM.read(25)){              //Выключаем Третье реле при downR3
    digitalWrite(OUT3,HIGH);}
      if (angData==EEPROM.read(23)){              //Выключаем Втором реле при downR2
    digitalWrite(OUT2,HIGH);}
      if (angData==0){                            //Выключаем реле диммера (по окончании диммирования)
//    digitalWrite(OUT0,HIGH);
//    digitalWrite(OUT1,HIGH);
//    digitalWrite(OUT2,HIGH);
//    digitalWrite(OUT3,HIGH);
    relayHigh();}
    tDimm=millis()+(EEPROM.read(27)*50);}         //Устанавливаем время следующего шага
    if (angData==0){val=0;}
}

//=========== Обработка Меню, выбор экрана
void menu(){
  lcd.clear();                                                  //Очищаем на всякий случай дисплейчик
  byte pos=0;
  while(1){ bLinkLed();                                         //Бесконечный цикл
    byte KEY=keyIr();
      val=0;  
    lcd.setCursor(0,1);
    lcd.print(pos+1);                                           //Печатаем номер.
    lcd.print(". ");
    lcd.print(menuTxt[pos]);                                    //Печатаем название
    if (KEY==3 && pos>0) {pos--;}                               //Уменьшить/увеличить позицию окна меню
  else if (pos==0 && KEY==3) {pos=6;}                           //Уменьшить/увеличить (циклично)
    if (KEY==4 && pos<6) {pos++;}
  else if (pos==6 && KEY==4) {pos=0;}
      winMe=pos;                                                //Переменная номера окна подменю
    if (KEY==5 && pos==0) setOnOff();    //"set Timer 1 >>>>" 0
    if (KEY==5 && pos==1) setOnOff();    //"set Timer 2 >>>>" 1
    if (KEY==5 && pos==2) setOnOff();    //"set Timer Lcd >>" 2
    if (KEY==5 && pos==3) setMoonLgh();  //"set MoonLight >>" 3
    if (KEY==5 && pos==4) setOnOff();    //"set Timer Co2 >>" 4
    if (KEY==5 && pos==5) setDimmer();   //"set Dimmer >>>>>" 5
    if (KEY==5 && pos==6) setClock();    //"set Clock >>>>>>" 6
    if (KEY==1){                                              //Выход из меню с проверкой и установкой блокировки от возврата       
    lcd.clear();                                              //Очищаем на всякий случай дисплейчик
      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);
      lcd.clear();                                       //Очищаем на всякий случай дисплейчик
//      lcd.blink();
    while(keyIr()!=1){                                   //Крутим цикл пока не будет Setup
    byte KEY=keyIr();                                    //Читаем состояние кнопок
    val=0;
//      delay(200);                                     //Если убрать, не работает подсветка уст.позиции
    lcd.setCursor(7,0);
    lcd.print("-On-  -Off-"); 
    lcd.setCursor(0,3);
    lcd.print("=== push to save ===");
    lcd.setCursor(1,1);
    lcd.print(winMe+1,DEC);                              //Печатаем номер программы таймера
    lcd.print("|");
    lcd.print(pos/3,DEC);                                //Печатаем позицию настройки параметра (замена blink)
    lcd.print("->");  
    lcd.setCursor(7,1);                                  //Выводим инфу о часах и минутах
     if (setHorClockOn<10) lcd.print("0");
    lcd.print(setHorClockOn,DEC);
    lcd.print(":");
     if (setMinClockOn<10) lcd.print("0"); 
    lcd.print(setMinClockOn,DEC);  
    lcd.print(" ");     
     if (setHorClockOff<10) lcd.print("0");
    lcd.print(setHorClockOff,DEC);
    lcd.print(":");
     if (setMinClockOff<10) lcd.print("0");
    lcd.print(setMinClockOff,DEC); 
    
    lcd.setCursor(pos,1);                                 //Устанавливаем курсор согласно позиции
    if (pos<3) pos=3;
    if (KEY==5 && pos<11) pos += 3;                       //Крутим позицию право-лево
    else if (KEY==2 && pos>3) pos -= 3;
    
    else if (pos==3 && KEY==3) setHorClockOn++;           //Крутим значения
    else if (pos==3 && KEY==4) setHorClockOn--;
    else if (pos==6 && KEY==3) setMinClockOn++;
    else if (pos==6 && KEY==4) setMinClockOn--;    
    else if (pos==9 && KEY==3) setHorClockOff++;
    else if (pos==9 && KEY==4) setHorClockOff--;    
    else if (pos==12 && KEY==3) setMinClockOff++;
    else if (pos==12 && KEY==4) setMinClockOff--; 
    
    if (setHorClockOn>23) setHorClockOn=0;                //Ограничиваем значения
    else if (setMinClockOn>59) setMinClockOn=0;
    else if (setHorClockOff>23) setHorClockOff=0;
    else if (setMinClockOff>59) setMinClockOff=0;
}                                                         //Конец цикла
//      lcd.noBlink(); 
      lcd.clear();                                        //Очищаем на всякий случай дисплейчик
   EEPROM.write(winMe*4+1, setHorClockOn);                //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, setMinClockOn); 
   EEPROM.write(winMe*4+3, setHorClockOff);
   EEPROM.write(winMe*4+4, setMinClockOff);
   lcd.setCursor(4,2);
   lcd.print("== Saved ==");
   delay(zadTime[4]);
}

//=========== Обработка Меню, Лунный свет
void setMoonLgh(){    
  byte pos=0;   
  setHorClockOffR3=  EEPROM.read(winMe*4+1);                //Считываем записанные значения таймеров
  setMinClockOffR3=  EEPROM.read(winMe*4+2);                //Адрес определяется как номер таймера*4 + четыре ячейки
  setHorClockOffR2=  EEPROM.read(winMe*4+3);
  setMinClockOffR2=  EEPROM.read(winMe*4+4);
      lcd.clear();                                          //Очищаем на всякий случай дисплейчик
//      lcd.blink();
    while(keyIr()!=1){                                      //Крутим цикл пока не будет Setup
    byte KEY=keyIr();                                       //Читаем состояние кнопок
    val=0;
//      delay(200);                                         //Если убрать, не работает подсветка уст.позиции
    lcd.setCursor(7,0);
    lcd.print("-R3-  -R2-"); 
    lcd.setCursor(0,3);
    lcd.print("=== push to save ===");
    lcd.setCursor(1, 1);
    lcd.print(winMe+1,DEC);                              //Печатаем номер программы таймера
    lcd.print("|");
    lcd.print(pos/3,DEC);                                //Печатаем позицию настройки параметра (замена blink)
    lcd.print("->");  
    lcd.setCursor(7,1);                                  //Выводим инфу о часах и минутах
     if (setHorClockOffR3<10) lcd.print("0");
    lcd.print(setHorClockOffR3,DEC);
    lcd.print(":");
     if (setMinClockOffR3<10) lcd.print("0"); 
    lcd.print(setMinClockOffR3,DEC);  
    lcd.print(" ");     
     if (setHorClockOffR2<10) lcd.print("0");
    lcd.print(setHorClockOffR2,DEC);
    lcd.print(":");
     if (setMinClockOffR2<10) lcd.print("0");
    lcd.print(setMinClockOffR2,DEC); 
    
    lcd.setCursor(pos,1);                                 //Устанавливаем курсор согласно позиции
    if (pos<3) pos=3;
    if (KEY==5 && pos<11) pos += 3;                       //Крутим позицию право-лево
    else if (KEY==2 && pos>3) pos -= 3;
    
    else if (pos==3 && KEY==3) setHorClockOffR3++;        //Крутим значения
    else if (pos==3 && KEY==4) setHorClockOffR3--;
    else if (pos==6 && KEY==3) setMinClockOffR3++;
    else if (pos==6 && KEY==4) setMinClockOffR3--;    
    else if (pos==9 && KEY==3) setHorClockOffR2++;
    else if (pos==9 && KEY==4) setHorClockOffR2--;    
    else if (pos==12 && KEY==3) setMinClockOffR2++;
    else if (pos==12 && KEY==4) setMinClockOffR2--; 
    
    if (setHorClockOffR3>23) setHorClockOffR3=0;            //Ограничиваем значения
    if (setHorClockOffR2>23) setHorClockOffR2=0;            //Ограничиваем значения
    else if (setMinClockOffR3>59) setMinClockOffR3=0;
    else if (setMinClockOffR2>59) setMinClockOffR2=0;
}                                                           //Конец цикла
//      lcd.noBlink(); 
      lcd.clear();                                          //Очищаем на всякий случай дисплейчик
   EEPROM.write(winMe*4+1, setHorClockOffR3);               //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, setMinClockOffR3); 
   EEPROM.write(winMe*4+3, setHorClockOffR2);
   EEPROM.write(winMe*4+4, setMinClockOffR2);
   lcd.setCursor(4,2);
   lcd.print("== Saved ==");
   delay(zadTime[4]);
}

//=========== Обработка Меню, параметры диммирования (максимальное значение и пределы OUT2,3)
void setDimmer(){    
  byte pos=0;   
  maxDimm=      EEPROM.read(winMe*4+1);                //Считываем записанные значения диммирования 
  upR2=         EEPROM.read(winMe*4+2);                //Адрес определяется как номер диммера*4 + семь ячеек          
  downR2=       EEPROM.read(winMe*4+3);
  upR3=         EEPROM.read(winMe*4+4);                          
  downR3=       EEPROM.read(winMe*4+5);
  pManDimmUp=   EEPROM.read(winMe*4+6);
  pManDimmDown= EEPROM.read(winMe*4+7);
      lcd.clear();                                     //Очищаем на всякий случай дисплейчик
//      lcd.blink();
    while(keyIr()!=1){                                 //Крутим цикл пока не будет Setup
    byte KEY=keyIr();                                  //Читаем состояние кнопок
    val=0;
//      delay(200);                                    //Если убрать, не работает подсветка уст.позиции
    lcd.setCursor(0,3);
    lcd.print("=== push to save ===");
    lcd.setCursor(0, 0);
    lcd.print(winMe+1,DEC);                              //Печатаем номер программы таймера
    lcd.print("|");
    lcd.print(pos/3,DEC);                                //Печатаем позицию настройки параметра (замена blink)
    lcd.print("->");  
    lcd.setCursor(7,0);                                  //Выводим инфу о часах и минутах
     if (maxDimm<10) lcd.print("0");
    lcd.print(maxDimm);
    lcd.print(" dimm");
    lcd.setCursor(0,1);
     if (upR2<10) lcd.print("0"); 
    lcd.print(upR2);  
    lcd.print("/");     
     if (downR2<10) lcd.print("0");
    lcd.print(downR2);
    lcd.print("   |  ");
     if (upR3<10) lcd.print("0");
    lcd.print(upR3);
    lcd.print("/");     
     if (downR3<10) lcd.print("0");
    lcd.print(downR3);
    lcd.setCursor(0,2);                                   //Выводим инфу о часах и минутах
     if (pManDimmUp<10) lcd.print("0");
    lcd.print(pManDimmUp,DEC);
    lcd.print(" *50ms");
    lcd.print("  | ");
     if (pManDimmDown<10) lcd.print("0"); 
    lcd.print(pManDimmDown,DEC); 
    lcd.print(" *50ms"); 
    
    lcd.setCursor(pos,0);                                 //Устанавливаем курсор согласно позиции
        if (pos<3) pos=3;
    if (KEY==5 && pos<21) pos += 3;                       //Крутим позицию право-лево
    else if (KEY==2 && pos>3) pos -= 3;
    
    else if (pos==3 && KEY==3) maxDimm++;                 //Крутим значения
    else if (pos==3 && KEY==4) maxDimm--;
    else if (pos==6 && KEY==3) upR2++;
    else if (pos==6 && KEY==4) upR2--;    
    else if (pos==9 && KEY==3) downR2++;
    else if (pos==9 && KEY==4) downR2--;    
    else if (pos==12 && KEY==3) upR3++;
    else if (pos==12 && KEY==4) upR3--;
    else if (pos==15 && KEY==3) downR3++;
    else if (pos==15 && KEY==4) downR3--; 
    else if (pos==18 && KEY==3) pManDimmUp++;
    else if (pos==18 && KEY==4) pManDimmUp--;
    else if (pos==21 && KEY==3) pManDimmDown++;
    else if (pos==21 && KEY==4) pManDimmDown--;
  
    if (pManDimmUp==0 && KEY==4) pManDimmUp=30;            //Реверсивное изменение значений
    if (pManDimmUp>30) pManDimmUp=0;                       //Ограничиваем значения
    if (pManDimmDown==0 && KEY==4) pManDimmDown=30;
    if (pManDimmDown>30) pManDimmDown=0;  
}                                                          //Конец цикла
//      lcd.noBlink(); 
      lcd.clear();                                         //Очищаем на всякий случай дисплейчик
   EEPROM.write(winMe*4+1, maxDimm);                       //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, upR2); 
   EEPROM.write(winMe*4+3, downR2);
   EEPROM.write(winMe*4+4, upR3);
   EEPROM.write(winMe*4+5, downR3);
   EEPROM.write(winMe*4+6, pManDimmUp);
   EEPROM.write(winMe*4+7, pManDimmDown);
   lcd.setCursor(4,2);
   lcd.print("== Saved ==");
   delay(zadTime[4]);
}

//=========== Обработка Меню, параметры установки времени и прочее
void setClock(){ // установка часов
  byte pos=0;
      lcd.clear();                                       //Очищаем на всякий случай дисплейчик
//      lcd.blink();
    while(keyIr()!=1){                                   //Крутим цикл пока не будет Setup
    byte KEY=keyIr();                                    //Читаем состояние кнопок
    val=0;
//      delay(200);                                      //Если убрать, не работает подсветка уст.позиции
    lcd.setCursor(0,3);
    lcd.print("=== push to save ===");
    lcd.setCursor(0, 0);
    lcd.print(winMe+1,DEC);                              //Печатаем номер программы таймера
    lcd.print("|");
    lcd.print(pos/3,DEC);                                //Печатаем позицию настройки параметра (замена blink)
    lcd.print("->");  
    lcd.setCursor(7,0);      
     if (hours<10) lcd.print("0");
    lcd.print(hours);
    lcd.print(":");
     if (minutes<10) lcd.print("0"); 
    lcd.print(minutes);
      lcd.print(":");
     if (seconds<10) lcd.print("0"); 
    lcd.print(seconds); 
    lcd.setCursor(0,1);
      if (day<10) lcd.print("0");
    lcd.print(day);
      lcd.print(" | ");
      if (date<10) lcd.print("0");
    lcd.print(date);
    lcd.print("/");
     if (month<10) lcd.print("0");
    lcd.print(month);
    lcd.print("/");
     if (year<10) lcd.print("0");
    lcd.print(year);
    
    lcd.setCursor(pos,0);
      if (pos<3) pos=3;                                     //Устанавливаем курсор согласно позиции
    if (KEY==5 && pos<21) pos += 3;                         //Крутим позицию право-лево
    else if (KEY==2 && pos>3) pos -= 3;
    
    else if (pos==3 && KEY==3) hours++;                     //Крутим значения
    else if (pos==3 && KEY==4) hours--;
    else if (pos==6 && KEY==3) minutes++;
    else if (pos==6 && KEY==4) minutes--;
    else if (pos==9 && KEY==3) seconds++;
    else if (pos==9 && KEY==4) seconds--;
    else if (pos==12 && KEY==3) day++;
    else if (pos==12 && KEY==4) day--;     
    else if (pos==15 && KEY==3) date++;
    else if (pos==15 && KEY==4) date--;    
    else if (pos==18 && KEY==3) month++;
    else if (pos==18 && KEY==4) month--;    
    else if (pos==21 && KEY==3) year++;
    else if (pos==21 && KEY==4) 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;
  }
//      lcd.noBlink(); 
      lcd.clear();                                        //Очищаем на всякий случай дисплейчик 
   setRtc(seconds, minutes, hours, day, date, month, year); 
   lcd.setCursor(4,2);
   lcd.print("== Saved ==");
   delay(zadTime[4]);
}

//========== Считывание напряжения
void voltM(){
  valueVo=analogRead(voltInput);                         //Read the value at analog input
  vout=(valueVo*5.0)/1024.0;                             //See text
  vin=vout/(R2/(R1+R2)); 
      if (vin<0.09){
  vin=0.0;}                                              //Statement to quash undesired reading
}

//========== Считывание Давления
void bar(){
      if (timeDps<millis()){                            //Конструкция жуткая и жрущая море ресурсов при расчете вещественных чисел.   
    dps.calcTrueTemperature();
    timeDps=millis()+1000;}
  dps.getPressure(&Pressure);
}

//=========== Считывание температур
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 tempRelay(){
      if (tzad<millis()&&flagDallas==1){
    temp[0]=DS18B20(addr1);
    temp[1]=DS18B20(addr2);
    temp[2]=DS18B20(addr3);
    prvMlsTemp=millis();
      flagDallas=0;}
      if (temp[0]>t[0]-tGistrsis/2){
    digitalWrite(RelayChn1,LOW);                 //Термо-реле 1-включается
//        lcd.setCursor(8, 2);
//        lcd.print("*");
  }     
      else if (temp[0]<t[0]+tGistrsis/2){
    digitalWrite(RelayChn1,HIGH);                //Термо-реле 1-выключается
//        lcd.setCursor(8, 2);
//        lcd.print("-");
  } 
      if (temp[1]>t[1]-tGistrsis/2){
    digitalWrite(RelayChn2,LOW);                 //Термо-реле 2-включается
//        lcd.setCursor(18, 2);
//        lcd.print("*");
  }     
      else if (temp[1]<t[1]+tGistrsis/2){
    digitalWrite(RelayChn2,HIGH);                //Термо-реле 2-выключается
//        lcd.setCursor(18, 2);
//        lcd.print("-");
  } 
} 

//=========== Обработка установки 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));
  }
}

//=========== Обработка Таймеров
void timer(){

//========== Таймер №1 
  int fulMin=hours*60+minutes;                                 //Переводим часы + минуты к полным минутам
  int fulMinOn1=      EEPROM.read(1)*60+EEPROM.read(2);        //Переводим часы + минуты включения 1 реле к полным минутам
  int fulMinOff1=     EEPROM.read(3)*60+EEPROM.read(4);        //Переводим часы + минуты выключения 1 реле к полным минутам
  int fulMinOn2=      EEPROM.read(5)*60+EEPROM.read(6);        //Переводим часы + минуты включения 2 реле к полным минутам
  int fulMinOff2=     EEPROM.read(7)*60+EEPROM.read(8);        //Переводим часы + минуты выключения 2 реле к полным минутам
  int fulMinOnLcd=    EEPROM.read(9)*60+EEPROM.read(10);       //Переводим часы + минуты включения Lcd к полным минутам
  int fulMinOffLcd=   EEPROM.read(11)*60+EEPROM.read(12);      //Переводим часы + минуты выключения Lcd к полным минутам
  int fulMinOffOut3=  EEPROM.read(13)*60+EEPROM.read(14);      //Переводим часы + минуты выключения OUT3 к полным минутам
  int fulMinOffOut2=  EEPROM.read(15)*60+EEPROM.read(16);      //Переводим часы + минуты выключения OUT2 к полным минутам
          
    if (fulMinOn1>fulMinOff1) {isNight=1;}                     //Если ночное время
    if (isNight==0){                                           //Если день
    if (fulMin>=fulMinOn1&&fulMin<fulMinOff1) {isLght[0]=1;}   //Проверяем интервал
   else {isLght[0]=0;}                                         //Если необходимо включить свет
  } else {                                                     //Если ночь
      if(fulMin-fulMinOn1>=0) {isLght[0]=1;}                   //Если больше или равно верхнему значению, то необходимо включить свет
   else {                                                      //Если необходимо включить свет
      if(fulMin<fulMinOff1) {isLght[0]=1;}                     //Если меньше нижнего значения, то необходимо включить свет
   else {isLght[0]=0;}                                         //Если необходимо включить свет
    }
  }  
    if((isLght[0]==1)&&(lghtStat[0]==0)){                      //Если свет еще не включен и выставлен флаг необходимости включить
    if (tDimm < millis()){                                     //И не дана команда на полное выключение
  (EEPROM.read(26)*50); dimmUp();} 
      if (angData==EEPROM.read(21)) {lghtStat[0]=1;}
  } else {
      if(isLght[0]==0&&lghtStat[0]==1){
    if (tDimm < millis()){
  (EEPROM.read(27)*50); dimmDown();} 
      if (angData==0){lghtStat[0]=0;}
  }
}
//========== Таймер №2
      if (fulMinOn2>fulMinOff2) {isNight=1;}                  //Если ночное время
    if (isNight==0){                                          //Если день
    if (fulMin>=fulMinOn2&&fulMin<fulMinOff2) {isLght[1]=1;}  //Проверяем интервал
   else {isLght[1]=0;}                                        //Если необходимо включить свет
  } else {                                                    //Если ночь
      if(fulMin-fulMinOn2>=0) {isLght[1]=1;}                  //Если больше или равно верхнему значению, то необходимо включить свет
   else {                                                     //Если необходимо включить свет
      if(fulMin<fulMinOff2) {isLght[1]=1;}                    //Если меньше нижнего значения, то необходимо включить свет
   else {isLght[1]=0; }                                       //Если необходимо включить свет
    }
  }  
    if((isLght[1]==1)&&(lghtStat[1]==0)){                     //Если свет еще не включен и выставлен флаг необходимости включить
    if (tDimm < millis()){                                    //И не дана команда на полное выключение
  (EEPROM.read(26)*50); dimmUp();}
      if (angData==EEPROM.read(21)) {lghtStat[1]=1;}
  } else {
      if(isLght[1]==0&&lghtStat[1]==1){
    if (tDimm < millis()){
  (EEPROM.read(27)*50); dimmDown();}
      if (angData==0){lghtStat[1]=0;}
  }
}
//========== Таймер Lcd-подсветки  
      if (fulMinOnLcd>fulMinOffLcd) {isNight=1;}              //Если ночное время
    if (isNight==0){                                          //Если день
    if (fulMin>=fulMinOnLcd&&fulMin<fulMinOffLcd) {isLcdt=1;}        //Проверяем интервал
   else {isLcdt=0;}                                           //Если необходимо включить подсветку Lcd
  } else {                                                    //Если ночь
      if(fulMin-fulMinOnLcd>=0) {isLcdt=1;}                   //Если больше или равно верхнему значению, то необходимо включить подсветку Lcd
   else {                                                     //Если необходимо включить подсветку Lcd
      if(fulMin<fulMinOffLcd) {isLcdt=1;}                     //Если меньше нижнего значения, то необходимо включить подсветку Lcd
   else {isLcdt=0;}                                           //Если необходимо включить подсветку Lcd
    }
  }  
    if((isLcdt==1)&&(lcdStat==0)){                            //Если подсветка Lcd еще не включена и выставлен флаг необходимости включить
    lcd.backlight(); lcdStat=1;
  } else {
      if(isLcdt==0&&lcdStat==1){
    lcd.noBacklight(); lcdStat=0;
  }
}
//========== Таймер "Лунного света"  
    if (fulMin>=fulMinOffOut3) {
       digitalWrite(OUT3,HIGH);}
    if (fulMin>=fulMinOffOut2) {
       digitalWrite(OUT2,HIGH);
} 
//========== Таймер СО2
}

/*
//=========== Обработка Bluetooth
void bluetooth() {
 if (Serial.available()>0){  
}
*/

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

//=========== Обработка отключения ВСЕХ OUT (реле)
void relayHigh(){
  digitalWrite(OUT0,HIGH);                            //Определяем инверсный выход в HIGH реле ATX
  digitalWrite(OUT1,HIGH);                            //Определяем инверсный выход в HIGH реле 1 канала Led
  digitalWrite(OUT2,HIGH);                            //Определяем инверсный выход в HIGH реле 2 канала Led
  digitalWrite(OUT3,HIGH);                            //Определяем инверсный выход в HIGH реле 3 канала Led
}

//=========== Обработки печати и вывода на дисплейчик (часы)
void printTime(){
      if (millis()-prvMlsTm>zadTime[3]){      //Проверяем интервал для обновления часов
    prvMlsTm=millis();                        //Вызываем ф-цию вывода времени на экран
  lcd.setCursor(0,0);
      if (hours<10) {lcd.print(0);lcd.print(hours);} else {lcd.print(hours);} 
  lcd.print(":"); 
      if (minutes<10) {lcd.print(0);lcd.print(minutes);} else {lcd.print(minutes);} 
  lcd.print(":"); 
      if (seconds<10) {lcd.print(0);lcd.print(seconds);} else {lcd.print(seconds);}
  } 
      if (millis()-prvMlsRazd>zadTime[4]){    //Проверяем интервал для обновления ":"
    prvMlsRazd=millis();
    lcd.setCursor(2,0);
    lcd.print(" ");
    lcd.setCursor(5,0);
    lcd.print(" ");
    lcd.setCursor(8,0);
    lcd.print(" ");
  }
}
//=========== Обработки печати и вывода на дисплейчик (напряжения, температуры, давление)
void printDin(){
      if (millis()-prvMlsVo>zadTime[7]){     //Проверяем интервал для обновления
    prvMlsVo=millis();
  lcd.setCursor(2,2);                        //Вывод значений температур на LCD                     
  lcd.print((temp[0]),1);
  lcd.setCursor(9,2);                          
  lcd.print((temp[1]),1);  
  lcd.setCursor(16,2);                          
  lcd.print((temp[2]),1);
  lcd.setCursor(9,3);
  lcd.print(vin);
  lcd.setCursor(4,1);
  lcd.print(Pressure/133.3,1);              //Выводим на экранчик показания атм.давления в мм.рт.столба
  } 
}

//=========== Обработки печати и вывода на дисплейчик СТАТИКИ
void printStat(){
        if (millis()-prvMlsTimer>zadTime[8]){   //Проверяем интервал для обновления 
       prvMlsTimer=millis();
      lcd.setCursor(16,1);
      lcd.print("pw\1");
      lcd.setCursor(0,1);
      lcd.print("bar\1");
      lcd.setCursor(0,2);
      lcd.print("a\1");
      lcd.setCursor(7,2);
      lcd.print("b\1");
      lcd.setCursor(14,2);
      lcd.print("c\1");
      lcd.setCursor(0,3);
      lcd.print("~");
      lcd.setCursor(2,3);
      lcd.print(":");
      lcd.setCursor(4,3);
      lcd.print(":");
      lcd.setCursor(7,3);
      lcd.print("v\1");
      lcd.setCursor(15,3);
      lcd.print("%\1");
      lcd.setCursor(9,0);
      if (date<10) {lcd.print(0);lcd.print(date);} else {lcd.print(date);} 
      lcd.print("/");
   if (month==1){lcd.print ("Jan");} 
   if (month==2){lcd.print ("Feb");} 
   if (month==3){lcd.print ("Mar");} 
   if (month==4){lcd.print ("Apr");} 
   if (month==5){lcd.print ("May");} 
   if (month==6){lcd.print ("Jun");} 
   if (month==7){lcd.print ("Jul");} 
   if (month==8){lcd.print ("Aug");} 
   if (month==9){lcd.print ("Sep");} 
   if (month==10){lcd.print ("Oct");} 
   if (month==11){lcd.print ("Nov");} 
   if (month==12){lcd.print ("Dec");} 
     lcd.print("/"); 
     lcd.print(year+2000); 
     lcd.setCursor(12,1);
   if (day==1){lcd.print ("Sun");} 
   if (day==2){lcd.print ("Mon");} 
   if (day==3){lcd.print ("Tue");} 
   if (day==4){lcd.print ("Wed");} 
   if (day==5){lcd.print ("Thu");} 
   if (day==6){lcd.print ("Fri");} 
   if (day==7){lcd.print ("Sat");}
   lcd.setCursor(19,1);                            //Вывод состояния ATX (Power ON\OFF)
   lcd.print(!digitalRead(OUT0));
   lcd.setCursor(1,3);                             //Вывод состояния выходов реле освещения
   lcd.print(!digitalRead(OUT1));
   lcd.setCursor(3,3);
   lcd.print(!digitalRead(OUT2));
   lcd.setCursor(5,3);
   lcd.print(!digitalRead(OUT3));
    }
      if (millis()-prvMlsOut>zadTime[0]){         //Проверяем интервал для обновления
     prvMlsOut=millis();
    lcd.setCursor(17,3);                          //Вывод состояния аналогового выхода диммирования
    lcd.print(angData);
    lcd.setCursor(18,3);
    lcd.print("  ");
    lcd.setCursor(17,3);
    lcd.print(angData);
  }
}

void loop(){
    timeRtc();
    timer();
    keyI();
      if (millis()-prvMlsTemp>zadTime[6]&&flagDallas!=1){dallas();}
    tempRelay();
    voltM();
    bar();
//    bluetooth();
    printTime();
    printDin();
    printStat();
}

Блютусина или вафля планировались для передачи параметров на смарт или на страничку. Без них можно но уж очень хочется. Вот почему в ардуинках нет 64кб к примеру а или 128 или 32 (за минусом загрузчиков и пр).

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

Как нету, Мега 256, там аж 256К. По большому счету, глобально убавить не выйдет, либо от чего то отказыватся, либо голый C+ учить((((, но ассемблер круче))))

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

350Сегодня приехал наконец ДХТ-11 , разобрал и впаял между первой и второй ногами (+ и data) резистрор в 10кОм, третий вывод неиспользовался и на четвертый GND. Добавил библиотеку, и воткнул в код. Размер увеличился всего на 350кБ а это значит что зря очковал и место ещё вполне....

выглядит так функция влажности к моему акваконтроллеру:

#include <DHT.h>  //Подключаем библиотеку для датчика влажности и температуры
//=====Humidity*
#define dhtPin 10                   //What pin we're connected to
#define dhtType DHT11               //DHT 11
DHT dht(dhtPin, dhtType);
float hmdt,tmpr;   //Температуру можно выкинуть и невключать в гл.переменную тем более такую как float :))
 void setup() {
  dht.begin(); }
//========== Считывание Влажности
void humiDity(){
 hmdt=dht.readHumidity();                              //Reading temperature or humidity takes about 250 milliseconds!
// tmpr=dht.readTemperature();                           //Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
}
void printDin(){
      if (millis()-prvMlsVo>zadTime[7]){   //Проверяем интервал для обновления напряжения
    prvMlsVo=millis();
    tft.setTextSize(1);
    tft.setTextColor(ST7735_YELLOW, ST7735_BLACK);
    tft.setCursor(98,50);
    tft.print(hmdt);
}
void loop(){
    humiDity();
}

Само собой кусочек пока из тестовой МЕГИ, в Nano и Lcd перенесу как потестю как следует. Вот и мне кажется брешет падлюка, показывет 21-23% ну этоже нивкакие ворота. Это почти пустыня.. Может резистро ненужен "подтягивающий". Вобщем или это шляпи и нужно что рекомендовали выше постами или пусть будет :)

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

11 он от рождения бяка, а 23% зимой с отоплением эт реально. Нужно с чем то сравнивать.

quartz70rus
Offline
Зарегистрирован: 12.02.2015

Вчера выткал DHT22, влажность ~23% ну и температура 28, при открытии окна падает температура до 26 влажность до 20%

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

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

Сам скетч, урезал максимально и то нехватило метса для авариынйх индикаторво и отключений, невлезла функция определения "уровня воды", работа с Wi-Fi. Пока довольствуюсь блютусинкой.

Итак скетчик для lcd:

#include <EEPROM.h>
#include <Wire.h>                   //Подключаем библиотеку для использования однопроводного интерфейса                                     
#include <LiquidCrystal_I2C.h>      //Подключаем библиотеку для использования I2C интерфейса
#include <OneWire.h>                //Подключаем библиотеку для температурного датчика DS18B20
#include <BMP085.h>                 //Подключаем библиотеку для маленького барометра
#include <DHT.h>                    //Подключаем библиотеку для маленького барометра (темп., абс.высота и атм.давление)
#include <IRremote.h>               //Подключаем библиотеку для IR сенсора
LiquidCrystal_I2C lcd(0x27,20,4);   //Устанавливаем LCD-адрес 0x27 для отображения 20 символов и 4 линии
byte currentLight=0;                //Переменная включения подсветки LCD 

//=====IR_Sensor*
#define recvPin 3                   //Вход IR-приемника и кнопки пульта
uint32_t val; 
IRrecv irrecv(recvPin);
decode_results results;

//=====IR_Dimmer*
byte angData=0;                     //Переменная выходов диммирования (из двух половинок :))
byte flagDimm=0;                    //Флаг для обработки "НЕОБРАТИМОГО" выключения Power_Off
unsigned long tDimm=millis();       //Переменная задержки auto_dimmer

//=====Termo_Relay*
#define tOUT1 4                     //Используем цифровой ПОРТ 4 для ПЕРВОГО канала термо-реле (вода) 
#define tOUT2 A1                    //Используем цифровой ПОРТ A1 для ВТОРОГО канала термо-реле (радиатор)
#define tOUT3 A3                    //Используем цифровой ПОРТ A3 для ТРЕТЬЕГО канала термо-реле (блок реле)

//=====Led_Relay*
#define OUT1 7                      //Используем цифровой ПОРТ 7 для 1 свето-релейного канала Dimm
#define OUT2 8                      //Используем цифровой ПОРТ 8 для 2 свето-релейного канала
#define OUT3 9                      //Используем цифровой ПОРТ 9 для 3 свето-релейного канала

//=====Other_Relay*
#define OUT0 10                     //Используем цифровой ПОРТ 10 для ATX (включение ATX (зелёный + черный))
#define OUT6 11                     //Используем цифровой ПОРТ 11 для CO2
//#define OUT7 12                     //Используем цифровой ПОРТ 12 для другое

//=====Dimmer_Out*
#define OUT4 5                      //Используем цифровой ПОРТ 5 для 1/2 SunSet канала (dimmer)
#define OUT5 6                      //Используем цифровой ПОРТ 6 для 1/2 SunSet канала (dimmer)

//=====Blink led*
//#define bLink 13                    //Индикатор и аварийный сброс

//=====VoltMeter*
int voltInput=A7;                   //Используем аналоговый вход A7 для измерения напряжения
float vout=0.0;
float vin=0.0;
float R1=21700.0;                   //Resistance of R1 (22K) - see text!
float R2=10370.0;                   //Resistance of R2 (12K) - see text!
int valueVo=0;

//=====Pressure*
BMP085 dps=BMP085();                //Digital Pressure Sensor 
long Pressure=0;
unsigned long timeDps=0;

//=====Humidity*
#define dhtPin A2                   //Используем цифровой ПОРТ 14 для входа датчика влажности DHT11
#define dhtType DHT11               //Определяем порт шины DHT11
DHT dht(dhtPin, dhtType);
float hmdt;

//=====Termo_Sensor*
int tempPin=2;                      //Определяем порт шины OneWire (IC) для температурного датчика DS18B20                               
OneWire ds(tempPin);                //Создаем объект для работы с термометром
byte flagDallas=0;                  //Флаг для обработки показаний с датчиков Dallas
byte data[12];
byte addr1[8]={0x28,0xC5,0x3B,0x5C,0x06,0x00,0x00,0x85};     //адрес датчика DS18B20_Вода в аквариуме
byte addr2[8]={0x28,0x86,0x48,0xEA,0x05,0x00,0x00,0xF6};     //адрес датчика DS18B20_Радиатор (2-ой канал, центр)
byte addr3[8]={0x28,0xF2,0x29,0xEB,0x05,0x00,0x00,0xE1};     //адрес датчика DS18B20_Блок реле
unsigned int raw;                   //Если экранированный кабель, можно подключать до 32 термо-датчиков DS18B20
float temp[3];                      //Температура аквариума / радиаторов Led / блока реле

//=====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));}

//=====Timer*
//    long lghtIntv=60000;            //Интервал для проверки вкл./выкл. освещения аквариума, 1 минута
byte lcdStat=0;                     //Флаг подсветки Lcd если включена, то в 1
byte lghtStat[2];                   //Флаг освещения, если включена, то в 1 в первом и втором таймере
byte co2Stat=0;                     //Флаг Co2, если включена, то в 1
byte isLcdt=0;                      //Флаг для обработки необходимости включить подсветку Lcd
byte isLght[2];                     //Флаг для обработки необходимости включить реле освещения в первом и втором таймере
byte isCo2t=0;                      //Флаг для обработки необходимости включить реле Co2
byte isNight=0;                     //Если включаем на ночь, т.е. начальное время больше конечного

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

byte setHorClockOffR3;              //Часы вЫключения OUT3, (R3)
byte setMinClockOffR3;              //Минуты вЫключения OUT3, (R3)
byte setHorClockOffR2;              //Часы вЫключения OUT2, (R2)
byte setMinClockOffR2;              //Минуты вЫключения OUT2, (R2)

byte setTemptGist;                  //Гистерезис температур (по 1/2 в каждую сторону)
byte setTemptAqu;                   //Максимальная температура t1 (вода в аквариуме)
byte setTemptLed;                   //Максимальная температура t2 (радиатор Led)
byte setTemptRel;                   //Максимальная температура t3 (блок коммутации, реле)

byte maxDimm;                       //Переменная определяет МАКСИМАЛЬНОЕ значение диммирования
byte upR2;                          //Переменная включения OUT2
byte downR2;                        //Переменная вЫключения OUT2
byte upR3;                          //Переменная включения OUT3
byte downR3;                        //Переменная вЫключения OUT3

byte pManDimmUp;                    //Период увеличения яркости 
byte pManDimmDown;                  //Период уменьшения яркости

//=====Delays*
unsigned long prvMlsTm=0;           //Предыдущее показание миллисекунд для обновления показания часов
unsigned long prvMlsRazd=0;         //Предыдущее показание миллисекунд для обновления ":"
unsigned long prvMlsVo=0;           //Предыдущее показание обновления показания вольтметра
unsigned long prvMlsOut=0;          //Предыдущее показание обновления показания OUT
//unsigned long prvMlsBar=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[8][17]={"set Timer 1 >>>>","set Timer 2 >>>>","set Timer Lcd >>",
                           "set MoonLight >>","set Timer Co2 >>","set Termorele >>",
                           "set Dimmer >>>>>","set Clock >>>>>>"};      //Массив с наименованиями для экрана

//=====Byte_Symbol*
byte equ[8]={B00000,B00000,B01110,B00000,B01110,B00000,B00000};  //Символ "=" но КОРОТКИЙ :) 

void setup() {
  Wire.begin();
  Serial.begin(9600);
  irrecv.enableIRIn();                                //Включаем IR-сенсор
  dps.init(MODE_STANDARD, 25000, true);               //250 meters, true = using meter units
    pinMode(voltInput,INPUT);                         //Определяем вход вольтметра  
    pinMode(tOUT1,OUTPUT);                            //Определяем выход 1-термореле охлаждения воды аквариума 
    pinMode(tOUT2,OUTPUT);                            //Определяем выход 2-термореле охлаждения радиаторов Led
    pinMode(tOUT3,OUTPUT);                            //Определяем выход 2-термореле охлаждения блока реле
  digitalWrite(tOUT1,HIGH);                           //Определяем инверсный выход в HIGH охлаждения воды аквариума
  digitalWrite(tOUT2,HIGH);                           //Определяем инверсный выход в HIGH охлаждения радиаторов Led
  digitalWrite(tOUT3,HIGH);                           //Определяем инверсный выход в HIGH охлаждения блока реле
     pinMode(OUT0,OUTPUT);                            //Определяем инверсный выход реле ATX 
     pinMode(OUT1,OUTPUT);                            //Определяем инверсные выходы реле 1 канала Led
     pinMode(OUT2,OUTPUT);                            //Определяем инверсные выходы реле 2 канала Led
     pinMode(OUT3,OUTPUT);                            //Определяем инверсные выходы реле 3 канала Led
     pinMode(OUT6,OUTPUT);                            //Определяем инверсные выходы реле подачи СО2
//     pinMode(bLink,OUTPUT);                           //Определяем аварийный "blink led"
//    pinMode(OUT7,OUTPUT);
  digitalWrite(OUT0,HIGH);                            //Определяем инверсный выход в HIGH реле ATX
  digitalWrite(OUT1,HIGH);                            //Определяем инверсный выход в HIGH реле 1 канала Led
  digitalWrite(OUT2,HIGH);                            //Определяем инверсный выход в HIGH реле 2 канала Led
  digitalWrite(OUT3,HIGH);                            //Определяем инверсный выход в HIGH реле 3 канала Led
  digitalWrite(OUT6,HIGH);                            //Определяем инверсный выход в HIGH реле СО2
//  digitalWrite(bLink,HIGH);                           //Определяем аварийный "blink led" в HIGH
//  digitalWrite(OUT7,HIGH);
  analogWrite(OUT4,angData);                          //Инициация выхода 1/2 диммера
  analogWrite(OUT5,angData);                          //Инициация выхода 1/2 диммера
      lcd.init();                                     //Инициализируем дисплейчик
      lcd.setBacklight(1);  
      lcd.createChar(1,equ);                          //Создаем символ под номером 1     
      lcd.clear();                                    //Очищаем на всякий случай дисплейчик
      lcd.setCursor(2,0);
      lcd.print("Aqua  Controller");                  //Выводим версию и прочее
      lcd.setCursor(2,1);
      lcd.print("      v4.2      ");
      lcd.setCursor(0,3);
      lcd.print("_0703_menu_app_");
  delay(2000);
      lcd.clear();                                   //Очистка дисплея и void (printTime, printDin, printStat)
}

//========== Обработка IR-сенсора, определение кнопок
byte keyIr(){
  if (irrecv.decode(&results)){       //Если пришел пакет и этот пакет не FF сохраняем правильный пакет в переменную
//  if (results.value!=0xFFFFFFFF){   //Если пришел FF, соответственно пропускаем.
    val=results.value; //}            //Сверяем значение из переменной val.. если пришла команда повтора (пакет с FF)    
    irrecv.resume();}                 //В переменной останется прошлый, правильный, пакет и код выполнится повторно.
//  Serial.println(val,HEX);          //Далее, очистить входящий буфер
//  Serial.println(" ");
  if (val==0x41BEC03F) return 1;      //setup      KEY1
  if (val==0x41BE40BF) return 2;      //left       KEY2
  if (val==0x41BED02F) return 3;      //up         KEY3
  if (val==0x41BE609F) return 4;      //down       KEY4 
  if (val==0x41BEB04F) return 5;      //right      KEY5
  if (val==0x41BEF00F) return 6;      //exit       POWER_KEY
  if (val==0x41BE708F) return 7;      //vol_down   KEY9
  if (val==0x41BE10EF) return 8;      //vol_up     KEY8
  if (val==0x41BE20DF) return 9;      //slide      KEY9
  if (val==0x41BEA05F) return 10;     //stop       KEY10
    else return 0;                    //ежели ничего ненажмато
}

//========== Обработка IR-кнопок
void keyI(){
  byte KEY=keyIr();            

//========== Обработка Входа в Меню
      if (KEY==1){                            //ВХОД В МЕНЮ и проверка блокировки от возврата. Принимаем код клавиши
    val=0;
    menu();}                                  //Если setup идем в меню
    
//========== Отключение LCD с кнопки
      if (KEY==9){ val=0;
    lcd.setBacklight(currentLight);
    currentLight=!currentLight;}

//========== Увеличение яркости (удержание кнопки) 188кБ
      if (KEY==5){ val=0;
      if (angData<255) angData++;
         analogWrite(OUT4,angData);
         analogWrite(OUT5,angData);
      if (angData>0){ 
         digitalWrite(OUT0,LOW);               //Включаем реле ATX
         digitalWrite(OUT1,LOW); }
}

//========== Уменьшение яркости (удержание кнопки)
      if (KEY==2){ val=0;
      if (angData!=0) angData--;
         analogWrite(OUT4,angData);
         analogWrite(OUT5,angData);
      if (angData==0) {                       //Выключаем реле диммера (по окончании диммирования)
         digitalWrite(OUT1,HIGH);
         digitalWrite(OUT2,HIGH);
         digitalWrite(OUT3,HIGH);
         digitalWrite(OUT0,HIGH);}            //Выключаем реле ATX
}

//========== Обработка "одного" нажатия   
      if (KEY==8 & flagDimm==0){              //Если нажата кнопка УВЕЛИЧЕНИЯ диммирования
      if (tDimm<millis()){                    //и не дана команда на полное выключение
    (EEPROM.read(30)*50); dimmUp();}          //Интервал УВЕЛИЧЕНИЯ диммирования
}
      if (KEY==7 & flagDimm==0){              //Здесь аналогично увеличению яркости
      if (tDimm<millis()){
    (EEPROM.read(31)*50); dimmDown();}        //Интервал Снижения диммирования
}
      if (KEY==6 & angData!=0){               //Power_Off. Если диммер включен, устанавливаем флаг
    flagDimm=1; }
      if (flagDimm==1){                       //Если флаг установлен, продолжаем уменьшение яркости
      if (angData==0){                        //Яркость на 0, флаг сбросили.
      flagDimm=0;
    digitalWrite(OUT1,HIGH);
    digitalWrite(OUT2,HIGH);
    digitalWrite(OUT3,HIGH);
    digitalWrite(OUT0,HIGH);}
      if (tDimm<millis()){                    //Последовательно уменьшаем яркость, кнопки заблокированы
    (EEPROM.read(31)*50)/2; dimmDown();}      //Интервал СНИЖЕНИЯ диммирования (по Power_Off)
  val=0; 
}  

//========== Обработка ATX, НЕдиммируемых реле
 if (KEY==3){
     val=0; if (!digitalRead(OUT1)!=0 && angData>=1) digitalWrite(OUT2,!digitalRead(OUT2));}
 if (KEY==3){ 
     val=0; if (!digitalRead(OUT1)!=0 && angData!=0) digitalWrite(OUT2,digitalRead(OUT2));}
 if (KEY==4){ 
     val=0; if (digitalRead(OUT1)==0 && angData>=1) digitalWrite(OUT3,!digitalRead(OUT3));}
 if (KEY==4){ 
     val=0; if (digitalRead(OUT1)==0 && angData!=0) digitalWrite(OUT3,digitalRead(OUT3));}
}

//========== Увеличение яркости (auto)
void dimmUp(){
      if (angData<EEPROM.read(25)){               //Ограничение верхнего значения диммирования, (0-255)
    angData++;                                    //Начало подъёма диммирования
    analogWrite(OUT4,angData);                    //Пишем в порты
    analogWrite(OUT5,angData);
      if (angData>0){                             //Включаем реле ATX и диммера на первом шаге (начало диммирования)
    digitalWrite(OUT0,LOW);
    digitalWrite(OUT1,LOW);}
      if (angData==EEPROM.read(26)){              //Включаем Второе реле при upR2
    digitalWrite(OUT2,LOW);}
      if (angData==EEPROM.read(28)){              //Включаем Третье реле при upR3
    digitalWrite(OUT3,LOW);}
    tDimm=millis()+(EEPROM.read(30)*50);}         //Устанавливаем время следующего шага
    if (angData==EEPROM.read(25)){val=0;}
}

//========== Уменьшение яркости (auto)
void dimmDown(){
      if (angData>0){
    angData--;                                    //Начало снижения диммирования 
    analogWrite(OUT4,angData);
    analogWrite(OUT5,angData);
      if (angData==EEPROM.read(29)){              //Выключаем Третье реле при downR3
    digitalWrite(OUT3,HIGH);}
      if (angData==EEPROM.read(27)){              //Выключаем Втором реле при downR2
    digitalWrite(OUT2,HIGH);}
      if (angData==0){                            //Выключаем реле диммера (по окончании диммирования)
    digitalWrite(OUT0,HIGH);
    digitalWrite(OUT1,HIGH);
    digitalWrite(OUT2,HIGH);
    digitalWrite(OUT3,HIGH);}
    tDimm=millis()+(EEPROM.read(31)*50);}         //Устанавливаем время следующего шага
    if (angData==0){val=0;}
}

//=========== Обработка Меню, выбор экрана
void menu(){
  lcd.clear();                                   //Очищаем на всякий случай дисплейчик
  byte pos=0;
  while(1){ //bLinkLed();                          //Бесконечный цикл
    byte KEY=keyIr();
      val=0;  
    lcd.setCursor(0,1);
    lcd.print(pos+1);                            //Печатаем номер
    lcd.print(". ");
    lcd.print(menuTxt[pos]);                     //Печатаем название
    if (KEY==3 && pos>0) {pos--;}                //Уменьшить/увеличить позицию окна меню
  else if (pos==0 && KEY==3) {pos=7;}            //Уменьшить/увеличить (циклично)
    if (KEY==4 && pos<7) {pos++;}
  else if (pos==7 && KEY==4) {pos=0;}
      winMe=pos;                                 //Переменная номера окна подменю
    if (KEY==5 && pos==0) setOnOff();      //"set Timer 1 >>>>" 0
    if (KEY==5 && pos==1) setOnOff();      //"set Timer 2 >>>>" 1
    if (KEY==5 && pos==2) setOnOff();      //"set Timer Lcd >>" 2
    if (KEY==5 && pos==3) setMoonLgh();    //"set MoonLight >>" 3
    if (KEY==5 && pos==4) setOnOff();      //"set Timer Co2 >>" 4
    if (KEY==5 && pos==5) setTermorele();  //"set Termorele >>" 5
    if (KEY==5 && pos==6) setDimmer();     //"set Dimmer >>>>>" 6
    if (KEY==5 && pos==7) setClock();      //"set Clock >>>>>>" 7
    if (KEY==1){                                 //Выход из меню с проверкой и установкой блокировки от возврата       
    lcd.clear();                                 //Очищаем на всякий случай дисплейчик
      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);
      lcd.clear();                                       //Очищаем на всякий случай дисплейчик
//      lcd.blink();
    while(keyIr()!=1){                                   //Крутим цикл пока не будет Setup
    byte KEY=keyIr();                                    //Читаем состояние кнопок
    val=0;
//      delay(200);                                      //Если убрать, не работает подсветка уст.позиции
    lcd.setCursor(7,0);
    lcd.print("-On-  -Off-"); 
    lcd.setCursor(0,3);
    lcd.print("=== push to save ===");
    lcd.setCursor(1,1);
    lcd.print(winMe+1,DEC);                              //Печатаем номер программы таймера
    lcd.print("|");
    lcd.print(pos/3,DEC);                                //Печатаем позицию настройки параметра (замена blink)
    lcd.print("->");  
    lcd.setCursor(7,1);                                  //Выводим инфу о часах и минутах
     if (setHorClockOn<10) lcd.print("0");
    lcd.print(setHorClockOn,DEC);
    lcd.print(":");
     if (setMinClockOn<10) lcd.print("0"); 
    lcd.print(setMinClockOn,DEC);  
    lcd.print(" ");     
     if (setHorClockOff<10) lcd.print("0");
    lcd.print(setHorClockOff,DEC);
    lcd.print(":");
     if (setMinClockOff<10) lcd.print("0");
    lcd.print(setMinClockOff,DEC);
    
    if (KEY==2 && pos==3){                                //Выход из подменю без сохранения       
      lcd.clear();                                        //Очищаем на всякий случай дисплейчик
    return; winMe=pos;} 
    
    lcd.setCursor(pos,1);                                 //Устанавливаем курсор согласно позиции
    if (pos<3) pos=3;
    if (KEY==5 && pos<11) pos += 3;                       //Крутим позицию право-лево
    else if (KEY==2 && pos>3) pos -= 3;
    
    else if (pos==3 && KEY==3) setHorClockOn++;           //Крутим значения
    else if (pos==3 && KEY==4) setHorClockOn--;
    else if (pos==6 && KEY==3) setMinClockOn++;
    else if (pos==6 && KEY==4) setMinClockOn--;    
    else if (pos==9 && KEY==3) setHorClockOff++;
    else if (pos==9 && KEY==4) setHorClockOff--;    
    else if (pos==12 && KEY==3) setMinClockOff++;
    else if (pos==12 && KEY==4) setMinClockOff--; 
    
    if (setHorClockOn>23) setHorClockOn=0;                //Ограничиваем значения
    else if (setMinClockOn>59) setMinClockOn=0;
    else if (setHorClockOff>23) setHorClockOff=0;
    else if (setMinClockOff>59) setMinClockOff=0;
}                                                         //Конец цикла
//      lcd.noBlink(); 
      lcd.clear();                                        //Очищаем на всякий случай дисплейчик
   EEPROM.write(winMe*4+1, setHorClockOn);                //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, setMinClockOn); 
   EEPROM.write(winMe*4+3, setHorClockOff);
   EEPROM.write(winMe*4+4, setMinClockOff);
   lcd.setCursor(4,2);
   lcd.print("== Saved ==");
   delay(zadTime[4]);
}

//=========== Обработка Меню, Лунный свет
void setMoonLgh(){    
  byte pos=0;   
  setHorClockOffR3=  EEPROM.read(winMe*4+1);               //Считываем записанные значения таймеров
  setMinClockOffR3=  EEPROM.read(winMe*4+2);               //Адрес определяется как номер таймера*4 + четыре ячейки
  setHorClockOffR2=  EEPROM.read(winMe*4+3);
  setMinClockOffR2=  EEPROM.read(winMe*4+4);
      lcd.clear();                                         //Очищаем на всякий случай дисплейчик
//      lcd.blink();
    while(keyIr()!=1){                                     //Крутим цикл пока не будет Setup
    byte KEY=keyIr();                                      //Читаем состояние кнопок
    val=0;
//      delay(200);                                        //Если убрать, не работает подсветка уст.позиции
    lcd.setCursor(7,0);
    lcd.print("-R3-  -R2-"); 
    lcd.setCursor(0,3);
    lcd.print("=== push to save ===");
    lcd.setCursor(1, 1);
    lcd.print(winMe+1,DEC);                                //Печатаем номер программы таймера
    lcd.print("|");
    lcd.print(pos/3,DEC);                                  //Печатаем позицию настройки параметра (замена blink)
    lcd.print("->");  
    lcd.setCursor(7,1);                                    //Выводим инфу о часах и минутах
     if (setHorClockOffR3<10) lcd.print("0");
    lcd.print(setHorClockOffR3,DEC);
    lcd.print(":");
     if (setMinClockOffR3<10) lcd.print("0"); 
    lcd.print(setMinClockOffR3,DEC);  
    lcd.print(" ");     
     if (setHorClockOffR2<10) lcd.print("0");
    lcd.print(setHorClockOffR2,DEC);
    lcd.print(":");
     if (setMinClockOffR2<10) lcd.print("0");
    lcd.print(setMinClockOffR2,DEC);
   
    if (KEY==2 && pos==3){                                  //Выход из подменю без сохранения       
      lcd.clear();                                          //Очищаем на всякий случай дисплейчик
    return;}    
    
    lcd.setCursor(pos,1);                                   //Устанавливаем курсор согласно позиции
    if (pos<3) pos=3;
    if (KEY==5 && pos<11) pos += 3;                         //Крутим позицию право-лево
    else if (KEY==2 && pos>3) pos -= 3;
    
    else if (pos==3 && KEY==3) setHorClockOffR3++;          //Крутим значения
    else if (pos==3 && KEY==4) setHorClockOffR3--;
    else if (pos==6 && KEY==3) setMinClockOffR3++;
    else if (pos==6 && KEY==4) setMinClockOffR3--;    
    else if (pos==9 && KEY==3) setHorClockOffR2++;
    else if (pos==9 && KEY==4) setHorClockOffR2--;    
    else if (pos==12 && KEY==3) setMinClockOffR2++;
    else if (pos==12 && KEY==4) setMinClockOffR2--; 
    
    if (setHorClockOffR3>23) setHorClockOffR3=0;            //Ограничиваем значения
    if (setHorClockOffR2>23) setHorClockOffR2=0;            //Ограничиваем значения
    else if (setMinClockOffR3>59) setMinClockOffR3=0;
    else if (setMinClockOffR2>59) setMinClockOffR2=0;
}                                                           //Конец цикла
//      lcd.noBlink(); 
      lcd.clear();                                          //Очищаем на всякий случай дисплейчик
   EEPROM.write(winMe*4+1, setHorClockOffR3);               //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, setMinClockOffR3); 
   EEPROM.write(winMe*4+3, setHorClockOffR2);
   EEPROM.write(winMe*4+4, setMinClockOffR2);
   lcd.setCursor(4,2);
   lcd.print("== Saved ==");
   delay(zadTime[4]);
}

//=========== Обработка Меню, параметры Термореле
void setTermorele(){
  byte pos=0;   
  setTemptGist= EEPROM.read(winMe*4+1);                //Считываем записанные значения таймеров
  setTemptAqu=  EEPROM.read(winMe*4+2);                //Адрес определяется как номер таймера*4 + четыре ячейки                
  setTemptLed=  EEPROM.read(winMe*4+3); 
  setTemptRel=  EEPROM.read(winMe*4+4);
      lcd.clear();                                     //Очищаем на всякий случай дисплейчик
//      lcd.blink();
    while(keyIr()!=1){                                 //Крутим цикл пока не будет Setup
    byte KEY=keyIr();                                  //Читаем состояние кнопок
    val=0;
//      delay(200);                                    //Если убрать, не работает подсветка уст.позиции
    lcd.setCursor(0,3);
    lcd.print("=== push to save ===");
    lcd.setCursor(0, 0);
    lcd.print(winMe+1,DEC);                            //Печатаем номер программы таймера
    lcd.print("|");
    lcd.print(pos/3,DEC);                              //Печатаем позицию настройки параметра (замена blink)
    lcd.print("->");  
    lcd.setCursor(7,0);                                //Выводим инфу о часах и минутах
     if (setTemptGist<10) lcd.print("0");
    lcd.print(setTemptGist);
    lcd.print(" C^");
    lcd.setCursor(0,1);
     if (setTemptAqu<10) lcd.print("0"); 
    lcd.print(setTemptAqu);  
    lcd.print(" | ");     
     if (setTemptLed<10) lcd.print("0");
    lcd.print(setTemptLed);
    lcd.print(" | ");
     if (setTemptRel<10) lcd.print("0");
    lcd.print(setTemptRel);
    
    if (KEY==2 && pos==3){                                //Выход из подменю без сохранения       
      lcd.clear();                                        //Очищаем на всякий случай дисплейчик
    return;}    
    
    lcd.setCursor(pos,0);                                 //Устанавливаем курсор согласно позиции
        if (pos<3) pos=3;
    if (KEY==5 && pos<12) pos += 3;                       //Крутим позицию право-лево
    else if (KEY==2 && pos>3) pos -= 3;
    
    else if (pos==3 && KEY==3) setTemptGist++;
    else if (pos==3 && KEY==4) setTemptGist--;
    else if (pos==6 && KEY==3) setTemptAqu++;             //Крутим значения
    else if (pos==6 && KEY==4) setTemptAqu--;
    else if (pos==9 && KEY==3) setTemptLed++;
    else if (pos==9 && KEY==4) setTemptLed--;    
    else if (pos==12 && KEY==3) setTemptRel++;
    else if (pos==12 && KEY==4) setTemptRel--; 
    
    if (setTemptGist>5) setTemptGist=1;                   //Ограничиваем значения
    else if (setTemptAqu>30) setTemptAqu=20;
    else if (setTemptLed>65) setTemptLed=35;
    else if (setTemptRel>70) setTemptRel=40;
}                                                         //Конец цикла
//      lcd.noBlink(); 
      lcd.clear();                                        //Очищаем на всякий случай дисплейчик
   EEPROM.write(winMe*4+1, setTemptGist);                 //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, setTemptAqu);
   EEPROM.write(winMe*4+3, setTemptLed); 
   EEPROM.write(winMe*4+4, setTemptRel);
   lcd.setCursor(4,2);
   lcd.print("== Saved ==");
   delay(zadTime[4]);
}

//=========== Обработка Меню, параметры диммирования (максимальное значение и пределы OUT2,3)
void setDimmer(){    
  byte pos=0;   
  maxDimm=      EEPROM.read(winMe*4+1);                //Считываем записанные значения диммирования 
  upR2=         EEPROM.read(winMe*4+2);                //Адрес определяется как номер диммера*4 + семь ячеек          
  downR2=       EEPROM.read(winMe*4+3);
  upR3=         EEPROM.read(winMe*4+4);                          
  downR3=       EEPROM.read(winMe*4+5);
  pManDimmUp=   EEPROM.read(winMe*4+6);
  pManDimmDown= EEPROM.read(winMe*4+7);
      lcd.clear();                                     //Очищаем на всякий случай дисплейчик
//      lcd.blink();
    while(keyIr()!=1){                                 //Крутим цикл пока не будет Setup
    byte KEY=keyIr();                                  //Читаем состояние кнопок
    val=0;
//      delay(200);                                    //Если убрать, не работает подсветка уст.позиции
    lcd.setCursor(0,3);
    lcd.print("=== push to save ===");
    lcd.setCursor(0, 0);
    lcd.print(winMe+1,DEC);                            //Печатаем номер программы таймера
    lcd.print("|");
    lcd.print(pos/3,DEC);                              //Печатаем позицию настройки параметра (замена blink)
    lcd.print("->");  
    lcd.setCursor(7,0);                                //Выводим инфу о часах и минутах
     if (maxDimm<10) lcd.print("0");
    lcd.print(maxDimm);
    lcd.print(" dimm");
    lcd.setCursor(0,1);
     if (upR2<10) lcd.print("0"); 
    lcd.print(upR2);  
    lcd.print("/");     
     if (downR2<10) lcd.print("0");
    lcd.print(downR2);
    lcd.print("   |  ");
     if (upR3<10) lcd.print("0");
    lcd.print(upR3);
    lcd.print("/");     
     if (downR3<10) lcd.print("0");
    lcd.print(downR3);
    lcd.setCursor(0,2);                                   //Выводим инфу о часах и минутах
     if (pManDimmUp<10) lcd.print("0");
    lcd.print(pManDimmUp,DEC);
    lcd.print(" *50ms");
    lcd.print("  | ");
     if (pManDimmDown<10) lcd.print("0"); 
    lcd.print(pManDimmDown,DEC); 
    lcd.print(" *50ms");
   
    if (KEY==2 && pos==3){                                //Выход из подменю без сохранения       
      lcd.clear();                                        //Очищаем на всякий случай дисплейчик
    return;}    
    
    lcd.setCursor(pos,0);                                 //Устанавливаем курсор согласно позиции
        if (pos<3) pos=3;
    if (KEY==5 && pos<21) pos += 3;                       //Крутим позицию право-лево
    else if (KEY==2 && pos>3) pos -= 3;
    
    else if (pos==3 && KEY==3) maxDimm++;                 //Крутим значения
    else if (pos==3 && KEY==4) maxDimm--;
    else if (pos==6 && KEY==3) upR2++;
    else if (pos==6 && KEY==4) upR2--;    
    else if (pos==9 && KEY==3) downR2++;
    else if (pos==9 && KEY==4) downR2--;    
    else if (pos==12 && KEY==3) upR3++;
    else if (pos==12 && KEY==4) upR3--;
    else if (pos==15 && KEY==3) downR3++;
    else if (pos==15 && KEY==4) downR3--; 
    else if (pos==18 && KEY==3) pManDimmUp++;
    else if (pos==18 && KEY==4) pManDimmUp--;
    else if (pos==21 && KEY==3) pManDimmDown++;
    else if (pos==21 && KEY==4) pManDimmDown--;
  
    if (pManDimmUp==0 && KEY==4) pManDimmUp=30;            //Реверсивное изменение значений
    if (pManDimmUp>30) pManDimmUp=0;                       //Ограничиваем значения
    if (pManDimmDown==0 && KEY==4) pManDimmDown=30;
    if (pManDimmDown>30) pManDimmDown=0;  
}                                                          //Конец цикла
//      lcd.noBlink(); 
      lcd.clear();                                         //Очищаем на всякий случай дисплейчик
   EEPROM.write(winMe*4+1, maxDimm);                       //Записываем НОВЫЕ значения
   EEPROM.write(winMe*4+2, upR2); 
   EEPROM.write(winMe*4+3, downR2);
   EEPROM.write(winMe*4+4, upR3);
   EEPROM.write(winMe*4+5, downR3);
   EEPROM.write(winMe*4+6, pManDimmUp);
   EEPROM.write(winMe*4+7, pManDimmDown);
   lcd.setCursor(4,2);
   lcd.print("== Saved ==");
   delay(zadTime[4]);
}

//=========== Обработка Меню, параметры установки времени
void setClock(){ // установка часов
  byte pos=0;
      lcd.clear();                                       //Очищаем на всякий случай дисплейчик
//      lcd.blink();
    while(keyIr()!=1){                                   //Крутим цикл пока не будет Setup
    byte KEY=keyIr();                                    //Читаем состояние кнопок
    val=0;
//      delay(200);                                      //Если убрать, не работает подсветка уст.позиции
    lcd.setCursor(0,3);
//    lcd.print("=== push to save ===");
    lcd.print("<<  -Exit | Ok -Save");    
    lcd.setCursor(0, 0);
    lcd.print(winMe+1,DEC);                              //Печатаем номер программы таймера
    lcd.print("|");
    lcd.print(pos/3,DEC);                                //Печатаем позицию настройки параметра (замена blink)
    lcd.print("->");  
    lcd.setCursor(7,0);      
     if (hours<10) lcd.print("0");
    lcd.print(hours);
    lcd.print(":");
     if (minutes<10) lcd.print("0"); 
    lcd.print(minutes);
      lcd.print(":");
     if (seconds<10) lcd.print("0"); 
    lcd.print(seconds); 
    lcd.setCursor(7,1);
      if (day<10) lcd.print("0");
    lcd.print(day);
      lcd.print(" | ");
      if (date<10) lcd.print("0");
    lcd.print(date);
    lcd.print("/");
     if (month<10) lcd.print("0");
    lcd.print(month);
    lcd.print("/");
     if (year<10) lcd.print("0");
    lcd.print(year);
    
    if (KEY==2 && pos==3){                                //Выход из подменю без сохранения       
      lcd.clear();                                        //Очищаем на всякий случай дисплейчик
    return;}    
    
    lcd.setCursor(pos,0);
      if (pos<3) pos=3;                                     //Устанавливаем курсор согласно позиции
    if (KEY==5 && pos<21) pos += 3;                         //Крутим позицию право-лево
    else if (KEY==2 && pos>3) pos -= 3;
    
    else if (pos==3 && KEY==3) hours++;                     //Крутим значения
    else if (pos==3 && KEY==4) hours--;
    else if (pos==6 && KEY==3) minutes++;
    else if (pos==6 && KEY==4) minutes--;
    else if (pos==9 && KEY==3) seconds++;
    else if (pos==9 && KEY==4) seconds--;
    else if (pos==12 && KEY==3) day++;
    else if (pos==12 && KEY==4) day--;     
    else if (pos==15 && KEY==3) date++;
    else if (pos==15 && KEY==4) date--;    
    else if (pos==18 && KEY==3) month++;
    else if (pos==18 && KEY==4) month--;    
    else if (pos==21 && KEY==3) year++;
    else if (pos==21 && KEY==4) 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;
  }
//      lcd.noBlink(); 
      lcd.clear();                                        //Очищаем на всякий случай дисплейчик 
   setRtc(seconds, minutes, hours, day, date, month, year); 
   lcd.setCursor(4,2);
   lcd.print("== Saved ==");
   delay(zadTime[4]);
}

//========== Считывание напряжения
void voltM(){
  valueVo=analogRead(voltInput);                         //Read the value at analog input
  vout=(valueVo*5.0)/1024.0;                             //See text
  vin=vout/(R2/(R1+R2)); 
      if (vin<0.09) {vin=0.0;}                           //Statement to quash undesired reading
}

//========== Считывание Давления
void bar(){
      if (timeDps<millis()){                             //Конструкция жуткая и жрущая море ресурсов при расчете вещественных чисел.   
  timeDps=millis()+1000;}
  dps.getPressure(&Pressure);
}

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

//=========== Считывание температур
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 tempRele(){
      if (tzad<millis()&&flagDallas==1){
    temp[0]=DS18B20(addr1);
    temp[1]=DS18B20(addr2);
    temp[2]=DS18B20(addr3);
    prvMlsTemp=millis();
      flagDallas=0;}
      if (temp[0]>EEPROM.read(22)-(EEPROM.read(21)/2)){
    digitalWrite(tOUT1,LOW);                             //Термо-реле 1-включается
//        lcd.setCursor(8, 2);
//        lcd.print("*");
  }     
      else if (temp[0]<EEPROM.read(22)+(EEPROM.read(21)/2)){
    digitalWrite(tOUT1,HIGH);                            //Термо-реле 1-выключается
//        lcd.setCursor(8, 2);
//        lcd.print("-");
  } 
      if (temp[1]>EEPROM.read(23)-(EEPROM.read(21)/2)){
    digitalWrite(tOUT2,LOW);                             //Термо-реле 2-включается
//        lcd.setCursor(18, 2);
//        lcd.print("*");
  }     
      else if (temp[1]>EEPROM.read(23)-(EEPROM.read(21)/2)){
    digitalWrite(tOUT2,HIGH);                           //Термо-реле 2-выключается
//        lcd.setCursor(18, 2);
//        lcd.print("-");
  }
        if (temp[2]>EEPROM.read(24)-(EEPROM.read(21)/2)){
    digitalWrite(tOUT3,LOW);                           //Термо-реле 3-включается
//        lcd.setCursor(18, 2);
//        lcd.print("*");
  }     
      else if (temp[2]<EEPROM.read(24)+(EEPROM.read(21)/2)){
    digitalWrite(tOUT3,HIGH);                          //Термо-реле 3-выключается
//        lcd.setCursor(18, 2);
//        lcd.print("-");
  }  
} 

//=========== Обработка установки 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));
  }
}

//=========== Обработка Таймеров
void timer(){

  int fulMin=hours*60+minutes;                                 //Переводим часы + минуты к полным минутам
  int fulMinOn1=      EEPROM.read(1)*60+EEPROM.read(2);        //Переводим часы + минуты включения 1 реле к полным минутам
  int fulMinOff1=     EEPROM.read(3)*60+EEPROM.read(4);        //Переводим часы + минуты выключения 1 реле к полным минутам
  int fulMinOn2=      EEPROM.read(5)*60+EEPROM.read(6);        //Переводим часы + минуты включения 2 реле к полным минутам
  int fulMinOff2=     EEPROM.read(7)*60+EEPROM.read(8);        //Переводим часы + минуты выключения 2 реле к полным минутам
  int fulMinOnLcd=    EEPROM.read(9)*60+EEPROM.read(10);       //Переводим часы + минуты включения Lcd к полным минутам
  int fulMinOffLcd=   EEPROM.read(11)*60+EEPROM.read(12);      //Переводим часы + минуты выключения Lcd к полным минутам
  int fulMinOffOut3=  EEPROM.read(13)*60+EEPROM.read(14);      //Переводим часы + минуты выключения OUT3 к полным минутам
  int fulMinOffOut2=  EEPROM.read(15)*60+EEPROM.read(16);      //Переводим часы + минуты выключения OUT2 к полным минутам
  int fulMinOnCo2=    EEPROM.read(17)*60+EEPROM.read(18);      //Переводим часы + минуты включения Co2 к полным минутам
  int fulMinOffCo2=   EEPROM.read(19)*60+EEPROM.read(20);      //Переводим часы + минуты выключения Co2 к полным минутам

//========== Таймер №1           
    if (fulMinOn1>fulMinOff1) {isNight=1;}                     //Если ночное время
    if (isNight==0){                                           //Если день
    if (fulMin>=fulMinOn1&&fulMin<fulMinOff1) {isLght[0]=1;}   //Проверяем интервал
   else {isLght[0]=0;}                                         //Если необходимо включить свет
  } else {                                                     //Если ночь
      if(fulMin-fulMinOn1>=0) {isLght[0]=1;}                   //Если больше или равно верхнему значению, то необходимо включить свет
   else {                                                      //Если необходимо включить свет
      if(fulMin<fulMinOff1) {isLght[0]=1;}                     //Если меньше нижнего значения, то необходимо включить свет
   else {isLght[0]=0;}                                         //Если необходимо включить свет
    }
  }  
    if((isLght[0]==1)&&(lghtStat[0]==0)){                      //Если свет еще не включен и выставлен флаг необходимости включить
    if (tDimm < millis()){                                     //И не дана команда на полное выключение
  (EEPROM.read(30)*50); dimmUp();} 
      if (angData==EEPROM.read(25)) {lghtStat[0]=1;}
  } else {
      if(isLght[0]==0&&lghtStat[0]==1){
    if (tDimm < millis()){
  (EEPROM.read(31)*50); dimmDown();} 
      if (angData==0){lghtStat[0]=0;}
  }
}
//========== Таймер №2
      if (fulMinOn2>fulMinOff2) {isNight=1;}                  //Если ночное время
    if (isNight==0){                                          //Если день
    if (fulMin>=fulMinOn2&&fulMin<fulMinOff2) {isLght[1]=1;}  //Проверяем интервал
   else {isLght[1]=0;}                                        //Если необходимо включить свет
  } else {                                                    //Если ночь
      if(fulMin-fulMinOn2>=0) {isLght[1]=1;}                  //Если больше или равно верхнему значению, то необходимо включить свет
   else {                                                     //Если необходимо включить свет
      if(fulMin<fulMinOff2) {isLght[1]=1;}                    //Если меньше нижнего значения, то необходимо включить свет
   else {isLght[1]=0; }                                       //Если необходимо включить свет
    }
  }  
    if((isLght[1]==1)&&(lghtStat[1]==0)){                     //Если свет еще не включен и выставлен флаг необходимости включить
    if (tDimm < millis()){                                    //И не дана команда на полное выключение
  (EEPROM.read(30)*50); dimmUp();}
      if (angData==EEPROM.read(25)) {lghtStat[1]=1;}
  } else {
      if(isLght[1]==0&&lghtStat[1]==1){
    if (tDimm < millis()){
  (EEPROM.read(31)*50); dimmDown();}
      if (angData==0){lghtStat[1]=0;}
  }
}
//========== Таймер Lcd-подсветки  
      if (fulMinOnLcd>fulMinOffLcd) {isNight=1;}              //Если ночное время
    if (isNight==0){                                          //Если день
    if (fulMin>=fulMinOnLcd&&fulMin<fulMinOffLcd) {isLcdt=1;}        //Проверяем интервал
   else {isLcdt=0;}                                           //Если необходимо включить подсветку Lcd
  } else {                                                    //Если ночь
      if(fulMin-fulMinOnLcd>=0) {isLcdt=1;}                   //Если больше или равно верхнему значению, то необходимо включить подсветку Lcd
   else {                                                     //Если необходимо включить подсветку Lcd
      if(fulMin<fulMinOffLcd) {isLcdt=1;}                     //Если меньше нижнего значения, то необходимо включить подсветку Lcd
   else {isLcdt=0;}                                           //Если необходимо включить подсветку Lcd
    }
  }  
    if((isLcdt==1)&&(lcdStat==0)){                            //Если подсветка Lcd еще не включена и выставлен флаг необходимости включить
    lcd.backlight(); lcdStat=1;
  } else {
      if(isLcdt==0&&lcdStat==1){
    lcd.noBacklight(); lcdStat=0;
  }
}
//========== Таймер СО2
      if (fulMinOnCo2>fulMinOffCo2) {isNight=1;}              //Если ночное время
    if (isNight==0){                                          //Если день
    if (fulMin>=fulMinOnCo2&&fulMin<fulMinOffCo2) {isCo2t=1;}        //Проверяем интервал
   else {isCo2t=0;}                                           //Если необходимо включить Co2
  } else {                                                    //Если ночь
      if(fulMin-fulMinOnCo2>=0) {isCo2t=1;}                   //Если больше или равно верхнему значению, то необходимо включить Co2
   else {                                                     //Если необходимо включить Co2
      if(fulMin<fulMinOffCo2) {isCo2t=1;}                     //Если меньше нижнего значения, то необходимо включить Co2
   else {isCo2t=0;}                                           //Если необходимо включить Co2
    }
  }  
    if((isCo2t==1)&&(co2Stat==0)){                            //Если Co2 еще не включен и выставлен флаг необходимости включить
    digitalWrite(OUT6,LOW); co2Stat=1;
  } else {
      if(isCo2t==0&&co2Stat==1){
    digitalWrite(OUT6,HIGH); co2Stat=0;
  }
}
//========== Таймер "Лунного света"  
    if (fulMin>=fulMinOffOut3){
       digitalWrite(OUT3,HIGH);}
    if (fulMin>=fulMinOffOut2){
       digitalWrite(OUT2,HIGH);
  } 
}

//=========== Обработка Bluetooth
void blueTooth(){
      if (Serial.available()){   
  byte i=Serial.read()-48;                                  //byte меньше int на 118 байт
    if (i==2) {if (!digitalRead(OUT1)!=0 && angData>=1) digitalWrite(OUT2, !digitalRead(OUT2));}
    if (i==2) {if (!digitalRead(OUT1)!=0 && angData!=0) digitalWrite(OUT2, digitalRead(OUT2));}
    if (i==3) {if (digitalRead(OUT1)==0 && angData>=1) digitalWrite(OUT3, !digitalRead(OUT3));}
    if (i==3) {if (digitalRead(OUT1)==0 && angData!=0) digitalWrite(OUT3, digitalRead(OUT3));}
//    if (i==3)digitalWrite(OUT6,!digitalRead(OUT6));
      if (i==4) Serial.print(temp[0]);
      if (i==5) Serial.print(temp[1]);
      if (i==6) Serial.print(temp[2]);
      if (i==7) Serial.print(hmdt);
      if (i==8) Serial.print(Pressure/133.3,1);
      if (i==9) Serial.print(vin);

      if (i==0){
      if (tDimm < millis()){
    (EEPROM.read(31)*50); dimmDown(); Serial.print(angData);} 
}
      if (i==1){
      if (tDimm<millis()){
    (EEPROM.read(30)*50); dimmUp(); Serial.print(angData);}
    }
  }
}
/*
//=========== Обработка Аврийного индикатора
void bLinkLed(){
      if (prvMlsbLink+zadTime[1]<millis()){          //Проверка условия
    prvMlsbLink=millis();                            //Установка задержки
    digitalWrite(bLink,!digitalRead(bLink));}        //Инверсия значения
}
*/
//=========== Обработки печати и вывода на дисплейчик (часы)
void printTime(){
      if (millis()-prvMlsTm>zadTime[3]){      //Проверяем интервал для обновления часов
    prvMlsTm=millis();                        //Вызываем ф-цию вывода времени на экран
  lcd.setCursor(0,0);
      if (hours<10) {lcd.print(0);lcd.print(hours);} else {lcd.print(hours);} 
  lcd.print(":"); 
      if (minutes<10) {lcd.print(0);lcd.print(minutes);} else {lcd.print(minutes);} 
  lcd.print(":"); 
      if (seconds<10) {lcd.print(0);lcd.print(seconds);} else {lcd.print(seconds);}
  } 
      if (millis()-prvMlsRazd>zadTime[4]){    //Проверяем интервал для обновления ":"
    prvMlsRazd=millis();
    lcd.setCursor(2,0);
    lcd.print(" ");
    lcd.setCursor(5,0);
    lcd.print(" ");
    lcd.setCursor(8,0);
    lcd.print(" ");
  }
}
//=========== Обработки печати и вывода на дисплейчик (напряжения, температуры, давление)
void printDin(){
      if (millis()-prvMlsVo>zadTime[7]){     //Проверяем интервал для обновления
    prvMlsVo=millis();
  lcd.setCursor(2,2);                        //Вывод значений температур на Lcd                     
  lcd.print((temp[0]),1);
  lcd.setCursor(9,2);                          
  lcd.print((temp[1]),1);  
  lcd.setCursor(16,2);                          
  lcd.print((temp[2]),1);
  lcd.setCursor(9,3);
  lcd.print(vin);                            //Выводим на экранчик значения напряжения
  lcd.setCursor(2,1);
  lcd.print(Pressure/133.3,1);               //Выводим на экранчик показания атм.давления в мм.рт.столба
  lcd.setCursor(8,1);
  lcd.print(hmdt,0);                         //Выводим на экранчик показания влажности в %
  } 
}

//=========== Обработки печати и вывода на дисплейчик СТАТИКИ
void printStat(){
        if (millis()-prvMlsTimer>zadTime[8]){   //Проверяем интервал для обновления 
       prvMlsTimer=millis();
      lcd.setCursor(16,1);
      lcd.print("pw\1");
      lcd.setCursor(12,1);
      lcd.print("~\1");
      lcd.setCursor(0,1);
      lcd.print("p\1");
      lcd.setCursor(10,1);
      lcd.print("%");
      lcd.setCursor(0,2);
      lcd.print("a\1");
      lcd.setCursor(7,2);
      lcd.print("b\1");
      lcd.setCursor(14,2);
      lcd.print("c\1");
      lcd.setCursor(0,3);
      lcd.print("~");
      lcd.setCursor(2,3);
      lcd.print(":");
      lcd.setCursor(4,3);
      lcd.print(":");
      lcd.setCursor(7,3);
      lcd.print("v\1");
      lcd.setCursor(15,3);
      lcd.print("%\1");
      lcd.setCursor(9,0);
      if (date<10) {lcd.print(0);lcd.print(date);} else {lcd.print(date);} 
      lcd.print("/");
   if (month==1){lcd.print ("Jan");} 
   if (month==2){lcd.print ("Feb");} 
   if (month==3){lcd.print ("Mar");} 
   if (month==4){lcd.print ("Apr");} 
   if (month==5){lcd.print ("May");} 
   if (month==6){lcd.print ("Jun");} 
   if (month==7){lcd.print ("Jul");} 
   if (month==8){lcd.print ("Aug");} 
   if (month==9){lcd.print ("Sep");} 
   if (month==10){lcd.print ("Oct");} 
   if (month==11){lcd.print ("Nov");} 
   if (month==12){lcd.print ("Dec");} 
     lcd.print("/"); 
     lcd.print(year+2000); 
     lcd.setCursor(14,1);
     lcd.print(!digitalRead(OUT6));                //Вывод состояния Co2 (Реле Со2)
/*     
   if (day==1){lcd.print ("Sun");} 
   if (day==2){lcd.print ("Mon");} 
   if (day==3){lcd.print ("Tue");} 
   if (day==4){lcd.print ("Wed");} 
   if (day==5){lcd.print ("Thu");} 
   if (day==6){lcd.print ("Fri");} 
   if (day==7){lcd.print ("Sat");}
*/   
   lcd.setCursor(19,1);                            //Вывод состояния ATX (Power ON\OFF)
   lcd.print(!digitalRead(OUT0));
   lcd.setCursor(1,3);                             //Вывод состояния выходов реле освещения
   lcd.print(!digitalRead(OUT1));
   lcd.setCursor(3,3);
   lcd.print(!digitalRead(OUT2));
   lcd.setCursor(5,3);
   lcd.print(!digitalRead(OUT3));
    }
      if (millis()-prvMlsOut>zadTime[0]){         //Проверяем интервал для обновления
     prvMlsOut=millis();
    lcd.setCursor(17,3);                          //Вывод состояния аналогового выхода диммирования
    lcd.print(angData);
    lcd.setCursor(18,3);
    lcd.print("  ");
    lcd.setCursor(17,3);
    lcd.print(angData);
  }
}                                                //05.03.15 Размер 30 614. Размер был 30,614кБ из 30,720кБ Nano

void loop(){
    timeRtc();
    timer();
    keyI();
      if (millis()-prvMlsTemp>zadTime[6]&&flagDallas!=1){dallas();}
    tempRele();
    voltM();
    bar();
    humiDity();
    blueTooth();
    printTime();
    printDin();
    printStat();
}

В нем немного "кояво" работает "парсер" работы ползунка Андроид-приложения - для диммирования, нужно что то искать иное, нежели вставлять Serial.setTimeout(4); при работе с Serial.parseInt(); последний работает НЕКорреткно без Timeout().

В остально ВСЁ просто и шикарно, Огромное спасибо Уважаемому bwn за терпение с которым он меня технически и научил многим пользоваться.

Видео из трёх частей о самом контроллере, его возможностях и самом трудном и интересном в нём - это МЕНЮ :)

http://www.youtube.com/watch?v=8zrWyRNFKww
и
http://www.youtube.com/watch?v=PVPW8kwCJHM
и
http://www.youtube.com/watch?v=E0oZzMSKLUQ

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

В целом вроде неплохо получилось, не зря мучались)))). Вы это лучше новой темой выложите с фотками, видео и конечным кодом, боюсь 7 страниц мало кто осилит, для желающих можно ссылку дать на эту тему.
По уменьшению размера, первое что просится, все текстовые сообщения длиной больше 3 знаков и повторяющиеся более 2 раз перенести в 129 строку (байт 200 выиграете). Еще почитайте "optiboot" для ардуино, сам не пробовал, но вроде как 1,5К можно убавить (тема была совсем на днях).

Да, проверил свой AM2301(DHT21), оказалось врет на 14%. Способ простой - баночка типа майонезной, на дно обычную соль, смачиваем водой с пипетки (должна быть влажная, не мокрая), засовываем датчик, закрываем плотнее и смотрим. Должно быть 75-76%.

 

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

bwn пишет:

Да, проверил свой AM2301(DHT21), оказалось врет на 14%. Способ простой - баночка типа майонезной, на дно обычную соль, смачиваем водой с пипетки (должна быть влажная, не мокрая), засовываем датчик, закрываем плотнее и смотрим. Должно быть 75-76%.

Ок, про оптимизацию почитаю обязательно. Ведь я вообще хотел ДВА постоянно меняющихся экранчика с инфой чтобы удобнее воспринимать не только мне, а в итоге бился за каждый десяток байт.

А вот про DHT-11 их я брал парочку и оба врут в итоге, сравнивал с несколькми тоже китайскими часиками в которых есть измерение влажнсоти и с метеостанцией Oregon, в итоге решил просто добавить "врущее" значение чтобы получить нужное (строка 0722     timeDps=millis()+1000;}) около 10-11% вранья в одном и 9% в другом, тестовом что на меге :)

Новую ветку сделаю и туда фоточки сборки контроллера его возможности и схему подключения (боюсь будет чт ото в фотошопе из фото модулей и их соединения:) )

serega.gram
Offline
Зарегистрирован: 15.04.2015

обалденный проект. если бы я раньше его нашёл, я бы заказал бы другие комплектующие. а блютуз там для чего

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

serega.gram пишет:

обалденный проект. если бы я раньше его нашёл, я бы заказал бы другие комплектующие. а блютуз там для чего

Блютуз для Андроида. А чем ваши комплектующие так сильно отличаются от здешних? Я же вам в самом начале на него ссылку давал.

serega.gram
Offline
Зарегистрирован: 15.04.2015

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

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

serega.gram пишет:

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

Экран здесь будет самое нудное. ТС больше всего времени потратил на меню. Самый безбольный для вас путь взять типа этого и не делать работу второй раз (хотя все равно под себя править придется). Реле автору были нужны по жизненной необходимости (большая мощность на освещение), если ваши транзюки потянут (здесь не помогу, пробуйте сами), то можно те же самые сигналы подавать на них напрямую.
Для нагревателей и помп (не знаю, что у вас будет от 220в) нужны либо реле, либо симмисторные ключи (решать вам).
Пульт - три варианта: 1. Найти дома дохлый девайс, у которого было IR управление и выдрать оттуда (я так и сделал когда понадобился). 2. Купить (недорогие они). 3. Можно все переписать под кнопки (в начальных версиях так и было), но здесь придется менять логику управления, на пульте кнопок много, а вам лепить пианино ни к чему.
Все красоты типа давления, влажности, напряжения ТС лепил для личного удовольствия. Можно этим воспользоватся, а можно и выкинуть.

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

Thorn, если читаешь, надеюсь не обижаешься, что в твою ветку перебрались?

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

Доброго дня. Коненчое непротив, правда как вам уже говорил ув. Вадим (bwn) - эта ветка холливар ещё тот, а все потому что практически с "- 0". Но счас очень доволен, собрал после на мелкой ардуинк, моторшилде , блютусинке и аппинвенторе своему сыну ДУ мелкий танк, в пыжика своего в больших планах подключится к CAN-шине и замутить свой БК (306-ой он и в нем почти ничего нет:(. Однако по поводу акваконтроллера.

Я так понял менять яркость вы планируете силовыми транзисторами в мое м случае это было диммирование самим драйвером. Но суть то неменяется всеравно задается таймер и время приращения\уменьшения.

Реле я использовал именно для снижения энергопотребления и полного отключения простаиваемой автоматики. Но к сожалению заявленные токи до 10А они врядли безболезненно "вытянут". В моих цепях каждое коммутирует не более 7-8А и при этом нагрев свыше 50 град и в итоге крышку на корпус контроллера уже нельзя было использовать, пришлось реле оставлять открытому воздуху. Ну это так мелочи

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

Термоконтроль так и непригодился, Ледики негреют радиаторы более 48град при естественном охлаждении, вода ненагревается выше 24 град (при пользовании Т5 и Т8 вода неопускалась ниже 27 град :).

Показания вольтметра оказались и вовсе бесполезны. Ну чео их контролировать (что 5В что 12В) - там и 1% нет оклонений - уберу и тем самым место в коде увеличу. 

Самый нужные оказались - это температуры, атм. давление и влажность как нестранно.

Со2 подается по времени - нет нужды замерять показания да и дорого.

ПО меню - самая моя любимая фишка, самое главное что ты независиш ни т вэб-морды, ни от загрузки настроек с ПК, выбрал нужное, сохранил вышел (правда вначале немог вкурить, почему изменения применённые неработают. казывается нужно РЕБУТАТЬ ардуинку).

После я заказывал самые простые энкодер и кнопу типа джлйстик PS. Последняя заменяет сразу 5 кнопок !!!! попробуйте её и места съэкономите и удобно. Энкодер продукт узкоспезиализированный, для нашего контроллера неочень.

Сожалею что немогу выложить схему электрическую принципиальную - всё только в фотошопе есть, смешно смотреть.

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

Thorn пишет:

ПО меню - самая моя любимая фишка, самое главное что ты независиш ни т вэб-морды, ни от загрузки настроек с ПК, выбрал нужное, сохранил вышел (правда вначале немог вкурить, почему изменения применённые неработают. казывается нужно РЕБУТАТЬ ардуинку).

А чего молчите, это не правильно. Код сейчас смотреть нет желания, но 99%, что причина в переменных, которые считываются один раз при запуске. Лекарство - либо вместо переменной для сравнения применять значение EEPROM напрямую, либо сделать функцию обновления после внесения изменений и при запуске.

serega.gram
Offline
Зарегистрирован: 15.04.2015

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

 

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

serega.gram пишет:

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

 

Мое личное мнение, что проще отпаять (аккуратно выкусить и впаять новую гребенку) экран от этого шилда и поставить на переходник I2C. Подпаятся можно и к шилду, но придется прозванивать выходы и разводить на переходник. Кнопки в этом случае останутся на аналоговом входе.
Но без пайки и проводов в любом случае не обойтись.

Vallu
Vallu аватар
Offline
Зарегистрирован: 17.10.2014

Всем приятного времени суток. Прошу помощи! Решил сделать авто управление аквариумом, автокормушка свет (закат, рассвет), включение фильтра ну и со временем еще чего нибудь прилеплю. Написал код для света по таймеру. Первая проблемма появилась когда включалось питание, то диоды загарались и когда проходило тестирование ардуины гасли и на чинали работать по заданному режиму. это дело исправл поставив реле на питание диодов с задержкой на время запуска ардуины. Вопрос, может можно как то обойтись без реле, а удалить проблемму программно?  И вторая проблемма когда заканчивается рассвет то свет должен гореть энное время заданное таймером, а потом переходить в режим заката, но этого не происходит, свет либо гаснет полностью после рассвета или тут же переходит в закат. Код прилогаю ниже может кто поможет? Зарание большое спасибо.


//обзываем выводы соответственно цвету
int REDpin = 9;
int BLUEpin = 10;
int WHITEpin = 11;
int RELAYpin = 2;

void setup()

 {   
   //включение реле 
   pinMode(RELAYpin, OUTPUT);  
   digitalWrite(RELAYpin, LOW);   
   delay(2000);  //пауза
   digitalWrite(RELAYpin, HIGH);}  

void loop(){ 
   
  for(int value = 0 ; value <= 255; value +=1)
  { 
    //яркость света увеличивается
    analogWrite(REDpin, 255-value);
    analogWrite(BLUEpin, 255-value);
    analogWrite(WHITEpin, 255-value);
    delay(60); //пауза
  }
  
  for(int value = 255 ; value == 255; value ==1)
  {  
    //свет горит
    analogWrite(REDpin, 255);
    analogWrite(BLUEpin, 255); 
    analogWrite(WHITEpin, 255);
    delay(50000); //пауза
  }
  
  for(int value = 0 ; value <= 255; value +=1)
  {  
    //яркость света уменьшается
    analogWrite(REDpin, value);
    analogWrite(BLUEpin, value);
    analogWrite(WHITEpin, value);
    delay(60); //пауза
  }
 
   for(int value = 0 ; value <= 255; value +=1)
   {   
    //свет не горит 
    analogWrite(REDpin, 255);
    analogWrite(BLUEpin, 255); 
    analogWrite(WHITEpin, 255);
    delay(70); //пауза
   }   

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

Vallu, попробуйте поставить в setup: analogWrite(REDpin, 255); и аналогично для других.
зачем вам 13 строка?
строки с 27 по 34 делают что то непонятное, а скорее всего ничего не делают.

И ликвидируйте все delay() по максимуму. Сейчас это незаметно, потом может стать проблемой. При корректной работе строк с 27 по 34 вы завесите дуину на 3 часа((((.

Vallu
Vallu аватар
Offline
Зарегистрирован: 17.10.2014

Со второй проблемой разобрался 

                                                //обзываем выводы
int REDpin = 9;
int BLUEpin = 10;
int WHITEpin = 11;
int RELAYpin = 2;
int val = 255;
void setup()

 {   
                                                 //включение реле 
   pinMode(RELAYpin, OUTPUT);  
   digitalWrite(RELAYpin, LOW);   
   delay(2000);                                  //пауза
   digitalWrite(RELAYpin, HIGH);}  

void loop(){    
  
   for(int value = 0 ; value <= 255; value +=1)
  { 
                                                  //яркость света увеличивается
    analogWrite(REDpin, 255-value);
    analogWrite(BLUEpin, 255-value);
    analogWrite(WHITEpin, 255-value);
    delay(60);                                   //пауза
  }
  
  for(int value = 0 ; value <= 255; value +=1)
   {   
                                                //свет горит 
    analogWrite(REDpin, 0);
    analogWrite(BLUEpin, 0); 
    analogWrite(WHITEpin, 0);
    delay(60);                                 //пауза
   }   

  
  for(int value = 0 ; value <= 255; value +=1)
  {  
                                                 //яркость света уменьшается
    analogWrite(REDpin, value);
    analogWrite(BLUEpin, value);
    analogWrite(WHITEpin, value);
    delay(60);                                   //пауза
  }
 
   for(int value = 0 ; value <= 255; value +=1)
   {   
                                                //свет не горит 
    analogWrite(REDpin, 255);
    analogWrite(BLUEpin, 255); 
    analogWrite(WHITEpin, 255);
    delay(60);                                 //пауза
   }   

}

строка 13 нужна для задержки реле на 2 сек что бы ардуино вошла в рабочее состояние, иначе диоды закараются и тутже тухнут. 27-34 нужны чтобы свет горел определенное время.

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

Она входит в рабочее состояние до setup. Попробуйте инициацию как я написал. И как у вас светики подключены?

Vallu
Vallu аватар
Offline
Зарегистрирован: 17.10.2014

да забыл описать саму схему. Имеем ардуино пока УНО, драйвера света, диодные ленты, БП на 12 и 5 В. пок пробовал запитать один диод от ардуины все работало прекрасно без реле, но как подключил драйвера появилась вспышеа в начале работы.

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

По вашему последнему коду, если вы вместо стр.27-34 напишете просто delay(15300); результат будет тот же. Цикл там не нужен.

Vallu
Vallu аватар
Offline
Зарегистрирован: 17.10.2014

Понял, спасибо сейчас попробую. но главный вопрос по реле.