Создание IoT-проектов (проектов интернета вещей) с сенсорными экранами раньше было головной болью, требующей множества компонентов, запутанной проводки и бесконечного поиска и устранения неисправностей. Но плата ESP32-S3 Box-3 значительно упрощает эту задачу. Это универсальная плата с двухъядерным процессором, сенсорным экраном и совместимостью с Arduino IDE. В этом руководстве мы возьмем эту удобную для разработчиков плату ESP32-S3 Box-3 и превратим ее в контроллер RGB-светодиодов с сенсорным управлением. Пайка и сложная настройка не требуются.

Эта универсальная плата упрощает настройку оборудования, объединяя необходимые компоненты в одном корпусе, что позволяет как начинающим, так и опытным разработчикам сосредоточиться на реализации встроенного ПО, а не на сложной сборке схем. Встроенный 2,4-дюймовый емкостный сенсорный ЖК-дисплей позволяет создавать профессиональные пользовательские интерфейсы для встроенных приложений, идеально подходящих для домашней автоматизации, панелей управления IoT и систем управления. Совместимость с Arduino IDE делает Box-3 доступным для разработчиков, знакомых с экосистемой Arduino.
Эта платформа хорошо подходит для прототипирования IoT-устройств, систем управления, AIoT-проектов и проектов, требующих визуальной и звуковой обратной связи. Для первоначальной настройки и примеров использования с данной платой смотрите смотрите наше предыдущее руководство по началу работы с платой ESP32-S3-BOX-3.

В этом пошаговом руководстве вы создадите полнофункциональный контроллер RGB-светодиодов с графическим сенсорным интерфейсом, используя Arduino IDE. Этот проект, подходящий для начинающих, познакомит вас с основами программирования ESP32-S3, одновременно создавая практическое приложение. Реализация охватывает ключевые особенности Box-3 и закладывает основу для разработки более сложных интерактивных приложений.
Технические характеристики ESP32-S3 Box-3: что делает ее идеальной для проектов IoT?
В состав ESP32-S3 Box-3 входят несколько ключевых компонентов, которые делают ее подходящей для интерактивных проектов программирования на Arduino:
- Двухъядерный процессор ESP32-S3, работающий на частоте 240 МГц.
- 512 КБ SRAM с дополнительными 8 МБ PSRAM.
- 16 МБ флэш-памяти для хранения программ.
- Встроенные модули Wi-Fi и Bluetooth для беспроводных IoT-приложений.
- 2,4-дюймовый TFT LCD-дисплей с разрешением 320x240 пикселей и контроллером ILI9342C.
- Емкостный сенсорный контроллер (GT911) с поддержкой мультитач-ввода.
- Регулировка подсветки.
- Множество разъемов для расширения функциональности, включая разъемы GPIO.
- Разъем USB-C для программирования и питания.
- Встроенный динамик и микрофон для проектов с аудиообратной связью.
Благодаря этим характеристикам Box-3 особенно хорошо подходит для проектов, требующих как визуальной обратной связи, так и аппаратного управления, например, для нашего проекта контроллера RGB-светодиодов.
Сравнение данной платы с традиционными платами ESP32 приведено в следующей таблице.
Что такое RGB-светодиодный модуль и как он работает?
Модуль RGB-светодиодов — это универсальный компонент освещения, способный воспроизводить миллионы цветов путем смешивания красного, зеленого и синего света. Модуль RGB-светодиодов, используемый в этом проекте программирования Arduino на базе ESP32-S3 Box-3, содержит три отдельных светодиода (красный, зеленый и синий) в одном корпусе.

Основы ШИМ-управления для RGB-светодиодов
Модуль подключается к трем выводам GPIO, настроенным для ШИМ (широтно-импульсной модуляции). ШИМ — это метод, позволяющий управлять яркостью светодиодов путем быстрого включения и выключения питания. Поскольку светодиоды имеют общий катод (заземление), мы управляем яркостью, изменяя ШИМ-сигнал на анодах. Значение ШИМ, равное 0, выключает светодиод, а 255 обеспечивает максимальную яркость.
Это означает, что вы можете создать 256 различных уровней яркости для каждого цвета, что приводит к более чем 16 миллионам возможных цветовых комбинаций (256 × 256 × 256). Каждый светодиод потребляет до 20 мА при полной яркости. При активации всех трех каналов общее потребление тока достигает 60 мА. Контакты GPIO ESP32-S3 могут безопасно обеспечивать этот ток, но для более крупных светодиодных матриц потребуются внешние схемы драйверов.
Распиновка RGB-светодиодного модуля
Как упоминалось выше, модуль RGB содержит светодиоды RGB в корпусе 5050, три отдельных токоограничивающих резистора и четырехконтактный разъем для подключения. Три контакта соединены с анодами красного, зеленого и синего светодиодов через токоограничивающие резисторы, а четвертый контакт является общим катодом. Ниже приведена схема расположения контактов и маркировки компонентов модуля RGB.

Назначение контактов данного модуля и их подключение к плате ESP32-S3 Box-3 представлены в следующей таблице.
Понимание распиновки ESP32-S3 Box-3 имеет важное значение для успешного программирования Arduino с использованием ESP32-S3 Box-3.
Как подключить RGB-светодиодный модуль к плате ESP32-S3 Box-3
Модуль RGB-светодиодов подключается к ESP32-S3 Box-3 через разъем расширения на док-станции. Следующая схема подключения обеспечивает оптимальную производительность и позволяет избежать конфликтов с внутренними периферийными устройствами. Следуйте этому простому руководству по подключению, чтобы подключить модуль RGB-светодиодов:

Данная схема подключения описана в следующей таблице.
Модуль RGB-светодиодов подключается к ESP32-S3 Box-3 через разъем расширения с помощью четырехпроводного соединения. Эти контакты также позволяют избежать конфликтов с внутренними периферийными устройствами устройства. Вот полная схема расположения контактов:
- Контакт GPIO 39 управляет каналом красного светодиода.
- Контакт GPIO 40 управляет каналом зеленого светодиода.
- Контакт GPIO 41 управляет каналом синего светодиода.
- Общий катодный вывод RGB-светодиода подключается к контакту заземления (GND) на плате Box-3.
Данная конфигурация позволяет осуществлять индивидуальное ШИМ-управление каждым цветом, используя при этом общий обратный путь через заземление.
Настройка Arduino IDE для программирования ESP32-S3 Box-3
⇒ Шаг 1: Установите Arduino IDE
Перед началом программирования убедитесь, что у вас установлены и правильно настроены компоненты для оптимального программирования Arduino ESP32-S3 Box-3.
⇒Шаг 2: Добавить поддержку платы ESP32 (критическая версия)
Для начала, код Arduino должен убедиться, что плата ESP32 уже установлена. Если вы еще не установили поддержку платы ESP32, перейдите в Tools > Board > Board Manager и найдите "ESP32". Убедитесь, что вы установили менеджер плат ESP32 версии 3.2.1, а не последнюю версию 3.3.0, поскольку на момент написания этого руководства последняя версия имеет некоторые проблемы совместимости с графической библиотекой, которую мы будем использовать.
Важно: В версии 3.3.0 обнаружены проблемы с библиотекой LovyanGFX, поэтому для этого проекта используйте версию 3.2.1.
⇒Шаг 3: Установите необходимые библиотеки
Следующий шаг — установка последней версии библиотеки LovyanGFX через менеджер библиотек Arduino IDE. Найти LovyanGFX можно, выполнив поиск "LovyanGFX" в менеджере библиотек. В качестве платы выберите ESP32-S3-Box в меню "Инструменты".
⇒ Шаг 4: Выберите правильную конфигурацию платы
В остальном все так же, как и при программировании любого другого ESP32. Просто подключите, напишите код и залейте прошивку. Прошивка создает упрощенный контроллер RGB-светодиодов с шестью предустановленными кнопками цвета и переключателем включения/выключения.
Объяснение работы кода
В этом разделе представлен подробный разбор кода Arduino с объяснением каждого компонента для начинающих программистов, использующих плату ESP32-S3 Box-3 Arduino. Полный код программы приведен в конце статьи.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <Arduino.h> #include <Wire.h> #define LGFX_ESP32_S3_BOX_V3 #include <LGFX_AUTODETECT.hpp> #include <LovyanGFX.hpp> #define RGB_RED 39 #define RGB_GREEN 40 #define RGB_BLUE 41 #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 240 #define HEADER_HEIGHT 50 #define BUTTON_MARGIN 15 #define BUTTON_ROWS 2 #define BUTTON_COLS 3 #define BUTTON_WIDTH ((SCREEN_WIDTH - (BUTTON_MARGIN * (BUTTON_COLS + 1))) / BUTTON_COLS) #define BUTTON_HEIGHT ((SCREEN_HEIGHT - HEADER_HEIGHT - (BUTTON_MARGIN * (BUTTON_ROWS + 1))) / BUTTON_ROWS) |
Директива препроцессора LGFX_ESP32_S3_BOX_V3 настраивает библиотеку LovyanGFX для аппаратного обеспечения ESP32-S3 Box-3. Это автоматически устанавливает параметры дисплея, настройки связи SPI и конфигурацию контроллера сенсорного экрана. Библиотека Wire обеспечивает связь по I2C, хотя эта упрощенная версия в основном опирается на встроенную поддержку сенсорного управления LovyanGFX. Контакты GPIO 39-41 выбраны для управления RGB-светодиодами, поскольку они поддерживают ШИМ-выход и позволяют избежать конфликтов с внутренними периферийными устройствами. Эти контакты обеспечивают достаточную пропускную способность по току для управления стандартными RGB-светодиодами без внешних транзисторов. В макете пользовательского интерфейса используются рассчитанные размеры, чтобы кнопки правильно отображались на дисплее 320x240. Высота заголовка в 50 пикселей обеспечивает место для названия и переключателя, а 15-пиксельные поля создают визуальное разделение между элементами интерфейса. Размеры кнопок рассчитываются автоматически на основе размера экрана и настроек полей. Такой подход обеспечивает согласованный макет независимо от размера дисплея и позволяет легко адаптировать интерфейс к различным разрешениям экрана.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
struct ColorRGB { uint8_t r, g, b; }; ColorRGB colorButtons[6] = { {255, 0, 0}, // RED {0, 255, 0}, // GREEN {0, 0, 255}, // BLUE {255, 255, 150}, // WHITE {255, 150, 0}, // YELLOW {255, 0, 255} // PURPLE }; String colorNames[6] = {"RED", "GREEN", "BLUE", "WHITE", "YELLOW", "PURPLE"}; bool ledOn = true; int selectedColor = 0; // Default to RED TouchPoint lastTouch = {0, 0, false}; |
Три параллельных массива хранят информацию о цвете: значения RGB для управления светодиодами, названия цветов для надписей на дисплее и системные цвета для фона кнопок. Такая организация упрощает управление цветом и обеспечивает согласованность между отображением на дисплее и выводом на светодиоды. Переменные состояния отслеживают текущее состояние светодиода, индекс выбранного цвета и предыдущее положение касания. Выбранный цвет по умолчанию равен 0 (красный), что обеспечивает немедленную визуальную обратную связь при запуске системы.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void setup() { Serial.begin(115200); lcd.init(); lcd.setBrightness(255); lcd.clear(TFT_BLACK); lcd.setFont(&fonts::FreeSans12pt7b); lcd.setTextColor(TFT_WHITE); lcd.setTextDatum(middle_center); lcd.drawString("RGB Controller", SCREEN_WIDTH/2, SCREEN_HEIGHT/2); pinMode(RGB_RED, OUTPUT); pinMode(RGB_GREEN, OUTPUT); pinMode(RGB_BLUE, OUTPUT); setLEDColor(0, 0, 0); drawUI(); updateLED(); Serial.println("Setup complete!"); |
Функция setup сначала инициализирует последовательную связь для отладки, затем настраивает контроллер дисплея и максимальную яркость для четкой видимости. На экране запуска отображается центрированный заголовок. Этот тест подтверждает работоспособность дисплея и предоставляет пользователю обратную связь во время инициализации системы. Контакты GPIO настроены как выходы для управления ШИМ. Вызов setLEDColor(0, 0, 0) гарантирует, что все светодиоды изначально находятся в выключенном состоянии, предотвращая неожиданное включение во время запуска. Затем функция drawUI используется для отрисовки графического интерфейса, после чего функция updateLED обновляет цвет светодиодов.
|
1 2 3 4 5 6 7 8 9 10 |
void loop() { TouchPoint touch = readTouch(); if (touch.touched && !lastTouch.touched) { handleTouch(touch.x, touch.y); } lastTouch = touch; delay(50); } |
Основной цикл реализует обнаружение сенсорных событий путем сравнения текущего и предыдущего состояний касания с помощью функции readTouch. Это предотвращает непрерывное срабатывание, когда пользователь удерживает палец на экране. Задержка в 50 мс обеспечивает частоту обновления 20 Гц. Как только обнаруживается новое касание, цикл вызывает функции обработки касания для остальных событий.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
TouchPoint readTouch() { TouchPoint point = {0, 0, false}; uint16_t x, y; if (lcd.getTouch(&x, &y)) { point.x = x; point.y = y; point.touched = true; } return point; } |
Считывание касаний полностью основано на встроенном драйвере сенсорного экрана LovyanGFX, что исключает необходимость в каких-либо дополнительных драйверах. Для этого мы считываем значения сенсорного ввода с помощью функции readTouch. Такой подход упрощает реализацию, сохраняя при этом надежное обнаружение касаний.
|
1 2 3 4 5 |
void drawUI() { lcd.clear(COLOR_BG); drawHeader(); drawColorButtons(); } |
Функция отрисовки пользовательского интерфейса очищает экран и перерисовывает все элементы интерфейса. Такой модульный подход позволяет выборочно обновлять интерфейс только при изменении определенных элементов, что повышает производительность и уменьшает мерцание.
|
1 2 3 4 5 6 7 8 9 10 |
void drawHeader() { lcd.fillRect(0, 0, SCREEN_WIDTH, HEADER_HEIGHT, COLOR_HEADER); lcd.setFont(&fonts::Font4); lcd.setTextColor(COLOR_WHITE); lcd.setTextDatum(middle_left); lcd.drawString("RGB LED Control", 15, HEADER_HEIGHT/2); drawToggle(); } |
Функция drawHeader создает четко выраженную визуальную область для заголовка и элементов управления. Шрифт Font4 обеспечивает хорошую читаемость при размере заголовка, а выравнивание текста по левому краю оставляет место для переключателя справа.
|
1 2 3 4 5 6 7 8 9 10 |
void drawToggle() { uint32_t sliderX = ledOn ? TOGGLE_X + TOGGLE_WIDTH - 37 : TOGGLE_X + 3; if (ledOn) { lcd.fillRoundRect(TOGGLE_X, TOGGLE_Y, TOGGLE_WIDTH, TOGGLE_HEIGHT, TOGGLE_HEIGHT/2, TFT_GREEN); } else { lcd.fillRoundRect(TOGGLE_X, TOGGLE_Y, TOGGLE_WIDTH, TOGGLE_HEIGHT, TOGGLE_HEIGHT/2, TFT_RED); } lcd.fillCircle(sliderX + 17, TOGGLE_Y + TOGGLE_HEIGHT/2, 17, COLOR_WHITE); } |
Функция drawToggle используется для отрисовки ползункового переключателя и задает цвет и положение для обозначения состояния: зеленый фон с ползунком, расположенным справа, означает ВКЛ. Красный фон с ползунком, расположенным слева, означает ВЫКЛ. Расчет положения ползунка обеспечивает плавные визуальные переходы.
|
1 2 3 4 5 6 7 8 9 10 11 |
void drawColorButtons() { for (int i = 0; i < 6; i++) { int row = i / BUTTON_COLS; int col = i % BUTTON_COLS; int x = BUTTON_MARGIN + col * (BUTTON_WIDTH + BUTTON_MARGIN); int y = HEADER_HEIGHT + BUTTON_MARGIN + row * (BUTTON_HEIGHT + BUTTON_MARGIN); drawColorButton(i, x, y); } } |
Функция drawColorButtons используется для отрисовки кнопок предопределенного цвета. Она использует сетку 2x3. Расчеты по строкам и столбцам равномерно распределяют кнопки по доступному пространству под заголовком. После расчета интервала функция drawColorButton создает кнопку.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void drawColorButton(int colorIndex, int x, int y) { if (colorIndex == selectedColor) { for (int i = 0; i < 6; i++) { lcd.drawRoundRect(x - i, y - i, BUTTON_WIDTH + 2*i, BUTTON_HEIGHT + 2*i, 12, TFT_SILVER); } } else { for (int i = 0; i < 2; i++) { lcd.drawRoundRect(x - i, y - i, BUTTON_WIDTH + 2*i, BUTTON_HEIGHT + 2*i, 12, TFT_SILVER); } for (int i = 2; i < 6; i++) { lcd.drawRoundRect(x - i, y - i, BUTTON_WIDTH + 2*i, BUTTON_HEIGHT + 2*i, 12, TFT_BLACK); } } } |
Границы кнопок создаются с помощью многослойного рисования для придания визуальной глубины. Выбранные кнопки получают более широкую рамку, а невыбранные — более узкую. Это обеспечивает четкую визуальную обратную связь о текущем выделении.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
void handleTouch(int x, int y) { if (x >= TOGGLE_X && x <= TOGGLE_X + TOGGLE_WIDTH && y >= TOGGLE_Y && y <= TOGGLE_Y + TOGGLE_HEIGHT) { ledOn = !ledOn; drawToggle(); updateLED(); return; } for (int i = 0; i < 6; i++) { int row = i / BUTTON_COLS; int col = i % BUTTON_COLS; int buttonX = BUTTON_MARGIN + col * (BUTTON_WIDTH + BUTTON_MARGIN); int buttonY = HEADER_HEIGHT + BUTTON_MARGIN + row * (BUTTON_HEIGHT + BUTTON_MARGIN); if (x >= buttonX && x <= buttonX + BUTTON_WIDTH && y >= buttonY && y <= buttonY + BUTTON_HEIGHT) { selectedColor = i; drawColorButtons(); updateLED(); return; } } |
Обработка касаний использует прямоугольное определение попадания для элементов пользовательского интерфейса. Переключатель занимает определенную область, и касание его переключает состояние светодиода, обновляет визуальное отображение и немедленно изменяет цвет светодиода. Определение цвета кнопок проходит циклом по всем шести кнопкам, вычисляя их положение и проверяя, попадают ли координаты касания в границы каждой кнопки. При касании кнопки обновляется выделение, все кнопки перерисовываются, чтобы показать новое состояние выделения, и светодиод меняет цвет.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void updateLED() { if (ledOn) { ColorRGB color = colorButtons[selectedColor]; setLEDColor(color.r, color.g, color.b); } else { setLEDColor(0, 0, 0); } } void setLEDColor(uint8_t r, uint8_t g, uint8_t b) { analogWrite(RGB_RED, r); analogWrite(RGB_GREEN, g); analogWrite(RGB_BLUE, b); } |
Управление светодиодами проверяет текущее состояние и применяет соответствующие значения цвета. При включении используются значения RGB выбранного цвета. При выключении все каналы обнуляются. Конфигурация с общим катодом позволяет напрямую применять значения ШИМ без инверсии.
Тестирование работы проекта
После успешной компиляции кода прошейте его в ESP32-S3 Box 3, как и любую другую плату ESP32-S3. После успешной прошивки устройство загрузится и отобразит графический интерфейс управления. Вот демонстрация этого процесса.

Репозиторий GitHub с кодом и схемой проекта
Вот ссылка на наш репозиторий GitHub, где вы найдете исходный код и все остальные необходимые файлы для создания собственного контроллера RGB-светодиодов с использованием ESP32-S3 Box 3 и Arduino IDE.
Как пользоваться интерфейсом RGB-контроллера
В графическом интерфейсе пользователя (GUI) в заголовке отображается название приложения и переключатель включения/выключения. Ниже расположены шесть кнопок с предопределенными цветами, расположенных в простой сетке 2x3, каждая из которых обозначена своим цветом. Пользователи могут коснуться любой из шести кнопок, чтобы изменить цвет светодиода на этот, при этом выбранная кнопка будет подсвечена для подтверждения. Переключатель включает или выключает светодиод, сохраняя при этом текущий выбранный цвет. Интерфейс быстро реагирует на касания и мгновенно обновляет как визуальное отображение, так и физический вывод светодиода.
Возможное развитие проекта
Поздравляем с завершением этого урока по ESP32-S3 Box-3 с Arduino IDE! Вы успешно освоили основы программирования ESP32-S3 Box-3 на Arduino, изучили ключевые аспекты распиновки ESP32-S3 Box-3 и, наконец, создали приложение для сенсорного экрана от начала до конца с аппаратным взаимодействием.
Этот проект дал вам базовые знания в области встраиваемых систем и разработки на Arduino. Вы научились управлять светодиодом с помощью ШИМ, писать приложения для сенсорных экранов, использовать и управлять GPIO, а также понимать, что представляет собой пользовательский интерфейс в приложении, использующем его. Многие из этих фундаментальных концепций могут быть применены ко многим другим проектам, от контроллеров домашней автоматизации и панелей управления IoT до простых беспроводных проектов IoT.
Часто задаваемые вопросы по программированию ESP32-S3 Box-3 с помощью Arduino
⇥ 1Q: Можно ли использовать разные контакты GPIO для RGB-светодиода?
Да, но убедитесь, что вы выбираете контакты с поддержкой ШИМ и избегайте контактов, используемых внутренними периферийными устройствами. Для оптимальной производительности рекомендуется использовать контакты GPIO 39, 40 и 41.
⇥ 2Q: Будет ли это работать с RGB-светодиодами с общим анодом?
Вам потребуется изменить код, чтобы инвертировать значения ШИМ. Замените значения analogWrite на (значение 255).
⇥ 3Q: Какой максимальный ток может выдержать светодиод ESP32-S3?
Каждый вывод GPIO может безопасно выдавать до 40 мА, но рекомендуется не превышать 20 мА на вывод. Для светодиодов с более высоким током используйте драйвер на транзисторе или MOSFET.
⇥ 4Q: Можно ли добавить больше цветов в интерфейс?
Да! Просто расширьте массив colorButtons и измените значения BUTTON_COLS/BUTTON_ROWS в коде.
⇥ 5Q: Какова процедура прошивки ESP32-S3 Box-3 с помощью Arduino IDE?
В Arduino IDE вы можете использовать менеджер плат для установки версии платы 3.2.1 для ESP32. После этого перейдите в меню Инструменты > Плата и выберите «ESP32-S3-Box». Затем вы можете загрузить свой скетч на устройство, подключенное через USB-C. Учтите, что используется версия 3.2.1, чтобы не было конфликтов с существующими библиотеками (например, LovyanGFX), которые будут возникать с версиями 3.3.0 и выше.
⇥ 6Q: Какую версию Arduino IDE рекомендуется использовать с ESP32-S3 Box-3?
Arduino IDE 1.8.19 и Arduino IDE 2.x достаточно хорошо работают с ESP32-S3 Box-3. Убедитесь, что установлена версия пакета платы 3.2.1. Версия 3.3.0 имеет известные проблемы совместимости с графическими библиотеками. Библиотека LovyanGFX требует именно эту версию пакета платы для корректной работы с сенсорным экраном.
⇥ 7Q: Какие контакты GPIO доступны на плате ESP32-S3 Box-3 для проектов Arduino?
Разъем расширения предлагает контакты GPIO 39-41 (с поддержкой ШИМ), GPIO 1-2 (UART), GPIO 8-9 (I2C) и GPIO 10-13 (SPI).
Полный код проекта
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
#include <Arduino.h> #include <Wire.h> #define LGFX_ESP32_S3_BOX_V3 #include <LGFX_AUTODETECT.hpp> #include <LovyanGFX.hpp> static LGFX lcd; // RGB LED pins #define RGB_RED 39 #define RGB_GREEN 40 #define RGB_BLUE 41 // Display settings #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 240 // UI Layout Constants #define HEADER_HEIGHT 50 #define BUTTON_MARGIN 15 #define BUTTON_ROWS 2 #define BUTTON_COLS 3 // Calculate button dimensions #define BUTTON_WIDTH ((SCREEN_WIDTH - (BUTTON_MARGIN * (BUTTON_COLS + 1))) / BUTTON_COLS) #define BUTTON_HEIGHT ((SCREEN_HEIGHT - HEADER_HEIGHT - (BUTTON_MARGIN * (BUTTON_ROWS + 1))) / BUTTON_ROWS) // Toggle button settings #define TOGGLE_WIDTH 70 #define TOGGLE_HEIGHT 40 #define TOGGLE_X (SCREEN_WIDTH - TOGGLE_WIDTH - 15) #define TOGGLE_Y ((HEADER_HEIGHT - TOGGLE_HEIGHT) / 2) // Color definitions #define COLOR_BG 0x1082 #define COLOR_HEADER 0x2124 #define COLOR_WHITE 0xFFFF #define COLOR_BLACK 0x0000 #define COLOR_GOLD 0xFFE0 // State variables struct ColorRGB { uint8_t r, g, b; }; struct TouchPoint { int16_t x, y; bool touched; }; // 6 predefined colors using LovyanGFX system colors ColorRGB colorButtons[6] = { {255, 0, 0}, // RED {0, 255, 0}, // GREEN {0, 0, 255}, // BLUE {255, 255, 150}, // WHITE {255, 150, 0}, // YELLOW {255, 0, 255} // PURPLE }; String colorNames[6] = {"RED", "GREEN", "BLUE", "WHITE", "YELLOW", "PURPLE"}; uint32_t systemColors[6] = {TFT_RED, TFT_GREEN, TFT_BLUE, TFT_WHITE, TFT_YELLOW, TFT_MAGENTA}; bool ledOn = true; int selectedColor = 0; // Default to RED TouchPoint lastTouch = {0, 0, false}; void setup() { Serial.begin(115200); delay(2000); Serial.println("Simple RGB LED Controller Starting..."); // Initialize display Serial.println("Initializing display..."); lcd.init(); lcd.setBrightness(255); // Test display lcd.clear(TFT_BLACK); lcd.setFont(&fonts::FreeSans12pt7b); lcd.setTextColor(TFT_WHITE); lcd.setTextDatum(middle_center); lcd.drawString("RGB Controller", SCREEN_WIDTH/2, SCREEN_HEIGHT/2); delay(2000); // Initialize RGB LED pins Serial.println("Initializing RGB LED..."); pinMode(RGB_RED, OUTPUT); pinMode(RGB_GREEN, OUTPUT); pinMode(RGB_BLUE, OUTPUT); // Turn off LED initially setLEDColor(0, 0, 0); // Draw UI drawUI(); updateLED(); Serial.println("Setup complete!"); } void loop() { TouchPoint touch = readTouch(); if (touch.touched && !lastTouch.touched) { handleTouch(touch.x, touch.y); } lastTouch = touch; delay(50); } TouchPoint readTouch() { TouchPoint point = {0, 0, false}; uint16_t x, y; if (lcd.getTouch(&x, &y)) { point.x = x; point.y = y; point.touched = true; } return point; } void drawUI() { // Clear screen lcd.clear(COLOR_BG); // Draw header drawHeader(); // Draw color buttons drawColorButtons(); } void drawHeader() { // Header background lcd.fillRect(0, 0, SCREEN_WIDTH, HEADER_HEIGHT, COLOR_HEADER); // Title lcd.setFont(&fonts::Font4); lcd.setTextColor(COLOR_WHITE); lcd.setTextDatum(middle_left); lcd.drawString("RGB LED Control", 15, HEADER_HEIGHT/2); // ON/OFF Toggle drawToggle(); } void drawToggle() { uint32_t sliderX = ledOn ? TOGGLE_X + TOGGLE_WIDTH - 37 : TOGGLE_X + 3; // Toggle background - GREEN when ON, RED when OFF if (ledOn) { lcd.fillRoundRect(TOGGLE_X, TOGGLE_Y, TOGGLE_WIDTH, TOGGLE_HEIGHT, TOGGLE_HEIGHT/2, TFT_GREEN); } else { lcd.fillRoundRect(TOGGLE_X, TOGGLE_Y, TOGGLE_WIDTH, TOGGLE_HEIGHT, TOGGLE_HEIGHT/2, TFT_RED); } // Toggle slider lcd.fillCircle(sliderX + 17, TOGGLE_Y + TOGGLE_HEIGHT/2, 17, COLOR_WHITE); // Add shadow effect lcd.drawCircle(sliderX + 17, TOGGLE_Y + TOGGLE_HEIGHT/2, 17, COLOR_BLACK); } void drawColorButtons() { for (int i = 0; i < 6; i++) { int row = i / BUTTON_COLS; int col = i % BUTTON_COLS; int x = BUTTON_MARGIN + col * (BUTTON_WIDTH + BUTTON_MARGIN); int y = HEADER_HEIGHT + BUTTON_MARGIN + row * (BUTTON_HEIGHT + BUTTON_MARGIN); drawColorButton(i, x, y); } } void drawColorButton(int colorIndex, int x, int y) { // Draw border with layered effect if (colorIndex == selectedColor) { // Selected - 6px silver border only for (int i = 0; i < 6; i++) { lcd.drawRoundRect(x - i, y - i, BUTTON_WIDTH + 2*i, BUTTON_HEIGHT + 2*i, 12, TFT_SILVER); } } else { // Non-selected - 2px silver inner + 4px black outer // First draw 2px Silver inner border for (int i = 0; i < 2; i++) { lcd.drawRoundRect(x - i, y - i, BUTTON_WIDTH + 2*i, BUTTON_HEIGHT + 2*i, 12, TFT_SILVER); } // Then draw 2px Black outer border for (int i = 2; i < 6; i++) { lcd.drawRoundRect(x - i, y - i, BUTTON_WIDTH + 2*i, BUTTON_HEIGHT + 2*i, 12, TFT_BLACK); } } // Draw button background if (colorIndex == 0) { // RED lcd.fillRoundRect(x, y, BUTTON_WIDTH, BUTTON_HEIGHT, 12, TFT_RED); } else if (colorIndex == 1) { // GREEN lcd.fillRoundRect(x, y, BUTTON_WIDTH, BUTTON_HEIGHT, 12, TFT_GREEN); } else if (colorIndex == 2) { // BLUE lcd.fillRoundRect(x, y, BUTTON_WIDTH, BUTTON_HEIGHT, 12, TFT_BLUE); } else if (colorIndex == 3) { // WHITE lcd.fillRoundRect(x, y, BUTTON_WIDTH, BUTTON_HEIGHT, 12, TFT_WHITE); } else if (colorIndex == 4) { // YELLOW lcd.fillRoundRect(x, y, BUTTON_WIDTH, BUTTON_HEIGHT, 12, TFT_YELLOW); } else if (colorIndex == 5) { // PURPLE/MAGENTA lcd.fillRoundRect(x, y, BUTTON_WIDTH, BUTTON_HEIGHT, 12, TFT_MAGENTA); } lcd.setFont(&fonts::FreeSansBold9pt7b);if (colorIndex == 3 || colorIndex == 4) { // Black text for WHITE and YELLOW lcd.setTextColor(TFT_BLACK); } else { // White text for all other colors lcd.setTextColor(TFT_WHITE); } lcd.setTextDatum(middle_center); lcd.drawString(colorNames[colorIndex], x + BUTTON_WIDTH/2, y + BUTTON_HEIGHT/2); } void handleTouch(int x, int y) { Serial.printf("Touch detected: X=%d, Y=%d\n", x, y); // Check if toggle was touched if (x >= TOGGLE_X && x <= TOGGLE_X + TOGGLE_WIDTH && y >= TOGGLE_Y && y <= TOGGLE_Y + TOGGLE_HEIGHT) { ledOn = !ledOn; drawToggle(); updateLED(); Serial.println(ledOn ? "LED turned ON" : "LED turned OFF"); return; } // Check if any color button was touched for (int i = 0; i < 6; i++) { int row = i / BUTTON_COLS; int col = i % BUTTON_COLS; int buttonX = BUTTON_MARGIN + col * (BUTTON_WIDTH + BUTTON_MARGIN); int buttonY = HEADER_HEIGHT + BUTTON_MARGIN + row * (BUTTON_HEIGHT + BUTTON_MARGIN); if (x >= buttonX && x <= buttonX + BUTTON_WIDTH && y >= buttonY && y <= buttonY + BUTTON_HEIGHT) { // Update selection selectedColor = i; // Redraw ALL color buttons to ensure proper border clearing drawColorButtons(); // Update LED updateLED(); Serial.printf("Color selected: %s (R:%d G:%d B:%d)\n", colorNames[i].c_str(), colorButtons[i].r, colorButtons[i].g, colorButtons[i].b); return; } } } void updateLED() { if (ledOn) { ColorRGB color = colorButtons[selectedColor]; setLEDColor(color.r, color.g, color.b); } else { setLEDColor(0, 0, 0); } } void setLEDColor(uint8_t r, uint8_t g, uint8_t b) { // Common cathode RGB LED analogWrite(RGB_RED, r); analogWrite(RGB_GREEN, g); analogWrite(RGB_BLUE, b); } |








Мне важно всё по программированию микроконтроллеров
Очень похвально что вы стремитесь в новым знаниям