FLProg + Nextion HMI. Урок 2

в 2:31, , рубрики: arduino, diy или сделай сам, flprog, nextion hmi, Блог компании FLProg, Железо, умный дом

FLProg + Nextion HMI. Урок 2 - 1

В прошлом уроке я рассказал о панели Nextion HMI и о создании проектов для этой панели в редакторе Nextion Editor.
В этом уроке я расскажу, как с помощью программы FLProg с платы Arduino управлять этой панелью. Для примера соберём простейшую погодную станцию, которая будет считывать данные с датчика температуры и влажности DHT-22 и отображать их на панели. Так же будет рисоваться график изменения этих параметров. Яркость подсветки экрана панели будет изменяться с помощью переменного резистора.

Схема тестового стенда.
FLProg + Nextion HMI. Урок 2 - 2

Сначала необходимо загрузить проект в панель (файл проекта в архиве ссылка на который в конце статьи – Lesson2.hmi).
Данный проект состоит из трёх экранов.
Первый экран служит для отображения температуры (страница “page0” индекс — 0).

FLProg + Nextion HMI. Урок 2 - 3

В его состав входят следующие элементы:
1 – Картинка с изображением спиртового термометра.
2 – Элемент “Progress bar”. С его помощью имитируется работа термометра.

Настройки элемента.
FLProg + Nextion HMI. Урок 2 - 4

Я рекомендую те элементы, с которыми планируется через UART всегда делать глобальными (атрибут “vccope” значение “global”), и соответственно задавать им уникальные имена (атрибут “objname”) в пределах всего проекта. Это ускоряет работу контроллера Arduino, и уменьшает код для неё. Объясню почему.
При попытке записи атрибута локального элемента, необходимо сначала запросит у панели текущую страницу (это отдельный запрос который занимает не менее 20 мс.). Если страница та, к которой принадлежит элемент, то значение отправляется на панель, если не та, то значение предназначенное для отправки записывается в переменную (для которой то же нужно место в памяти). При переходе на страницу с элементом, необходимо сразу обновить его атрибуты последними актуальными значениями, поскольку при отрисовке страницы локальные переменные инициализируются значениями, заданными при создании проекта. И если на станице достаточно много элементов управляемых с контроллера, то при переходе на неё этот контроллер достаточно долго будет занят обновлением всех элементов.
Для глобального элемента всё намного проще. Записать значения атрибутов для него можно в любой момент времени, и при отрисовке страницы используются последние значения. Значит, отпадает необходимость в запросе номера страницы перед отправкой и необходимость переменой для хранения значения.
Но конечно всё зависит от проекта. Если проект для панели очень большой, и места для глобальных элементов не хватает, то можно как бы занять память у контроллера и сделать их локальными.
3. Текстовое поле для вывода температуры.

Параметры элемента.
FLProg + Nextion HMI. Урок 2 - 5

В качестве фона выбрано вырезанное изображение (атрибут “sta” значение “crop image”). А в качестве изображения, которое используется для вырезки, используется то же, которое используется для фона всей страницы (атрибут “picc” – индекс изображения из библиотеки изображений). Благодаря этому текс получается как бы с прозрачным фоном.
Как я уже писал в прошлом уроке, панель не умеет работать с дробными и отрицательными числами, а для температуры как раз возможно и то и другое. Поэтому для вывода значения температуры используется текстовое поле, в которое с контроллера будет сразу отправляться готовая строка.
4. Вырезанное изображение.

Параметры элемента.
FLProg + Nextion HMI. Урок 2 - 6

С помощью данного элемента будет показываться солнышко при превышении температуры выше заданного предела. Вообще – то можно было использовать обычную картинку, и изменять её видимость, но поскольку пример обучающий, я решил использовать именно этот элемент. Я сам достаточно долго понимал идеологию этого элемента, попытаюсь показать, как он работает. Для его работы я сделал две картинки, одну с солнышком, другую без солнышка.

FLProg + Nextion HMI. Урок 2 - 7

FLProg + Nextion HMI. Урок 2 - 8

Элемент отображает участок привязанной к нему картинки (атрибут “picc” – индекс картинки в библиотеке изображений). Левый верхний угол это участка находится в координатах вставки элемента (атрибуты “x” и “y”) и имеет ширину и высоту элемента (атрибуты “w” и “h”). В процессе работы программы контроллера при необходимости будет изменяться привязка элемента к картинке.

5. Кнопка.

Параметры элемента.
FLProg + Nextion HMI. Урок 2 - 9

При нажатии на кнопку происходит переход на следующую страницу. В качестве фона для кнопки использовал картинку. Для обоих состояний использовал оду и ту же картинку (атрибуты “pic” и “pic2” – индексы картинок в библиотеке изображений) поскольку нажатого состояния никогда не будет видно, при нажатии на кнопку сразу происходит переход на следующую страницу. Поскольку ничего в этой кнопке менять не будем, оставил её локальной и имя по умолчанию.

Код в событии “Touch Press Event”.
FLProg + Nextion HMI. Урок 2 - 10

Второй экран служит для отображения влажности (страница “page1” индекс — 1).
FLProg + Nextion HMI. Урок 2 - 11

Для фона страницы использовал картинку с подготовленным изображением шкалы гигрометра.
FLProg + Nextion HMI. Урок 2 - 12

Рассмотрим элементы, входящие в страницу.

1. Элемент “Gaude”, который будет симулировать работу гигрометра.

Параметры элемента.
FLProg + Nextion HMI. Урок 2 - 13

