#1 2023-12-11 16:34:18

aleksmuraxa
Учасник
Зареєстрований: 2023-12-11
Повідомлень: 6

ищу того кто поможет допилить скетч

Всем привет! У меня есть уже готовый проект.Он работает и реализован в железе. В двух словах это суточное реле времени на 3 канала которое включает и выключает нагрузку 12v. в определеное время. проблема в том что минимальное время работы таймера 1 мин. а для меня это много.( Видимо так в скетче прописано.А так как не я писал код я не знаю как это изменить) Нужно переделать время включения от 1 сек. с возможностью регулировки. Вся схема управляется через энкодер.
Вопрос такой: насколько сложно это переписать? Сколько это стоит?

Неактивний

#2 2023-12-11 16:41:47

г0cть
Гість

Re: ищу того кто поможет допилить скетч

Для ответа на вопрос сначала нужно увидеть код

#3 2023-12-11 17:40:53

г0cть
Гість

Re: ищу того кто поможет допилить скетч

куда его можно скинуть?

#4 2023-12-11 17:48:57

г0cть
Гість

Re: ищу того кто поможет допилить скетч

Над формой ответа есть кнопочка с надписью Code. Сюда и вставляйте

#5 2023-12-11 17:59:32

aleksmuraxa
Учасник
Зареєстрований: 2023-12-11
Повідомлень: 6

Re: ищу того кто поможет допилить скетч

#include <avr/pgmspace.h> // Подключаем библиотеку для работы с PROGMEM Arduino для хранения символов индикаторов
#include <EEPROM.h> // Подключаем библиотеку для работы с EEPROM Arduino для хранения счетчиков таймеров
#include <Wire.h> // Подключаем библиотеку для работы с шиной I2C
#include <LiquidCrystal_I2C.h> // Подключаем библиотеку для работы с ЖК-дисплеем по блестящему I2C
#include <iarduino_Encoder_tmr.h> // Подключаем плагин iarduino_Encoder_tmr для работы с энкодерами через аппаратный таймер
#include <iarduino_RTC.h> // Подключаем библиотеку iarduino_RTC для работы с часами реального времени

// ОБЪЯВЛЯЕМ КОНСТАНТЫ КОТОРЫЕ МОЖНО РЕДАКТИРОВАТЬ: //
#define pinEncA 2 // Определяем константу с ключом № вывода Arduino к этому подключённому выводу «A» энкодера
#define pinEncB 3 // Определяем константу с ключом № вывода Arduino к этому подключённому выводу «B» энкодера
#define pinEncBTN 4 // Определяем константу с кодом № вывода Arduino к этому подключённому выводу «S» энкодера (кнопка)

#define pinChanel_1 5 // Определяем константу с номером вывода Arduino, который будет являться выводом 1 канала (указываются только выводы с ШИМ, кроме выводов подключения 2 таймером Arduino)
#define pinChanel_2 6 // Определяем константу с номером вывода Arduino, который будет проявляться выводом 2 канала (указываются только выводы с ШИМ, кроме выводов подключения 2 таймером Arduino)
#define pinChanel_3 9 // Определяем константу с номером вывода Arduino, который будет являться выводом 3 канала (указываются только выводы с ШИМ, кроме выводов подключения 2 таймером Arduino)
#define pinChanel_4 10 // Определяем константу с номером вывода Arduino, который будет являться выводом 4 канала (указываются только выводы с ШИМ, кроме выводов вывода 2 таймером Arduino)

#define maxTimers 20 // Определяем константу с указанием максимального количества таймеров. Число не должно превышать количество байт EEPROM/8 (для Arduino Uno максимальное значение 128)

// ОБЪЯВЛЯЕМ КОНСТАНТЫ И ПЕРЕМЕННЫЕ НЕОБХОДИМЫЕ ДЛЯ РАБОТЫ СКЕТЧА: //
const byte rusMem[38][8] PROGMEM = { // Определяем массив в области памяти программ, каждый элемент которого является матрицей (еще одним массивом) представление символа на дисплее
  { 31, 16, 16, 30, 17, 17, 30, 0 },
  { 0, 0, 30, 17, 30, 17, 30, 0 }, // Б, в, № матрицы символа в массиве: 00, 01
  { 31, 16, 16, 16, 16, 16, 16, 0 },
  { 0, 0, 30, 16, 16, 16, 16, 0 }, // Г, г, № матрицы символа в массиве: 02, 03
  { 6, 10, 10, 10, 10, 10, 31, 17 },
  { 10, 10, 14, 2, 2, 0, 0, 0 }, // Д, 4, № матрицы символа в массиве: 04, 05
  { 17, 17, 17, 19, 21, 25, 17, 0 },
  { 0, 0, 17, 19, 21, 25, 17, 0 }, // И, и, № матрицы символа в массиве: 06, 07
  { 21, 17, 17, 19, 21, 25, 17, 0 },
  { 10, 4, 17, 19, 21, 25, 17, 0 }, // Й, й, № матрицы, символа в массиве: 08, 09
  { 0, 0, 18, 20, 24, 20, 18, 0 },
  { 0, 0, 17, 27, 21, 17, 17, 0 }, // к, м, № матрицы символа в массиве: 10, 11
  { 7, 9, 9, 9, 9, 9, 17, 0 },
  { 0, 0, 7, 9, 9, 9, 17, 0 }, // Л, л, № матрицы, символа в массиве: 12, 13
  { 31, 17, 17, 17, 17, 17, 17, 0 },
  { 0, 0, 17, 17, 31, 17, 17, 0 }, // П н, № матрицы символа в массиве: 14, 15
  { 17, 17, 17, 15, 1, 17, 14, 0 },
  { 0, 0, 31, 4, 4, 4, 4, 0 }, // У, т, № матрицы, символа в массиве: 16, 17
  { 17, 17, 17, 15, 1, 1, 1, 0 },
  { 0, 0, 17, 17, 15, 1, 1, 0 }, // Ч, ч, № матрицы, символа в массиве: 18, 19
  { 17, 17, 17, 29, 19, 19, 29, 0 },
  { 0, 0, 17, 17, 29, 19, 29, 0 }, // Ы, ы, № символа матрицы в массиве: 20, 21
  { 16, 16, 16, 30, 17, 17, 30, 0 },
  { 0, 0, 0, 0, 0, 0, 21, 0 }, // Ь, ..., № матрицы, символа в массиве: 22, 23
  { 18, 21, 21, 29, 21, 21, 18, 0 },
  { 0, 0, 18, 21, 29, 21, 18, 0 }, // Ю, ю, № матрицы символа в массиве: 24, 25
  { 15, 17, 17, 15, 5, 9, 17, 0 },
  { 0, 0, 15, 17, 15, 5, 9, 0 }, // Я, я, № матрицы символа в массиве: 26, 27
  { 31, 4, 31, 0, 31, 16, 31, 0 },
  { 16, 31, 16, 0, 10, 21, 31, 0 }, // ПН, ВТ № матрицы, символа в массиве: 28, 29
  { 28, 20, 31, 0, 17, 17, 31, 0 },
  { 16, 31, 16, 0, 31, 4, 28, 0 }, // СР, ЧТ № символа матрицы в массиве: 30, 31
  { 16, 31, 16, 0, 31, 16, 31, 0 },
  { 23, 21, 31, 0, 17, 17, 31, 0 }, // ПТ, СБ № матрицы, символа в массиве: 32, 33
  { 17, 17, 31, 0, 10, 21, 31, 0 },
  { 4, 12, 4, 4, 14, 0, 0, 0 }, // ВС, 1 № матрицы символа в массиве: 34, 35
  { 14, 2, 14, 8, 14, 0, 0, 0 },
  { 14, 2, 14, 2, 14, 0, 0, 0 }
}; // 2, 3 № матрицы, символа в массиве: 36, 37

