ESP32-C3 и TFT-дисплей: вывод времени по Wi-Fi

          ESP32-C3 Super Mini — это компактная отладочная плата, построенная на базе системы на кристалле (SoC) ESP32C3FH4 от компании Espressif Systems. Если Вы уже познакомились с Super Mini, то пора приступать к практике!

          В рамках данной статьи мы подробно рассмотрим алгоритм начала работы с отладочной платой. Выполним быстрый старт с использованием среды программирования Arduino IDE.

          Но мы не просто классически помигаем светодиодом «Hello, World!». Мы подключим TFT-дисплей и будем выводить на него текущее реальное время, получая данные из Интернета через Wi-Fi. Таким образом, мы рассмотрим сразу самые интересные задачи: подключение внешней периферии и работа с Wi-Fi.

ESP32-C3 TFT-дисплей ST7735

Подключение TFT-дисплея ST7735S к ESP32-C3

          Для начала соберём экспериментальную схему. Воспользуемся TFT-дисплеем на базе контроллера ST7735S с диагональю экрана 0,96 дюйма и разрешением 80 на 160 пикселей. Подключим индикатор к Super Mini в соответствии с таблицей и схемой, представленными ниже:

          Ниже представлен макет в сборе:


Настройка Arduino IDE для ESP32-С3

          Для работы с ESP32 необходимо убедиться, что среда разработки Arduino IDE 2 имеет необходимые настройки. Для этого в главном меню «Файл» из выпадающего списка выберите раздел «Параметры»:

          В поле «Дополнительные ссылки для Менеджера плат» вставьте указанную ниже ссылку, после чего нажмите кнопку «OK»:

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

          Далее переходим к загрузке библиотек для отладочных плат. Для этого в меню «Инструменты» выбираем «Плата» -> «Менеджер плат»:

          Откроется менеджер, в котором нужно найти по запросу «esp32» библиотеки «Arduino ESP32 Boards» и «esp32 от Espressif Systems». Устанавливаем их:

          Установка «esp32 от Espressif Systems» может занять некоторое время. А в процессе установки «Arduino Boards» появится окно с предложением установить драйвера — устанавливаем:

          По завершению установки подключите контроллер к компьютеру, используя желательно USB-кабель длиной не более 1,5 метра. При первом подключении на Windows 10 должна произойти автоматическая установка драйвера (USB JTAG/serial debug unit):

          В диспетчере устройств должно появиться соответствующее устройство:

          После всех установок выбираем целевую плату ESP32C3 Dev Module, которая соответствует нашей Super Mini:

          Также укажите COM-порт, который при установке драйверов был выделен системой для работы:

          Возможно, если Вы используете более старую версию среды разработки, то потребуется дополнительно установить драйвера для USB-UART преобразователей CH340/341 или CP2102. Для этого скачайте и установите драйвера:

ссылка на CH340

ссылка на CP2102.

          Как уже упоминалось в начале статьи, в рамках проекта «быстрый старт» мы будем выводить на дисплей реальное Московское время, получаемое из Интернета, к которому подключимся по Wi-Fi.

          Для работы потребуются библиотеки Adafruit_ST7735 (с библиотекой tft_eSPI могут быть проблемы из-за несовместимости с SPI-интерфейсом чипа):

          Более подробно по работе с TFT-дисплеем на базе контроллера ST7735 с библиотекой Adafruit_ST7735 Вы можете прочитать в соответствующей инструкции.

          Также потребуется библиотека NTPClient, которая позволяет соединяться с сервером NTP (Network Time Protocol) и поддерживать синхронизацию времени:


Программный код (скетч)

          Теперь перейдём к коду программы. Ниже представлен полный листинг кода с подробными комментариями:

// Подключение необходимых библиотек
#include <Adafruit_GFX.h>        // Базовая графическая библиотека для дисплеев
#include <Adafruit_ST7735.h>     // Специфичная библиотека для дисплеев ST7735
#include <SPI.h>                 // Библиотека для работы с SPI-интерфейсом
#include <WiFi.h>                // Библиотека для работы с WiFi на ESP32
#include <NTPClient.h>           // Библиотека NTP-клиента для получения времени
#include <WiFiUdp.h>             // Библиотека UDP для работы с NTP

// Настройки WiFi сети
const char* ssid = "SSID_Wi-Fi";       // Название WiFi сети (SSID)
const char* password = "password";     // Пароль от WiFi сети

// Настройки временной зоны
const long utcOffsetInSeconds = 10800; // Смещение UTC+3 для Москвы (3 часа × 3600 секунд)

// Создание объектов для работы с временем
WiFiUDP ntpUDP;                        // UDP-соединение для NTP
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds); // NTP-клиент

// Определение пинов для подключения дисплея
#define TFT_CS    7   // Пин выбора чипа
#define TFT_RST   10  // Пин сброса
#define TFT_DC    1   // Пин выбора данных/команды
#define TFT_SCLK  4   // Пин тактового сигнала
#define TFT_MOSI  6   // Пин передачи данных

// Инициализация объекта дисплея с указанием используемых пинов
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

// Переменные для отслеживания изменений времени
int lastHour = -1;    // Предыдущее значение часов (инициализировано невалидным значением)
int lastMinute = -1;  // Предыдущее значение минут
int lastSecond = -1;  // Предыдущее значение секунд
bool firstRun = true; // Флаг первого запуска программы

