я черпаю вдохновение в заказах в сети))) с вау эффектом наверное нечего не придумать… я додумался только до того что бы часы сделать, время из сети (выводится с помощью фото цифр) + анимация ниже, 10 ползунков которые указывают какую анимацию выводить по очереди…
кстате совершенно случайно обнаружил баг, каждое второе, четвертое, 6, 8 воспроизведение зацикленной анимации выводится 34-36 секунд, а каждое 1,3,5 и т.д. за 20-22 секунды и просто в тупике, скорость может быть гораздо больше, и обидно как то иногда смотреть медленную анимацию
вот последний код, библиотека если что тут https://github.com/Bodmer/TJpg_Decoder лично я просто в тупике… если есть время, и для вас причина очевидна, подскажите пж в чем она))) и можно выводить еще быстрее кажется…
#include <TFT_eSPI.h>
#include <TJpg_Decoder.h>
#include <SPI.h>
#include <SD.h>
using namespace fs;
#define SD_CS 5
#define TFT_BL 12
#define TOTAL_FRAMES 420
#define SCREEN_W 128
#define SCREEN_H 160
#define IMG_W 113
#define IMG_H 164
#define POS_X ((SCREEN_W - IMG_W) / 2)
#define POS_Y ((SCREEN_H - IMG_H) / 2)
TFT_eSPI tft = TFT_eSPI();
uint16_t* frameBuffer = nullptr;
uint16_t currentFrame = 0;
uint8_t* jpgBuffer = nullptr;
size_t jpgSize = 0;
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) {
if (y >= tft.height()) return 0;
if (frameBuffer != nullptr) {
uint16_t* dest = frameBuffer + (y * SCREEN_W + x);
uint16_t* src = bitmap;
for (int row = 0; row < h; row++) {
memcpy(dest + row * SCREEN_W, src + row * w, w * 2);
}
}
return 1;
}
bool loadJpgToMemory(uint16_t frameNum) {
char filename[20];
sprintf(filename, "/%03d.jpg", frameNum);
File file = SD.open(filename);
if (!file) return false;
jpgSize = file.size();
if (jpgBuffer != nullptr) {
free(jpgBuffer);
jpgBuffer = nullptr;
}
jpgBuffer = (uint8_t*)malloc(jpgSize);
if (jpgBuffer == nullptr) {
file.close();
return false;
}
size_t bytesRead = file.read(jpgBuffer, jpgSize);
file.close();
return bytesRead == jpgSize;
}
// ★ ФУНКЦИЯ СБРОСА ДЕКОДЕРА ★
void resetDecoder() {
// Полный сброс декодера
TJpgDec.setJpgScale(1);
TJpgDec.setCallback(tft_output);
// Небольшая пауза для стабилизации
delay(5);
Serial.println("Decoder reset!");
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n=== ST7735 FIXED ===");
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, HIGH);
tft.init();
tft.setRotation(0);
tft.setSwapBytes(true);
tft.fillScreen(TFT_BLACK);
if (!SD.begin(SD_CS, SPI)) {
Serial.println("SD Error!");
while(1);
}
Serial.println("SD mounted!");
TJpgDec.setJpgScale(1);
TJpgDec.setCallback(tft_output);
if (!SD.exists("/001.jpg")) {
Serial.println("File 001.jpg not found!");
while(1);
}
size_t bufferSize = SCREEN_W * SCREEN_H * sizeof(uint16_t);
frameBuffer = (uint16_t*)malloc(bufferSize);
if (frameBuffer == nullptr) {
Serial.println("No memory!");
while(1);
}
if (!loadJpgToMemory(1)) {
Serial.println("Failed to load first jpg!");
while(1);
}
memset(frameBuffer, 0, bufferSize);
TJpgDec.drawJpg(POS_X, POS_Y, jpgBuffer, jpgSize);
tft.pushImage(0, 0, SCREEN_W, SCREEN_H, frameBuffer);
Serial.println("Started!");
}
void loop() {
char filename[20];
sprintf(filename, "/%03d.jpg", currentFrame + 1);
if (loadJpgToMemory(currentFrame + 1)) {
memset(frameBuffer, 0, SCREEN_W * SCREEN_H * 2);
TJpgDec.drawJpg(POS_X, POS_Y, jpgBuffer, jpgSize);
tft.pushImage(0, 0, SCREEN_W, SCREEN_H, frameBuffer);
}
currentFrame++;
// ★ КОГДА АНИМАЦИЯ ЗАКАНЧИВАЕТСЯ - ПОЛНЫЙ СБРОС ★
if (currentFrame >= TOTAL_FRAMES) {
currentFrame = 0;
// Освобождаем буфер
if (jpgBuffer != nullptr) {
free(jpgBuffer);
jpgBuffer = nullptr;
}
// Сбрасываем декодер
resetDecoder();
// Принудительно очищаем экран
tft.fillScreen(TFT_BLACK);
// Загружаем первый кадр заново
if (loadJpgToMemory(1)) {
memset(frameBuffer, 0, SCREEN_W * SCREEN_H * 2);
TJpgDec.drawJpg(POS_X, POS_Y, jpgBuffer, jpgSize);
tft.pushImage(0, 0, SCREEN_W, SCREEN_H, frameBuffer);
}
Serial.println("=== CYCLE RESTART ===");
// Небольшая задержка для стабилизации
delay(10);
}
}