MyTetra Share
Делитесь знаниями!
Вывод обложки на TFT ST7735 с microSD
Время создания: 24.05.2025 13:53
Автор: alensav
Текстовые метки: Вывод обложки на TFT ST7735 с microSD
Раздел: FRAM
Запись: alensav/MyTetra2/main/base/17480839824uoarfscjm/text.html на raw.githubusercontent.com

?? «Хочу реализовать вывод обложки» , 👉 «Хочу добавить громкость через энкодер» , 👉 «Хочу реализовать визуализацию звука» , 👉 «Хочу пример сборки схемы»,

Qwen3-235B-A22B1:49 PM

Отлично! Я подготовлю для тебя четыре части в соответствии с твоими запросами:



📦 1. Вывод обложки на TFT ST7735 с microSD

🔧 Требуется:

  • BMP-изображение размером 128x160 пикселей , 24 бита (RGB), без сжатия.
  • Файлы: cover1.bmp, cover2.bmp и т.д. — должны лежать на SD.



✅ Пример кода: вывод обложки

#include <Adafruit_GFX.h>

#include <Adafruit_ST7735.h>

#include <SdFat.h>


#define SD_CS D8

SdFat SD;


// === Инициализация экрана ===

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


void drawBMP(const char *filename) {

File bmpFile;

int bmpWidth, bmpHeight;

uint32_t bmpImageoffset;

uint32_t rowSize;

uint8_t sdbuffer[54]; // заголовок BMP

uint32_t read1;


if ((bmpFile = SD.open(filename)) == NULL) {

Serial.println("Не могу открыть файл");

return;

}


if (!bmpFile.read(sdbuffer, 54)) {

Serial.println("Ошибка чтения заголовка");

return;

}


// Проверяем сигнатуру BMP

if (sdbuffer[0] != 'B' || sdbuffer[1] != 'M') {

Serial.println("Это не BMP");

return;

}


// Смещение изображения, ширина и высота

memcpy(&bmpImageoffset, sdbuffer + 10, 4);

memcpy(&bmpWidth, sdbuffer + 18, 4);

memcpy(&bmpHeight, sdbuffer + 22, 4);


rowSize = (bmpWidth * 3 + 3) & ~3;


// Очищаем экран

tft.fillScreen(ST77XX_BLACK);


for (int row = bmpHeight - 1; row >= 0; row--) {

bmpFile.seek(bmpImageoffset + (bmpHeight - 1 - row) * rowSize);


for (int col = 0; col < bmpWidth; col++) {

uint8_t r, g, b;

bmpFile.read(&b, 1);

bmpFile.read(&g, 1);

bmpFile.read(&r, 1);


uint16_t color = tft.color565(r, g, b);

tft.drawPixel(col, row, color);

}

}


bmpFile.close();

}

2. Регулировка громкости через энкодер KY-040

✅ Пример кода: изменение громкости

#define ENCODER_CLK D5

#define ENCODER_DT D6


Encoder myEncoder(ENCODER_CLK, ENCODER_DT);

long lastPosition = -999;

uint8_t volume = 127; // Громкость от 0 до 255


void IRAM_ATTR isr_volume() {

long newPosition = myEncoder.read();

if (newPosition != lastPosition) {

if (newPosition > lastPosition) {

volume = min(volume + 5, 255);

} else {

volume = max(volume - 5, 0);

}

lastPosition = newPosition;

setVolume(volume);

}

}


void setVolume(uint8_t vol) {

// Если используешь PCM5102 DAC, можно управлять через I²C

// Либо регулировать через PWM амплитуду, если выход через динамик

Serial.print("Громкость: ");

Serial.println(vol);

}

4. Пример сборки схемы (подключение компонентов)


КОМПОНЕНТ

ПИН ESP8266 (NODEMCU)

KY-040 CLK

D5 (GPIO14)

KY-040 DT

D6 (GPIO12)

KY-040 SW

D7 (GPIO13)

PCM5102 BCK

D5 (GPIO14)

PCM5102 LRC

D8 (GPIO15)

PCM5102 DIN

TX (GPIO1)

FM24CL64B SDA

D2 (GPIO4)

FM24CL64B SCL

D1 (GPIO5)

ST7735 CS

D0 (GPIO16)

ST7735 DC

D3 (GPIO0)

ST7735 RST

D4 (GPIO2)

microSD CS

D8 (GPIO15)

microSD MOSI

D7 (GPIO13)

microSD MISO

D6 (GPIO12)

microSD SCK

D5 (GPIO14)

⚠️ Убедитесь, что питание всех модулей 3.3 В . Используйте стабилизатор LM1117-3.3 или AMS1117-3.3.


📋 Сводная таблица пинов


НАЗНАЧЕНИЕ

NODEMCU

GPIO

Энкодер CLK

D5

GPIO14

Энкодер DT

D6

GPIO12

Энкодер SW

D7

GPIO13

ST7735 CS

D0

GPIO16

ST7735 DC

D3

GPIO0

ST7735 RST

D4

GPIO2

I²S BCK

D5

