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

r_a_s
Offline
Зарегистрирован: 23.09.2020

Добрый День.



Необходимо дописать готовый скетч (добавить опрос датчиков влажности)



ТЗ:

Во вложении скетч, таймер времени, на 4 зоны.

На данный момент выглядит сейчас вот так:
 

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

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

 



В скетче нужно поле для того что бы указывать какое значение с датчика влажности является 0% а какое 100%, можно одно поле для всех датчиков (+/- значения будут одинаковые).

Датчиков влажности будет 4, как и каналов для реле. По умолчанию датчик №1 должен быть подвязан к каналу №1, датчик №2 должен быть подвязан к каналу №2 и тд.

В таймерах есть настройка "УРОВЕНЬ СИГНАЛА" - это поле нужно заменить на "УРОВЕНЬ ВЛАЖНОСТИ", соответственно перед запуском таймера ардуино должно считать с датчика % влажности, проверить какой стоит %  в настройках таймера и если он равен или меньше установленного то запустить таймер, если значение выше то не запускать таймер.
 
001#include <avr/pgmspace.h>                                                                     //  Подключаем библиотеку для работы с PROGMEM Arduino для хранения символов дисплея
002#include <EEPROM.h>                                                                           //  Подключаем библиотеку для работы с EEPROM  Arduino для хранения значений таймеров
003#include <Wire.h>                                                                             //  Подключаем библиотеку для работы с шиной I2C
004#include <LiquidCrystal_I2C.h>                                                                //  Подключаем библиотеку для работы с LCD дисплеем по шине I2C
005#include <iarduino_Encoder_tmr.h>                                                             //  Подключаем библиотеку GyverEncoder для работы с энкодерами через аппаратный таймер
006#include <iarduino_RTC.h>                                                                     //  Подключаем библиотеку iarduino_RTC для работы с часами реального времени
007                                                                                              //
008//   ОБЪЯВЛЯЕМ КОНСТАНТЫ КОТОРЫЕ МОЖНО РЕДАКТИРОВАТЬ:                                         //
009     const uint8_t   pinEncA     =              7;                                            //  Определяем константу с указанием № вывода Arduino к которому подключён вывод «A» энкодера
010     const uint8_t   pinEncB     =              8;                                            //  Определяем константу с указанием № вывода Arduino к которому подключён вывод «B» энкодера
011     const uint8_t   pinEncBTN   =              4;                                            //  Определяем константу с указанием № вывода Arduino к которому подключён вывод «S» энкодера (кнопка)
012     const uint8_t   pinChanel_1 =              5;                                            //  Определяем константу с указанием № вывода Arduino который будет являеться выводом 1 канала (указываются только выводы с ШИМ, кроме выводов используемых 2 таймером Arduino)
013     const uint8_t   pinChanel_2 =              6;                                            //  Определяем константу с указанием № вывода Arduino который будет являеться выводом 2 канала (указываются только выводы с ШИМ, кроме выводов используемых 2 таймером Arduino)
014     const uint8_t   pinChanel_3 =              9;                                            //  Определяем константу с указанием № вывода Arduino который будет являеться выводом 3 канала (указываются только выводы с ШИМ, кроме выводов используемых 2 таймером Arduino)
015     const uint8_t   pinChanel_4 =              10;                                           //  Определяем константу с указанием № вывода Arduino который будет являеться выводом 4 канала (указываются только выводы с ШИМ, кроме выводов используемых 2 таймером Arduino)
016     const uint8_t   maxTimers   =              20;                                           //  Определяем константу с указанием максимального количества таймеров. Число не должно превышать количество байт EEPROM/8 (для Arduino Uno максимальное значение 128)
017                                                                                              //
018//   ОБЪЯВЛЯЕМ КОНСТАНТЫ И ПЕРЕМЕННЫЕ НЕОБХОДИМЫЕ ДЛЯ РАБОТЫ СКЕТЧА:                          //
019     const byte      rusMem[38][8] PROGMEM =    {                                             //  Определяем массив в области памяти программ, каждый элемент которого является матрицей (еще одим массивом) представления символа на дисплее
020                     {31,16,16,30,17,17,30, 0}, { 0, 0,30,17,30,17,30, 0},                    //  Б,  в,  № матрицы символа в массиве: 00, 01
021                     {31,16,16,16,16,16,16, 0}, { 0, 0,30,16,16,16,16, 0},                    //  Г,  г,  № матрицы символа в массиве: 02, 03
022                     { 6,10,10,10,10,10,31,17}, {10,10,14, 2, 2, 0, 0, 0},                    //  Д,  4,  № матрицы символа в массиве: 04, 05
023                     {17,17,17,19,21,25,17, 0}, { 0, 0,17,19,21,25,17, 0},                    //  И,  и,  № матрицы символа в массиве: 06, 07
024                     {21,17,17,19,21,25,17, 0}, { 10,4,17,19,21,25,17, 0},                    //  Й,  й,  № матрицы символа в массиве: 08, 09
025                     { 0, 0,18,20,24,20,18, 0}, { 0, 0,17,27,21,17,17, 0},                    //  к,  м,  № матрицы символа в массиве: 10, 11
026                     { 7, 9, 9, 9, 9, 9,17, 0}, { 0, 0, 7, 9, 9, 9,17, 0},                    //  Л,  л,  № матрицы символа в массиве: 12, 13
027                     {31,17,17,17,17,17,17, 0}, { 0, 0,17,17,31,17,17, 0},                    //  П   н,  № матрицы символа в массиве: 14, 15
028                     {17,17,17,15, 1,17,14, 0}, { 0, 0,31, 4, 4, 4, 4, 0},                    //  У,  т,  № матрицы символа в массиве: 16, 17
029                     {17,17,17,15, 1, 1, 1, 0}, { 0, 0,17,17,15, 1, 1, 0},                    //  Ч,  ч,  № матрицы символа в массиве: 18, 19
030                     {17,17,17,29,19,19,29, 0}, { 0, 0,17,17,29,19,29, 0},                    //  Ы,  ы,  № матрицы символа в массиве: 20, 21
031                     {16,16,16,30,17,17,30, 0}, { 0, 0, 0, 0, 0, 0,21, 0},                    //  Ь, ..., № матрицы символа в массиве: 22, 23
032                     {18,21,21,29,21,21,18, 0}, { 0, 0,18,21,29,21,18, 0},                    //  Ю,  ю,  № матрицы символа в массиве: 24, 25
033                     {15,17,17,15, 5, 9,17, 0}, { 0, 0,15,17,15, 5, 9, 0},                    //  Я,  я,  № матрицы символа в массиве: 26, 27
034                     {31, 4,31, 0,31,16,31, 0}, {16,31,16, 0,10,21,31, 0},                    //  ПН, ВТ  № матрицы символа в массиве: 28, 29
035                     {28,20,31, 0,17,17,31, 0}, {16,31,16, 0,31, 4,28, 0},                    //  СР, ЧТ  № матрицы символа в массиве: 30, 31
036                     {16,31,16, 0,31,16,31, 0}, {23,21,31, 0,17,17,31, 0},                    //  ПТ, СБ  № матрицы символа в массиве: 32, 33
037                     {17,17,31, 0,10,21,31, 0}, { 4,12, 4, 4,14, 0, 0, 0},                    //  ВС, 1   № матрицы символа в массиве: 34, 35
038                     {14, 2,14, 8,14, 0, 0, 0}, {14, 2,14, 2,14, 0, 0, 0}};                   //  2,  3   № матрицы символа в массиве: 36, 37
039     uint8_t         valArray[7] =              {0,0,0,0,0,0,0};                              //  Определяем массив элементы которого будут хранить различную информацию в зависимости от режима
040     char            valChar[5] =               "    ";                                       //  Определяем массив символов (строку) информация которой будет отображаться на дисплее мигая
041     uint8_t         valMode =                  0;                                            //  Определяем переменную для хранения текущего режима (например: режим 31 - установка времени)
042     uint8_t         valSubMode =               0;                                            //  Определяем переменную для хранения текущего подрежима (например: режим 31, подрежим 0 - установка часов, подрежим 1 - установка минут, подрежим 2 - установка секунд)
043     uint8_t         valTimerNum =              0;                                            //  Определяем переменную для хранения номера выбранного таймера (от 0 до maxTimers-1)
044     bool            flgDisplayUpdate =         1;                                            //  Определяем флаговую переменную, установка которой будет сигнализировать о необходимости обновления дисплея
045     void            funcEncoderRead           (void);                                        //  Объявляем функцию в которой будут выполняться действия зависящие от состояния энкодера и режима
046     void            funcDisplayUpdate         (void);                                        //  Объявляем функцию в которой будет обновляться информация дисплея в зависимости от режима, подрежима, выбранного таймера и значений массива valArray
047     void            funcSetPWM                (void);                                        //  Объявляем функцию которая будет устанавливать сигналы ШИМ на каналах если текущее время совпало с временем таймеров
048     void            funcSetChars              (uint8_t=255,uint8_t=255,uint8_t=255,uint8_t=255,uint8_t=255,uint8_t=255,uint8_t=255); // Объявляем функцию записывающую до 7 символов из массива rusMem по номерам его элементов в область CGRAM дисплея
049     uint8_t         funcReadTimer             (uint8_t=0, uint8_t=0);                        //  Объявляем функцию для чтения одного из параметров таймера (№ таймера, № параметра)
050     void            funcSaveTimer             (uint8_t=0, uint8_t=0, uint8_t=0);             //  Объявляем функцию для записи одного из параметров таймера (№ таймера, № параметра, значение параметра)
051     uint8_t         funcFindTimer             (void);                                        //  Объявляем функцию для поиска № следующего свободного (не установленного) таймера
052     bool            funcTestTimer             (void);                                        //  Объявляем функцию для проверки соответствия данных в ячейках EEPROM Arduino значениям таймеров (если скетч запускается впервые, то данные в ячейках не будут соответствовать значениям таймеров и можно будет подготовить EEPROM к первому запуску скетча)
053LiquidCrystal_I2C    lcd                       (0x27,16,2);                                   //  Объявляем объект lcd  для работы с дисплеем указывая (адрес I2C = 0x27, количество столбцов = 16, количество строк = 2)
054iarduino_Encoder_tmr enc                       (pinEncA,pinEncB);                             //  Объявляем объект enc  для работы с энкодером указывая (№ вывода A, № вывода B)
055iarduino_RTC         time                      (RTC_DS3231);                                  //  Объявляем объект time для работы с часами RTC указывая (тип модуля)
056#define              encPRESS 3                                                               //  Определяем константу для удобочитаемости при определении состояния энкодера
057                                                                                              //
058void setup(){                                                                                 //
059     enc.begin();                                                                             //  Инициируем работу с энкодером
060     time.begin();                                                                            //  Инициируем работу с RTC модулем
061     pinMode(pinEncBTN,   INPUT_PULLUP);                                                      //  Переводим вывод с кнопкой энкодера в режим входа
062     pinMode(pinChanel_1, OUTPUT);                                                            //  Переводим вывод 1 канала в режим выхода
063     pinMode(pinChanel_2, OUTPUT);                                                            //  Переводим вывод 1 канала в режим выхода
064     pinMode(pinChanel_3, OUTPUT);                                                            //  Переводим вывод 1 канала в режим выхода
065     pinMode(pinChanel_4, OUTPUT);                                                            //  Переводим вывод 1 канала в режим выхода
066     lcd.init();                                                                              //  Инициируем работу с LCD дисплеем
067     lcd.backlight();                                                                         //  Включаем подсветку LCD дисплея
068     funcSetChars(12,6);                                                                      //  Загружаем элементы 12 и 6 массива rusMem в память CGRAM LCD дисплея. Эти элементы содержат графическое представление символов: «Л» и «И»
069     lcd.setCursor(0,0);                                                                      //  Устанавливаем курсор в верхний левый угол экрана (0 столбец, 0 строка)
070     lcd.print(F("PE\1E BPEMEH\2"));                                                          //  Выводим надпись «PEЛE BPEMEHИ». Буквы «Л» и «И» заменяем знаком '\' и №, под которыми их графические представления были загружены в память CGRAM LCD дисплея.
071     lcd.setCursor(5,1);                                                                      //  Устанавливаем курсор в 5 столбец 1 строки (нумерация начинается с 0)
072     lcd.print(F("YV1"));                                                             //  Выводим надпись «iarduino.ru».
073     delay(2000);                                                                             //  Ждём, что бы надпись отображаемую на дисплее успели прочитать
074     lcd.clear();                                                                             //  Чистим экран,
075     if(!funcTestTimer()){                                                                    //  Если значения в EEPROM не соответствуют значениям таймера (например первый запуск данного скетча), то ...
076         funcSetChars(14,4,2);                                                                //  Загружаем элементы 14, 4 и 2 массива rusMem в память CGRAM LCD дисплея. Эти элементы содержат графическое представление символов: «П», «Д» и «Г»
077         lcd.setCursor(0,0);                                                                  //  Устанавливаем курсор в верхний левый угол экрана (0 столбец, 0 строка)
078         lcd.print(F("\1O\2\3OTOBKA..."));                                                    //  Выводим надпись «ПOДГOTOBKA...». Буквы «П», «Д» и «Г» заменяем знаком '\' и №, под которыми их графические представления были загружены в память CGRAM LCD дисплея.
079         for(uint8_t i=0; i<maxTimers; i++){                                                  //  Проходим по всем возможным таймерам
080         for(uint8_t j=0; j<8;  j++){                                                         //  Проходим по всем возможным параметрам каждого таймера
081             funcSaveTimer(i,j,0);                                                            //  Обнуляем все возможные параметры каждого таймера
082         }}  delay(1000); lcd.clear();                                                        //  Ждём, что бы надпись отображаемую на дисплее успели прочитать, а потом чистим экран
083     }                                                                                        //
084}                                                                                             //
085                                                                                              //
086void loop(){                                                                                  //
087     funcEncoderRead();                                                                       //  Выполняем действия в соответствии с состоянием энкодера и режимом valMode
088     funcDisplayUpdate();                                                                     //  Обновляем информацию на дисплее в соответствии с режимом valMode и только если установлен флаг flgDisplayUpdate
089     funcSetPWM();                                                                            //  Выводим ШИМ
090}                                                                                             //
091                                                                                              //
092//   ВЫПОЛНЕНИЕ ДЕЙСТВИЙ ПРИ ИЗМЕНЕНИИ СОТОЯНИЯ ЭНКОДЕРА И В ЗАВИСИМОСТИ ОТ ТЕКУЩЕГО РЕЖИМА   //
093void funcEncoderRead(void){                                                                   //
094     int i=enc.read();                                                                        //  Определяем переменную i в которую читаем состояние энкодера (может принимать 1 из 3 значений: 0, encLEFT, encRIGHT а далее к ним прибавится еще и значение encPRESS)
095     int j=255;                                                                               //  Определяем переменную j для хранения № режима меню, в который требуется перейти (значение 255 означает что переход в другой режим не требуется)
096     if(!digitalRead(pinEncBTN)){i=encPRESS;}                                                  //  Если нажата кнопка энкодера, то устанавливаем переменную i в значение encPRESS
097     switch(valMode){                                                                         //  Далее действуем в зависимости от значения переменной valMode (которая хранит № текущего режима меню)
098         case  0:               if(i==encPRESS){j= 1;}                                        //  Если установлен режим 0 "Вне меню", то ...
099     /*  "00:00:00        " */  flgDisplayUpdate=1;                                           //  Устанавливаем флаг flgDisplayUpdate сигнализирующий о необходимости обновить информацию на дисплее
100     /*  "00.00.0000 XX   " */                                                                //
101         break;                                                                               //
102         case  1:               if(i==encPRESS){j=funcReadTimer()?11:12; valTimerNum=0;}      //  Если установлен режим 1: "Меню" и нажав на энкодер, можно выбрать пункт "ТАЙМЕРЫ", то ...
103     /*  "меню:           " */  if(i==encLEFT ){j= 3;}                                        //  Если энкодер поворачивается влево, то переходим в режим 3
104     /*  "<   ТАЙМЕРЫ    >" */  if(i==encRIGHT){j= 2;}                                        //  Если энкодер поворачивается вправо, то переходим в режим 2
105         break;                                                                               //
106         case  2:               if(i==encPRESS){j=21;}                                        //  Если установлен режим 2: "Меню" и нажав на энкодер, можно выбрать пункт "ЧАСЫ", то ...
107     /*  "меню:           " */  if(i==encLEFT ){j= 1;}                                        //  Если энкодер поворачивается влево, то переходим в режим 1
108     /*  "<     ЧАСЫ     >" */  if(i==encRIGHT){j= 3;}                                        //  Если энкодер поворачивается вправо, то переходим в режим 3
109         break;                                                                               //  Если установлен режим 3: "Меню" и нажав на энкодер, можно выбрать пункт "ВЫХОД", то ...
110         case  3:               if(i==encPRESS){j= 0; valArray[0]=valArray[1]=valArray[2]=valArray[3]=0;}
111     /*  "меню:           " */  if(i==encLEFT ){j= 2;}                                        //  Если энкодер поворачивается влево, то переходим в режим 2
112     /*  "<    ВЫХОД     >" */  if(i==encRIGHT){j= 1;}                                        //  Если энкодер поворачивается вправо, то переходим в режим 1
113         break;                                                                               //
114         case 11:               if(i==encPRESS){j=51;}                                        //  Если установлен режим 11: "Меню>таймеры" и нажав на энкодер, можно выбрать один из таймеров, то ...
115     /*  "меню>таймеры:   " */  if(i==encLEFT ){if(valTimerNum){valTimerNum--; lcd.clear(); flgDisplayUpdate=1;}else{j=14;}}
116     /*  "< 00:00-00:00-1>" */  if(i==encRIGHT){valTimerNum++; if(valTimerNum>=maxTimers){j=13;}else if(funcReadTimer(valTimerNum)){lcd.clear(); flgDisplayUpdate=1;}else{j=12;}}
117         break;                                                                               //
118         case 12:               if(i==encPRESS){j=41;}                                        //  Если установлен режим 12: "Меню>таймеры" и нажав на энкодер, можно выбрать пункт "НОВЫЙ ТАЙМЕР", то ...
119     /*  "меню>таймеры:   " */  if(i==encLEFT ){j=funcReadTimer()?11:14; if(funcReadTimer()){valTimerNum=funcFindTimer()-1;}}
120     /*  "< НОВЫЙ ТАЙМЕР >" */  if(i==encRIGHT){j=funcReadTimer()?13:14;}                     //  Если энкодер поворачивается вправо, то переходим в режим 13 или 14 (зависит от наличия установленных таймеров)
121         break;                                                                               //
122         case 13:               if(i==encPRESS){j=42;}                                        //  Если установлен режим 13: "Меню>таймеры" и нажав на энкодер, можно выбрать пункт "CTEPETЬ BCE ТАЙМЕРЫ", то ...
123     /*  "меню>таймеры:   " */  if(i==encLEFT ){j=funcFindTimer()<maxTimers?12:11; valTimerNum=j==11?maxTimers-1:0;}
124     /*  "< CTEPETЬ BCE  >" */  if(i==encRIGHT){j=14; valTimerNum=0;}                         //  Если энкодер поворачивается вправо, то переходим в режим 14 и указываем что выбран таймер № 0
125         break;                                                                               //
126         case 14:               if(i==encPRESS){j= 1;}                                        //  Если установлен режим 14: "Меню>таймеры" и нажав на энкодер, можно выбрать пункт "ВЫХОД", то ...
127     /*  "меню>таймеры:   " */  if(i==encLEFT ){j=funcReadTimer()?13:(funcFindTimer()<maxTimers?12:11); valTimerNum=0;}
128     /*  "<    ВЫХОД     >" */  if(i==encRIGHT){j=funcReadTimer()?11:(funcFindTimer()<maxTimers?12:13); valTimerNum=0;}
129         break;                                                                               //  Если установлен режим 21: "Меню>часы" и нажав на энкодер, можно выбрать пункт "ВРЕМЯ", то ...
130         case 21:               if(i==encPRESS){j=31; valSubMode=0; time.gettime(); valArray[0]=time.Hours; valArray[1]=time.minutes; valArray[2]=time.seconds;}
131     /*  "меню>часы:      " */  if(i==encLEFT ){j=23;}                                        //  Если энкодер поворачивается влево, то переходим в режим 23
132     /*  "<    ВРЕМЯ     >" */  if(i==encRIGHT){j=22;}                                        //  Если энкодер поворачивается вправо, то переходим в режим 22
133         break;                                                                               //  Если установлен режим 22: "Меню>часы" и нажав на энкодер, можно выбрать пункт "ДАТА", то ...
134         case 22:               if(i==encPRESS){j=32; valSubMode=0; time.gettime(); valArray[0]=time.day; valArray[1]=time.month; valArray[2]=time.year; valArray[3]=time.weekday;}
135     /*  "меню>часы:      " */  if(i==encLEFT ){j=21;}                                        //  Если энкодер поворачивается влево, то переходим в режим 21
136     /*  "<     ДАТА     >" */  if(i==encRIGHT){j=23;}                                        //  Если энкодер поворачивается вправо, то переходим в режим 23
137         break;                                                                               //
138         case 23:               if(i==encPRESS){j= 2;}                                        //  Если установлен режим 23: "Меню>часы" и нажав на энкодер, можно выбрать пункт "ВЫХОД", то ...
139     /*  "меню>часы:      " */  if(i==encLEFT ){j=22;}                                        //  Если энкодер поворачивается влево, то переходим в режим 22
140     /*  "<    ВЫХОД     >" */  if(i==encRIGHT){j=21;}                                        //  Если энкодер поворачивается вправо, то переходим в режим 21
141         break;                                                                               //  Если установлен режим 31: "Меню>часы>вpeмя" и управляя энкодером, можно установить время, то ...
142         case 31:               if(i==encPRESS){                        if(valSubMode==0){valSubMode=1;}else if(valSubMode==1){valSubMode=2;}else if(valSubMode==2){time.settime(valArray[2],valArray[1],valArray[0]); j=21;}}
143     /*  "меню>часы>вpeмя:" */  if(i==encLEFT ){valArray[valSubMode]--; if(valArray[0]>23){valArray[0]=23;} if(valArray[1]>59){valArray[1]=59;} if(valArray[2]>59){valArray[2]=59;}}
144     /*  "    00:00:00    " */  if(i==encRIGHT){valArray[valSubMode]++; if(valArray[0]>23){valArray[0]= 0;} if(valArray[1]>59){valArray[1]= 0;} if(valArray[2]>59){valArray[2]= 0;}}
145                                flgDisplayUpdate=1;                                           //  Устанавливаем флаг flgDisplayUpdate сигнализирующий о необходимости обновить информацию на дисплее
146         break;                                                                               //  Если установлен режим 32: "Меню>часы>дата" и управляя энкодером, можно установить дату, то ...
147         case 32:               if(i==encPRESS){                        if(valSubMode==0){valSubMode=1;}else if(valSubMode==1){valSubMode=2;}else if(valSubMode==2){valSubMode=3;}else if(valSubMode==3){time.settime(-1,-1,-1,valArray[0],valArray[1],valArray[2],valArray[3]); j=22;}}
148     /*  "MEHЮ>ЧACЫ>ДATA: " */  if(i==encLEFT ){valArray[valSubMode]--; if(valArray[0]==0){valArray[0]=31;} if(valArray[1]==0){valArray[1]=12;} if(valArray[2]>99){valArray[2]=99;} if(valArray[3]>6){valArray[3]=6;}}
149     /*  " 00.00.0000 пт  " */  if(i==encRIGHT){valArray[valSubMode]++; if(valArray[0]>31){valArray[0]= 1;} if(valArray[1]>12){valArray[1]= 1;} if(valArray[2]>99){valArray[2]= 0;} if(valArray[3]>6){valArray[3]=0;}}
150                                flgDisplayUpdate=1;                                           //  Устанавливаем флаг flgDisplayUpdate сигнализирующий о необходимости обновить информацию на дисплее
151         break;                                                                               //
152         case 41:                                                                             //  Если установлен режим 41: "HOBЫЙ TAЙMEP CO3ДAH", то данный режим сбросится в режим 61 через 2 секунды вне зависимости от состояния энкодера ...
153     /*  "  HOBЫЙ TAЙMEP  " */  j=61; valTimerNum=funcFindTimer(); valSubMode=0; valArray[0]=0; valArray[1]=0; valArray[2]=0; valArray[3]=0; valArray[4]=1; funcSaveTimer(valTimerNum,0,1); funcSaveTimer(valTimerNum,1); funcSaveTimer(valTimerNum,2); funcSaveTimer(valTimerNum,3); funcSaveTimer(valTimerNum,4); funcSaveTimer(valTimerNum,5,1); funcSaveTimer(valTimerNum,6,100); funcSaveTimer(valTimerNum,7,127);
154     /*  "     CO3ДAH     " */  delay(2000);                                                  //
155         break;                                                                               //
156         case 42:                                                                             //  Если установлен режим 42: "BCE TAЙMEPЫ УДAЛEHЫ", то данный режим сбросится в режим 12 через 2 секунды вне зависимости от состояния энкодера ...
157     /*  "  BCE TAЙMEPЫ   " */  j=12; for(valArray[0]=0; valArray[0]<maxTimers; valArray[0]++){funcSaveTimer(valArray[0]);}
158     /*  "    УДAЛEHЫ     " */  delay(2000);                                                  //
159         break;                                                                               //
160         case 43:                                                                             //  Если установлен режим 43: "TAЙMEP УДAЛEH", то данный режим сбросится в режим 11 или 12 через 2 секунды вне зависимости от состояния энкодера ...
161     /*  "     TAЙMEP     " */  j=12; valArray[0]=valTimerNum; valArray[1]=funcFindTimer()-1; if(valArray[0]<valArray[1]){j=11; valTimerNum=valArray[0];}else if(valArray[1]>0){j=11; valTimerNum=valArray[0]-1;} for(int k=valArray[0]; k<valArray[1]; k++){for(uint8_t l=0; l<8; l++){funcSaveTimer(k,l,funcReadTimer(k+1,l));}} funcSaveTimer(valArray[1]);
162     /*  "     УДAЛEH     " */  delay(2000);                                                  //
163         break;                                                                               //  Если установлен режим 51: "Меню>тайmеры>выбранный_таймер" и нажав на энкодер, можно выбрать пункт "BPEMЯ  И KAHAЛ", то ...
164         case 51:               if(i==encPRESS){j=61; valSubMode=0; valArray[0]=funcReadTimer(valTimerNum,1); valArray[1]=funcReadTimer(valTimerNum,2); valArray[2]=funcReadTimer(valTimerNum,3); valArray[3]=funcReadTimer(valTimerNum,4); valArray[4]=funcReadTimer(valTimerNum,5);}
165     /*  "m>тайmеры>00:00." */  if(i==encLEFT ){j=55;}                                        //  Если энкодер поворачивается влево, то переходим в режим 55
166     /*  "<BPEMЯ  И KAHAЛ>" */  if(i==encRIGHT){j=52;}                                        //  Если энкодер поворачивается вправо, то переходим в режим 52
167         break;                                                                               //  Если установлен режим 52: "Меню>тайmеры>выбранный_таймер" и нажав на энкодер, можно выбрать пункт "ПOBTOPЫ", то ...
168         case 52:               if(i==encPRESS){j=62; valSubMode=0; valArray[0]=bitRead(funcReadTimer(valTimerNum,7),6); valArray[1]=bitRead(funcReadTimer(valTimerNum,7),5); valArray[2]=bitRead(funcReadTimer(valTimerNum,7),4); valArray[3]=bitRead(funcReadTimer(valTimerNum,7),3); valArray[4]=bitRead(funcReadTimer(valTimerNum,7),2); valArray[5]=bitRead(funcReadTimer(valTimerNum,7),1); valArray[6]=bitRead(funcReadTimer(valTimerNum,7),0);}
169     /*  "m>тайmеры>00:00." */  if(i==encLEFT ){j=51;}                                        //  Если энкодер поворачивается влево, то переходим в режим 51
170     /*  "<ПО ДНЯМ НЕДЕЛИ>" */  if(i==encRIGHT){j=53;}                                        //  Если энкодер поворачивается вправо, то переходим в режим 53
171         break;                                                                               //  Если установлен режим 53: "Меню>тайmеры>выбранный_таймер" и нажав на энкодер, можно выбрать пункт "УPOBEHЬ CИГНАЛА", то ...
172         case 53:               if(i==encPRESS){j=63; valArray[0]=funcReadTimer(valTimerNum,6);}
173     /*  "m>тайmеры>00:00." */  if(i==encLEFT ){j=52;}                                        //  Если энкодер поворачивается влево, то переходим в режим 52
174     /*  "< УPOBEHb CИГН.>" */  if(i==encRIGHT){j=54;}                                        //  Если энкодер поворачивается вправо, то переходим в режим 54
175         break;                                                                               //
176         case 54:               if(i==encPRESS){j=43;}                                        //  Если установлен режим 54: "Меню>тайmеры>выбранный_таймер" и нажав на энкодер, можно выбрать пункт "CTEPETЬ TAЙMEP", то ...
177     /*  "m>тайmеры>00:00." */  if(i==encLEFT ){j=53;}                                        //  Если энкодер поворачивается влево, то переходим в режим 53
178     /*  "<CTEPETЬ TAЙMEP>" */  if(i==encRIGHT){j=55;}                                        //  Если энкодер поворачивается вправо, то переходим в режим 55
179         break;                                                                               //
180         case 55:               if(i==encPRESS){j=11;}                                        //  Если установлен режим 55: "Меню>тайmеры>выбранный_таймер" и нажав на энкодер, можно выбрать пункт "ВЫХОД", то ...
181     /*  "m>тайmеры>00:00." */  if(i==encLEFT ){j=54;}                                        //  Если энкодер поворачивается влево, то переходим в режим 54
182     /*  "<    ВЫХОД     >" */  if(i==encRIGHT){j=51;}                                        //  Если энкодер поворачивается вправо, то переходим в режим 51
183         break;                                                                               //  Если установлен режим 61: "Меню>тайmеры>выбранный_таймер>время_и_канал" и управляя энкодером, можно установить время и канал таймера, то ...
184         case 61:               if(i==encPRESS){if(valSubMode==0){valSubMode=1;}else if(valSubMode==1){valSubMode=2;}else if(valSubMode==2){valSubMode=3;}else if(valSubMode==3){valSubMode=4;}else if(valSubMode==4){
185                                j=51; funcSaveTimer(valTimerNum,0,1); funcSaveTimer(valTimerNum,1,valArray[0]); funcSaveTimer(valTimerNum,2,valArray[1]); funcSaveTimer(valTimerNum,3,valArray[2]); funcSaveTimer(valTimerNum,4,valArray[3]); funcSaveTimer(valTimerNum,5,valArray[4]);}}
186     /*  "м>таймер>вpeмя: " */  if(i==encLEFT ){valArray[valSubMode]--; if(valArray[0]>23){valArray[0]=23;} if(valArray[1]>59){valArray[1]=59;} if(valArray[2]>23){valArray[2]=23;} if(valArray[3]>59){valArray[3]=59;} if(valArray[4]==0){valArray[4]=4;}}
187     /*  " 00:00-00:00 к0 " */  if(i==encRIGHT){valArray[valSubMode]++; if(valArray[0]>23){valArray[0]= 0;} if(valArray[1]>59){valArray[1]= 0;} if(valArray[2]>23){valArray[2]= 0;} if(valArray[3]>59){valArray[3]= 0;} if(valArray[4]> 4){valArray[4]=1;}}
188                                flgDisplayUpdate=1;                                           //  Устанавливаем флаг flgDisplayUpdate сигнализирующий о необходимости обновить информацию на дисплее
189         break;                                                                               //  Если установлен режим 62: "Меню>тайmеры>выбранный_таймер>повторы" и управляя энкодером, можно установить повторы таймера, то ...
190         case 62:               if(i==encPRESS){flgDisplayUpdate=1; if(valSubMode==0){valSubMode=1;}else if(valSubMode==1){valSubMode=2;}else if(valSubMode==2){valSubMode=3;}else if(valSubMode==3){valSubMode=4;}else if(valSubMode==4){valSubMode=5;}else if(valSubMode==5){valSubMode=6;}else if(valSubMode==6){
191                                j=52; uint8_t k=0; bitWrite(k,6,valArray[0]); bitWrite(k,5,valArray[1]); bitWrite(k,4,valArray[2]); bitWrite(k,3,valArray[3]); bitWrite(k,2,valArray[4]); bitWrite(k,1,valArray[5]); bitWrite(k,0,valArray[6]); funcSaveTimer(valTimerNum,7,k); lcd.noBlink();}}
192     /*  " * * * * * * *  " */  if(i==encLEFT ){flgDisplayUpdate=1; if(valArray[valSubMode]){valArray[valSubMode]=0;}else{valArray[valSubMode]=1;}}
193     /*  " ^ ^ ^ ^ ^ ^ ^  " */  if(i==encRIGHT){flgDisplayUpdate=1; if(valArray[valSubMode]){valArray[valSubMode]=0;}else{valArray[valSubMode]=1;}}
194         break;                                                                               //  Если установлен режим 63: "Меню>тайmеры>выбранный_таймер>уровень_сигнала" и управляя энкодером, можно установить уровень сигнала таймера, то ...
195         case 63:               if(i==encPRESS){j=53; funcSaveTimer(valTimerNum,6,valArray[0]);}
196     /*  "м>тaймep>cигнaл:" */  if(i==encLEFT ){flgDisplayUpdate=1; valArray[0]-=5; if(valArray[0]>100){valArray[0]=  5;} if(valArray[0]<5){valArray[0]=5;}}
197     /*  "      100%      " */  if(i==encRIGHT){flgDisplayUpdate=1; valArray[0]+=5; if(valArray[0]>100){valArray[0]=100;}}
198         break;                                                                               //
199     }                                                                                        //
200     if(j<255){lcd.clear(); flgDisplayUpdate=1; valMode=j;}                                   //  Если требуется сменить режим, то чистим экран, устанавливаем флаг необходимости обновления экрана flgDisplayUpdate и устанавливаем новый режим valMode
201     if(i==encPRESS){while(!digitalRead(pinEncBTN)){delay(50);}}                               //  Если была нажата кнопка энкодера, то ждём пока она не будет отпущена (с задержками по 50мс для подавления дребезга)
202}                                                                                             //
203                                                                                              //
204//   ОБНОВЛЕНИЕ ИНФОРМАЦИИ НА ДИСПЛЕЕ                                                         //
205void funcDisplayUpdate(){                                                                     //
206     if(flgDisplayUpdate){      flgDisplayUpdate=0;                                           //  Обновление дисплея происходит только если был установлен флаг flgDisplayUpdate
207     switch(valMode){                                                                         //  Далее действуем в зависимости от значения переменной valMode (которая хранит № текущего режима меню)
208         case  0:               funcSetChars(35,36,37,5,3,0,time.weekday==4?18:14);           //  Если установлен режим 0, то загружаем символы в CGRAM лисплея в следующем порядке: 1-«1» 2-«2» 3-«3» 4-«4» 5-«г» 6-«Б» 7-«П/Ч» и выводим информацию для данного режима на дисплей ...
209     /*  "00:00:00        " */  lcd.setCursor(0, 0); lcd.print(time.gettime("H:i:s"));        //  Выводим верхнюю строку
210     /*  "00.00.0000г. ПН " */  lcd.setCursor(0, 1); lcd.print(time.gettime("d.m.Y\5."));     //
211                                lcd.setCursor(13,1); lcd.print(time.weekday==1?"\7H":(time.weekday==2?"BT":(time.weekday==3?"CP":(time.weekday==4?"\7T":(time.weekday==5?"\7T":(time.weekday==6?"C\6":("BC")))))));
212                                lcd.setCursor(12,0); lcd.print("    "); valArray[4]=15; if(valArray[3]){lcd.setCursor(valArray[4],0); lcd.print("\4"); valArray[4]--;} if(valArray[2]){lcd.setCursor(valArray[4],0); lcd.print("\3"); valArray[4]--;} if(valArray[1]){lcd.setCursor(valArray[4],0); lcd.print("\2"); valArray[4]--;} if(valArray[0]){lcd.setCursor(valArray[4],0); lcd.print("\1"); valArray[4]--;}
213         break;                                                                               //
214         case  1:               funcSetChars(11,15,25,9,20);                                  //  Если установлен режим 1, то загружаем символы в CGRAM лисплея в следующем порядке: 1м 2н 3ю 4Й 5Ы и выводим информацию для данного режима на дисплей ...
215     /*  "меню:           " */  lcd.setCursor(0, 0); lcd.print(F("\1e\2\3:"));                //  Выводим верхнюю строку
216     /*  "<   ТАЙМЕРЫ    >" */  lcd.setCursor(0, 1); lcd.print(F("<   TA\4MEP\5    >"));      //
217         break;                                                                               //
218         case  2:               funcSetChars(11,15,25,18,20);                                 //  Если установлен режим 2, то загружаем символы в CGRAM лисплея в следующем порядке: 1м 2н 3ю 4Ч 5Ы и выводим информацию для данного режима на дисплей ...
219     /*  "меню:           " */  lcd.setCursor(0, 0); lcd.print(F("\1e\2\3:"));                //  Выводим верхнюю строку
220     /*  "<     ЧАСЫ     >" */  lcd.setCursor(0, 1); lcd.print(F("<     \4AC\5     >"));      //
221         break;                                                                               //
222         case  3:               funcSetChars(11,15,25,4,20);                                  //  Если установлен режим 3, то загружаем символы в CGRAM лисплея в следующем порядке: 1м 2н 3ю 4Д 5Ы и выводим информацию для данного режима на дисплей ...
223     /*  "меню:           " */  lcd.setCursor(0, 0); lcd.print(F("\1e\2\3:"));                //  Выводим верхнюю строку
224     /*  "<    ВЫХОД     >" */  lcd.setCursor(0, 1); lcd.print(F("<    B\5XO\4     >"));      //
225         break;                                                                               //
226         case 11:               funcSetChars(15,25,17,9,21);                                  //  Если установлен режим 11, то загружаем символы в CGRAM лисплея в следующем порядке: 1н 2ю 3т 4й 5ы и выводим информацию для данного режима на дисплей ...
227     /*  "меню>таймеры:   " */  lcd.setCursor(0, 0); lcd.print(F("me\1\2>\3a\4mep\5:"));      //  Выводим верхнюю строку
228     /*  "< 00:00-00:00-1>" */  lcd.setCursor(0, 1); lcd.print(F("< 00:00-00:00-0>"));        //
229                                lcd.setCursor(2, 1); lcd.print(funcReadTimer(valTimerNum,1)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,1));
230                                lcd.setCursor(5, 1); lcd.print(funcReadTimer(valTimerNum,2)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,2));
231                                lcd.setCursor(8, 1); lcd.print(funcReadTimer(valTimerNum,3)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,3));
232                                lcd.setCursor(11,1); lcd.print(funcReadTimer(valTimerNum,4)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,4));
233                                lcd.setCursor(14,1);                                                    lcd.print(funcReadTimer(valTimerNum,5));
234         break;                                                                               //
235         case 12:               funcSetChars(15,25,17,9,21,8,20);                             //  Если установлен режим 12, то загружаем символы в CGRAM лисплея в следующем порядке: 1н 2ю 3т 4й 5ы 6Й 7Ы и выводим информацию для данного режима на дисплей ...
236     /*  "меню>таймеры:   " */  lcd.setCursor(0, 0); lcd.print(F("me\1\2>\3a\4mep\5:"));      //  Выводим верхнюю строку
237     /*  "< НОВЫЙ ТАЙМЕР >" */  lcd.setCursor(0, 1); lcd.print(F("< HOB\7\6 TA\6MEP >"));     //
238         break;                                                                               //
239         case 13:               funcSetChars(15,25,17,9,21,22);                               //  Если установлен режим 13, то загружаем символы в CGRAM лисплея в следующем порядке: 1н 2ю 3т 4й 5ы 6Ь и выводим информацию для данного режима на дисплей ...
240     /*  "меню>таймеры:   " */  lcd.setCursor(0, 0); lcd.print(F("me\1\2>\3a\4mep\5:"));      //  Выводим верхнюю строку
241     /*  "< CTEPETь BCE  >" */  lcd.setCursor(0, 1); lcd.print(F("< CTEPET\6 BCE  >"));       //
242         break;                                                                               //
243         case 14:               funcSetChars(15,25,17,9,21,4,20);                             //  Если установлен режим 14, то загружаем символы в CGRAM лисплея в следующем порядке: 1н 2ю 3т 4й 5ы 6Д 7Ы и выводим информацию для данного режима на дисплей ...
244     /*  "меню>таймеры:   " */  lcd.setCursor(0, 0); lcd.print(F("me\1\2>\3a\4mep\5:"));      //  Выводим верхнюю строку
245     /*  "<    ВЫХОД     >" */  lcd.setCursor(0, 1); lcd.print(F("<    B\7XO\6     >"));      //
246         break;                                                                               //
247         case 21:               funcSetChars(11,15,25,19,21,26);                              //  Если установлен режим 21, то загружаем символы в CGRAM лисплея в следующем порядке: 1м 2н 3ю 4ч 5ы 6Я и выводим информацию для данного режима на дисплей ...
248     /*  "меню>часы:      " */  lcd.setCursor(0, 0); lcd.print(F("\1e\2\3>\4ac\5:"));         //  Выводим верхнюю строку
249     /*  "<    ВРЕМЯ     >" */  lcd.setCursor(0, 1); lcd.print(F("<    BPEM\6     >"));       //
250         break;                                                                               //
251         case 22:               funcSetChars(11,15,25,19,21,4);                               //  Если установлен режим 22, то загружаем символы в CGRAM лисплея в следующем порядке: 1м 2н 3ю 4ч 5ы 6Д и выводим информацию для данного режима на дисплей ...
252     /*  "меню>часы:      " */  lcd.setCursor(0, 0); lcd.print(F("\1e\2\3>\4ac\5:"));         //  Выводим верхнюю строку
253     /*  "<     ДАТА     >" */  lcd.setCursor(0, 1); lcd.print(F("<     \6ATA     >"));       //
254         break;                                                                               //
255         case 23:               funcSetChars(11,15,25,19,21,4,20);                            //  Если установлен режим 23, то загружаем символы в CGRAM лисплея в следующем порядке: 1м 2н 3ю 4ч 5ы 6Д 7Ы и выводим информацию для данного режима на дисплей ...
256     /*  "меню>часы:      " */  lcd.setCursor(0, 0); lcd.print(F("\1e\2\3>\4ac\5:"));         //  Выводим верхнюю строку
257     /*  "<    ВЫХОД     >" */  lcd.setCursor(0, 1); lcd.print(F("<    B\7XO\6     >"));      //
258         break;                                                                               //
259         case 31:               funcSetChars(11,15,25,19,21,1,27);                            //  Если установлен режим 31, то загружаем символы в CGRAM лисплея в следующем порядке: 1м 2н 3ю 4ч 5ы 6в 7я и выводим информацию для данного режима на дисплей ...
260     /*  "меню>часы>вpeмя:" */  lcd.setCursor(0, 0); lcd.print(F("\1e\2\3>\4ac\5>\6pe\1\7:"));//  Выводим верхнюю строку
261     /*  "    00:00:00    " */  lcd.setCursor(4, 1); valChar[0]=valArray[0]/10+48; valChar[1]=valArray[0]%10+48; valChar[2]=0; lcd.print((millis()%1000<500 && valSubMode==0)?"  ":valChar); lcd.print(":");
262                                lcd.setCursor(7, 1); valChar[0]=valArray[1]/10+48; valChar[1]=valArray[1]%10+48; valChar[2]=0; lcd.print((millis()%1000<500 && valSubMode==1)?"  ":valChar); lcd.print(":");
263                                lcd.setCursor(10,1); valChar[0]=valArray[2]/10+48; valChar[1]=valArray[2]%10+48; valChar[2]=0; lcd.print((millis()%1000<500 && valSubMode==2)?"  ":valChar);
264         break;                                                                               //
265         case 32:               funcSetChars(24,18,20,4,14,0);                                //  Если установлен режим 32, то загружаем символы в CGRAM лисплея в следующем порядке: 1Ю 2Ч 3Ы 4Д 5П 6Б и выводим информацию для данного режима на дисплей ...
266     /*  "MEHЮ>ЧACЫ>ДATA: " */  lcd.setCursor(0, 0); lcd.print(F("MEH\1>\2AC\3>\4ATA:"));     //  Выводим верхнюю строку
267     /*  " 00.00.0000 пт  " */  lcd.setCursor(1, 1); valChar[0]=valArray[0]/10+48; valChar[1]=valArray[0]%10+48; valChar[2]=0; lcd.print((millis()%1000<500 && valSubMode==0)?"  ":valChar); lcd.print(".");
268                                lcd.setCursor(4, 1); valChar[0]=valArray[1]/10+48; valChar[1]=valArray[1]%10+48; valChar[2]=0; lcd.print((millis()%1000<500 && valSubMode==1)?"  ":valChar); lcd.print(".");
269                                lcd.setCursor(7, 1); valChar[0]='2'; valChar[1]='0'; valChar[2]=valArray[2]/10+48; valChar[3]=valArray[2]%10+48; valChar[4]=0; lcd.print((millis()%1000<500 && valSubMode==2)?"    ":valChar);
270                                lcd.setCursor(12,1); strcpy(valChar,(valArray[3]==1?"\5H":(valArray[3]==2?"BT":(valArray[3]==3?"CP":(valArray[3]==4?"\2T":(valArray[3]==5?"\5T":(valArray[3]==6?"C\6":("BC")))))))); valChar[2]=0; lcd.print((millis()%1000<500 && valSubMode==3)?"  ":valChar);
271         break;                                                                               //
272         case 41:               funcSetChars(20,8,4);                                         //  Если установлен режим 41, то загружаем символы в CGRAM лисплея в следующем порядке: 1Ы 2Й 3Д и выводим информацию для данного режима на дисплей ...
273     /*  "  HOBЫЙ TAЙMEP  " */  lcd.setCursor(2, 0); lcd.print(F("HOB\1\2 TA\2MEP"));         //  Выводим верхнюю строку
274     /*  "     CO3ДAH     " */  lcd.setCursor(5, 1); lcd.print(F("CO3\3AH"));                 //
275         break;                                                                               //
276         case 42:               funcSetChars(20,8,4,16,12);                                   //  Если установлен режим 42, то загружаем символы в CGRAM лисплея в следующем порядке: 1Ы 2Й 3Д 4У 5Л и выводим информацию для данного режима на дисплей ...
277     /*  "  BCE TAЙMEPЫ   " */  lcd.setCursor(2, 0); lcd.print(F("BCE TA\2MEP\1"));           //  Выводим верхнюю строку
278     /*  "    УДAЛEHЫ     " */  lcd.setCursor(4, 1); lcd.print(F("\4\3A\5EH\1"));             //
279         break;                                                                               //
280         case 43:               funcSetChars(8,16,4,12);                                      //  Если установлен режим 43, то загружаем символы в CGRAM лисплея в следующем порядке: 1Й 2У 3Д 4Л и выводим информацию для данного режима на дисплей ...
281     /*  "     TAЙMEP     " */  lcd.setCursor(5, 0); lcd.print(F("TA\1MEP"));                 //  Выводим верхнюю строку
282     /*  "     УДAЛEH     " */  lcd.setCursor(5, 1); lcd.print(F("\2\3A\4EH"));               //
283         break;                                                                               //
284         case 51:               funcSetChars(17,9,21,23,26,6,12);                             //  Если установлен режим 51, то загружаем символы в CGRAM лисплея в следующем порядке: 1т 2й 3ы 4. 5Я 6И 7Л и выводим информацию для данного режима на дисплей ...
285     /*  "m>тайmеры>00:00." */  lcd.setCursor(0, 0); lcd.print(F("m>\1a\2mep\3>"));           //  Выводим верхнюю строку
286     /*  "<BPEM*  * KAHA*>" */  lcd.setCursor(10,0); lcd.print(funcReadTimer(valTimerNum,1)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,1)); lcd.print(":");
287                                lcd.setCursor(13,0); lcd.print(funcReadTimer(valTimerNum,2)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,2)); lcd.print("\4");
288                                lcd.setCursor(0, 1); lcd.print(F("<BPEM\5  \6 KAHA\7>"));     //
289         break;                                                                               //
290         case 52:               funcSetChars(17,9,21,23,14,20);                               //  Если установлен режим 52, то загружаем символы в CGRAM лисплея в следующем порядке: 1т 2й 3ы 4. 5П 6Ы и выводим информацию для данного режима на дисплей ...
291     /*  "m>тайmеры>00:00." */  lcd.setCursor(0, 0); lcd.print(F("m>\1a\2mep\3>"));           //  Выводим верхнюю строку
292     /*  "<ПО ДНЯМ НЕДЕЛИ>" */  lcd.setCursor(10,0); lcd.print(funcReadTimer(valTimerNum,1)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,1)); lcd.print(":");
293                                lcd.setCursor(13,0); lcd.print(funcReadTimer(valTimerNum,2)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,2)); lcd.print("\4");
294                                lcd.setCursor(0, 1); lcd.print(F("<   \5OBTOP\6    >"));      //
295         break;                                                                               //
296         case 53:               funcSetChars(17,9,21,23,16,6,2);                              //  Если установлен режим 53, то загружаем символы в CGRAM лисплея в следующем порядке: 1т 2й 3ы 4. 5У 6И 7Г и выводим информацию для данного режима на дисплей ...
297     /*  "m>тайmеры>00:00." */  lcd.setCursor(0, 0); lcd.print(F("m>\1a\2mep\3>"));           //  Выводим верхнюю строку
298     /*  "< УPOBEHb CИГН.>" */  lcd.setCursor(10,0); lcd.print(funcReadTimer(valTimerNum,1)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,1)); lcd.print(":");
299                                lcd.setCursor(13,0); lcd.print(funcReadTimer(valTimerNum,2)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,2)); lcd.print("\4");
300                                lcd.setCursor(0, 1); lcd.print(F("< \5POBEHb C\6\7H.>"));     //
301         break;                                                                               //
302         case 54:               funcSetChars(17,9,21,23,22,8);                                //  Если установлен режим 54, то загружаем символы в CGRAM лисплея в следующем порядке: 1т 2й 3ы 4. 5Ь 6Й и выводим информацию для данного режима на дисплей ...
303     /*  "m>тайmеры>00:00." */  lcd.setCursor(0, 0); lcd.print(F("m>\1a\2mep\3>"));           //  Выводим верхнюю строку
304     /*  "<CTEPETЬ TAЙMEP>" */  lcd.setCursor(10,0); lcd.print(funcReadTimer(valTimerNum,1)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,1)); lcd.print(":");
305                                lcd.setCursor(13,0); lcd.print(funcReadTimer(valTimerNum,2)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,2)); lcd.print("\4");
306                                lcd.setCursor(0, 1); lcd.print(F("<CTEPET\5 TA\6MEP>"));      //
307         break;                                                                               //
308         case 55:               funcSetChars(17,9,21,23,20,4);                                //  Если установлен режим 55, то загружаем символы в CGRAM лисплея в следующем порядке: 1т 2й 3ы 4. 5Ы 6Д и выводим информацию для данного режима на дисплей ...
309     /*  "m>тайmеры>00:00." */  lcd.setCursor(0, 0); lcd.print(F("m>\1a\2mep\3>"));           //  Выводим верхнюю строку
310     /*  "<    ВЫХОД     >" */  lcd.setCursor(10,0); lcd.print(funcReadTimer(valTimerNum,1)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,1)); lcd.print(":");
311                                lcd.setCursor(13,0); lcd.print(funcReadTimer(valTimerNum,2)<10?"0":""); lcd.print(funcReadTimer(valTimerNum,2)); lcd.print("\4");
312                                lcd.setCursor(0, 1); lcd.print(F("<    B\5XO\6     >"));      //
313         break;                                                                               //
314         case 61:               funcSetChars(11,17,9,21,1,27,10);                             //  Если установлен режим 61, то загружаем символы в CGRAM лисплея в следующем порядке: 1м 2т 3й 4ы 5в 6я 7к и выводим информацию для данного режима на дисплей ...
315     /*  "м>таймер>вpeмя: " */  lcd.setCursor(0, 0); lcd.print(F("\1>\2a\3\1ep>\5pe\1\6:"));  //  Выводим верхнюю строку
316     /*  " 00:00-00:00 к0 " */  lcd.setCursor(1, 1); valChar[0]=valArray[0]/10+48; valChar[1]=valArray[0]%10+48; valChar[2]=0; lcd.print((millis()%1000<500 && valSubMode==0)?"  ":valChar); lcd.print(":");
317                                lcd.setCursor(4, 1); valChar[0]=valArray[1]/10+48; valChar[1]=valArray[1]%10+48; valChar[2]=0; lcd.print((millis()%1000<500 && valSubMode==1)?"  ":valChar); lcd.print("-");
318                                lcd.setCursor(7, 1); valChar[0]=valArray[2]/10+48; valChar[1]=valArray[2]%10+48; valChar[2]=0; lcd.print((millis()%1000<500 && valSubMode==2)?"  ":valChar); lcd.print(":");
319                                lcd.setCursor(10,1); valChar[0]=valArray[3]/10+48; valChar[1]=valArray[3]%10+48; valChar[2]=0; lcd.print((millis()%1000<500 && valSubMode==3)?"  ":valChar);
320                                lcd.setCursor(13,1); valChar[0]=7;                 valChar[1]=valArray[4]   +48; valChar[2]=0; lcd.print((millis()%1000<500 && valSubMode==4)?"  ":valChar);
321         break;                                                                               //
322         case 62:               funcSetChars(28,29,30,31,32,33,34);                           //  Если установлен режим 62, то загружаем символы в CGRAM лисплея в следующем порядке: 1-ПН 2-ВТ 3-СР 4-ЧТ 5-ПТ 6-ВТ 7-СР и выводим информацию для данного режима на дисплей ...
323     /*  " * * * * * * *  " */  lcd.setCursor(1, 0); lcd.print("\1 \2 \3 \4 \5 \6 \7");       //  Выводим верхнюю строку
324     /*  " ^ ^ ^ ^ ^ ^ ^  " */  lcd.setCursor(1, 1); lcd.print(valArray[0]?"^":" "); lcd.setCursor(3, 1); lcd.print(valArray[1]?"^":" "); lcd.setCursor(5, 1); lcd.print(valArray[2]?"^":" "); lcd.setCursor(7, 1); lcd.print(valArray[3]?"^":" "); lcd.setCursor(9, 1); lcd.print(valArray[4]?"^":" "); lcd.setCursor(11,1); lcd.print(valArray[5]?"^":" "); lcd.setCursor(13,1); lcd.print(valArray[6]?"^":" ");
325                                lcd.setCursor(valSubMode*2+1, 1); lcd.blink();                //
326         break;                                                                               //
327         case 63:               funcSetChars(11,17,9,7,3,15,13);                              //  Если установлен режим 63, то загружаем символы в CGRAM лисплея в следующем порядке: 1м 2т 3й 4и 5г 6н 7л и выводим информацию для данного режима на дисплей ...
328     /*  "м>тaймep>cигнaл:" */  lcd.setCursor(0, 0); lcd.print(F("\1>\2a\3\1ep>c\4\5\6a\7:"));//  Выводим верхнюю строку
329     /*  "      100%      " */  lcd.setCursor(6, 1); valChar[0]=valArray[0]/100+48; valChar[1]=valArray[0]%100/10+48; valChar[2]=valArray[0]%10+48; valChar[3]=0; lcd.print(valChar); lcd.print("%");
330         break;                                                                               //
331}    }}                                                                                       //
332                                                                                              //
333//   ВЫВОД СИГНАЛОВ ШИМ                                                                       //
334void funcSetPWM(void){                                                                        //
335     static uint8_t setChanel[4] = {0,0,0,0};                                                 //  Определяем массив, каждый элемент которого соответствует уровню сигнала (от 0 до 100%) установленного на соответствующем канале
336     if(valMode==0){                                                                          //  Если текущий режим равен 0 "Вне меню", то ...
337         uint8_t  getChanel[4]   = {0,0,0,0};                                                 //  Определяем массив, каждый элемент которого соответствует уровню сигнала (от 0 до 100%) прочитанного из октивированного таймера для соответствующего канала
338         uint32_t timeRTC        = 0;                                                         //  Определяем переменную для хранения текущего времени ввиде секунд прошедших с полуночи текущего дня (от 00:00:00)
339         uint32_t timeTimerStart = 0;                                                         //  Определяем переменную для хранения времени старта таймера (для каждого таймера в теле цикла for) ввиде секунд прошедших с полуночи текущего дня (от 00:00:00)
340         uint32_t timeTimerStop  = 0;                                                         //  Определяем переменную для хранения времени сброса таймера (для каждого таймера в теле цикла for) ввиде секунд прошедших с полуночи текущего дня (от 00:00:00)
341         uint8_t  timeWeekday    = 0;                                                         //  Определяем переменную для хранения текущего деня недели в формате: 1-ПН, 2-ВТ, 3-СР, 4-ЧТ, 5-ПТ, 6-СБ, 7-ВС
342         valArray[0]=valArray[1]=valArray[2]=valArray[3]=0;                                   //  В первые 4 элемента массива valArray будет записана 1, если на соответствующем канале будет установлен сигнал
343         timeRTC = (uint32_t) time.Hours*3600+time.minutes*60+time.seconds;                   //  Получаем количество секунд прошедшее с полуночи текущего дня (от 00:00:00). Значения переменных объекта time являются актуальными, т.к. в данном режиме (valMode) в функции funcDisplayUpdate было обращение к функции time.gettime
344         timeWeekday = time.weekday; if(timeWeekday==0){timeWeekday=7;}                       //  Получаем текущий день недели в формате: 1-ПН, 2-ВТ, 3-СР, 4-ЧТ, 5-ПТ, 6-СБ, 7-ВС
345         for(uint8_t i=0; i<maxTimers; i++){                                                  //  Проходим по всем таймерам, ...
346         if (funcReadTimer(i)){                                                               //  Если очередной таймер является установленным, то ...
347         if (bitRead(funcReadTimer(i,7),7-timeWeekday)){                                      //  Если день недели повтора таймера совпал с текушим днём недели, то ...
348             timeTimerStart=(uint32_t)funcReadTimer(i,1)*3600+funcReadTimer(i,2)*60;          //  Читаем время старта очередного таймера ввиде количества секунд прошедших от полуночи текущего дня (от 00:00:00)
349             timeTimerStop =(uint32_t)funcReadTimer(i,3)*3600+funcReadTimer(i,4)*60;          //  Читаем время сброса очередного таймера ввиде количества секунд прошедших от полуночи текущего дня (от 00:00:00)
350             if(timeTimerStart<=timeRTC && timeRTC<timeTimerStop){                            //  Если текущее время находится между временем старта и сброса таймера, то ...
351                 getChanel[funcReadTimer(i,5)-1]=funcReadTimer(i,6);                          //  Читаем из таймера уровень сигнала который требуется установить на требуемом канале
352                 valArray [funcReadTimer(i,5)-1]=1;                                           //  Сохраняем тот факт, что установлен сигнал на требуемом канале
353             }                                                                                //
354         }}}                                                                                  //
355         if(setChanel[0]!=getChanel[0]){setChanel[0]=getChanel[0]; analogWrite(pinChanel_1, map(getChanel[0], 0,100, 0,255));} // выводим ШИМ на 1 канал
356         if(setChanel[1]!=getChanel[1]){setChanel[1]=getChanel[1]; analogWrite(pinChanel_2, map(getChanel[1], 0,100, 0,255));} // выводим ШИМ на 2 канал
357         if(setChanel[2]!=getChanel[2]){setChanel[2]=getChanel[2]; analogWrite(pinChanel_3, map(getChanel[2], 0,100, 0,255));} // выводим ШИМ на 3 канал
358         if(setChanel[3]!=getChanel[3]){setChanel[3]=getChanel[3]; analogWrite(pinChanel_4, map(getChanel[3], 0,100, 0,255));} // выводим ШИМ на 4 канал
359     }                                                                                        //
360}                                                                                             //
361//   ЗАПИСЬ ДО 7 СИМВОЛОВ В CGRAM ДИСПЛЕЯ                                                     //
362void funcSetChars(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4, uint8_t i5, uint8_t i6, uint8_t i7){ byte i[8];
363     if(i1<255){memcpy_P(i, rusMem[i1], 8); lcd.createChar(1, i);}                            //  Записываем символ i (взятый из элемента № i1 массива rusMem хранящегося в PROGMEM Arduino) в CGRAM дисплея под номером 1
364     if(i2<255){memcpy_P(i, rusMem[i2], 8); lcd.createChar(2, i);}                            //  Записываем символ i (взятый из элемента № i2 массива rusMem хранящегося в PROGMEM Arduino) в CGRAM дисплея под номером 2
365     if(i3<255){memcpy_P(i, rusMem[i3], 8); lcd.createChar(3, i);}                            //  Записываем символ i (взятый из элемента № i3 массива rusMem хранящегося в PROGMEM Arduino) в CGRAM дисплея под номером 3
366     if(i4<255){memcpy_P(i, rusMem[i4], 8); lcd.createChar(4, i);}                            //  Записываем символ i (взятый из элемента № i4 массива rusMem хранящегося в PROGMEM Arduino) в CGRAM дисплея под номером 4
367     if(i5<255){memcpy_P(i, rusMem[i5], 8); lcd.createChar(5, i);}                            //  Записываем символ i (взятый из элемента № i5 массива rusMem хранящегося в PROGMEM Arduino) в CGRAM дисплея под номером 5
368     if(i6<255){memcpy_P(i, rusMem[i6], 8); lcd.createChar(6, i);}                            //  Записываем символ i (взятый из элемента № i6 массива rusMem хранящегося в PROGMEM Arduino) в CGRAM дисплея под номером 6
369     if(i7<255){memcpy_P(i, rusMem[i7], 8); lcd.createChar(7, i);}                            //  Записываем символ i (взятый из элемента № i7 массива rusMem хранящегося в PROGMEM Arduino) в CGRAM дисплея под номером 7
370}                                                                                             //
371//   ЧТЕНИЕ ОДНОГО ИЗ ПАРАМЕТРОВ ТАЙМЕРА                                                      //
372uint8_t funcReadTimer(uint8_t i, uint8_t j){return EEPROM[i*8+j];}                            //
373//   ПОИСК НОВОГО ТАЙМЕРА                                                                     //
374uint8_t funcFindTimer(void){uint8_t i=0; while(funcReadTimer(i)){i++; if(i>=maxTimers){break;}} return i;}
375//   СОХРАНЕНИЕ ОДНОГО ИЗ ПАРАМЕТРОВ ТАЙМЕРА                                                  //
376void funcSaveTimer(uint8_t i, uint8_t j, uint8_t k){EEPROM[i*8+j]=k;}                         //
377//   ПРОВЕРКА ДАННЫХ ТАЙМЕРОВ В EEPROM                                                        //
378bool funcTestTimer(void){for(uint8_t i=0; i<maxTimers; i++){if(funcReadTimer(i,0)>1){return false;} if(funcReadTimer(i,1)>23){return false;} if(funcReadTimer(i,2)>59){return false;} if(funcReadTimer(i,3)>23){return false;} if(funcReadTimer(i,4)>59){return false;}} return true;}

 

 

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Я совсем не уверен что датчик влажности и датчик дождя это одно и то же.
Например у меня в системе заводской датчик дождя выглядит
как пачка пластин которые намокают и разбухают просто нажимая микрик.
И высыхают.
При этом всё происходит достаточно медленно.
То есть ведут себя как почва.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Программа, скорее всего, написана кубиками.  За одно это дописывание обойдётся в $100.

vvadim
Offline
Зарегистрирован: 23.05.2012

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

если будет внятное полное тз - пишите 7808543@gmail.com

Green
Offline
Зарегистрирован: 01.10.2015
Бармалей
Бармалей аватар
Offline
Зарегистрирован: 23.09.2019

Если писать не кубиками, программа будет раз в пять короче.

Kakmyc
Offline
Зарегистрирован: 15.01.2018
Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Бесплатный совет ТСу. Единственный способ использовать датчик влажности для ухода за газоном, это заглубить его сантиметров на 30. Датчик дождя вообще противопоказан газону. Там множество погодных факторов влияет, но дождь в их число попадает только в том случае, если выпало за сутки 15-20 мм, а это редкость. Мониторить нужно температуру воздуха и инсоляцию в первую очередь. Исходя из этих показателей, сезона и из особенностей почвы устанавливать режим и норму полива, которая летом может составлять 10-25 литром на м2 в сутки. И да, газон должен проливаться сантиметров на 30-40 сразу, потом время на подсушку верних 10-15 см и снова обильный пролив. Иначе дернина будет слабенькая

Бармалей
Бармалей аватар
Offline
Зарегистрирован: 23.09.2019

Датчик такой?

rst
Offline
Зарегистрирован: 25.06.2018

Бармалей пишет:
Если писать не кубиками, программа будет раз в пять короче.
...и, соответственно, выглядеть она будет дешевле.  ;)))

rst
Offline
Зарегистрирован: 25.06.2018

Rumata пишет:
Единственный способ использовать датчик влажности для ухода за газоном, это заглубить его сантиметров на 30.
Не обязательно. Имхо - достаточно его положить на грунт и накрыть сверху каким-нить колпаком.

Судя по моим датчикам (DHT20 и BME280 с али) - достаточно просто выдохнуть даже не на них, а просто рядом - у них уже показания подпрыгивают. Это даже если без перегара. ;)

r_a_s
Offline
Зарегистрирован: 23.09.2020

Спасибо.

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

r_a_s
Offline
Зарегистрирован: 23.09.2020

Да, Такой

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

rst пишет:

Имхо - достаточно его положить на грунт и накрыть сверху каким-нить колпаком.

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