uint8_t valArray[7] = { 0, 0, 0, 0, 0, 0, 0 }; // Определяем элементы массива, которые будут хранить различную информацию в зависимости от режима
uint32_t мс;
char valChar[5] = " "; // Определим символы массива (строку), информацию, которая будет использоваться в физическом языке на дисплее мигая.
uint8_t valMode = 0; // Определяем переменную для хранения текущего режима (например: режим 31 - установка времени)
uint8_t valSubMode = 0; // Определим переменную для хранения текущего режима подрежима (например: режим 31, подрежим 0 - установка часов, подрежим 1 - установка минут, подрежим 2 - установка секунд)
uint8_t valTimerNum = 0; // Определяем переменную для хранения номера таймера (от 0 до maxTimers-1)
bool flgDisplayUpdate = 1; // Определяем флаговую переменную, установка которой будет сигнализировать о необходимости обновления дисплея
недействительный funcEncoderRead (недействительный); // Объявляем функцию, в которой будут выполняться действия определения от состояния энкодера и режима
недействительный funcDisplayUpdate (недействительный); // Объявляем функцию, в которой будет обновляться информация дисплея в зависимости от режима, подрежима, плотности таймера и результатов массива valArray
недействительный funcSetPWM (недействительный); // Объявляем функцию, которая будет сохранять сигналы ШИМ на каналах, если время тока совпало с таймерами таймеров
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
uint8_t funcReadTimer(uint8_t = 0, uint8_t = 0); // Объявляем функцию для чтения одного из параметров таймера (№ таймера, № параметра)
void funcSaveTimer(uint8_t = 0, uint8_t = 0, uint8_t = 0); // Объявляем функцию для записи одного из параметров таймера (№ таймера, № параметра, значение параметра)
uint8_t funcFindTimer (недействительный); // Объявляем функцию для поиска № следующего свободного (не установленного) таймера
bool funcTestTimer (недействительный); // Объявляем функцию для проверки соответствия данных в ячейках EEPROM значениям таймеров Arduino (если скетч запускается первоначально, то данные в ячейках не соответствуют значениям таймеров и можно будет подготовить EEPROM к первому запуску скетча)
LiquidCrystal_I2C ЖК (0x27, 16, 2); // Объявляем объект lcd для работы с отображением указателя (адрес I2C = 0x27, количество столбцов = 16, количество строк = 2)
iarduino_Encoder_tmr enc(pinEncA, pinEncB); // Объявляем объект enc для работы с энкодером указывая (№ вывода A, № вывода B)
время iarduino_RTC (RTC_DS1307); // Объявляем время объекта для работы с часами RTC указывая (тип модуля)
#define encPRESS 2 // Определяем константу для удобочитаемости при определении состояния энкодера

недействительная настройка() {
  enc.begin(); // Инициируемая работа с энкодером
  время.begin(); // Инициируемая работа с модулем RTC
  pinMode(pinEncBTN, INPUT); // Переводим вывод с ключом энкодера в режим входа
  pinMode (pinChanel_1, ВЫХОД); // Переводим вывод 1 канала в режим выхода
  pinMode (pinChanel_2, ВЫХОД); // Переводим вывод 2 канала в режим выхода
  pinMode (pinChanel_3, ВЫХОД); // Переводим вывод 3 канала в режим выхода
  pinMode (pinChanel_4, ВЫХОД); // Переводим вывод 4 канала в режим выхода
  ЖК.инит(); // Инициируемая работа с ЖК-дисплеем
  ЖК.подсветка(); // Включаем подсветку LCD дисплея
  funcSetChars(12, 6); // Загружаем элементы 12 и 6 массива rusMem в память CGRAM LCD дисплея. Эти элементы содержат графическое представление символов: «Л» и «И».
  lcd.setCursor(0, 0); // Устанавливаем курсор в верхний левый угол экрана (0 столбец, 0 строк)
  lcd.print(F(" PE1E BPEMEH2")); // Выводим надпись «PEЛE BPEMEHИ». Буквы «L» и «I» заменяются знаками «» и №, в соответствии с которыми их графические изображения были загружены в память ЖК-дисплея CGRAM.
// lcd.setCursor(5, 1); // Устанавливаем курсор в 5 столбцов 1 строки (нумерация начинается с 0)
// lcd.print(F("iarduino.ru")); // Выводим надпись «iarduino.ru».
  задержка (2000); // Ждём, что бы надпись отображаемую на дисплее удалось прочитать
  ЖК.Очистить(); // Чистим экран,
  if (!funcTestTimer()) { // Если значения в EEPROM не соответствуют значениям таймера (например, первый запуск данного скетча), то ...
    funcSetChars(14, 4, 2); // Загружаем элементы 14, 4 и 2 массива rusMem в память CGRAM LCD дисплея. Эти элементы содержат графическое представление символов: «П», «Д» и «Г».
    lcd.setCursor(0, 0); // Устанавливаем курсор в верхний левый угол экрана (0 столбец, 0 строк)
    lcd.print(F("1O23ОТОБКА...")); // Выводим надпись «ПОДГОТОВКА...». Буквы «П», «Д» и «Г» заменяются знаком «» и №, в соответствии с которыми их графические представления загружены в память CGRAM ЖК-дисплея.
    for (uint8_t i = 0; i < maxTimers; i++) { // Проходим по всем возможным таймерам
      for (uint8_t j = 0; j < 8; j++) { // Проходим по всем возможным параметрам каждого таймера
        funcSaveTimer (я, j, 0); // Обнуляем все возможные параметры каждого таймера
      }
    }
    задержка(1000);
    ЖК.Очистить(); // Ждём, что бы надпись отображаемую на дисплее удалось прочитать, а потом почистим экран
  }
}