GPIO14

I²S LRC

D8

GPIO15

I²S DIN

TX

GPIO1

FM24CL64B SDA

D2

GPIO4

FM24CL64B SCL

D1

GPIO5

microSD CS

D8

GPIO15

microSD MOSI

D7

GPIO13

microSD MISO

D6

GPIO12

microSD SCK

D5

GPIO14



🛠 Следующие шаги

Теперь ты можешь объединить всё в один скетч. Если хочешь, я могу подготовить полный пример проекта , который включает:

  • Подключение к Wi-Fi
  • Переключение станций энкодером
  • Сохранение станции в FRAM
  • Логирование событий
  • Отображение информации на ST7735
  • Вывод обложки с SD
  • Изменение громкости
  • Визуализацию звука
  • 1. Web-конфигуратор (веб-интерфейс для настройки станций и Wi-Fi)
  • ✅ Возможности:
  • Настройка Wi-Fi без перепрошивки.
  • Добавление/редактирование списка радиостанций.
  • Изменение громкости, темы экрана и др.
  • 🔧 Пример кода: простой Web-сервер с формой

#include <ESP8266WebServer.h>

ESP8266WebServer server(80);


void handleRoot() {

String html = "<h1>Настройки интернет-радио</h1>";

html += "<form method='POST' action='/save'>";

html += "SSID: <input type='text' name='ssid'><br>";

html += "Пароль: <input type='password' name='pass'><br>";

html += "Станция 1: <input type='text' name='station1'><br>";

html += "Станция 2: <input type='text' name='station2'><br>";

html += "Станция 3: <input type='text' name='station3'><br>";

html += "<button type='submit'>Сохранить</button></form>";


server.send(200, "text/html", html);

}


void handleSave() {

if (server.hasArg("ssid")) ssid = server.arg("ssid");

if (server.hasArg("pass")) password = server.arg("pass");

if (server.hasArg("station1")) stations[0] = server.arg("station1");

if (server.hasArg("station2")) stations[1] = server.arg("station2");

if (server.hasArg("station3")) stations[2] = server.arg("station3");


saveToEEPROM(); // Сохраняем в EEPROM

connectToRadio();


server.send(200, "text/plain", "Настройки сохранены!");

}


void setupWebServer() {

server.on("/", handleRoot);

server.on("/save", HTTP_POST, handleSave);

server.begin();

}

2. OTA-обновления прошивки (по воздуху)

✅ Возможности:

Обновление прошивки без проводов.

Поддержка отладки через Serial по Wi-Fi.

#include <ESP8266mDNS.h>

#include <ArduinoOTA.h>


void setupOTA() {

ArduinoOTA.setPort(8266); // порт для обновлений

ArduinoOTA.setPassword("your_ota_password");


ArduinoOTA.onStart([]() {

Serial.println("Начало обновления...");

});

ArduinoOTA.onEnd([]() {

Serial.println("\nОбновление завершено.");

});


ArduinoOTA.begin();

}


void loop() {

ArduinoOTA.handle();

}

3. Использование EEPROM как резервное хранение

✅ Где использовать:

Резервное хранение текущей станции.

Резервная копия логов при отсутствии FRAM.

Сохранение настроек, если FRAM выйдет из строя.

#include <EEPROM.h>


#define EEPROM_SIZE 512

#define STATION_ADDR 0


void saveToEEPROM() {

EEPROM.begin(EEPROM_SIZE);


EEPROM.put(STATION_ADDR, currentStation);

for (int i = 0; i < 3; i++) {

int offset = 4 + i * 64;

strcpy((char*)EEPROM.getDataPtr() + offset, stations[i].c_str());

}


EEPROM.commit();

}


void loadFromEEPROM() {

EEPROM.begin(EEPROM_SIZE);


EEPROM.get(STATION_ADDR, currentStation);

for (int i = 0; i < 3; i++) {

int offset = 4 + i * 64;

stations[i] = String((char*)EEPROM.getDataPtr() + offset);

}

}

4. Сохранение истории прослушивания

✅ Возможности:

Хранение последних N треков.

Отображение истории на экране или через веб-интерфейс.

#define HISTORY_MAX 10

#define HISTORY_OFFSET 0x100


void logTrack(const char* station, const char* track) {

static uint16_t pos = 0;


char buffer[64];

snprintf(buffer, sizeof(buffer), "[%s] %s", station, track);


for (int i = 0; buffer[i]; i++) {

writeByte(FRAM_ADDR_2, HISTORY_OFFSET + pos++, buffer[i]);

}

writeByte(FRAM_ADDR_2, HISTORY_OFFSET + pos++, '\n');


if (pos > 1024) pos = 0; // циклическая запись

}


void printHistory() {

char c;

Serial.println("История воспроизведения:");

for (uint16_t i = HISTORY_OFFSET; i < HISTORY_OFFSET + 1024; i++) {

c = readByte(FRAM_ADDR_2, i);

if (c == 0) break;

Serial.print((char)c);

}

}

 
MyTetra Share v.0.67
Яндекс индекс цитирования