• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ESP8266+ST7735S, как заставить работать корректно кириллические шрифты

Fill

New member
Решил тут поиграться с дисплеем ST7735S, ну какие-то навыки есть минимальные, интернет + GPT в помощь
Код:
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include <TimeLib.h>
#include <OneWire.h>
#include <DallasTemperature.h>


// Подключение дисплея
#define TFT_CS   D2
#define TFT_RST  D4
#define TFT_DC   D3

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

// Настройки Wi-Fi
const char *ssid = "Имя сети";
const char *password = "Пароль";

// Настройки NTP
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "ru.pool.ntp.org", 10800, 60000); // Синхронизация каждую минуту (60000 мс)

// Подключение DS18B20
#define ONE_WIRE_BUS D1 // Пин, к которому подключен датчик
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// Переменные для времени
unsigned long previousEpoch = 0;
int prevHour = -1;
int prevMinute = -1;
int prevSecond = -1;
bool colonVisible = true;

// Переменные для температуры
float currentTemp = 0.0;
float prevTemp = -100.0;
bool tempRequestInProgress = false; // Флаг состояния обновления температуры

// Переменные для таймера обновления температуры
unsigned long lastTempUpdate = 0; // Время последнего обновления температуры
const unsigned long tempUpdateInterval = 1000; // Интервал обновления температуры (мс)

void updateTemperature() {
  if (!tempRequestInProgress) {
    // Запрос температуры
    sensors.requestTemperatures();
    tempRequestInProgress = true;
    return;
  }

  // Считывание температуры
  currentTemp = sensors.getTempCByIndex(0);
  tempRequestInProgress = false;

  // Если температура изменилась, обновляем её отображение
  if (abs(currentTemp - prevTemp) >= 0.1) {
    prevTemp = currentTemp;

    tft.setTextSize(4);
    tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
    tft.setCursor(5, 60);
    tft.printf("%.1f C", currentTemp);

    // Рисуем символ градуса и "C"
    tft.setTextSize(1); // Уменьшаем размер шрифта для градуса и C
    tft.setCursor(110, 60); // Место для символа градуса
    tft.print("o");        // Символ "C"
  }
}

void setup() {
  Serial.begin(115200);

  // Инициализация дисплея
  tft.initR(INITR_BLACKTAB);
  tft.fillScreen(ST7735_BLACK);
  tft.setRotation(1);

  // Установка яркости дисплея (по желанию)
  pinMode(TFT_LED, OUTPUT);
  analogWrite(TFT_LED, 64); // Уменьшаем яркость (от 0 до 255)

  // Подключение к Wi-Fi
  tft.setTextSize(1);
  tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
  tft.setCursor(10, 10);
  tft.print("Connecting...");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  tft.fillScreen(ST7735_BLACK);
  tft.setCursor(10, 10);
  tft.print("WiFi connected!");

  // Инициализация NTP и DS18B20
  timeClient.begin();
  timeClient.update();
  sensors.begin();

  // Установка времени
  setTime(timeClient.getEpochTime());
  previousEpoch = now();

  // Обновление температуры при старте
  updateTemperature();

  delay(2000);
  tft.fillScreen(ST7735_BLACK);
}

void loop() {
  // Обновление времени
  timeClient.update();
  unsigned long currentEpoch = timeClient.getEpochTime();
  if (currentEpoch != previousEpoch) {
    setTime(currentEpoch);
    previousEpoch = currentEpoch;
  }

  int currentHour = hour();
  int currentMinute = minute();
  int currentSecond = second();

  // Обновление времени на дисплее
  if (currentHour != prevHour || currentMinute != prevMinute) {
    prevHour = currentHour;
    prevMinute = currentMinute;

    tft.setTextSize(5);
    tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
    tft.setCursor(5, 10);
    tft.printf("%02d", currentHour);

    tft.setCursor(95, 10);
    tft.printf("%02d", currentMinute);
  }

  // Мигающее двоеточие
  if (currentSecond != prevSecond) {
    prevSecond = currentSecond;
    colonVisible = !colonVisible;

    tft.setTextSize(5);
    tft.setCursor(63, 10);
    if (colonVisible) {
      tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
      tft.print(":");
    } else {
      tft.setTextColor(ST7735_BLACK, ST7735_BLACK);
      tft.print(":");
    }
  }

  // Таймер обновления температуры
  unsigned long currentMillis = millis();
  if (currentMillis - lastTempUpdate >= tempUpdateInterval) {
    lastTempUpdate = currentMillis;
    updateTemperature();
  }
}
Вышел вот такой рабочий код, попытки нарисовать символ "градуса" не привели к успеху, решил сразу копать сразу в сторону русификации, думаю там заодно и с символом "градуса" разберусь....
В общем насколько я понял, без подключения стороннего шрифта, дисплей кириллицу не поддерживает, всяческие перекодировки из utf8 в win1251 к успеху не привели - иероглифы.
Далее вот такой код с подключением шрифта
Код:
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include <TimeLib.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "FontsRus/FreeMonoBold6.h"