Поскольку управлять им будем из контроллера, то он сделан глобальным. В качестве фона выбрано вырезанное изображение (атрибут “sta”) и в качестве него выбранно фоновое изображение страницы (атрибут “picc”).

2. Числовое поле.

Параметры элемента.
FLProg + Nextion HMI. Урок 2 - 14

В данном поле будет отображаться значение влажности. Поскольку панель не поддерживает работы с дробными числами, будем выводить значение влажности без дробной части. В качестве фона выбрано вырезанное изображение (атрибут “sta” значение “crop image”). А в качестве изображения, которое используется для вырезки, используется то же, которое используется для фона всей страницы (атрибут “picc” – индекс изображения из библиотеки изображений). Для красоты отображения настроил выравнивание вправо (атрибут “xcen” значение — 2), а рядом поставил текстовое поле (3) со значением “%”. Настройки фона для него аналогичны настройкам числового поля.

Параметры текстового поля (3).
FLProg + Nextion HMI. Урок 2 - 15

4 и 5. Кнопки предыдущая страница и следующая страница. При нажатии кнопки 4 происходит переход на первую страницу, а при нажатии на кнопку 5 происходит переход на следующую. Настройки отображения кнопок аналогичны кнопке на первой странице.

Настройки кнопки 4(«Предыдущая страница»)
FLProg + Nextion HMI. Урок 2 - 16

Код в событии “Touch Press Event” для кнопки 4(«Предыдущая страница»).
FLProg + Nextion HMI. Урок 2 - 17

Настройки кнопки 5(«Следующая страница»)
FLProg + Nextion HMI. Урок 2 - 18

Код в событии “Touch Press Event” для кнопки 5(«Следующая страница»).
FLProg + Nextion HMI. Урок 2 - 19

Третья страница – График изменения температуры и влажности (“page2” индекс — 2).
FLProg + Nextion HMI. Урок 2 - 20

На данной странице будет, выводится график изменения температуры и влажности. Рассмотрим элементы, входящие в станицу.

1. Элемент Waveform.

Параметры элемента.
FLProg + Nextion HMI. Урок 2 - 21

На прошлом уроке я уже писал, что данный элемент не умеет (надеюсь пока) становится глобальным, то есть значение атрибута переключить можно, но это ни к чему не приведёт. Так что я оставил его локальным (кто его знает, а вдруг всё-таки память глобальных переменных он всё-таки кушает). В данном элементе будет два канала отображения (атрибут “ch” значение — 2).

2 и 3 –просто текстовые поля, показывающие оси графиков.

4 –Кнопка назад. Аналогична такой – же кнопке на предыдущем экране, за исключением кода в обработчике события.

Код в событии “Touch Press Event” для кнопки 4(«Предыдущая страница»).
FLProg + Nextion HMI. Урок 2 - 22

С панелью разобрались, теперь займёмся контроллером. Я не буду рассказывать, как открывать программу FLProg, создавать проект и рисовать схему. Всё это я рассказывал в предыдущих уроках (урок 1, урок 2), и кроме того много информации об этом есть в учебном центре на сайте проекта. Поэтому я буду сразу показывать готовые схемы плат и рассказывать, что на них происходит.

Плата 1. Чтение данных с датчика.
FLProg + Nextion HMI. Урок 2 - 23

Для получения значений температуры и влажности с датчик DHT-22 используется блок В1 – “DHT11, DHT21, DHT22”(Библиотека элементов, папка “Датчики”).

Настройки блока (вызываются двойным кликом на нём).
FLProg + Nextion HMI. Урок 2 - 24

В настройках задаются пин, к которому подключён выход “Data” датчика, тип датчика, и наличие выходов температуры и влажности. Так же выбирается режим опроса датчика. Я настроил опрос датчика один раз в 5 секунд.

Поскольку контроллеры Arduino не очень хорошо работают с числами с плавающей запятой, да и работа с ними съедает много памяти, я сразу перевожу все значения в формат Integer. Для этого служат блоки В3 и В4 – «Преобразование Float в Integer» (библиотека элементов, папка «Конвертация типов»), которые обрезают дробную часть числа. Для того что бы ни потерять десятые доли градуса, значение температуры полученное с датчика сначала умножается на 10 с помощью блока В2 – “MUL(*)”(библиотека элементов, папка «Математика»).
Затем полученные значения в формате Integer заносятся в соответствующие переменные.

Плата 2. Вывод значения температуры на панель.
FLProg + Nextion HMI. Урок 2 - 25

В данном проекте я использую именованные соединения. Подробнее о них можно узнать в соответствующем уроке.
Для того что бы ограничить нагрузку на контроллер имеет смысл отправлять данные на панель только когда изменились данные. Поэтому сначала мы определяем, что данные изменились. Для этого используется блок В5 – “Детектор изменения числа” (библиотека элементов, папка – «Базовые блоки»). Данный блок контролирует число на своём входе «Value» и при его изменении формирует на выходе импульс длинной в один цикл выполнения программы.
После этого мы готовим строку для отправки в текстовое поле панели. Сначала делим значение температуры, помноженное на 10, на константу типа Float со значением 10.Таким образом, получаем значение температуры с дробной частью. Делаем это с помощью блока В6 – “DIV(/)”(библиотека элементов, папка «Математика»). Затем полученное значение в формате Float превращаем в строку с помощью блока В7 – «Преобразование строк» (библиотека элементов, папка «Конвертация типов»). Затем полученную строку соединяем со строковой константой « С» с помощью блока В8 – «Сложение строк» (библиотека элементов, папка «Строки»). Результирующую строку подаём на вход блока записи значения атрибута в панель Nextion HMI В9 – «Задать параметр» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «Элементы»).
Данный блок записывает значение в заданный атрибут.