недействительный цикл() {
  мс = миллис();
  funcEncoderRead(); // Выполняем действие в соответствии с состоянием энкодера и режимом valMode
  funcDisplayUpdate(); // Обновляем информацию на дисплее в соответствии с режимом valMode и только если установлен флаг flgDisplayUpdate
  funcSetPWM(); // Выводим ШИМ
}
// ВЫПОЛНЕНИЕ ДЕЙСТВИЯ ПРИ ИЗМЕНЕНИЯХ СОТОЯНИЯ ЭНКОДЕРА И В ЗАВИСИМОСТИ ОТ ТЕКУЩЕГО РЕЖИМА //
недействительный funcEncoderRead (недействительный) {
  статический uint32_t msBtn = 0;
  статический bool btn = ложь;
  int я = enc.read(); // Определяем переменную i в которой читаем состояние энкодера (может принять 1 из 3 результатов: 0, encLEFT, encRIGHT а далее к ним еще прибавится и значение encPRESS)
  интервал j = 255; // Определим переменную j для хранения № режима меню, в котором необходимо перейти (значение 255 означает, что переход в другой режим не требуется)
  если (!digitalRead(pinEncBTN)) {
    if (!btn && ms - msBtn > 50) {
      я = энкПРЕСС;
      БТН = правда;
    }
  } // Если нажать кнопку энкодера, то можно установить переменную i в значение encPRESS
  еще {
    БТН = ложь;
    мсБтн = мс;
  }
  switch (valMode) { // Далее действует в зависимости от значения переменной valMode (которая хранит № текущего режима меню)
    случай 0:
      если (я == encPRESS) {
        j = 1;
      } // Если установлен режим 0 "Вне меню", то ...
      /* "00:00:00" */
      flgDisplayUpdate = 1; // Устанавливаем флаг flgDisplayUpdate сигнализирующий о необходимости обновления информации на дисплее
      /* "00.00.0000 ХХ" */
      перерыв;
    Дело 1:
      если (я == encPRESS) {
        j = funcReadTimer()? 11:12;
        валТимерНум = 0;
      } // Если установлен режим 1: «Меню» и кнопки на энкодер, можно выбрать пункт «ТАЙМЕРЫ», то ...
      /* "меню: " */
      если (я == encLEFT) {
        j = 3;
      } // Если энкодер поворачивается влево, то переходим в режим 3
      /* "< ТАЙМЕРЫ >" */
      если (я == encRIGHT) {
        j = 2;
      } // Если энкодер поворачивается вправо, то переходим в режим 2
      перерыв;
    случай 2:
      если (я == encPRESS) {
        j = 21;
      } // Если установлен режим 2: «Меню» и кнопки на энкодер, можно выбрать пункт «ЧАСЫ», то...
      /* "меню: " */
      если (я == encLEFT) {
        j = 1;
      } // Если энкодер поворачивается влево, то переходим в режим 1
      /* "< ЧАСЫ >" */
      если (я == encRIGHT) {
        j = 3;
      } // Если энкодер поворачивается вправо, то переходим в режим 3
      перерыв;
    // Если установлен режим 3: «Меню» и кнопки на энкодер, можно выбрать пункт «ВЫХОД», то ...
    случай 3:
      если (я == encPRESS) {
        j = 0;
        valArray[0] = valArray[1] = valArray[2] = valArray[3] = 0;
      }
      /* "меню: " */
      если (я == encLEFT) {
        j = 2;
      } // Если энкодер поворачивается влево, то переходим в режим 2
      /* "< ВЫХОД >" */
      если (я == encRIGHT) {
        j = 1;
      } // Если энкодер поворачивается вправо, то переходим в режим 1
      перерыв;
    случай 11:
      если (я == encPRESS) {
        j = 51;
      } // Если установлен режим 11: «Меню>таймеры» и кнопки на энкодер, можно выбрать один из таймеров, то...
      /* "меню>таймеры: " */
      если (я == encLEFT) {
        если (valTimerNum) {
          valTimerNum--;
          ЖК.Очистить();
          flgDisplayUpdate = 1;
        } еще {
          j = 14;
        }
      }
      /* "< 00:00-00:00-1>" */
      если (я == encRIGHT) {
        валТимерНум++;
        if (valTimerNum >= maxTimers) {
          j = 13;
        } Еще если (funcReadTimer(valTimerNum)) {
          ЖК.Очистить();
          flgDisplayUpdate = 1;
        } еще {
          j = 12;
        }
      }
      перерыв;
    случай 12:
      если (я == encPRESS) {
        j = 41;
      } // Если установлен режим 12: «Меню>таймеры» и кнопки на энкодер, можно выбрать пункт «НОВЫЙ ТАЙМЕР», то ...
      /* "меню>таймеры: " */
      если (я == encLEFT) {
        j = funcReadTimer()? 11:14;
        если (funcReadTimer()) {
          valTimerNum = funcFindTimer() - 1;
        }
      }
      /* "< НОВЫЙ ТАЙМЕР >" */
      если (я == encRIGHT) {
        j = funcReadTimer()? 13:14;
      } // Если энкодер поворачивается вправо, то переходим в режим 13 или 14 (зависит от приложения установленных таймеров)
      перерыв;
    случай 13:
      если (я == encPRESS) {
        j = 42;
      } // Если установлен режим 13: «Меню>таймеры» и кнопки на энкодер, можно выбрать пункт «CTEPETЬ BCE ТАЙМЕРЫ», то ...
      /* "меню>таймеры: " */
      если (я == encLEFT) {
        j = funcFindTimer() <maxTimers? 12:11;
        valTimerNum = j == 11? МаксТаймерс — 1:0;
      }
      /* "< CTEPETЬ BCE >" */
      если (я == encRIGHT) {
        j = 14;
        валТимерНум = 0;
      } // Если энкодер поворачивается вправо, то переходим в режим 14 и указываем, что выбран таймер № 0
      перерыв;
    случай 14:
      если (я == encPRESS) {
        j = 1;
      } // Если установлен режим 14: "Меню>таймеры" и кнопки на энкодер, можно выбрать пункт "ВЫХОД", то...
      /* "меню>таймеры: " */
      если (я == encLEFT) {
        j = funcReadTimer()? 13: (funcFindTimer() <maxTimers? 12: 11);
        валТимерНум = 0;
      }
      /* "< ВЫХОД >" */
      если (я == encRIGHT) {
        j = funcReadTimer()? 11: (funcFindTimer() <maxTimers? 12: 13);
        валТимерНум = 0;
      }
      перерыв;
    // Если установлен режим 21: «Меню>часы» и кнопки на энкодер, можно выбрать пункт «ВРЕМЯ», то ...
    случай 21:
      если (я == encPRESS) {
        j = 31;
        валСубрежим = 0;
        время.gettime();
        valArray[0] = время.Часы;
        valArray[1] = время.минуты;
        valArray[2] = время.секунды;
      }
      /* "меню>часы: " */
      если (я == encLEFT) {
        j = 23;
      } // Если энкодер поворачивается влево, то переходим в режим 23
      /* "< ВРЕМЯ >" */
      если (я == encRIGHT) {
        j = 22;
      } // Если энкодер поворачивается вправо, то переходим в режим 22
      перерыв;
    // Если установлен режим 22: «Меню>часы» и кнопки на энкодер, можно выбрать пункт «ДАТА», то ...
    случай 22:
      если (я == encPRESS) {
        j = 32;
        валСубрежим = 0;
        время.gettime();
        valArray[0] = время.день;
        valArray[1] = время.месяц;
        valArray[2] = время.год;
        valArray[3] = время.день недели;
      }
      /* "меню>часы: " */
      если (я == encLEFT) {
        j = 21;
      } // Если энкодер поворачивается влево, то переходим в режим 21
      /* "< ДАТА >" */
      если (я == encRIGHT) {
        j = 23;
      } // Если энкодер поворачивается вправо, то переходим в режим 23
      перерыв;
    случай 23:
      если (я == encPRESS) {
        j = 2;
      } // Если установлен режим 23: «Меню>часы» и нажать на энкодер, можно выбрать пункт «ВЫХОД», то ...
      /* "меню>часы: " */
      если (я == encLEFT) {
        j = 22;
      } // Если энкодер поворачивается влево, то переходим в режим 22
      /* "< ВЫХОД >" */
      если (я == encRIGHT) {
        j = 21;
      } // Если энкодер поворачивается вправо, то переходим в режим 21
      перерыв;
    // Если установлен режим 31: "Меню>часы>впемя" и управляя энкодером, можно установить время, чтобы ...
    случай 31:
      если (я == encPRESS) {
        если (valSubMode == 0) {
          валСубрежим = 1;
        } еще если (valSubMode == 1) {
          валСубрежим = 2;
        } еще если (valSubMode == 2) {
          time.settime(valArray[2], valArray[1], valArray[0]);
          j = 21;
        }
      }
      /* "меню>часы>впемя:" */
      если (я == encLEFT) {
        valArray[valSubMode] --;
        если (valArray[0] > 23) {
          valArray[0] = 23;
        }
        если (valArray[1] > 59) {
          valArray[1] = 59;
        }
        если (valArray[2] > 59) {
          valArray[2] = 59;
        }
      }
      /* " 00:00:00 " */
      если (я == encRIGHT) {
        valArray[valSubMode]++;
        если (valArray[0] > 23)
          valArray[0] = 0;
        если (valArray[1] > 59)
          valArray[1] = 0;
        если (valArray[2] > 59)
          valArray[2] = 0;
      }
      flgDisplayUpdate = 1; // Установим флаг flgDisplayUpdate сигнализирующий о необходимости обновить информацию на дисплее
      перерыв;
    // Если установлен режим 32: «Меню>часы>дата» и управление энкодером, можно установить метки, то ...
    случай 32:
      если (я == encPRESS) {
        если (valSubMode == 0)
          валСубрежим = 1;
        иначе, если (valSubMode == 1)
          валСубрежим = 2;
        иначе, если (valSubMode == 2)
          валСубрежим = 3;
        иначе если (valSubMode == 3) {
          time.settime(-1, -1, -1, valArray[0], valArray[1], valArray[2], valArray[3]);
          j = 22;
        }
      }
      /* "MEHЮ>ЧАСЫ>ДАННЫЕ: " */
      если (я == encLEFT) {
        valArray[valSubMode] --;
        если (valArray[0] == 0)
          valArray[0] = 31;
        если (valArray[1] == 0)
          valArray[1] = 12;
        если (valArray[2] > 99)
          valArray[2] = 99;
        если (valArray[3] > 6)
          valArray[3] = 6;
      }
      /* "00.00.0000 пт" */
      если (я == encRIGHT) {
        valArray[valSubMode]++;
        если (valArray[0] > 31)
          valArray[0] = 1;
        если (valArray[1] > 12)
          valArray[1] = 1;
        если (valArray[2] > 99)
          valArray[2] = 0;
        если (valArray[3] > 6)
          valArray[3] = 0;
      }
      flgDisplayUpdate = 1; // Устанавливаем флаг flgDisplayUpdate сигнализирующий о необходимости обновления информации на дисплее
      перерыв;
    случай 41:
      // Если установлен режим 41: "HOBЫЙ ТАЙМЕП CO3ДАH", то данный режим сбрасывается в режим 61 через 2 секунды вне зависимости от состояния энкодера ...
      /* " ХОБЫЙ ТАЙМЕП " */
      j = 61;
      valTimerNum = funcFindTimer();
      валСубрежим = 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);
      /* " CO3ДАH " */
      задержка (2000);
      перерыв;
    случай 42:
      // Если установлен режим 42: "BCE ТАЙМЕПЫ УДАЛЕХЫ", то данный режим сбрасывается в режим 12 через 2 секунды вне зависимости от состояния энкодера ...
      /* "BCE ТАЙМЕПЫ" */
      j = 12;
      for (valArray[0] = 0; valArray[0] < maxTimers; valArray[0]++) {
        funcSaveTimer(valArray[0]);
      }
      /* " УДАЛЕХЫ " */
      задержка (2000);
      перерыв;
    случай 43:
      // Если установлен режим 43: "ТАЙМЕП УДАЛЕХ", то данный режим сбрасывается в режим 11 или 12 через 2 секунды вне зависимости от состояния энкодера ...
      /* " ТАЙМЕП " */
      j = 12;
      valArray[0] = valTimerNum;
      valArray[1] = funcFindTimer() - 1;
      если (valArray[0] < valArray[1]) {
        j = 11;
        valTimerNum = valArray[0];
      } иначе если (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]);
      /* " УДАЛЕХ " */
      задержка (2000);
      перерыв;
    // Если установлен режим 51: "Меню>таймеры>выбранный_таймер" и нажмите на энкодер, можно выбрать пункт "БПЕМЯ И КАХАЛ", то...
    случай 51:
      если (я == encPRESS) {
        j = 61;
        валСубрежим = 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);
      }
      /* "m>таймеры>00:00." */
      если (я == влево)
        j = 55; // Если энкодер поворачивается влево, то переходим в режим 55
      /* "<БПЕМЯ И КАХАЛ>" */
      если (я == encRIGHT)
        j = 52; // Если энкодер поворачивается вправо, то переходим в режим 52
      перерыв;
    // Если установлен режим 52: "Меню>таймеры>выбранный_таймер" и нажав на энкодер, можно выбрать пункт "ПОБТОПЫ", то...
    случай 52:
      если (я == encPRESS) {
        j = 62;
        валСубрежим = 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);
      }
      /* "m>таймеры>00:00." */
      если (я == влево)
        j = 51; // Если энкодер поворачивается влево, то переходим в режим 51
      /* "< ПОБТОПЫ >" */
      если (я == encRIGHT)
        j = 53; // Если энкодер поворачивается вправо, то переходим в режим 53
      перерыв;
    // Если установлен режим 53: "Меню>таймеры>выбранный_таймер" и нажав на энкодер, можно выбрать пункт "УПОБЕХЬ ЦИГНАЛА", то ...
    случай 53:
      если (я == encPRESS) {
        j = 63;
        valArray[0] = funcReadTimer(valTimerNum, 6);
      }
      /* "m>таймеры>00:00." */
      если (я == влево)
        j = 52; // Если энкодер поворачивается влево, то переходим в режим 52
      /* "< УPOBEHb CIGN.>" */
      если (я == encRIGHT)
        j = 54; // Если энкодер поворачивается вправо, то переходим в режим 54
      перерыв;
    случай 54:
      если (я == encPRESS)
        j = 43; // Если установлен режим 54: "Меню>таймеры>выбранный_таймер" и нажав на энкодер, можно выбрать пункт "CTEPETЬ ТАЙМЕП", то ...
      /* "m>таймеры>00:00." */
      если (я == влево)
        j = 53; // Если энкодер поворачивается влево, то переходим в режим 53
      /* "<CTEPETЬ ТАЙМЕП>" */
      если (я == encRIGHT)
        j = 55; // Если энкодер поворачивается вправо, то переходим в режим 55
      перерыв;
    случай 55:
      если (я == encPRESS)
        j = 11; // Если установлен режим 55: "Меню>таймеры>выбранный_таймер" и нажав на энкодер, можно выбрать пункт "ВЫХОД", то...
      /* "m>таймеры>00:00." */
      если (я == влево)
        j = 54; // Если энкодер поворачивается влево, то переходим в режим 54
      /* "< ВЫХОД >" */
      если (я == encRIGHT)
        j = 51; // Если энкодер поворачивается вправо, то переходим в режим 51
      перерыв;
    // Если установлен режим 61: "Меню>таймеры>выбранный_таймер>время_и_канал" и управляя энкодером, можно установить время и таймер канала, чтобы ...
    случай 61:
      если (я == encPRESS) {
        если (valSubMode == 0)
          валСубрежим = 1;
        иначе, если (valSubMode == 1)
          валСубрежим = 2;
        иначе, если (valSubMode == 2)
          валСубрежим = 3;
        иначе, если (valSubMode == 3)
          валСубрежим = 4;
        иначе если (valSubMode == 4) {
          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]);
        }
      }
      /* "м>таймер>впемя: " */
      если (я == encLEFT) {
        valArray[valSubMode] --;
        если (valArray[0] > 23)
          valArray[0] = 23;
        если (valArray[1] > 59)
          valArray[1] = 59;
        если (valArray[2] > 23)
          valArray[2] = 23;
        если (valArray[3] > 59)
          valArray[3] = 59;
        если (valArray[4] == 0)
          valArray[4] = 4;
      }
      /* " 00:00-00:00 к0 " */
      если (я == encRIGHT) {
        valArray[valSubMode]++;
        если (valArray[0] > 23)
          valArray[0] = 0;
        если (valArray[1] > 59)
          valArray[1] = 0;
        если (valArray[2] > 23)
          valArray[2] = 0;
        если (valArray[3] > 59)
          valArray[3] = 0;
        если (valArray[4] > 4)
          valArray[4] = 1;
      }
      flgDisplayUpdate = 1; // Устанавливаем флаг flgDisplayUpdate сигнализирующий о необходимости обновления информации на дисплее
      перерыв;
    //Есть выбранный режим 62: "Меню>таймеры>выбранный_таймер>повторы" и управляя энкодером, можно установить повторы таймера, чтобы ...
    случай 62:
      если (я == encPRESS) {
        flgDisplayUpdate = 1;
        если (valSubMode == 0)
          валСубрежим = 1;
        иначе, если (valSubMode == 1)
          валСубрежим = 2;
        иначе, если (valSubMode == 2)
          валСубрежим = 3;
        иначе, если (valSubMode == 3)
          валСубрежим = 4;
        иначе, если (valSubMode == 4)
          валСубрежим = 5;
        иначе, если (valSubMode == 5)
          валСубрежим = 6;
        иначе если (valSubMode == 6) {
          j = 52;
          uint8_t k = 0;
          bitWrite(к, 6, valArray[0]);
          bitWrite(к, 5, valArray[1]);
          bitWrite(к, 4, valArray[2]);
          bitWrite(к, 3, valArray[3]);
          bitWrite(k, 2, valArray[4]);
          bitWrite(k, 1, valArray[5]);
          bitWrite(к, 0, valArray[6]);
          funcSaveTimer (valTimerNum, 7, k);
          ЖК.noBlink();
        }
      }
      /* " * * * * * * * " */
      если (я == encLEFT) {
        flgDisplayUpdate = 1;
        если (valArray[valSubMode])
          valArray[valSubMode] = 0;
        еще
          valArray[valSubMode] = 1;
      }
      /* " ^ ^ ^ ^ ^ ^ ^ " */
      если (я == encRIGHT) {
        flgDisplayUpdate = 1;
        если (valArray[valSubMode])
          valArray[valSubMode] = 0;
        еще
          valArray[valSubMode] = 1;
      }
      перерыв;
    // Если установлен режим 63: "Меню>таймеры>выбранный_таймер>уровень_сигнала" и управляя энкодером, можно установить уровень сигнала таймера, чтобы ...
    случай 63:
      если (я == encPRESS) {
        j = 53;
        funcSaveTimer(valTimerNum, 6, valArray[0]);
      }
      /* "м>таймеп>сигнал:" */
      если (я == encLEFT) {
        flgDisplayUpdate = 1;
        valArray[0] -= 5;
        если (valArray[0] > 100)
          valArray[0] = 5;
        если (valArray[0] <5)
          valArray[0] = 5;
      }
      /* " 100% " */
      если (я == encRIGHT) {
        flgDisplayUpdate = 1;
        valArray[0] += 5;
        если (valArray[0] > 100)
          valArray[0] = 100;
      }
      перерыв;
  }
  если (j < 255) {
    ЖК.Очистить();
    flgDisplayUpdate = 1;
    valMode = j;
  }
  // Если требуется сменить режим, почистить экран, установить флаг Необходимо обновить экран flgDisplayUpdate и установить новый режим valMode
  если (я == encPRESS) {
    в то время как (digitalRead (pinEncBTN)) {
      задержка(50);
    }
  } // Если была нажата кнопка энкодера, то ждём пока она не будет отпущена (с задержками на 50мс для подавления дребезга)
}
// ОБНОВЛЕНИЕ ИНФОРМАЦИИ НА ДИСПЛЕЕ //
недействительный funcDisplayUpdate() {
  если (flgDisplayUpdate) {
    флгдисплейупдате = 0; // Обновление дисплея происходит только если был установлен флаг flgDisplayUpdate
    switch (valMode) { // Далее действует в зависимости от значения переменной valMode (которая хранит № текущего режима меню)
      случай 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-« П/Ч» и выводим информацию для данного режима на индикаторе...
        /* "00:00:00" */
        lcd.setCursor(0, 0);
        lcd.print(time.gettime("Ч:и:с")); // Выводим верхний текст
        /* "00.00.0000г. ПН" */
        lcd.setCursor(0, 1);
        lcd.print(time.gettime("dmY5."));
        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 ? "C6" : ("BC")))))));
        lcd.setCursor(12, 0);
        ЖК.принт(" ");
        valArray[4] = 15;
        если (valArray[3]) {
          lcd.setCursor(valArray[4], 0);
          lcd.print("4");
          valArray[4]--;
        }
        если (valArray[2]) {
          lcd.setCursor(valArray[4], 0);
          lcd.print("3");
          valArray[4]--;
        }
        если (valArray[1]) {
          lcd.setCursor(valArray[4], 0);
          lcd.print("2");
          valArray[4]--;
        }
        если (valArray[0]) {
          lcd.setCursor(valArray[4], 0);
          lcd.print("1");
          valArray[4]--;
        }
        перерыв;
      Дело 1:
        funcSetChars(11, 15, 25, 9, 20);
        // Если установлен режим 1, загружаем символы в липлея CGRAM в следующем порядке: 1м 2н 3ю 4Й 5Ы и выводим информацию для данного режима на дисплее ...
        /* "меню: " */
        lcd.setCursor(0, 0);
        lcd.print(F("1e23:")); // Выводим верхний текст
        /* "< ТАЙМЕРЫ >" */
        lcd.setCursor(0, 1);
        lcd.print(F("<TA4MEP5 >"));
        перерыв;
      случай 2:
        funcSetChars(11, 15, 25, 18, 20); // Если установлен режим 2, то загружаем символы в лисплея CGRAM в следующем порядке: 1м 2н 3ю 4Ч 5Ы и выводим информацию для данного режима на индикаторе ...
        /* "меню: " */
        lcd.setCursor(0, 0);
        lcd.print(F("1e23:")); // Выводим верхний текст
        /* "< ЧАСЫ >" */ lcd.setCursor(0, 1);
        lcd.print(F("<4AC5 >")); //
        перерыв;
      случай 3:
        funcSetChars(11, 15, 25, 4, 20); // Если установлен режим 3, загружаем символы в липлея CGRAM в следующем порядке: 1м 2н 3ю 4Д 5Ы и выводим информацию для данного режима на индикаторе ...
        /* "меню: " */
        lcd.setCursor(0, 0);
        lcd.print(F("1e23:")); // Выводим верхний текст
        /* "< ВЫХОД >" */
        lcd.setCursor(0, 1);
        lcd.print(F("< B5XO4 >"));
        перерыв;
      случай 11:
        funcSetChars(15, 25, 17, 9, 21); // Если установлен режим 11, загружаем символы в лисплей CGRAM в следующем порядке: 1н 2ю 3т 4й 5ы и выводим информацию для данного режима на дисплее ...
        /* "меню>таймеры: " */
        lcd.setCursor(0, 0);
        lcd.print(F("me12>3a4mep5:")); // Выводим верхний текст
        /* "< 00:00-00:00-1>" */
        lcd.setCursor(0, 1);
        lcd.print(F("<00:00-00:00-0>"));
        lcd.setCursor(2, 1);
        lcd.print(funcReadTimer(valTimerNum, 1) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 1));
        lcd.setCursor(5, 1);
        lcd.print(funcReadTimer(valTimerNum, 2) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 2));
        lcd.setCursor(8, 1);
        lcd.print(funcReadTimer(valTimerNum, 3) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 3));
        lcd.setCursor(11, 1);
        lcd.print(funcReadTimer(valTimerNum, 4) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 4));
        lcd.setCursor(14, 1);
        lcd.print(funcReadTimer(valTimerNum, 5));
        перерыв;
      случай 12:
        funcSetChars(15, 25, 17, 9, 21, 8, 20); // Если установлен режим 12, загружаем символы в лисплей CGRAM в следующем порядке: 1н 2ю 3т 4й 5ы 6Й 7Ы и выводим информацию для данного режима на дисплее ...
        /* "меню>таймеры: " */
        lcd.setCursor(0, 0);
        lcd.print(F("me12>3a4mep5:")); // Выводим верхний текст
        /* "< НОВЫЙ ТАЙМЕР >" */
        lcd.setCursor(0, 1);
        lcd.print(F("<HOB76 TA6MEP >"));
        перерыв;
      случай 13:
        funcSetChars(15, 25, 17, 9, 21, 22); // Если установлен режим 13, загружаем символы в лисплей CGRAM в следующем порядке: 1н 2ю 3т 4й 5ы 6Ь и выводим информацию для данного режима на дисплее ...
        /* "меню>таймеры: " */
        lcd.setCursor(0, 0);
        lcd.print(F("me12>3a4mep5:")); // Выводим верхний текст
        /* "< CTEPETь BCE >" */
        lcd.setCursor(0, 1);
        lcd.print(F("< CTEPET6 BCE >"));
        перерыв;
      случай 14:
        funcSetChars(15, 25, 17, 9, 21, 4, 20); // Если установлен режим 14, загружаем символы в лисплей CGRAM в следующем порядке: 1н 2ю 3т 4й 5ы 6Д 7Ы и выводим информацию для данного режима на дисплее ...
        /* "меню>таймеры: " */
        lcd.setCursor(0, 0);
        lcd.print(F("me12>3a4mep5:")); // Выводим верхний текст
        /* "< ВЫХОД >" */
        lcd.setCursor(0, 1);
        lcd.print(F("< B7XO6 >"));
        перерыв;
      случай 21:
        funcSetChars(11, 15, 25, 19, 21, 26); // Если установлен режим 21, то загружаем символы в лисплей CGRAM в следующем порядке: 1м 2н 3ю 4ч 5ы 6Я и выводим информацию для данного режима на дисплее ...
        /* "меню>часы: " */
        lcd.setCursor(0, 0);
        lcd.print(F("1e23>4ac5:")); // Выводим верхний текст
        /* "< ВРЕМЯ >" */
        lcd.setCursor(0, 1);
        lcd.print(F("<BPEM6 >"));
        перерыв;
      случай 22:
        funcSetChars(11, 15, 25, 19, 21, 4); // Если установлен режим 22, то загружаем символы в лисплей CGRAM в следующем порядке: 1м 2н 3ю 4ч 5ы 6Д и выводим информацию для данного режима на дисплее ...
        /* "меню>часы: " */
        lcd.setCursor(0, 0);
        lcd.print(F("1e23>4ac5:")); // Выводим верхний текст
        /* "< ДАТА >" */
        lcd.setCursor(0, 1);
        lcd.print(F("< 6ATA >"));
        перерыв;
      случай 23:
        funcSetChars(11, 15, 25, 19, 21, 4, 20); // Если установлен режим 23, загружаем символы в лисплей CGRAM в следующем порядке: 1м 2н 3ю 4ч 5ы 6Д 7Ы и выводим информацию для данного режима на дисплее ...
        /* "меню>часы: " */
        lcd.setCursor(0, 0);
        lcd.print(F("1e23>4ac5:")); // Выводим верхний текст
        /* "< ВЫХОД >" */
        lcd.setCursor(0, 1);
        lcd.print(F("< B7XO6 >"));
        перерыв;
      случай 31:
        funcSetChars(11, 15, 25, 19, 21, 1, 27); // Если установлен режим 31, загружаем символы в лисплей CGRAM в следующем порядке: 1м 2н 3ю 4ч 5ы 6в 7я и выводим информацию для данного режима на дисплее ...
        /* "меню>часы>впемя:" */
        lcd.setCursor(0, 0);
        lcd.print(F("1e23>4ac5>6pe17:")); // Выводим верхний текст
        /* " 00:00:00 " */
        lcd.setCursor(4, 1);
        valChar[0] = valArray[0] / 10 + 48;
        valChar[1] = valArray[0] % 10 + 48;
        валЧар[2] = 0;
        lcd.print((millis() % 1000 < 500 && valSubMode == 0) ? " " : valChar);
        жк.принт(":");
        lcd.setCursor(7, 1);
        valChar[0] = valArray[1] / 10 + 48;
        valChar[1] = valArray[1] % 10 + 48;
        валЧар[2] = 0;
        lcd.print((millis() % 1000 < 500 && valSubMode == 1) ? " " : valChar);
        жк.принт(":");
        lcd.setCursor(10, 1);
        valChar[0] = valArray[2] / 10 + 48;
        valChar[1] = valArray[2] % 10 + 48;
        валЧар[2] = 0;
        lcd.print((millis() % 1000 < 500 && valSubMode == 2) ? " " : valChar);
        перерыв;
      случай 32:
        funcSetChars(24, 18, 20, 4, 14, 0); // Если установлен режим 32, загружаем символы в лисплей CGRAM в следующем порядке: 1Ю 2Ч 3Ы 4Д 5П 6Б и выводим информацию для данного режима на дисплее ...
        /* "MEHЮ>ЧАСЫ>ДАННЫЕ: " */ lcd.setCursor(0, 0);
        lcd.print(F("MEH1>2AC3>4ATA:")); // Выводим верхний текст
        /* "00.00.0000 пт" */
        lcd.setCursor(1, 1);
        valChar[0] = valArray[0] / 10 + 48;
        valChar[1] = valArray[0] % 10 + 48;
        валЧар[2] = 0;
        lcd.print((millis() % 1000 < 500 && valSubMode == 0) ? " " : valChar);
        жк.печать(".");
        lcd.setCursor(4, 1);
        valChar[0] = valArray[1] / 10 + 48;
        valChar[1] = valArray[1] % 10 + 48;
        валЧар[2] = 0;
        lcd.print((millis() % 1000 < 500 && valSubMode == 1) ? " " : valChar);
        жк.печать(".");
        lcd.setCursor(7, 1);
        valChar[0] = '2';
        valChar[1] = '0';
        valChar[2] = valArray[2] / 10 + 48;
        valChar[3] = valArray[2] % 10 + 48;
        валЧар[4] = 0;
        lcd.print((millis() % 1000 < 500 && valSubMode == 2) ? " " : valChar);
        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 ? "C6" : ("BC"))))))));
        валЧар[2] = 0;
        lcd.print((millis() % 1000 < 500 && valSubMode == 3) ? " " : valChar);
        перерыв;
      случай 41:
        funcSetChars(20, 8, 4); // Если установлен режим 41, загружаем символы в лисплей CGRAM в следующем порядке: 1Ы 2Й 3D и выводим информацию для данного режима на дисплее ...
        /* " ХОБЫЙ ТАЙМЕП " */
        lcd.setCursor(2, 0);
        lcd.print(F("HOB12 TA2MEP")); // Выводим верхний текст
        /* " CO3ДАH " */
        lcd.setCursor(5, 1);
        lcd.print(F("CO33AH"));
        перерыв;
      случай 42:
        funcSetChars(20, 8, 4, 16, 12); // Если установлен режим 42, загружаем символы в липлея CGRAM в следующем порядке: 1Ы 2Й 3Д 4У 5Л и выводим информацию для данного режима на индикаторе ...
        /* "BCE ТАЙМЕПЫ" */
        lcd.setCursor(2, 0);
        lcd.print(F("BCE TA2MEP1")); // Выводим верхний текст
        /* " УДАЛЕХЫ " */
        lcd.setCursor(4, 1);
        lcd.print(F("43A5EH1"));
        перерыв;
      случай 43:
        funcSetChars(8, 16, 4, 12); // Если установлен режим 43, загружаем символы в лисплей CGRAM в следующем порядке: 1Й 2У 3Д 4Л и выводим информацию для данного режима на дисплее ...
        /* " ТАЙМЕП " */
        lcd.setCursor(5, 0);
        lcd.print(F("TA1MEP")); // Выводим верхний текст
        /* " УДАЛЕХ " */
        lcd.setCursor(5, 1);
        lcd.print(F("23A4EH"));
        перерыв;
      случай 51:
        funcSetChars(17, 9, 21, 23, 26, 6, 12); // Если установлен режим 51, загружаем символы в лисплей CGRAM в следующем порядке: 1т 2й 3ы 4. 5Я 6И 7Л и выводим информацию для данного режима на дисплее ...
        /* "m>таймеры>00:00." */
        lcd.setCursor(0, 0);
        lcd.print(F("m>1a2mep3>")); // Выводим верхний текст
        /* "<BPEM* * КАХА*>" */
        lcd.setCursor(10, 0);
        lcd.print(funcReadTimer(valTimerNum, 1) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 1));
        жк.принт(":");
        lcd.setCursor(13, 0);
        lcd.print(funcReadTimer(valTimerNum, 2) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 2));
        lcd.print("4");
        lcd.setCursor(0, 1);
        lcd.print(F("<BPEM5 6 KAHA7>"));
        перерыв;
      случай 52:
        funcSetChars(17, 9, 21, 23, 14, 20); // Если установлен режим 52, загружаем символы в лисплей CGRAM в следующем порядке: 1т 2й 3ы 4.5П 6Ы и выводим информацию для данного режима на дисплее ...
        /* "m>таймеры>00:00." */
        lcd.setCursor(0, 0);
        lcd.print(F("m>1a2mep3>")); // Выводим верхний текст
        /* "< ПОБТОПЫ >" */
        lcd.setCursor(10, 0);
        lcd.print(funcReadTimer(valTimerNum, 1) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 1));
        жк.принт(":");
        lcd.setCursor(13, 0);
        lcd.print(funcReadTimer(valTimerNum, 2) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 2));
        lcd.print("4");
        lcd.setCursor(0, 1);
        lcd.print(F("<5OBTOP6 >"));
        перерыв;
      случай 53:
        funcSetChars(17, 9, 21, 23, 16, 6, 2); // Если установлен режим 53, загружаем символы в лисплей CGRAM в следующем порядке: 1т 2й 3ы 4. 5У 6И 7Г и выводим информацию для данного режима на дисплее ...
        /* "m>таймеры>00:00." */
        lcd.setCursor(0, 0);
        lcd.print(F("m>1a2mep3>")); // Выводим верхний текст
        /* "< УPOBEHb CIGN.>" */
        lcd.setCursor(10, 0);
        lcd.print(funcReadTimer(valTimerNum, 1) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 1));
        жк.принт(":");
        lcd.setCursor(13, 0);
        lcd.print(funcReadTimer(valTimerNum, 2) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 2));
        lcd.print("4");
        lcd.setCursor(0, 1);
        lcd.print(F("<5POBEHb C67H.>"));
        перерыв;
      случай 54:
        funcSetChars(17, 9, 21, 23, 22, 8); // Если установлен режим 54, загружаем символы в лисплей CGRAM в следующем порядке: 1т 2й 3ы 4. 5Ь 6Й и выводим информацию для данного режима на дисплее ...
        /* "m>таймеры>00:00." */
        lcd.setCursor(0, 0);
        lcd.print(F("m>1a2mep3>")); // Выводим верхний текст
        /* "<CTEPETЬ ТАЙМЕП>" */
        lcd.setCursor(10, 0);
        lcd.print(funcReadTimer(valTimerNum, 1) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 1));
        жк.принт(":");
        lcd.setCursor(13, 0);
        lcd.print(funcReadTimer(valTimerNum, 2) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 2));
        lcd.print("4");
        lcd.setCursor(0, 1);
        lcd.print(F("<CTEPET5 TA6MEP>"));
        перерыв;
      случай 55:
        funcSetChars(17, 9, 21, 23, 20, 4); // Если установлен режим 55, загружаем символы в лисплей CGRAM в следующем порядке: 1т 2й 3ы 4.5Ы 6Д и выводим информацию для данного режима на дисплее ...
        /* "m>таймеры>00:00." */
        lcd.setCursor(0, 0);
        lcd.print(F("m>1a2mep3>")); // Выводим верхний текст
        /* "< ВЫХОД >" */
        lcd.setCursor(10, 0);
        lcd.print(funcReadTimer(valTimerNum, 1) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 1));
        жк.принт(":");
        lcd.setCursor(13, 0);
        lcd.print(funcReadTimer(valTimerNum, 2) < 10? "0": "");
        lcd.print(funcReadTimer(valTimerNum, 2));
        lcd.print("4");
        lcd.setCursor(0, 1);
        lcd.print(F("< B5XO6 >"));
        перерыв;
      случай 61:
        funcSetChars(11, 17, 9, 21, 1, 27, 10); // Если установлен режим 61, загружаем символы в лисплей CGRAM в следующем порядке: 1м 2т 3й 4ы 5в 6я 7к и выводим информацию для данного режима на дисплее ...
        /* "м>таймер>впемя: " */
        lcd.setCursor(0, 0);
        lcd.print(F("1>2a31ep>5pe16:")); // Выводим верхний текст
        /* " 00:00-00:00 к0 " */
        lcd.setCursor(1, 1);
        valChar[0] = valArray[0] / 10 + 48;
        valChar[1] = valArray[0] % 10 + 48;
        валЧар[2] = 0;
        lcd.print((millis() % 1000 < 500 && valSubMode == 0) ? " " : valChar);
        жк.принт(":");
        lcd.setCursor(4, 1);
        valChar[0] = valArray[1] / 10 + 48;
        valChar[1] = valArray[1] % 10 + 48;
        валЧар[2] = 0;
        lcd.print((millis() % 1000 < 500 && valSubMode == 1) ? " " : valChar);
        жк.принт("-");
        lcd.setCursor(7, 1);
        valChar[0] = valArray[2] / 10 + 48;
        valChar[1] = valArray[2] % 10 + 48;
        валЧар[2] = 0;
        lcd.print((millis() % 1000 < 500 && valSubMode == 2) ? " " : valChar);
        жк.принт(":");
        lcd.setCursor(10, 1);
        valChar[0] = valArray[3] / 10 + 48;
        valChar[1] = valArray[3] % 10 + 48;
        валЧар[2] = 0;
        lcd.print((millis() % 1000 < 500 && valSubMode == 3) ? " " : valChar);
        lcd.setCursor(13, 1);
        валЧар[0] = 7;
        valChar[1] = valArray[4] + 48;
        валЧар[2] = 0;
        lcd.print((millis() % 1000 < 500 && valSubMode == 4) ? " " : valChar);
        перерыв;
      случай 62:
        funcSetChars(28, 29, 30, 31, 32, 33, 34); // Если установлен режим 62, загружаем символы в лисплей CGRAM в следующем порядке: 1-ПН 2-ВТ 3-СР 4-ЧТ 5-ПТ 6-ВТ 7-СР и выводим информацию для данного режима на дисплее ...
        /* " * * * * * * * " */
        lcd.setCursor(1, 0);
        lcd.print("1 2 3 4 5 6 7"); // Выводим верхний текст
        /* " ^ ^ ^ ^ ^ ^ ^ " */
        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] ? "^" : " ");
        lcd.setCursor(valSubMode * 2 + 1, 1);
        ЖК.мигать();
        перерыв;
      случай 63:
        funcSetChars(11, 17, 9, 7, 3, 15, 13); // Если установлен режим 63, загружаем символы в лисплей CGRAM в следующем порядке: 1м 2т 3й 4и 5г 6н 7л и выводим информацию для данного режима на дисплее ...
        /* "м>таймеп>сигнал:" */
        lcd.setCursor(0, 0);
        lcd.print(F("1>2a31ep>c456a7:")); // Выводим верхний текст
        /* " 100% " */
        lcd.setCursor(6, 1);
        valChar[0] = valArray[0] / 100 + 48;
        valChar[1] = valArray[0] % 100/10 + 48;
        valChar[2] = valArray[0] % 10 + 48;
        валЧар[3] = 0;
        lcd.print(valChar);
        lcd.print("%");
        перерыв;
    }
  }
}
// ВЫВОД СИГНАЛОВ ШИМ //
недействительный funcSetPWM (недействительный) {
  статический uint8_t setChanel[4] = { 0, 0, 0, 0 }; // Определяем массив, каждый элемент которого соответствует сигналу от 0 до 100%, установленному на соответствующем канале
  if (valMode == 0) { // Если текущий режим регулируется 0 "Вне меню", то ...
    uint8_t getChanel[4] = { 0, 0, 0, 0 }; // Определяем массив, каждый элемент которого соответствует сигналу от 0 до 100%, прочитанному из активированного таймера для соответствующего канала.
    uint32_t timeRTC = 0; // Определяем переменную для хранения текущего времени в виде секунд прошедших с полуночи текущего дня (от 00:00:00)
    uint32_t timeTimerStart = 0; // Определяем переменную для хранения времени запуска таймера (для каждого таймера в теле цикле) в виде секунд прошедших с полуночей текущего дня (от 00:00:00)
    uint32_t timeTimerStop = 0; // Определяем переменную для хранения времени сброса таймера (для каждого таймера в теле цикле) в виде секунд прошедших с полуночей текущего дня (от 00:00:00)
    uint8_t timeWeekday = 0; // Определяем переменную для хранения текущего дня недели в формате: 1-ПН, 2-ВТ, 3-СР, 4-ЧТ, 5-ПТ, 6-СБ, 7-ВС
    valArray[0] = valArray[1] = valArray[2] = valArray[3] = 0; // В первых 4 элементах массива valArray будет указано 1, если на соответствующем канале будет установлен сигнал
    timeRTC = (uint32_t)время.Часы * 3600 + время.минуты * 60 + время.секунды; // Получаем количество секунд прошедшего с полуночи текущего дня (от 00:00:00). Значения запроса объекта времени являются актуальными, т.к. в данном режиме (valMode) в функции funcDisplayUpdate было обращение к функции time.gettime
    timeWeekday = время.weekday;
    если (времяWeekday == 0)
      времяБудний день = 7; // Получаем текущий день недели в формате: 1-ПН, 2-ВТ, 3-СР, 4-ЧТ, 5-ПТ, 6-СБ, 7-ВС
    for (uint8_t i = 0; i < maxTimers; i++) { // Проходим по всем таймерам, ...
      if (funcReadTimer(i)) { // Если установлен очередной таймер, то ...
        if (bitRead(funcReadTimer(i, 7), 7 - timeWeekday)) { // Если день недели повтора таймера совпал с текущим днём недели, то ...
          timeTimerStart = (uint32_t)funcReadTimer(i, 1) * 3600 + funcReadTimer(i, 2) * 60; // Читаем время запуска очередного таймера в виде количества секунд, прошедших от полуночи текущего дня (от 00:00:00)
          timeTimerStop = (uint32_t)funcReadTimer(i, 3) * 3600 + funcReadTimer(i, 4) * 60; // Читаем время сброса очередного таймера в виде количества секунд, прошедших от полуночи текущего дня (от 00:00:00)
          if (timeTimerStart <= timeRTC && timeRTC < timeTimerStop) { // Если текущее время находится между запуском таймера и сбросом таймера, то ...
            getChanel[funcReadTimer(i, 5) - 1] = funcReadTimer(i, 6); // Читаем из таймера уровень сигнала, который требуется установить на требуемом канале
            valArray[funcReadTimer(i, 5) - 1] = 1; // Сохраняем тот факт, что установлен сигнал на требуемом канале
          }
        }
      }
    }
    if (setChanel[0] != getChanel[0]) {
      setChanel[0] = getChanel[0];
      аналогWrite(pinChanel_1, карта(getChanel[0], 0, 100, 0, 255));
    } // выводим ШИМ на 1 канал
    if (setChanel[1] != getChanel[1]) {
      setChanel[1] = getChanel[1];
      аналогWrite(pinChanel_2, карта(getChanel[1], 0, 100, 0, 255));
    } // выводим ШИМ на 2 канал
    if (setChanel[2] != getChanel[2]) {
      setChanel[2] = getChanel[2];
      аналогWrite(pinChanel_3, карта(getChanel[2], 0, 100, 0, 255));
    } // выводим ШИМ на 3 канал
    if (setChanel[3] != getChanel[3]) {
      setChanel[3] = getChanel[3];
      AnalogWrite(pinChanel_4, map(getChanel[3], 0, 100, 0, 255));
    } // выводим ШИМ на 4 канал
  }
}
// ЗАПИСЬ ДО 7 СИМВОЛОВ В CGRAM ДИСПЛЕЯ
void funcSetChars(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4, uint8_t i5, uint8_t i6, uint8_t i7) {
  байт я[8];
  если (i1 < 255) {
    memcpy_P(i, rusMem[i1], 8);
    lcd.createChar(1, я);
  } // Записываем символ i (взятый из элемента № i1 массива rusMem, хранящегося в PROGMEM Arduino) в графах CGRAM под номером
  если (i2 < 255) {
    memcpy_P(i, rusMem[i2], 8);
    lcd.createChar(2, я);
  } // Записываем символ i (взятый из элемента № i2 массива rusMem, хранящегося в PROGMEM Arduino) в графах CGRAM под номером 2
  если (i3 < 255) {
    memcpy_P(i, rusMem[i3], 8);
    lcd.createChar(3, я);
  } // Записываем символ i (взятый из элемента № i3 массива rusMem, хранящегося в PROGMEM Arduino) в графах CGRAM под номером 3
  если (i4 < 255) {
    memcpy_P(i, rusMem[i4], 8);
    lcd.createChar(4, я);
  } // Записываем символ i (взятый из элемента № i4 массива rusMem, хранящегося в PROGMEM Arduino) в графах CGRAM под номером 4
  если (i5 < 255) {
    memcpy_P(i, rusMem[i5], 8);
    lcd.createChar(5, я);
  } // Записываем символ i (взятый из элемента № i5 массива rusMem, хранящегося в PROGMEM Arduino) в графах CGRAM под номером 5
  если (i6 < 255) {
    memcpy_P(i, rusMem[i6], 8);
    lcd.createChar(6, я);
  } // Записываем символ i (взятый из элемента № i6 массива rusMem, хранящегося в PROGMEM Arduino) в графах CGRAM под номером 6
  если (i7 < 255) {
    memcpy_P(i, rusMem[i7], 8);
    lcd.createChar(7, я);
  } // Записываем символ i (взятый из элемента № i7 массива rusMem, хранящегося в PROGMEM Arduino) в графах CGRAM под номером 7
}
// ЧТЕНИЕ ОДНОГО ИЗ ПАРАМЕТРОВ ТАЙМЕРА
uint8_t funcReadTimer(uint8_t i, uint8_t j) {
  вернуть EEPROM[i * 8 + j];
}
// ПОИСК НОВОГО ТАЙМЕРА
uint8_t funcFindTimer (недействительный) {
  uint8_t я = 0;
  в то время как (funcReadTimer (я)) {
    я++;
    if (i >= maxTimers) {
      перерыв;
    }
  }
  вернуть я;
}
// СОХРАНЕНИЕ ОДНОГО ИЗ ПАРАМЕТРОВ ТАЙМЕА
void funcSaveTimer(uint8_t i, uint8_t j, uint8_t k) {
  ЭСППЗУ[я * 8 + j] = к;
}
// ПРОВЕРКА ДАННЫХ ТАЙМЕРОВ В EEPROM
bool funcTestTimer (недействительный) {
  for (uint8_t я = 0; я <maxTimers; я++) {
    если (funcReadTimer(i, 0) > 1) {
      вернуть ложь;
    }
    если (funcReadTimer(i, 1) > 23) {
      вернуть ложь;
    }
    если (funcReadTimer(i, 2) > 59) {
      вернуть ложь;
    }
    если (funcReadTimer(i, 3) > 23) {
      вернуть ложь;
    }
    если (funcReadTimer(i, 4) > 59) {
      вернуть ложь;
    }
  }
  вернуть истину;
}