// Подключение дисплея
#define TFT_CS   D2
#define TFT_RST  D4
#define TFT_DC   D3

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

// Настройки Wi-Fi
const char *ssid = "Имя сети";
const char *password = "Пароль";

// Настройки NTP
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "ru.pool.ntp.org", 10800, 60000); // Синхронизация каждую минуту (60000 мс)

// Подключение DS18B20
#define ONE_WIRE_BUS D1 // Пин, к которому подключен датчик
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// Переменные для времени
unsigned long previousEpoch = 0;
int prevHour = -1;
int prevMinute = -1;
int prevSecond = -1;
bool colonVisible = true;

// Переменные для температуры
float currentTemp = 0.0;
float prevTemp = -100.0;
bool tempRequestInProgress = false; // Флаг состояния обновления температуры

// Переменные для таймера обновления температуры
unsigned long lastTempUpdate = 0; // Время последнего обновления температуры
const unsigned long tempUpdateInterval = 1000; // Интервал обновления температуры (мс)

void updateTemperature() {
  if (!tempRequestInProgress) {
    // Запрос температуры
    sensors.requestTemperatures();
    tempRequestInProgress = true;
    return;
  }

  // Считывание температуры
  currentTemp = sensors.getTempCByIndex(0);
  tempRequestInProgress = false;

  // Если температура изменилась, обновляем её отображение
  if (abs(currentTemp - prevTemp) >= 0.1) {
    prevTemp = currentTemp;

    tft.setTextSize(3);
    tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
    tft.setCursor(5, 80);
    tft.fillRect(5, 80, 120, 30, ST7735_BLACK); // Очистка области перед выводом температуры
    tft.printf("%.1f C", currentTemp);
  }
}

void setup() {
  Serial.begin(115200);

  // Инициализация дисплея
  tft.initR(INITR_BLACKTAB);
  tft.fillScreen(ST7735_BLACK);
  tft.setRotation(1);

  // Подключение к Wi-Fi
  tft.setTextSize(1);
  tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
  tft.setFont(&FreeMonoBold6pt8b);  // Установка кастомного шрифта
  tft.setCursor(10, 10);
  tft.print("Подключение...");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  tft.fillScreen(ST7735_BLACK);
  tft.setCursor(10, 10);
  tft.print("WiFi connected!");

  // Инициализация NTP и DS18B20
  timeClient.begin();
  timeClient.update();
  sensors.begin();

  // Установка времени
  setTime(timeClient.getEpochTime());
  previousEpoch = now();

  // Обновление температуры при старте
  updateTemperature();

  delay(2000);
  tft.fillScreen(ST7735_BLACK);
}

void loop() {
  // Обновление времени
  timeClient.update();
  unsigned long currentEpoch = timeClient.getEpochTime();
  if (currentEpoch != previousEpoch) {
    setTime(currentEpoch);
    previousEpoch = currentEpoch;
  }

  int currentHour = hour();
  int currentMinute = minute();
  int currentSecond = second();

  // Обновление времени на дисплее
  if (currentHour != prevHour || currentMinute != prevMinute) {
    prevHour = currentHour;
    prevMinute = currentMinute;

    // Очистка области перед обновлением часов
    tft.setTextSize(3);
    tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
    tft.fillRect(5, 35, 60, 30, ST7735_BLACK); // Очистка области для часов
    tft.setCursor(5, 35);
    tft.printf("%02d", currentHour);

    // Очистка области перед обновлением минут
    tft.fillRect(95, 35, 60, 30, ST7735_BLACK); // Очистка области для минут
    tft.setCursor(95, 35);
    tft.printf("%02d", currentMinute);
  }

  // Мигающее двоеточие
  if (currentSecond != prevSecond) {
    prevSecond = currentSecond;
    colonVisible = !colonVisible;

    tft.setTextSize(3);
    tft.setCursor(63, 35);
    tft.fillRect(63, 35, 20, 30, ST7735_BLACK); // Очистка области для двоеточия
    if (colonVisible) {
      tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
      tft.print(":");
    } else {
      tft.setTextColor(ST7735_BLACK, ST7735_BLACK);
      tft.print(":");
    }
  }

  // Таймер обновления температуры
  unsigned long currentMillis = millis();
  if (currentMillis - lastTempUpdate >= tempUpdateInterval) {
    lastTempUpdate = currentMillis;
    updateTemperature();
  }
}
в итоге и так и сяк fillRect(), fillScreen() работает криво, выглядит не эстетично, через setTextColor(foreground, background) работает идеально, но только со стандартным шрифтом, а с костюмными происходит наслоение.
photo_2025-02-10_12-59-43.jpg
photo_2025-02-10_13-01-16.jpg
 

pvvx

Активный участник сообщества
1739278863612.png
Поиск Google, YouTube или DeepSeek: "squareline studio esp32" и т.д.
Бесплатной версии SquareLine вам хватит на создание любых меню и отображений для ESP.
 
Сверху Снизу