Параметрирование блока.

По двойному клику на блоке открывается окно редактора блока.
FLProg + Nextion HMI. Урок 2 - 26

Если в проекте ещё не было создано ни одной панели, то необходимо создать панель. Если необходимая панель уже была создана, её можно выбрать из выпадающего списка нажав кнопку 3. Выбранную панель можно изменить с помощью кнопки «Изменить панель»(2). Для создания панели нажимаем кнопку «Добавить панель» (1). Откроется окно создания панели.
FLProg + Nextion HMI. Урок 2 - 27

В данном диалоге выбираем порт для подключения панели (в нашем уроке — SoftwareSerial). В случае выбора SoftwareSerial необходимо так же выбрать пины назначаемые как сигналы RX и TX порта UART (в нашем случае 2 и 3). Так же необходимо назначить имя панели. Оно должно быть уникально. В проекте может быть подключено несколько панелей, столько насколько хватит свободных портов UART. Ия каждой панели должно быть уникальным в пределах проекта. В этом же диалоге можно добавить страницы входящие в панель. Чем и займёмся. Нажимаем кнопку добавить страницу. Открывается окно создания страницы.
FLProg + Nextion HMI. Урок 2 - 28

В этом окне нам необходимо ввести имя страницы и её ID. Эту информацию можно узнать из проекта в редакторе Nextin Editor.
FLProg + Nextion HMI. Урок 2 - 29

По умолчанию стартовой (открываемой при старте контроллера) страницей будет страница с ID равным 0, но можно в свойствах любой страницы поставить галочку «Стартовая страница» и она станет стартовой.
В данном окне можно добавить интересующие нас элементы, находящиеся на этой странице. Нажимаем кнопку «Добавить элемент».
Открывается окно создания элемента.
FLProg + Nextion HMI. Урок 2 - 30

Здесь нам надо выбрать тип и вид элемента, ввести его имя, индекс, и если элемент глобальный – установить соответствующую галочку. Все эти данные можно подсмотреть в проекте в редакторе Nextin Editor.
FLProg + Nextion HMI. Урок 2 - 31

После заполнения всех данных нажимаем «Готово», а затем в окне создания странице таким же образом добавляем все интересующие нас элементы на этой странице.
FLProg + Nextion HMI. Урок 2 - 32

После создания всех элементов на странице, так же нажимаем кнопку «Готово» в окне создания странице и в окне создания панели по тому же сценарию создаём остальные страницы.
FLProg + Nextion HMI. Урок 2 - 33

FLProg + Nextion HMI. Урок 2 - 34

FLProg + Nextion HMI. Урок 2 - 35

Заканчиваем создание панели уже привычной кнопкой «Готово».
В редакторе блока выбираем страницу “page0” элемент «Текст» с именем “tnt” и его атрибут «Текст (txt)». В качестве значения выбираем вход.
FLProg + Nextion HMI. Урок 2 - 36

Блок настроен.
Рассматриваем схему дальше.
Опытным путём было определенно, что значению -40 градусов нарисованного градусника соответствует значение 10 в элементе «Progress bar» расположенного на нём, а значению 50 градусов на термометре – значению 91 прогресс бара. В соответствии с этим масштабируем значение переменой «Температура х10» с помощью блока В10 – “Scale” (Библиотека элементов, папка «Масштабирование») не забывая о том, что у нас значение температуры умножено на 10. Параметры этого блока.
FLProg + Nextion HMI. Урок 2 - 37

Отмасштабированное значение температуры отправляется на панель с помощью блока В11 – «Задать параметр» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «Элементы»). Настройки этого блока.
FLProg + Nextion HMI. Урок 2 - 38

Следующий блок В12 — «Comparator» (библиотека элементов, папка «Сравнение») определяет превышение текущей температурой уставки заданной значением по умолчанию переменной «Уставка — Жарко». Она составляет 290 (не забываем, что у нас везде проходит температура, умноженная на 10).
FLProg + Nextion HMI. Урок 2 - 39

Блок В12 настроен, выдавать на своём выходе логическую единицу при превышении значением на входе “I1” значения на входе “I2”.
FLProg + Nextion HMI. Урок 2 - 40

Блоки B13, B14 и В15 образовывают схемы детектирования изменения дискретного сигнала. Блоки В13 и В14 – Rtrig (библиотека элементов, папка «Триггеры») при появлении переднего фронта дискретного сигнала выдают на своём выходе импульс длительностью 1 цикл выполнения программы. Блок В14 за счёт инверсии на своём входе детектирует задний фронт сигнала «Превышение порога». Блок В15 –OR (библиотека элементов, папка «Базовые элементы») при наличии логической единицы на любом из входов выдаёт на свой выход логическую единицу. Таким образом, формируется сигнал «Отправка данных при превышении порога». По переднему фронту этого сигнала происходит отправка команды на изменение цвета шрифта текстового поля отображающего текущую температуру. Отправка происходит с помощью блока В17– «Задать параметр» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «Элементы»). Настройки этого блока.
FLProg + Nextion HMI. Урок 2 - 41

Значение, передаваемое в команде, выбирается с помощью блока B16 – “Switch”(библиотека элементов, папка «Переключатель»). Этот блок при низком логическом уровне на своём входе передает на выход значение с входа «0» а при высоком, с входа «1». Значение цветов подаваемые на входы переключателя задаются с помощью блоков В44 и В45 – «Цветовая константа Hight Color» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «Цвет»). Цвет выбирается в редакторе блока (двойной клик на блоке).
FLProg + Nextion HMI. Урок 2 - 42