Неактивний

#6 2023-12-11 18:01:14

aleksmuraxa
Учасник
Зареєстрований: 2023-12-11
Повідомлень: 6

Re: ищу того кто поможет допилить скетч

этот код я скачал с какого-то сайта. правда он не компилировался. человек мне помог и сделал чтобы он работал.

Неактивний

#7 2023-12-11 18:35:40

г0cть
Гість

Re: ищу того кто поможет допилить скетч

aleksmuraxa пише:

он не компилировался. человек мне помог и сделал чтобы он работал.

Ну так выложите код который компилируется. Иначе за переделку кода в таком виде ИМХО цена будет с тремя 0.

#8 2023-12-11 19:52:43

aleksmuraxa
Учасник
Зареєстрований: 2023-12-11
Повідомлень: 6

Re: ищу того кто поможет допилить скетч

я уже его выложил

Неактивний

#9 2023-12-11 20:01:06

г0cть
Гість

Re: ищу того кто поможет допилить скетч

Ну, тогда 10000

#10 2023-12-11 23:01:14

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 205

Re: ищу того кто поможет допилить скетч

Є код, не спаплюжений автоперекладачем?

В цьому "коді", як можна зрозуміти, налаштування кожного таймера зберігається в EEPROM у такому форматі:

#байта   значення
   0     активний/неактивний
   1     година увімкнення
   2     хвилина увімкнення
   3     година вимкнення
   4     хвилина вимкнення
   5     номер канала
   6     рівень сигнала
   7     бітова маска днів тижня

