Разработка панели управления WS2812 с использованием дисплея AT HMI и Easy HMI

Я создавал подобные проекты для дисплея Nextion и сделал серию уроков для него. Затем создал аналогичный проект для дисплея DWIN. Пришло время сделать такой же проект для своего дисплея AT HMI. Создавать интерфейс буду в разработанном мной программном обеспечении Easy HMI. Подробнее о данной программе я рассказывал ранее, а также о том, как можно управлять дисплеем по UART и какие команды для этого уже есть. А сегодня на практике используем полученные знания и создадим наш замечательный проект.

Создаем интерфейс в Easy HMI.


Важно! Easy HMI работает исключительно с дисплеями AT HMI.

Создаем интерфейс в Easy HMI.

Создание интерфейса для дисплея AT HMI сейчас достаточно простой процесс. Нужно просто добавить в проект виджеты, расставить их как нужно и, при необходимости, изменить цвет элементов, надписи, размер текста и размер линий. И всё – интерфейс для проекта готов. При этом один и тот же виджет можно использовать для разных проектов и дисплеев с разным разрешением. Для данного проекта я сделаю интерфейсы для дисплеев 2,8 дюйма с разрешением 320х240 пикселей и для 3,5-дюймового дисплея с разрешением 480х320 пикселей. Скачать исходные материалы можно внизу статьи в разделе «Файлы для скачивания». Несмотря на значительную разницу в разрешении этих дисплеев, переделать пришлось только модульные виджеты (они содержат большое количество компонентов и сделаны в виде самостоятельного модуля). Как создавать виджеты, я расскажу в уроках.

Создание интерфейса для дисплея AT HMI сейчас достаточно простой процесс.

Используемые модули для интерфейса дисплея 3,5 дюйма:

  • #8 – Кнопка включения
  • #10 – Кнопка выбор цвета
  • #52 – Плашка с закруглением – синего цвета
  • #152 – Модуль яркость, громкость
  • #153 – Модуль смены режима -2

Используемые модули для интерфейса дисплея 3,5 дюйма

Список используемых модулей для дисплея 2,8 дюйма вы можете посмотреть самостоятельно, открыв проект, который находится в прикреплённом файле внизу статьи. Эти и другие модули можно скачать вместе с программой Easy HMI и попробовать создать свой интерфейс. Посмотреть, что получится, можно в эмуляторе – не обязательно покупать дисплей для тестирования и проверки работы этого ПО.

Список используемых модулей для дисплея 2,8 дюйма вы можете посмотреть самостоятельно

Пример добавления виджета в проект.

Давайте рассмотрим, как происходит добавление виджетов в проект на примере добавления кнопок изменения цвета подсветки. Для этого нужно нажать на кнопку «Загрузить виджет».

Добавление виджетов в проект на примере добавления кнопок изменения цвета подсветки.

В открывшемся окне выбираем виджет «10 – Кнопка выбор цвета».

В открывшемся окне выбираем виджет «10 – Кнопка выбор цвета».

Виджет добавлен в проект, но он расположится в левом верхнем углу эмулятора со стандартными параметрами цвета и текста.

Виджет добавлен в проект, но он расположится в левом верхнем углу эмулятора со стандартными параметрами цвета и текста.

Как переместить его на нужную позицию нашего интерфейса? Для этого кликнем по родительскому элементу, который следует сразу за названием виджета «10 – Кнопка выбор цвета», в данном случае это кнопка.

Как переместить его на нужную позицию нашего интерфейса?

И меняем позицию кнопки – тем самым изменяем и позицию самого виджета со всеми вложенными элементами. Также здесь же можно изменить размер кнопки и другие параметры. Строка ниже (3) позволяет редактировать текст кнопки.

И меняем позицию кнопки – тем самым изменяем и позицию самого виджета со всеми вложенными элементами.

Цвет кнопки здесь изменить нельзя. Чтобы создавать кнопки разного цвета, нужно изменять цвет при редактировании виджета. Это можно делать параллельно с созданием проекта. Для этого переходим во вкладку «Виджеты» и видим, что у нас уже открыт виджет, который мы только что добавили в проект. Да, последний добавленный виджет в проект автоматически открывается для редактирования.

Цвет кнопки здесь изменить нельзя. Чтобы создавать кнопки разного цвета, нужно изменять цвет при редактировании виджета.


Здесь нам нужно изменить цвета и, если требуется, другие параметры. Например, для дисплея другого размера нужно изменить размер кнопки и размер текста. Всё, теперь можно добавить кнопку в проект.

Здесь нам нужно изменить цвета и, если требуется, другие параметры.


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

В проекте есть модульные виджеты.

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

Схема подключения дисплея AT HMI к Arduino UNO + WS2812.

Схема подключения дисплея AT HMI к Arduino UNO + WS2812.

Схема подключения будет аналогичной для Arduino NANO, Arduino Pro Mini и т.д.

Схема подключения дисплея AT HMI к ESP8266 + WS2812.

Схема подключения дисплея AT HMI к ESP8266 + WS2812.

Схема подключения нарисована для Wemos D1 mini, но она будет аналогичной для других плат на базе модуля ESP-12E, ESP-12F, ESP-12S, таких как: NodeMCU, WeMos и т.д.

Код для Arduino, WeMos (ESP8266).

Код для Arduino, ESP8266 и других микроконтроллеров будет состоять из функций для работы с дисплеем по UART и код для работы с адресными светодиодами. О командах UART для работы с дисплеем я рассказывал в предыдущей статье. Сейчас сделаем удобные функции, чтобы можно было пользоваться ими при создании проектов не только для Arduino, WeMos, но и для других отладочных плат на других микроконтроллерах. Например, переделать данный пример под ESP32 не составит большого труда. Я стараюсь, чтобы код был максимально простым и универсальным.

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

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

На основной вкладке led_ATHMI_3_5-ESP8266_1_1.ino располагаются основные настройки и функции setup() и loop().
На вкладке display.ino находятся функции для работы с дисплеем. Основные функции, которые помогают отправлять данные на дисплей для изменения свойств элементов на дисплее, находятся внизу вкладки. Все функции подписаны, и написан пример, какую команду функция отправляет на дисплей.

На вкладке display.ino находятся функции для работы с дисплеем.

Вверху над страницей находится массив строк с названиями световых эффектов, которые нужны для работы со светодиодами. Их нужно прописать здесь, так как в коде работы с дисплеем мы отправляем на дисплей название световых эффектов.

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

На вкладке display.ino находятся функции для работы с дисплеем.

Несмотря на то, что код старался не усложнять, написал один массив с адресами кнопок на дисплее. Если вы откроете эмулятор и выставите вывод ID кнопок, то увидите, что это за кнопки.Кстати, скопировать ID элемента очень просто – достаточно кликнуть по нему левой кнопкой мыши.

 Кстати, скопировать ID элемента очень просто – достаточно кликнуть по нему левой кнопкой мыши.

uint16_t array_btn[] = {0xA1F, 0xA22, 0xA25, 0xA28, 0xA2B, 0xA2E, 0xA31, 0xA34}; // Адреса кнопок

Также эти ID используются для обработчика команд нажатия на кнопки изменения цвета подсветки. Но я прописал их полностью в коде, не используя массив, чтобы было более понятно. При необходимости можно упростить код и использовать массив для обработки данных с кнопок. Сделаю пример, как это реализовать, в уроках.

Разбор кода, полученные данные от дисплея.

Функция ReadSerial() читает данные из порта и, при получении конца строки, данные передаёт в функцию AnalyseString(), где происходит обработка полученных команд. А именно, мы получаем информацию о нажатии кнопок и нажатии кнопок с фиксацией.

Разбор кода, полученные данные от дисплея.


Кнопка включения имеет 2 состояния, так как она с фиксацией. Нажали – пришла команда 1 в конце. Нажали повторно – пришла команда с 0 в конце. Как я объяснял в статье о командах UART, команда состоит из стартовых символов, ID кнопки и после знака равенства – состояние кнопки.

Кнопка включения имеет 2 состояния, так как она с фиксацией.

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

Отправляем данные на дисплей.

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

Отправляем данные на дисплей.

Кнопка включения и выключения подсветки.

Начнём с кнопки включения подсветки. Здесь у меня 2 функции для работы с линиями: первая функция изменяет толщину линии, вторая изменяет цвет линии.

SendLnWidth(0xA03, 8);
SendLnColor(0xA02, 0xCCCCCC);

Вернее, двух линий, так как иконка нарисована из двух линий. В функцию передаём ID элемента в HEX формате (число в шестнадцатеричной системе счисления 0xA03). Второй параметр – это ширина линии (8) , у второй функции – это цвет линии также в HEX формате RGB888 (0xCCCCCC). Этот формат достаточно распространён, и можно получить цвет с помощью любого графического редактора или сайта для подбора цвета и палитры.
Остальные функции в данном блоке кода для работы с адресными светодиодами.

flag_off_led = true;                          // блакируем изменения яркости с кнопко ярче и темнее
last_brightnessLED = brightnessLED;
brightnessLED = 0;                            // первоначальная яркость
FastLED.setBrightness(25.5 * brightnessLED);  // Яркость 0%
Кнопки переключения эффектов.

Передают название эффектов из массива.

SendTxTxt(0xA1B, phrases[last_effect]);  // устанавливаем текст на плашке с id 0xA18

Для этого в функцию передаётся ID элемента текста на дисплее в HEX формате и текст из массива также по его индексу строки phrases[last_effect]. Здесь можно просто написать текст в кавычках для отправки текста на дисплей по аналогии с тем, что сделано в блоке setup(). SendTxTxt(0xA18, "Статический цвет"); – это позволяет убедиться, что при старте программы будет точно установлен режим «статический цвет».

Остальные функции работают по аналогии.

Остальные функции работают по аналогии. В некоторых функциях кроме посля ID передаётся больше, чем один параметр. Например, для смены цвета кнопки и плашки нужно передать 2 цвета для создания градиента. Если не нужно создавать градиент, передавать всё равно нужно 2 цвета, но одного значения, например, белый RGB888 = #FFFFFF.

//== изменяем цвет плашки  num_element = id, data_color = 0xFFFFFF, data_color2 = 0xCCCCCC
void SendPlTColor(uint16_t num_element, uint32_t data_color, uint32_t data_color2) {
  String data_txt_local = "pl." + String(num_element, HEX) + ".col=" + String(data_color, HEX) + ";" + String(data_color2, HEX) + "\n";  // pl.A03.col=000000;CCCCCC\n
  mySoftwareSerial.print(data_txt_local);                                                                                                // Отправляем
  num_element = 0;                                                                                                                       // Очищаем переменную
  data_color = 0;
  data_color2 = 0;  // Очищаем переменную
}
//== изменяем Размер плашки  num_element = id, data_width = 200, data_height = 100
void SendPlSize(uint16_t num_element, uint16_t data_width, uint16_t data_height) {
  String data_txt_local = "pl." + String(num_element, HEX) + ".siz=" + String(data_width) + ";" + String(data_height) + "\n";  // pl.A03.siz=200;100\n
  mySoftwareSerial.print(data_txt_local);                                                                                      // Отправляем
  num_element = 0;                                                                                                             // Очищаем переменную
  data_width = 0;
  data_height = 0;  // Очищаем переменную
}

Работаем с массивом адресов кнопок изменения цвета подсветки.

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

uint16_t array_btn[] = {0xA1F, 0xA22, 0xA25, 0xA28, 0xA2B, 0xA2E, 0xA31, 0xA34}; // Адреса кнопок

Да, нажатия кнопок прописаны «в лоб», и обработка массива немного нелогична. Но для читабельности кода и чтобы было проще понять, что делает код, сделал так. В уроке напишу, как уменьшить код с использованием массива для отсеивания нажатия на кнопку.

//--- изменяем цвет статического режима --- //
  if ((incStr.indexOf("BtA1F=1") >= 0)) {
    if (last_effect > 0)  // если педыдущий режим был не статический цвет
    {
      SendTxTxt(0xA1B, phrases[0]);
      last_effect = 0;  // ставим эффект на статический цвет
    }
    SendBtSnus(array_btn[last_color] , 0);   // снимаем блок с пред. кнопки
    SendPlSwich(array_btn[last_color], 0);  // возвращаем кнопку в изночальное положения
    last_color = 0;                         // изменяем цвет на 1 в массиве CRGB Colors_p[]
    SendBtSnus(array_btn[last_color], 1);   // ставим блок на текущ. кнопку
  }
  if ((incStr.indexOf("BtA22=1") >= 0)) {
    if (last_effect != 0)  // если педыдущий режим был не статический цвет
    {
      SendTxTxt(0xA1B, phrases[0]);
      last_effect = 0;  // ставим эффект на статический цвет
    }
    SendBtSnus(array_btn[last_color], 0);   // снимаем блок с пред. кнопки
    SendPlSwich(array_btn[last_color], 0);  // возвращаем кнопку в изночальное положения
    last_color = 1;                         // изменяем цвет на 1 в массиве CRGB Colors_p[]
    SendBtSnus(array_btn[last_color], 1);   // ставим блок на текущ. кнопку
  }

При нажатии на кнопку «смены цвета» нам нужно первым делом проверить, какой режим был включен. Если не «статический», то меняем надпись – это у нас первый элемент массива с текстом режимов. Функция будет выглядеть так: SendTxTxt(0xA1B, phrases[0]);.
Затем снимаем блокировку с предыдущей кнопки, так как кнопка с фиксацией, её нужно вернуть в не нажатое состояние. Для этого служит вторая функция SendPlSwich(array_btn[last_color], 0);
Затем нам нужно заблокировать текущую кнопку. Для этого в переменную last_color = 1; сохраняем номер текущей кнопки в массиве ID. Как видим, здесь мы можем сравнить с массивом, какая кнопка нажата – это играет роль отладки кода. А при нажатии другой кнопки смены цвета мы знаем, какая была нажата ранее, и повторяем процедуру, которая описана выше.

    SendBtSnus(array_btn[last_color], 0);   // снимаем блок с пред. кнопки
    SendPlSwich(array_btn[last_color], 0);  // возвращаем кнопку в изночальное положения
    last_color = 1;                         // изменяем цвет на 1 в массиве CRGB Colors_p[]
    SendBtSnus(array_btn[last_color], 1);   // ставим блок на текущ. кнопку

В проекте мы использовали не все функции, которые прописаны для работы с элементами на дисплее. Вы можете использовать их в своих проектах. Также дописать по аналогии недостающие функции для управления элементами, опираясь на команды из статьи: «Описание UART протокола для Easy HMI 0.1.0».

// --== Функции для отправки данных на дисплей ==---//
//== отправка текста num_element = id, data_txt = "текст"
void SendTxTxt(uint16_t num_element, String data_txt) {
  String data_txt_local = "tx." + String(num_element, HEX) + ".txt=" + data_txt + "\n";  // tx.A09.txt=Привет\n
  mySoftwareSerial.print(data_txt_local);                                                // Отправляем
  num_element = 0;                                                                       // Очищаем переменную
  data_txt = "";                                                                         // Очищаем переменную
}
//== изменяем состояние кнопки с фиксацией (не применимо для кнопки без фиксации)  num_element = id, data_swi = 0/1
void SendPlSwich(uint16_t num_element, bool data_swi) {
  String data_txt_local = "bt." + String(num_element, HEX) + ".swi=" + String(data_swi) + "\n";  //bt.A1F.swi=1\n
  mySoftwareSerial.print(data_txt_local);                                                        // Отправляем
  num_element = 0;                                                                               // Очищаем переменную
  data_swi = 0;                                                                                  // Очищаем переменную
}
//== блакируем кнопки с фиксацией и без фиксации  num_element = id, data_stt = 0/1
void SendBtSnus(uint16_t num_element, bool data_stt) {
  String data_txt_local = "bt." + String(num_element, HEX) + ".stt=" + String(data_stt) + "\n";  // bt.A06.stt=1\n
  mySoftwareSerial.print(data_txt_local);                                                        // Отправляем
  num_element = 0;                                                                               // Очищаем переменную
  data_stt = 0;                                                                                  // Очищаем переменную
}
//== изменяем цвет плашки  num_element = id, data_color = 0xFFFFFF, data_color2 = 0xCCCCCC
void SendPlTColor(uint16_t num_element, uint32_t data_color, uint32_t data_color2) {
  String data_txt_local = "pl." + String(num_element, HEX) + ".col=" + String(data_color, HEX) + ";" + String(data_color2, HEX) + "\n";  // pl.A03.col=000000;CCCCCC\n
  mySoftwareSerial.print(data_txt_local);                                                                                                // Отправляем
  num_element = 0;                                                                                                                       // Очищаем переменную
  data_color = 0;
  data_color2 = 0;  // Очищаем переменную
}
//== изменяем Размер плашки  num_element = id, data_width = 200, data_height = 100
void SendPlSize(uint16_t num_element, uint16_t data_width, uint16_t data_height) {
  String data_txt_local = "pl." + String(num_element, HEX) + ".siz=" + String(data_width) + ";" + String(data_height) + "\n";  // pl.A03.siz=200;100\n
  mySoftwareSerial.print(data_txt_local);                                                                                      // Отправляем
  num_element = 0;                                                                                                             // Очищаем переменную
  data_width = 0;
  data_height = 0;  // Очищаем переменную
}
//== Изменяем ширину линии  num_element = id, data_wdt = 6
void SendLnWidth(uint16_t num_element, uint8_t data_wdt) {
  String data_txt_local = "ln." + String(num_element, HEX) + ".wdt=" + String(data_wdt) + "\n";  // ln.A08.wdt=6\n
  mySoftwareSerial.print(data_txt_local);                                                        // Отправляем
  num_element = 0;                                                                               // Очищаем переменную
  data_wdt = 0;                                                                                  // Очищаем переменную
}
//== изменяем цвет линии  num_element = id, data_color = 0xFFFFFF
void SendLnColor(uint16_t num_element, uint32_t data_color) {
  String data_txt_local = "ln." + String(num_element, HEX) + ".col=" + String(data_color, HEX) + "\n";  // ln.A03.col=000000\n
  mySoftwareSerial.print(data_txt_local);                                                                                                // Отправляем
  num_element = 0;                                                                                                                       // Очищаем переменную
  data_color = 0;
}
// перходим на другой экран  data_screen = 2
void SendScreen(uint16_t data_screen) {
  String data_txt_local = "sc.1.num=" + String(data_screen) + "\n";  // sc.1.num=2\n
  mySoftwareSerial.print(data_txt_local);                            // Отправляем
  data_screen = 0;                                                   // Очищаем переменную
}

На этом всё. Более подробно будем разбираться с работой дисплеев AT HMI и программным обеспечением EasyHMI в уроках. В уроках поэтапно расскажу, как создать этот проект и подробно опишу функции для работы с дисплеем.

По все вопросам вы можете написать мне в соц. сетях:

Понравился проект Руководство по созданию панели управления WS2812 на базе AT HMI и Arduino? Не забудь поделиться с друзьями в соц. сетях.

А также подписаться на наш канал на YouTube, вступить в группу Вконтакте, в Telegram.

Спасибо за внимание!

Технологии начинаются с простого!

Фотографии к статье

Файлы для скачивания

Библиотеки для проекта Библиотеки для проекта.zip364 Kb 23 Скачать
Код для Arduino и дисплея 3,5 Код для Arduino и дисплея 3,5.zip6 Kb 21 Скачать
Код для ESP8266 и дисплея 3,5 Код для ESP8266 и дисплея 3,5.zip6 Kb 23 Скачать
Код для ESP8266 и дисплея 2.8 Код для ESP8266 и дисплея 2.8.zip6 Kb 23 Скачать
Программа Easy HMI 0.1.1 с виджетами и проектами Программа Easy HMI 0.1.1 с виджетами и проектами.zip1800 Kb 23 Скачать

Комментарии

Ваше Имя*


Разработка проектов