Для выбора цвета необходимо нажать кнопку «Изменить». Откроется окно выбора цвета.
FLProg + Nextion HMI. Урок 2 - 43

В нём выставляя значение составляющих R(красный), G(зелёный) и B(синий) выбирается необходимый цвет.
Так же по переднему фронту сигнала «Отправка данных при превышении порога» происходит отправка команды на изменение привязки вырезанного изображения. Происходит это при помощи блока В19 – «Задать параметр» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «Элементы»).
Настройки этого блока.
FLProg + Nextion HMI. Урок 2 - 44

Выбор индекса изображения происходит при помощи блока В18 – “Switch”(библиотека элементов, папка «Переключатель»). Его работа была описана выше. Значение индекса необходимого изображения можно посмотреть в проекте Nextion Editor в библиотеке изображений.
FLProg + Nextion HMI. Урок 2 - 45
С передачей данных о температуре закончили. Перейдём к влажности.

Плата 3. Вывод влажности.
FLProg + Nextion HMI. Урок 2 - 46

Как и в случае температуры в первую очередь создаем сигнал «Отправка данных при изменении влажности». Делаем это при помощи блока В20 – “Детектор изменения числа” (библиотека элементов, папка – «Базовые блоки»). Работа этого блока была описана ранее. По этому сигналу происходит отправка значения в числовое поле отображающее влажность. Делается это с помощью блока В21– «Задать параметр» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «Элементы»).
Настройки этого блока.
FLProg + Nextion HMI. Урок 2 - 47

Опытным путём было определенно, что для значения 0% влажности нарисованной шкалы гигрометра в проекте панели значение элемента “Gayge” рисующего стрелку составляет 314 а для 100% влажности – 226. При этом стрелка переходит через значение 0. При переводе в линейные значения, получаем непрерывный диапазон от -46(0%) до 226(100%). В соответствии с этими данными настраиваем блок B22 –“Scale”.
Параметры блока.
FLProg + Nextion HMI. Урок 2 - 48

Поскольку значения для элемента “Gauge” не могут быть отрицательными, то для высчитывания угла отклонения стрелки при таких значениях, в случае отрицательной величины, к ней добавляется значение 360. Делаем это с помощью блока B23-“SUMM(+)” (библиотека элементов, папка «Математика»). Определяем что число меньше 0 с помощью блока В26 – “Comparator”(библиотека элементов, папка «Сравнение»). Его выход управляет переключателем В24 – “Switch” (библиотека элементов, папка «Переключатель») и выбранное значение отправляется на панель с помощью блока В25 – «Задать параметр» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «Элементы»).
Настройки этого блока.
FLProg + Nextion HMI. Урок 2 - 49

Следующая плата вывод графика изменения температуры и влажности.
FLProg + Nextion HMI. Урок 2 - 50

Ка я уже писал в начале урока, элемент Waveform не умеет быть глобальным элементом и перерисовывается пустым при каждом открытии страницы, на которой он находится. Придётся обходить это ограничение. Для начала определяем номер страницы, которая загружена на панели в текущий момент. Для этого используем блок В27 – «Получить Id текущей страницы» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «Страница»). В настройках этого блока нужно только выбрать панель, к которой будем обращаться с данным запросом.
FLProg + Nextion HMI. Урок 2 - 51

Номер страницы, полученный от этого блока, сравнивается с индексом нужной нам страницы (2) с помощью блока В28 – “Comparator” (библиотека элементов, папка «Сравнение»). Если открыта нужная страница, то в переменную «Отрыта страница графика» записывается логическая единица, если нет, то логический ноль.
С помощью блока В29 – “Generator” (библиотека элементов, папка «Таймеры»), вырабатывается сигнал на запись очередной точки на график. Данный блок генерирует импульсы с заданной длительностью импульса и паузы.
Настройки блока.
FLProg + Nextion HMI. Урок 2 - 52

Тип генератора выбран «Симметричный мультивибратор», значит, длительность импульса равна длительности паузы. При настройке длительности импульса равной 5 секунд, соответственно пауза будет то же 5 сек. Передний фронт импульса будет приходить каждые 10 секунд. Этот фронт выделяется блоком В30 – “Rtrig” (библиотека элементов, папка «Триггеры»), и записывается в переменную «Команда на запись очередной точки».
По переднему фронту сигнала «Открыта страница графика» который будет выделен при помощи блока В31 – “Rtrig” (библиотека элементов, папка «Триггеры») будет сформирован сигнал «Отправка истории графика». По этому сигналу в панель на график будет отправлено содержимое массивов, в которых хранятся значения точек отображающих график изменения. Для температуры это будет сделано с помощью блока В32 –«Отправка массива на график» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «График»). Блок настраивается с помощью редактора блока.
FLProg + Nextion HMI. Урок 2 - 53

Сначала надо создать массив, в котором будет, хранится история графика температуры. Для этого нажимаем кнопку «Создать». Откроется окно создания массива.
FLProg + Nextion HMI. Урок 2 - 54

В этом оке необходимо ввести имя массива, тип (используем Byte, поскольку элемент Waveform принимает максимальное значение 255). Размер берётся равным ширине графика (330).
После создания выбираем панель, страницу, элемент и канал на котором будет рисоваться график.
FLProg + Nextion HMI. Урок 2 - 55

Таким же образом настраиваем блок для отправки массива с данными о влажности на панель В33 –«Отправка массива на график» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «График»). В его настройках создаем другой массив для хранения этих данных.
FLProg + Nextion HMI. Урок 2 - 56

Теперь необходимо подготовить данные для графика температуры. Этот график своей осью будет иметь линию на высоте 160 точек от низа графика. Для того что бы на графике были виднее изменения температуры, разделим значение переменной «Температура х10» на 5 (то есть как бы умножив реальное значение температуры на 2) с помощью блока В35 и прибавим к нему смещение с помощью блока В36. Результат занесём в переменную «Температура со сдвигом для графика».
С помощью блока В37 –«Стек» (библиотека элементов, папка «массивы») по импульсу в переменной «Команда на запись очередной точки» значение из переменной «Температура со сдвигом для графика» записывается в массив по принципу стека (первый элемент массива удаляется, остальные сдвигаются на один, а в последний записывается значение). Блок параметрируется с помощью редактора блоков.
FLProg + Nextion HMI. Урок 2 - 57

В редакторе выбираем нужный массив, нажав на кнопку «Выбрать».
Таким же образом настраиваем блок В34 –«Стек» (библиотека элементов, папка «массивы») для записи в массив значения влажности, выбрав в соответствующий массив.
Если открыта страница графика, закончена передача массивов на график, и пришла команда на запись очередной точки, то значения новых точек отправляются на соответствующие графики. Это необходимо для того что бы во время показа страницы графики продолжали строится. Соблюдение этих условий контролируется с помощью блока В38 – “AND” (библиотека элементов, папка «Базовые элементы»). Этот блок выдает на своем выходе единицу, если на всех его входах находится логическая единица. На график очередное значение температуры со сдвигом отправляется с помощью блока В40 – «Добавить точку на график» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «График»).
Настройки блока.
FLProg + Nextion HMI. Урок 2 - 58

Так же настраивается блок отправки очередного значения влажности на график В39 – «Добавить точку на график» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «График»).
FLProg + Nextion HMI. Урок 2 - 59

Закончили с выводом графика.

Плата 5. Регулировка яркости подсветки.
FLProg + Nextion HMI. Урок 2 - 60

Значение заданной с помощью переменного резистора яркости подсветки считывается с помощью блока аналогового входа «Яркость». Поскольку значение яркости подсветки панели задается в пределах 0 до 100, масштабируем считанное значение из диапазона 0-1023 в диапазон 0-100 с помощью блока В41 – “Scale”.
Настройки блока.
FLProg + Nextion HMI. Урок 2 - 61

Затем определяем факт изменения этого значения с помощью блока В42 – «Детектор изменения числа». Этот блок имеет немного нестандартные настройки.
FLProg + Nextion HMI. Урок 2 - 62

Для того что бы не изменять яркость на каждое движение переменного резистора в блоке настроена зона нечувствительности со значением 5. То есть блок сработает при изменении значения на входе более чем на 5 в любую сторону. При срабатывании блока на панель будет отправлена команда установить новую яркость подсветки с помощью блока В43 – «Установить уровень подсветки» (библиотека элементов -> папка «Панель Nextion HMI» -> папка «Система»).
Настройки блока
FLProg + Nextion HMI. Урок 2 - 63

Работа над программой для контроллера закончена.

Для тех, кому интересно под споллером код получившегося скетча.

#include <SoftwareSerial.h>
#include "DHT.h"
DHT _dht1(4, DHT22);

SoftwareSerial Serial100(2, 3);

byte _FLPArray142003126[330] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
byte _FLPArray239384258[330] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int _SUETFLPATemp = 0;
byte _nextionSaveDataVAL_P0_E2;
long _nextionSaveDataPCO_P0_E3;
String _nextionSaveDataTXT_P0_E3;
byte _nextionSaveDataPICC_P0_E4;
int _nextionSaveDataVAL_P1_E2;
long _nextionSaveDataVAL_P1_E4;
String _nextionCommandTempString;
struct _nextionLissenStruct {
  char code;
  String result;
  long number;
};
_nextionLissenStruct _nextionTempLissen;
int nextionGetPageIdTempVar = 0;
int NextionPanel_47525121_PageIdOut = 0;
int _hasNumberChangeInTemp = 0;
int _gtv1;
int _gtv2;
int _gtv3 = 290;
bool _gtv4 = 0;
bool _gtv5 = 0;
int _gtv6;
unsigned long _dht1Tti = 0UL;
float _dht1t = 0.00;
float _dht1h = 0.00;
bool _changeNumber1_Out = 0;
int _changeNumber1_OLV;
bool _nextionSetAttr1_isNU = 0;
bool _nextionSetAttr1_oldState = 0;
bool _nextionSetAttr2_isNU = 0;
bool _nextionSetAttr2_oldState = 0;
bool _trgrt1 = 0;
bool _trgrt1I = 0;
bool _trgrt2 = 0;
bool _trgrt2I = 0;
bool _nextionSetAttr3_isNU = 0;
bool _nextionSetAttr3_oldState = 0;
long _swi1;
bool _nextionSetAttr4_isNU = 0;
bool _nextionSetAttr4_oldState = 0;
byte _swi2;
bool _nextionSetAttr5_isNU = 0;
bool _nextionSetAttr5_oldState = 0;
bool _changeNumber2_Out = 0;
int _changeNumber2_OLV;
int _swi3;
bool _nextionSetAttr6_isNU = 0;
bool _nextionSetAttr6_oldState = 0;
bool _trgrt3 = 0;
bool _trgrt3I = 0;
bool _gen1I = 0;
bool _gen1O = 0;
unsigned long _gen1P = 0UL;
bool _trgrt5 = 0;
bool _trgrt5I = 0;
bool _nextionAddPointToWave1_OldState = 0;
bool _nextionAddPointToWave2_OldState = 0;
bool _SFLPAS1;
bool _SFLPAS2;
bool _nextionSendArraytToWave1_OldState = 0;
bool _nextionSendArraytToWave2_OldState = 0;
bool _nextionSetLighting1_OldStae = 0;
bool _changeNumber3_Out = 0;
int _changeNumber3_OLV;
void setup()
{
  Serial100.begin(9600);
  _dht1.begin();
  nextionSendCommand("", 100);
  nextionAck(100);
  nextionSendCommand("page 0", 100);
  delay(100);
  nextionAck(100);
}
void loop()
{ nextionGetPageIdTempVar = nextionAskPageNamper(100);
  if ( ! (nextionGetPageIdTempVar < 0) ) {
    NextionPanel_47525121_PageIdOut = nextionGetPageIdTempVar;
  };
  if (_isTimer(_dht1Tti, 5000)) {
    _dht1Tti = millis();
    float tempDht4;
    tempDht4 = _dht1.readTemperature();
    if (!(isnan(tempDht4))) {
      _dht1t = tempDht4;
    }
    tempDht4 = _dht1.readHumidity();
    if (!(isnan(tempDht4))) {
      _dht1h = tempDht4;
    }
  }



  _gtv1 = (int((_dht1t) * (10)));
  _gtv2 = (int(_dht1h));
  if ((_gtv1) > (_gtv3)) {
    if (_trgrt1I) {
      _trgrt1 = 0;
    } else {
      _trgrt1 = 1;
      _trgrt1I = 1;
    }
  } else {
    _trgrt1 = 0;
    _trgrt1I = 0;
  };
  if ((_gtv1) > (_gtv3))
  {
    _swi1 = 63488;
  }
  else
  {
    _swi1 = 2016;
  }
  if (!((_gtv1) > (_gtv3))) {
    if (_trgrt2I) {
      _trgrt2 = 0;
    } else {
      _trgrt2 = 1;
      _trgrt2I = 1;
    }
  } else {
    _trgrt2 = 0;
    _trgrt2I = 0;
  };
  if ((_gtv1) > (_gtv3))
  {
    _swi2 = 2;
  }
  else
  {
    _swi2 = 0;
  }
  if (_changeNumber1_Out) {
    _changeNumber1_Out = 0;
  } else {
    _hasNumberChangeInTemp = _gtv1;
    if (_hasNumberChangeInTemp != _changeNumber1_OLV) {
      _changeNumber1_OLV = _hasNumberChangeInTemp;
      _changeNumber1_Out = 1;
    }
  }
  if (_changeNumber1_Out) {
    if (! _nextionSetAttr1_oldState ) {
      _nextionSetAttr1_oldState = 1;
      _nextionSetAttr1_isNU = 1;
      _nextionSaveDataTXT_P0_E3 =  ((( _floatToStringWitRaz((_gtv1) / (10.00), 1))) + (String(" C"))) ;
    }
  } else {
    _nextionSetAttr1_oldState = 0;
  } if (_nextionSetAttr1_isNU) {
    _nextionCommandTempString = String("page0.tnt.txt="") + _nextionSaveDataTXT_P0_E3 + String(""");
    nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
    _nextionSetAttr1_isNU = 0;
  } if (_changeNumber1_Out) {
    if (! _nextionSetAttr2_oldState ) {
      _nextionSetAttr2_oldState = 1;
      _nextionSetAttr2_isNU = 1;
      _nextionSaveDataVAL_P0_E2 =  (map((_gtv1), (-400), (500), (10), (91))) ;
    }
  } else {
    _nextionSetAttr2_oldState = 0;
  } if (_nextionSetAttr2_isNU) {
    _nextionCommandTempString = String("page0.tpb.val=") + String(_nextionSaveDataVAL_P0_E2);
    nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
    _nextionSetAttr2_isNU = 0;
  } if (( (_trgrt1) || (_trgrt2) )) {
    if (! _nextionSetAttr3_oldState ) {
      _nextionSetAttr3_oldState = 1;
      _nextionSetAttr3_isNU = 1;
      _nextionSaveDataPCO_P0_E3 =  _swi1 ;
    }
  } else {
    _nextionSetAttr3_oldState = 0;
  }
  if (nextionAskPageNamper(100) == 0) {
    if (_nextionSetAttr3_isNU) {
      _nextionCommandTempString = String("page0.tnt.pco=") + String(_nextionSaveDataPCO_P0_E3);
      nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
      _nextionCommandTempString = "ref tnt";
      nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
      _nextionSetAttr3_isNU = 0;
    }
  } else {
    _nextionSetAttr3_isNU = 1;
  }
  if (( (_trgrt1) || (_trgrt2) )) {
    if (! _nextionSetAttr4_oldState ) {
      _nextionSetAttr4_oldState = 1;
      _nextionSetAttr4_isNU = 1;
      _nextionSaveDataPICC_P0_E4 =  _swi2 ;
    }
  } else {
    _nextionSetAttr4_oldState = 0;
  }
  if (nextionAskPageNamper(100) == 0) {
    if (_nextionSetAttr4_isNU) {
      _nextionCommandTempString = String("page0.tci.picc=") + String(_nextionSaveDataPICC_P0_E4);
      nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
      _nextionCommandTempString = "ref tci";
      nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
      _nextionSetAttr4_isNU = 0;
    }
  } else {
    _nextionSetAttr4_isNU = 1;
  }
  if (((map((_gtv2), (0), (100), (-46), (226)))) < (0))
  {
    _swi3 = ((map((_gtv2), (0), (100), (-46), (226)))) + (360);
  }
  else
  {
    _swi3 = (map((_gtv2), (0), (100), (-46), (226)));
  }
  if (_changeNumber2_Out) {
    _changeNumber2_Out = 0;
  } else {
    _hasNumberChangeInTemp = _gtv2;
    if (_hasNumberChangeInTemp != _changeNumber2_OLV) {
      _changeNumber2_OLV = _hasNumberChangeInTemp;
      _changeNumber2_Out = 1;
    }
  }
  if (_changeNumber2_Out) {
    if (! _nextionSetAttr5_oldState ) {
      _nextionSetAttr5_oldState = 1;
      _nextionSetAttr5_isNU = 1;
      _nextionSaveDataVAL_P1_E4 =  _gtv2 ;
    }
  } else {
    _nextionSetAttr5_oldState = 0;
  } if (_nextionSetAttr5_isNU) {
    _nextionCommandTempString = String("page1.humN.val=") + String(_nextionSaveDataVAL_P1_E4);
    nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
    _nextionSetAttr5_isNU = 0;
  } if (_changeNumber2_Out) {
    if (! _nextionSetAttr6_oldState ) {
      _nextionSetAttr6_oldState = 1;
      _nextionSetAttr6_isNU = 1;
      _nextionSaveDataVAL_P1_E2 =  _swi3 ;
    }
  } else {
    _nextionSetAttr6_oldState = 0;
  } if (_nextionSetAttr6_isNU) {
    _nextionCommandTempString = String("page1.humG.val=") + String(_nextionSaveDataVAL_P1_E2);
    nextionSendCommand(_nextionCommandTempString.c_str(), 100);  nextionAck(100);
    _nextionSetAttr6_isNU = 0;
  } if (1) {
    if (! _gen1I) {
      _gen1I = 1;
      _gen1O = 1;
      _gen1P = millis();
    }
  } else {
    _gen1I = 0 ;
    _gen1O = 0;
  }
  if (_gen1I) {
    if ( _isTimer ( _gen1P , 5000 )) {
      _gen1P = millis();
      _gen1O = ! _gen1O;
    }
  }
  if (_gen1O) {
    if (_trgrt5I) {
      _trgrt5 = 0;
    } else {
      _trgrt5 = 1;
      _trgrt5I = 1;
    }
  } else {
    _trgrt5 = 0;
    _trgrt5I = 0;
  };
  if (_gtv4) {
    if (_trgrt3I) {
      _trgrt3 = 0;
    } else {
      _trgrt3 = 1;
      _trgrt3I = 1;
    }
  } else {
    _trgrt3 = 0;
    _trgrt3I = 0;
  };
  _gtv4 = (NextionPanel_47525121_PageIdOut) == (2);
  _gtv5 = _trgrt5;
  if (_trgrt3) {
    if ( ! _nextionAddPointToWave1_OldState) {
      _nextionAddPointToWave1_OldState = 1;
      if (nextionAskPageNamper(100) == 2) {
        for (int nextionSATWTemp = 0;  nextionSATWTemp < 330;  nextionSATWTemp ++) {
          _nextionCommandTempString = String ("add 1,1,") + String (_FLPArray142003126[nextionSATWTemp]);
          nextionSendCommand(_nextionCommandTempString.c_str(), 100);
        } delay (50);
      }
    }
  } else {
    _nextionAddPointToWave1_OldState = 0;
  }

  if (_trgrt3) {
    if ( ! _nextionAddPointToWave2_OldState) {
      _nextionAddPointToWave2_OldState = 1;
      if (nextionAskPageNamper(100) == 2) {
        for (int nextionSATWTemp = 0;  nextionSATWTemp < 330;  nextionSATWTemp ++) {
          _nextionCommandTempString = String ("add 1,0,") + String (_FLPArray239384258[nextionSATWTemp]);
          nextionSendCommand(_nextionCommandTempString.c_str(), 100);
        } delay (50);
      }
    }
  } else {
    _nextionAddPointToWave2_OldState = 0;
  }

  if (_gtv5) {
    if (!_SFLPAS1) {
      _SFLPAS1 =  1;
      for (_SUETFLPATemp = 0; _SUETFLPATemp < 329; _SUETFLPATemp = _SUETFLPATemp + 1 ) {
        _FLPArray239384258[_SUETFLPATemp ] = _FLPArray239384258[_SUETFLPATemp + 1];
      }  _FLPArray239384258[329] = _gtv2;
    }
  }  else {
    _SFLPAS1 = 0;
  }
  _gtv6 = ((_gtv1) / (5)) + (160);
  if (_gtv5) {
    if (!_SFLPAS2) {
      _SFLPAS2 =  1;
      for (_SUETFLPATemp = 0; _SUETFLPATemp < 329; _SUETFLPATemp = _SUETFLPATemp + 1 ) {
        _FLPArray142003126[_SUETFLPATemp ] = _FLPArray142003126[_SUETFLPATemp + 1];
      }  _FLPArray142003126[329] = _gtv6;
    }
  }  else {
    _SFLPAS2 = 0;
  }
  if (( (_gtv5) && (!(_trgrt3)) && (_gtv4) )) {
    if ( ! _nextionSendArraytToWave1_OldState) {
      _nextionSendArraytToWave1_OldState = 1;
      if (nextionAskPageNamper(100) == 2) {
        _nextionCommandTempString = String ("add 1,0,") + String (_gtv2);
        nextionSendCommand(_nextionCommandTempString.c_str(), 100); delay (50);
      }
    }
  } else {
    _nextionSendArraytToWave1_OldState = 0;
  }

  if (( (_gtv5) && (!(_trgrt3)) && (_gtv4) )) {
    if ( ! _nextionSendArraytToWave2_OldState) {
      _nextionSendArraytToWave2_OldState = 1;
      if (nextionAskPageNamper(100) == 2) {
        _nextionCommandTempString = String ("add 1,1,") + String (_gtv6);
        nextionSendCommand(_nextionCommandTempString.c_str(), 100); delay (50);
      }
    }
  } else {
    _nextionSendArraytToWave2_OldState = 0;
  }

  if (_changeNumber3_Out) {
    _changeNumber3_Out = 0;
  } else {
    _hasNumberChangeInTemp = (map(( (analogRead (0))), (0), (1023), (0), (100)));
    if (((_hasNumberChangeInTemp > _changeNumber3_OLV) && ((_hasNumberChangeInTemp - _changeNumber3_OLV ) > 5)) || ((_hasNumberChangeInTemp < _changeNumber3_OLV) && ((_changeNumber3_OLV - _hasNumberChangeInTemp ) > 5) ))
    {
      _changeNumber3_OLV = _hasNumberChangeInTemp;
      _changeNumber3_Out = 1;
    }
  }
  if (_changeNumber3_Out) {
    if (!(_nextionSetLighting1_OldStae)) {
      _nextionSetLighting1_OldStae = 1;
      _nextionCommandTempString = String("dim=") + String((map(( (analogRead (0))), (0), (1023), (0), (100))));
      nextionSendCommand(_nextionCommandTempString.c_str(), 100);
    }
  } else {
    _nextionSetLighting1_OldStae = 0;
  }




}
bool _isTimer(unsigned long startTime, unsigned long period )
{
  unsigned long currentTime;
  currentTime = millis();
  if (currentTime >= startTime) {
    return (currentTime >= (startTime + period));
  } else {
    return (currentTime >= (4294967295 - startTime + period));
  }
}
String  _floatToStringWitRaz(float value, int raz)
{
  float tv;
  int ti = int(value);
  String ts = String(ti);
  if (raz == 0) {
    return ts;
  }
  ts += ".";
  float tf = abs(value - ti);
  for (int i = 1; i <= raz; i++ )
  {
    tv = tf * 10;
    ti = int(tv);
    ts += String(ti);
    tf = (tv - ti);
  }
  return ts;
}
void nextionSendCommand(const char* cmd, byte port )
{
  while (Serial100.available()) {
    Serial100.read();
  }
  Serial100.print(cmd);
  Serial100.write(0xFF);
  Serial100.write(0xFF);
  Serial100.write(0xFF);
}
boolean nextionAck( byte port )
{
  uint8_t bytes[4] = {0};
  Serial100.setTimeout(20); if (sizeof(bytes) != Serial100.readBytes((char *)bytes, sizeof(bytes))) {
    return 0;
  }

  if ((bytes[1] == 0xFF) && (bytes[2] == 0xFF) && (bytes[3] == 0xFF)) {
    switch (bytes[0]) {
      case 0x00:
        return false; break;
      case 0x01:
        return true; break;
      default:
        return false;
    }
  }
}
struct _nextionLissenStruct nextionListen( byte port )
{
  char _bite;
  char _end = 0xff;
  String cmd;
  _nextionLissenStruct temp;
  int countEnd = 0;
  delay(10);
  while (Serial100.available() > 0) {
    if (Serial100.available() > 0) {
      _bite = Serial100.read();
      cmd += _bite;
      if (_bite == _end) {
        countEnd++;
      }
      if (countEnd == 3) {
        break;
      }
    }
  }
  temp.result = "";
  temp.code = 'z';
  temp.number = 0;
  switch (cmd[0]) {
    case 'e':
      temp.code = 'e';
      countEnd = 0;
      for (uint8_t i = 0; i < cmd.length(); i++) {
        if (cmd[i] == _end) {
          countEnd++;
        }
        temp.result += String(cmd[i], HEX);
        if (countEnd == 3) {
          return temp;
        }
        temp.result += " ";
      }
      break;
    case 'f':
      temp.code = 'f';
      temp.result = String(cmd[1], DEC);
      return temp;
      break;
    case 'g':
      temp.code = 'g';
      temp.result = String(cmd[2], DEC) + "," + String(cmd[4], DEC) + "," + String(cmd[5], DEC);
      return temp;
      break;
    case 'h':
      temp.code = 'h';
      temp.result = String(cmd[2], DEC) + "," + String(cmd[4], DEC) + "," + String(cmd[5], DEC);
      temp.result = "68 " + temp.result;
      return temp;
      break;
    case 'p':
      temp.code = 'p';
      temp.result = cmd.substring(1, cmd.length() - 3);
      return temp;
      break;
    case 'q':
      temp.code = 'q';
      temp.number = (cmd[4] << 24) | (cmd[3] << 16) | (cmd[2] << 8) | (cmd[1]);
      return temp;
      break;
    default:
      return temp;
      break;
  }
  return temp;
}
int nextionAskPageNamper(byte port)
{
  int result;
  _nextionLissenStruct temp;
  nextionSendCommand("sendme", port);
  temp = nextionListen(port);
  if ((temp.code == 'f') && (temp.result != "")) {
    result = temp.result.toInt();
  } else {
    result = -1;
  }
  return result;
}

Небольшое видео с демонстрацией.

Архив с проектом для панели и проектом для контроллера.
В следующем уроке поучимся управлять контроллером Arduino из панели.

Автор: FLProg

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js