Тобто час задається дискретно по хвилинах.
Щоб зробити по секундах, можна доповнити структуру ще двома полями: секунда увімкнення і секунда вимкнення. Тоді в обчисленні часу замість

timeTimerStart = (uint32_t)funcReadTimer(i, 1) * 3600 + funcReadTimer(i, 2) * 60;
timeTimerStop = (uint32_t)funcReadTimer(i, 3) * 3600 + funcReadTimer(i, 4) * 60; 

буде щось типу

timeTimerStart = (uint32_t)funcReadTimer(i, 1) * 3600 + funcReadTimer(i, 2) * 60 + funcReadTimer(i, 8);
timeTimerStop = (uint32_t)funcReadTimer(i, 3) * 3600 + funcReadTimer(i, 4) * 60 + funcReadTimer(i, 9);

Тоді структура займатиме 10 байт замість 8-ми, тому потрібно змінити індексування EEPROM:

uint8_t funcReadTimer(uint8_t i, uint8_t j) {
  return EEPROM[i * 10 + j];
}
...
void funcSaveTimer(uint8_t i, uint8_t j, uint8_t k) {
  EEPROM[i * 10 + j] = k;
}

і решту коду, де очікується 8-байтова структура. Відповідно зміниться і кількість доступних таймерів з "кількість байт EEPROM/8" на "кількість байт EEPROM/10".
Також знадобиться додати установку секунд в UI.