void setup() {
  // Инициализация последовательного порта для отладки
  Serial.begin(115200);
  
  // ИНИЦИАЛИЗАЦИЯ ДИСПЛЕЯ
  tft.initR(INITR_BLACKTAB);  // Инициализация дисплея с конкретной таблицей инициализации
  tft.setRotation(3);         // Установка ориентации дисплея (3 = 270 градусов)
  tft.fillScreen(ST7735_BLACK); // Очистка экрана черным цветом
  
  // Настройки Wi-Fi
  WiFi.setTxPower(WIFI_POWER_19_5dBm);	// максимальная мощность
  WiFi.setSleep(false);
  WiFi.mode(WIFI_STA);

  // ПОДКЛЮЧЕНИЕ К WI-FI
  Serial.println("Подключение к WiFi...");
  WiFi.begin(ssid, password); // Начало процесса подключения к WiFi
  
  // Ожидание успешного подключения к WiFi
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);              // Пауза 500 мс между попытками
    Serial.print(".");       // Вывод точки в монитор порта для индикации процесса
  }
  
  // Вывод сообщения об успешном подключении
  Serial.println("\nWiFi подключен!");
  Serial.print("IP адрес: ");
  Serial.println(WiFi.localIP()); // Вывод полученного IP-адреса
  
  // НАСТРОЙКА NTP-КЛИЕНТА
  timeClient.begin();                    // Запуск NTP-клиента
  timeClient.setTimeOffset(utcOffsetInSeconds); // Установка временного смещения
  
  // Получение времени с NTP-сервера
  delay(1000);        // Краткая пауза для стабилизации соединения
  timeClient.update(); // Первоначальное обновление времени
  
  // ОТРИСОВКА СТАТИЧЕСКИХ ЭЛЕМЕНТОВ ИНТЕРФЕЙСА
  drawStaticElements(); // Вызов функции отрисовки неизменяемых элементов
}

void loop() {
  timeClient.update(); // Запрос актуального времени с NTP-сервера
  
  // ПРЕОБРАЗОВАНИЕ ВРЕМЕНИ В ЧАСЫ, МИНУТЫ И СЕКУНДЫ
  unsigned long epochTime = timeClient.getEpochTime(); // Получение времени в формате Unix Epoch
  struct tm *ptm = gmtime((time_t *)&epochTime);       // Преобразование в структуру tm
  
  // Извлечение компонентов времени из структуры
  int hour = ptm->tm_hour;   // Текущие часы (0-23)
  int minute = ptm->tm_min;  // Текущие минуты (0-59)
  int second = ptm->tm_sec;  // Текущие секунды (0-59)
  
  // ПРОВЕРКА ИЗМЕНЕНИЯ ВРЕМЕНИ ДЛЯ ОПТИМИЗАЦИИ ОБНОВЛЕНИЯ ДИСПЛЕЯ
  // Обновляем дисплей только если время изменилось или это первый запуск
  if (firstRun || hour != lastHour || minute != lastMinute || second != lastSecond) {
    updateTimeDisplay(hour, minute, second); // Вызов функции обновления отображения времени
    
    // Сохранение текущих значений для сравнения в следующей итерации
    lastHour = hour;
    lastMinute = minute;
    lastSecond = second;
    firstRun = false; // Сброс флага первого запуска
  }
  
  delay(200); // Пауза 200 мс перед следующей итерацией для снижения нагрузки
}

void drawStaticElements() {
  // Функция отрисовки статических (неизменяемых) элементов интерфейса
  
  // Настройка параметров текста для надписи "MOSCOW"
  tft.setTextColor(ST7735_WHITE); // Установка белого цвета текста
  tft.setTextSize(2);             // Установка размера шрифта 2 (примерно 16 пикселей в высоту)
  tft.setCursor(40, 40);          // Установка позиции курсора для начала текста (x=40, y=40)
  
  tft.print("MOSCOW");            // Вывод текста "MOSCOW" на дисплей
}

void updateTimeDisplay(int hour, int minute, int second) {
  // Функция обновления отображения времени на дисплее
  
  // ОЧИСТКА ОБЛАСТИ ВРЕМЕНИ ПЕРЕД ВЫВОДОМ НОВОГО ЗНАЧЕНИЯ
  // fillRect(x, y, width, height, color) - рисует закрашенный прямоугольник
  // Параметры подобраны для полного покрытия текста "00:00:00" размером шрифта 3
  tft.fillRect(5, 65, 150, 35, ST7735_BLACK); // Очистка области черным цветом
  
  // НАСТРОЙКА ПАРАМЕТРОВ ТЕКСТА ДЛЯ ВЫВОДА ВРЕМЕНИ
  tft.setTextColor(ST7735_CYAN); // Установка бирюзового цвета для времени
  tft.setTextSize(3);            // Установка крупного размера шрифта (примерно 24 пикселя)
  tft.setCursor(10, 70);         // Установка позиции для вывода времени (x=10, y=70)
  
  // ФОРМАТИРОВАНИЕ ВРЕМЕНИ В СТРОКУ
  char timeStr[9]; // Создание буфера для строки времени (8 символов + нуль-терминатор)
  
  // Форматирование времени в формат "ЧЧ:ММ:СС" с ведущими нулями
  sprintf(timeStr, "%02d:%02d:%02d", hour, minute, second);
  // %02d - целое число, дополненное нулями до 2 знаков
  
  tft.print(timeStr); // Вывод отформатированной строки времени на дисплей
}

          Перед компиляцией и прошивкой замените имя сети Wi-Fi и пароль доступа.

          В коде для оптимизации обновление дисплея производится только при изменении значения времени (динамические элементы). При этом статические элементы (надпись «MOSCOW») рисуются один раз при инициализации контроллера в функции setup().

          Чтобы не выполнять полную перерисовку всего экрана, очищается лишь только область отображения времени.


Заключение

          На этом наш быстрый старт успешно завершен! Мы не просто помигали светодиодом, а создали полноценное сетевое устройство, которое самостоятельно подключается к Интернету, получает актуальные данные и выводит их на экран.

Читайте также:  Измерение переменного напряжения микроконтроллером