Buonasera, ho creato un progetto in cui volevo far apparire sul mio display tft 480x320 SPI un immagine jpg a tutto schermo, che ho, tramite photoshop, ridimensionato proprio a 480x320 e salvato in jpg. Grazie alla libreria JPEGDecoder pensavo di decomprimere l'immagine e farla visualizzare sul mio schermo, ma tutto cio che si vede è quello che allego nella foto. Qualcuno saprebbe dirmi il motivo? Aggiungo anche il codice che ho caricato sul mio ESP32.
#include <SPI.h>
#include <SD.h>
#include <TFT_eSPI.h>
#include <JPEGDecoder.h>
#define SD_CS 5 // Chip Select per SD
#define DISPLAY_CS 15 // Chip Select per TFT
#define TOUCH_CS 21 // Chip Select per Touch (se presente)
TFT_eSPI tft = TFT_eSPI();
// ============================
// Disattiva tutti i CS
// ============================
void disattivaTuttiCS() {
digitalWrite(SD_CS, HIGH);
digitalWrite(DISPLAY_CS, HIGH);
digitalWrite(TOUCH_CS, HIGH);
}
// ============================
// Setup
// ============================
void setup() {
Serial.begin(115200);
delay(500);
pinMode(SD_CS, OUTPUT);
pinMode(DISPLAY_CS, OUTPUT);
pinMode(TOUCH_CS, OUTPUT);
disattivaTuttiCS();
tft.begin();
Serial.println("🔧 Inizializzazione SD...");
digitalWrite(SD_CS, LOW);
delay(500);
if (!SD.begin(SD_CS, tft.getSPIinstance())) {
Serial.println("❌ Errore: SD non montata!");
return;
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
Serial.println("❌ Nessuna SD rilevata.");
return;
}
Serial.print("📀 SD trovata: ");
switch (cardType) {
case CARD_MMC: Serial.println("MMC"); break;
case CARD_SD: Serial.println("SDSC"); break;
case CARD_SDHC: Serial.println("SDHC"); break;
default: Serial.println("Sconosciuto"); break;
}
Serial.print("📏 Dimensione: ");
Serial.print(SD.cardSize() / (1024 * 1024));
Serial.println(" MB");
tft.setRotation(1); // landscape
tft.fillScreen(TFT_BLACK);
}
// ============================
// Loop
// ============================
void loop() {
mostraJPEG("/masarlogo_sd.jpg", 0, 0); // Carica solo l'immagine masarlogo.jpg
delay(3000); // Rimuovi altre immagini e lascia solo questa
}
// ===================================
// Mostra immagine JPG
// ===================================
void mostraJPEG(const char *filename, int xpos, int ypos) {
disattivaTuttiCS();
digitalWrite(SD_CS, LOW);
File jpegFile = SD.open(filename, FILE_READ);
if (!jpegFile) {
Serial.print("❌ Errore apertura file: ");
Serial.println(filename);
return;
}
Serial.println("===========================");
Serial.print("📂 Disegno file: "); Serial.println(filename);
Serial.println("===========================");
bool decoded = JpegDec.decodeSdFile(jpegFile);
jpegFile.close();
digitalWrite(SD_CS, HIGH);
digitalWrite(DISPLAY_CS, LOW);
if (decoded) {
jpegInfo(); // stampa informazioni
jpegRender(xpos, ypos);
} else {
Serial.println("❌ Formato JPEG non supportato.");
}
digitalWrite(DISPLAY_CS, HIGH);
disattivaTuttiCS();
}
// ===================================
// Rendering JPEG
// ===================================
void jpegRender(int xpos, int ypos) {
uint16_t *pImg;
uint16_t mcu_w = JpegDec.MCUWidth;
uint16_t mcu_h = JpegDec.MCUHeight;
uint32_t max_x = JpegDec.width + xpos;
uint32_t max_y = JpegDec.height + ypos;
uint32_t min_w = (JpegDec.width % mcu_w == 0) ? mcu_w : JpegDec.width % mcu_w;
uint32_t min_h = (JpegDec.height % mcu_h == 0) ? mcu_h : JpegDec.height % mcu_h;
uint32_t win_w, win_h;
// Calcola la scala per ridimensionare l'immagine allo schermo
uint16_t screenWidth = tft.width();
uint16_t screenHeight = tft.height();
float scaleX = (float)screenWidth / JpegDec.width;
float scaleY = (float)screenHeight / JpegDec.height;
float scale = min(scaleX, scaleY); // Adatta l'immagine mantenendo il rapporto
// Ridimensiona l'immagine se è troppo grande
uint16_t newWidth = JpegDec.width * scale;
uint16_t newHeight = JpegDec.height * scale;
if (newWidth > screenWidth) newWidth = screenWidth;
if (newHeight > screenHeight) newHeight = screenHeight;
bool swap = tft.getSwapBytes();
tft.setSwapBytes(true);
uint32_t drawTime = millis();
while (JpegDec.read()) {
pImg = JpegDec.pImage;
int mcu_x = JpegDec.MCUx * mcu_w + xpos;
int mcu_y = JpegDec.MCUy * mcu_h + ypos;
win_w = (mcu_x + mcu_w <= max_x) ? mcu_w : min_w;
win_h = (mcu_y + mcu_h <= max_y) ? mcu_h : min_h;
// Adatta i blocchi dell'immagine alla dimensione dello schermo
if ((mcu_x + win_w <= newWidth) && (mcu_y + win_h <= newHeight)) {
tft.pushImage(mcu_x, mcu_y, win_w, win_h, pImg);
} else if ((mcu_y + win_h) >= newHeight) {
JpegDec.abort();
}
}
tft.setSwapBytes(swap);
showTime(millis() - drawTime);
}
// ===================================
// Info JPEG
// ===================================
void jpegInfo() {
Serial.println("📷 JPEG Info");
Serial.print("📏 Dimensione: "); Serial.print(JpegDec.width); Serial.print(" x "); Serial.println(JpegDec.height);
Serial.print("🧩 MCU: "); Serial.print(JpegDec.MCUWidth); Serial.print(" x "); Serial.println(JpegDec.MCUHeight);
Serial.print("🧱 Blocchi per riga: "); Serial.println(JpegDec.MCUSPerRow);
Serial.print("🧱 Blocchi per colonna: "); Serial.println(JpegDec.MCUSPerCol);
}
// ===================================
// Tempo di rendering
// ===================================
void showTime(uint32_t msTime) {
Serial.print("⏱️ Disegno completato in ");
Serial.print(msTime);
Serial.println(" ms");
}