Якщо буде достатньо дискретності в 2 секунди (тобто тільки 0, 2, 4, .. 58 секунд), то можна упакувати поле часу в ті ж два байта і обійтись без зміни розміру структури: 5 біт на години, 6 біт на хвилини і 5 біт на секунди. Або зберігати час просто як кількість 2-секундних інтервалів від початку доби.

UPD: ще, щоб не змінювати розмір структури, але отримати дискретність в 1 секунду, можна використати біти з нульового байта структури і упакувати додаткові біти секунд у нього.

Остання редакція dimich (2023-12-11 23:11:09)

Неактивний

#11 2023-12-12 11:29:48

aleksmuraxa
Учасник
Зареєстрований: 2023-12-11
Повідомлень: 6

Re: ищу того кто поможет допилить скетч

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

Неактивний

#12 2023-12-12 13:48:44

г0cть
Гість

Re: ищу того кто поможет допилить скетч

aleksmuraxa пише:

потрібно шукати інше рішення

Вполне возможно. В сети можно найти кучу различных таймеров. Все зависит от ваших потребностей. Или вам нужен именно суточный многоканальный?

#13 2023-12-12 18:24:57

aleksmuraxa
Учасник
Зареєстрований: 2023-12-11
Повідомлень: 6

Re: ищу того кто поможет допилить скетч

Тему закрываю. решение найдено. Всем спасибо за дискуссию и советы!

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму