Componenti · 16 min di lettura

ILI9341 Arduino: collegare il display TFT, touch e immagini da SD

Collegare un display TFT ILI9341 ad Arduino: livelli 3,3 V sull'Uno, Adafruit GFX, touch XPT2046, BMP da SD, ESP32 con TFT_eSPI e soluzione allo schermo bianco.

Collegare un ILI9341 ad Arduino è il modo più economico e diffuso per aggiungere al tuo progetto un display da 240×320 pixel con 65 mila colori. Questi moduli TFT da 2,4 e 2,8 pollici su scheda rossa si collegano in SPI con pochi fili, e le versioni touch hanno anche un controller touch XPT2046 e uno slot per schede microSD. Con un solo modulo puoi mostrare grafica a colori, pulsanti touch e immagini lette dalla scheda. È ideale per menu, cruscotti, giochi e cornici digitali, dove un OLED o un LCD a caratteri non bastano più.

In questa guida imparerai passo dopo passo come funziona il modulo, come collegare in sicurezza le uscite a 5 V dell'Arduino Uno agli ingressi a 3,3 V del display, come disegnare testi, forme e colori con le librerie Adafruit_ILI9341 e Adafruit GFX, come leggere il touch e come mostrare immagini BMP da una scheda SD. Poi vedremo il disegno molto più veloce sull'ESP32 con TFT_eSPI, l'uso di MicroPython sul Raspberry Pi Pico e tutte le cause dello "schermo bianco", un problema che quasi tutti incontrano almeno una volta.

Modulo display TFT a colori ILI9341
Modulo display TFT a colori ILI9341: 240×320 pixel, collegamento SPI e 65 mila colori. Le versioni touch hanno sulla scheda anche un chip XPT2046 e uno slot microSD.

Che cos'è il display TFT ILI9341 e come funziona?

L'ILI9341 è il chip driver che si trova dietro al vetro. Contiene circa 172 KB di memoria video (GRAM) che conserva tutti i 240×320 pixel. Arduino invia comandi e dati di colore a questa memoria tramite SPI, e il chip aggiorna l'immagine da solo decine di volte al secondo. Per questo l'immagine non deve stare nella RAM di Arduino: anche un Uno con 2 KB di RAM può pilotare un grande display a colori. Per disegnare qualcosa si sceglie prima una finestra (x, y, larghezza, altezza) e poi si inviano i pixel di quella finestra uno dopo l'altro. Il pin DC indica se il byte inviato è un comando (LOW) o un dato (HIGH). I colori di solito si inviano nel formato RGB565, cioè 16 bit per pixel: 5 bit di rosso, 6 di verde e 5 di blu. Il funzionamento del bus SPI è spiegato in dettaglio in Che cos'è l'SPI.

CaratteristicaValore
Chip driverILI9341
Risoluzione240×320 pixel (320×240 in orizzontale)
Colori65.536 colori con RGB565 (il chip ne gestisce 262 mila)
Dimensioni2,2", 2,4", 2,8" e 3,2" (tutti 240×320)
InterfacciaSPI a 4 fili: CS, DC, SCK, MOSI (MISO per la lettura)
Alimentazione (VCC)3,3–5 V (regolatore da 3,3 V sulla scheda)
Livello logico3,3 V (non tollera i 5 V)
ConsumoCirca 0,3–0,6 W, quasi tutto per la retroilluminazione
TouchResistivo, controller XPT2046 (sui modelli touch)
Hardware extraSlot per scheda microSD (pin SPI separati)

2,4 o 2,8 pollici? Modulo SPI o shield per Uno

CaratteristicaModulo SPI 2,4"Modulo SPI 2,8"Shield 2,4" per Uno
Risoluzione240×320240×320240×320
CollegamentoSPI, con cavettiSPI, con cavettiParallelo a 8 bit, si innesta sopra l'Uno
Pin usati5 per il display, 8–9 con touch e SD5 per il display, 8–9 con touch e SDQuasi tutti (D2–D9, A0–A4, D10–D13 per la SD)
DriverILI9341ILI9341Variabile: ILI9341, ILI9325, ST7789 e altri
LibreriaAdafruit_ILI9341, TFT_eSPIAdafruit_ILI9341, TFT_eSPIMCUFRIEND_kbv
TouchXPT2046 (SPI)XPT2046 (SPI)Analogico a 4 fili (libreria TouchScreen)
ESP32 e PicoAdattoAdattoPensato per Uno e Mega

Questo articolo parla del modulo SPI, perché funziona anche con ESP32 e Pico e lascia liberi la maggior parte dei pin dell'Uno. I due moduli SPI hanno esattamente gli stessi pin e lo stesso codice; il display da 2,8 pollici ha pixel un po' più grandi, quindi è più facile centrare i pulsanti touch. Se il tuo display è uno shield che si innesta direttamente sull'Uno, le librerie SPI non possono pilotarlo e il risultato di solito è uno schermo bianco. Per uno shield del genere installa la libreria MCUFRIEND_kbv, leggi l'ID del driver con tft.readID() (0x9341 per l'ILI9341) e avvialo con tft.begin(ID). Per un'alternativa più piccola ma più nitida guarda Display TFT ST7789, e per confrontare tutte le opzioni leggi Tipi di display per Arduino.

Pinout dell'ILI9341 e tabella dei collegamenti

Su un lato del modulo c'è il connettore principale a 14 pin: i primi 9 servono al display, gli ultimi 5, che iniziano con T_, al touch. I 4 pin sul lato opposto (SD_CS, SD_MOSI, SD_MISO, SD_SCK) vanno allo slot della scheda. I tre dispositivi possono condividere lo stesso bus SPI (SCK, MOSI, MISO); solo i loro pin CS devono essere separati. La tabella corrisponde a tutti gli sketch di questo articolo; sul Pico il touch è collegato a un bus SPI separato per via della differenza di velocità.

Pin del moduloArduino Uno (tramite convertitore di livello)ESP32Raspberry Pi Pico
VCC5V3V33V3(OUT)
GNDGNDGNDGND
CSD10GPIO 15GP17
RESETD8GPIO 4GP21
DCD9GPIO 2GP20
SDI (MOSI)D11GPIO 23GP19
SCKD13GPIO 18GP18
LED3.3V3V33V3(OUT)
SDO (MISO)D12 (diretto)GPIO 19GP16
T_CLKD13GPIO 18GP10
T_CSD7GPIO 21GP13
T_DIND11GPIO 23GP11
T_DOD12 (diretto)GPIO 19GP12
T_IRQD2 (diretto)LiberoLibero
SD_CSD4GPIO 5Libero
SD_MOSI / SD_MISO / SD_SCKD11 / D12 / D13GPIO 23 / 19 / 18Libero
Il pin VCC dei moduli ILI9341 accetta 5 V, ma i pin di segnale sono solo a 3,3 V. Il regolatore sulla scheda abbassa soltanto l'alimentazione; sulle linee CS, DC, RESET, SCK e MOSI non c'è alcuna conversione di livello. Collegare direttamente le uscite a 5 V dell'Uno porta spesso a uno schermo bianco e a volte danneggia il chip in modo permanente. Il ponticello J1 sul retro serve a escludere il regolatore: chiudilo con lo stagno solo se alimenti VCC a 3,3 V. Con J1 chiuso, dare 5 V a VCC brucia il display.

Conversione di livello a 3,3 V sull'Arduino Uno

ESP32 e Raspberry Pi Pico lavorano già a 3,3 V, quindi puoi collegare il display direttamente. Sulle schede a 5 V come Uno, Nano e Mega, invece, ogni linea che va da Arduino al display deve essere portata a 3,3 V: CS, DC, RESET, SCK, MOSI e, se usi touch e SD, T_CLK, T_DIN, T_CS, SD_CS, SD_MOSI e SD_SCK. Le linee SDO, T_DO, SD_MISO e T_IRQ, che vanno dal display ad Arduino, non hanno bisogno di convertitore: l'Uno legge come HIGH qualsiasi tensione sopra i 3 V, e un'uscita a 3,3 V la supera. In pratica ci sono quattro strade:

  • Buffer 74HC4050 (la soluzione più pulita): si alimenta a 3,3 V, accetta 5 V sugli ingressi e converte 6 linee in un solo chip. È veloce e funziona senza problemi con l'SPI a 8 MHz. Anche il vecchio CD4050 va bene, ma è lento; se l'immagine si rovina dovrai abbassare la velocità dell'SPI. Per il solo display bastano 5 linee; con touch e SD si aggiungono T_CS e SD_CS, quindi 7 in tutto: per la settima usa un secondo chip o un partitore di tensione.
  • Partitori di tensione con resistenze: per ogni linea metti 1 kΩ tra il pin di Arduino e quello del display, e 2 kΩ tra il pin del display e GND; ottieni 5 V × 2 / 3 ≈ 3,3 V. Puoi calcolare altre coppie di resistenze con il calcolatore di partitore di tensione. È economico, ma 10 resistenze per 5 linee affollano la breadboard.
  • Modulo convertitore di livello già pronto: i moduli a 4 o 8 canali con MOSFET BSS138 si collegano facilmente, ma le loro resistenze di pull-up ammorbidiscono i fronti del segnale alle alte velocità. Se l'immagine si rovina, porta l'SPI a 4 MHz con tft.begin(4000000). Trovi il confronto tra i metodi in Convertitore di livello logico.
  • Il metodo da evitare: il trucco diffuso della "resistenza da 10 kΩ in serie su ogni linea" scarica la tensione in eccesso sui diodi di protezione interni del chip. Può funzionare per un po', ma è instabile e alla lunga può danneggiare il display.

Passo dopo passo: primo test con Adafruit_ILI9341

  1. Nell'Arduino IDE apri il Gestore librerie, cerca Adafruit ILI9341 e installala. Quando chiede delle dipendenze scegli Install all, così vengono installate anche Adafruit GFX e Adafruit BusIO. Se è la tua prima libreria, ti aiuterà Come aggiungere una libreria Arduino.
  2. Per il touch installa anche la libreria XPT2046_Touchscreen di Paul Stoffregen. La libreria SD è già inclusa nell'Arduino IDE.
  3. Collega il display seguendo la tabella qui sopra, sull'Uno tramite un convertitore di livello. Per il primo test puoi lasciare liberi i pin del touch e della SD.
  4. Carica lo sketch seguente e apri il Monitor seriale a 9600 baud. Sul display dovresti vedere testi e forme, nel Monitor seriale i codici di diagnosi del display.
  5. Prova anche gli esempi inclusi: File > Esempi > Adafruit ILI9341 > graphicstest misura quanti microsecondi richiede ogni operazione di disegno.
C++ (Arduino IDE)
1#include <SPI.h>
2#include <Adafruit_GFX.h>
3#include <Adafruit_ILI9341.h>
4
5#define TFT_CS  10   // ekran seçme / chip select
6#define TFT_DC  9    // komut/veri seçimi / command/data select
7#define TFT_RST 8    // donanım reset / hardware reset
8
9Adafruit_ILI9341 tft(TFT_CS, TFT_DC, TFT_RST);   // donanım SPI: D11 MOSI, D13 SCK / hardware SPI
10uint16_t orange;                                  // kendi rengimiz / our own colour
11
12void setup() {
13  Serial.begin(9600);
14  tft.begin();                                    // Uno'da 8 MHz SPI / 8 MHz SPI on Uno
15
16  // Teşhis: çalışan ekranda 0x94 ve 0xC0 beklenir / Diagnostics: a working display reports 0x94 and 0xC0
17  Serial.print(F("Power Mode: 0x"));
18  Serial.println(tft.readcommand8(ILI9341_RDMODE), HEX);
19  Serial.print(F("Self Diagnostic: 0x"));
20  Serial.println(tft.readcommand8(ILI9341_RDSELFDIAG), HEX);
21
22  tft.setRotation(1);                             // yatay, 320x240 / landscape, 320x240
23  tft.fillScreen(ILI9341_BLACK);
24  orange = tft.color565(255, 128, 0);             // RGB'den RGB565'e / RGB to RGB565
25
26  tft.setTextColor(ILI9341_WHITE);
27  tft.setTextSize(3);                             // 18x24 piksel karakter / 18x24 px characters
28  tft.setCursor(10, 10);
29  tft.print(F("BlueGrays"));
30  tft.setTextColor(ILI9341_CYAN);
31  tft.setTextSize(2);
32  tft.setCursor(10, 45);
33  tft.print(F("ILI9341 320x240"));
34
35  tft.fillRect(10, 75, 90, 60, ILI9341_RED);                  // dolu dikdörtgen / filled rectangle
36  tft.drawRect(115, 75, 90, 60, ILI9341_GREEN);               // çerçeve / outline
37  tft.fillCircle(265, 105, 30, ILI9341_BLUE);                 // dolu daire / filled circle
38  tft.fillRoundRect(10, 150, 140, 50, 10, orange);            // yuvarlak köşeli düğme / rounded button
39  tft.drawTriangle(180, 200, 240, 150, 300, 200, ILI9341_YELLOW);
40  tft.drawFastHLine(0, 220, 320, ILI9341_MAGENTA);            // yatay çizgi / horizontal line
41}
42
43void loop() {
44  // Arka plan rengiyle yazınca eski rakam silinir, ekran titremez / writing with a background colour erases the old digits, no flicker
45  tft.setTextColor(ILI9341_WHITE, orange);
46  tft.setTextSize(2);
47  tft.setCursor(22, 167);
48  tft.print(millis() / 1000);
49  tft.print(F(" s"));
50  delay(200);
51}
FunzioneCosa fa
tft.begin(frequenza)Avvia il display; senza frequenza usa l'SPI a 8 MHz sull'Uno e a 40 MHz sull'ESP32
tft.setRotation(0–3)Sceglie l'orientamento: 0 e 2 verticale (240×320), 1 e 3 orizzontale (320×240)
tft.fillScreen(colore)Colora tutto lo schermo con un solo colore
tft.setTextColor(testo, sfondo)Imposta il colore del testo; con il colore di sfondo sovrascrive in modo pulito il testo precedente
tft.setTextSize(n)Ingrandisce il testo n volte; dimensione 1 = caratteri da 6×8 pixel
tft.drawRect / fillRect(x, y, larghezza, altezza, colore)Contorno di rettangolo o rettangolo pieno
tft.fillRoundRect(x, y, larghezza, altezza, r, colore)Rettangolo pieno con angoli arrotondati; ideale per i pulsanti
tft.drawCircle / fillCircle(x, y, r, colore)Cerchio o cerchio pieno
tft.color565(r, g, b)Converte valori RGB da 0–255 in un colore a 16 bit
tft.readcommand8(comando)Legge un registro del display (MISO deve essere collegato); per la diagnosi

La libreria include costanti di colore già pronte (19, come ILI9341_RED, ILI9341_NAVY e ILI9341_ORANGE); per un colore tuo usa color565(). Questa funzione affianca i 5 bit più alti del rosso, i 6 bit più alti del verde e i 5 bit più alti del blu: colore = (R >> 3) << 11 | (G >> 2) << 5 | (B >> 3). Per l'arancione (255, 165, 0), ad esempio, 31 << 11 = 0xF800 e 41 << 5 = 0x0520 si combinano in 0xFD20, esattamente il valore di ILI9341_ORANGE nella libreria. Il verde riceve un bit in più perché l'occhio umano è più sensibile al verde.

Cancellare con fillScreen() e riscrivere ogni volta i numeri che cambiano fa sfarfallare lo schermo; sull'Uno colorare tutto il display richiede almeno 0,15 secondi con l'SPI a 8 MHz. Usa invece setTextColor(testo, sfondo) come nello sketch, oppure cancella con fillRect() solo la piccola zona che cambia. Scrivere i testi fissi dentro F("...") fa anche risparmiare i 2 KB di RAM dell'Uno; per i problemi di memoria leggi Memoria insufficiente su Arduino.

Leggere il touch screen XPT2046

Nei moduli touch c'è un sottile strato resistivo sopra il vetro. Dove premono il dito o un pennino, due strati conduttivi si toccano; il chip XPT2046 misura la posizione X e Y di quel punto con un ADC a 12 bit come valori grezzi da 0 a 4095 e fornisce anche un valore di pressione (Z). La libreria considera assente il tocco se Z è sotto 400. Il chip sta sullo stesso bus SPI del display, ma comunica più lentamente, intorno ai 2 MHz; la libreria regola da sola la velocità a ogni lettura. Il pin T_IRQ va a LOW quando tocchi lo schermo ed evita al processore letture inutili. Lo sketch seguente trasforma lo schermo in una piccola lavagna: scegli un colore dai riquadri in alto e cancelli lo schermo con il pulsante "SIL" (cancella).

C++ (Arduino IDE)
1#include <SPI.h>
2#include <Adafruit_GFX.h>
3#include <Adafruit_ILI9341.h>
4#include <XPT2046_Touchscreen.h>
5
6#define TFT_CS  10
7#define TFT_DC  9
8#define TFT_RST 8
9#define T_CS    7    // dokunmatik seçme / touch chip select
10#define T_IRQ   2    // dokununca LOW olur / goes LOW on touch
11#define SD_CS   4    // SD kullanılmıyor, HIGH tutulur / SD unused, kept HIGH
12
13// Kalibrasyon: Seri Monitör'deki ham değerlerle değiştir / Calibration: replace with the raw values from Serial Monitor
14#define TS_MINX 300
15#define TS_MAXX 3800
16#define TS_MINY 300
17#define TS_MAXY 3800
18
19Adafruit_ILI9341 tft(TFT_CS, TFT_DC, TFT_RST);
20XPT2046_Touchscreen ts(T_CS, T_IRQ);
21
22uint16_t brush = ILI9341_YELLOW;                  // fırça rengi / brush colour
23
24void drawPalette() {
25  tft.fillRect(0, 0, 40, 40, ILI9341_RED);
26  tft.fillRect(40, 0, 40, 40, ILI9341_GREEN);
27  tft.fillRect(80, 0, 40, 40, ILI9341_BLUE);
28  tft.fillRect(120, 0, 40, 40, ILI9341_YELLOW);
29  tft.drawRect(260, 0, 60, 40, ILI9341_WHITE);    // silme düğmesi / clear button
30  tft.setTextColor(ILI9341_WHITE);
31  tft.setTextSize(2);
32  tft.setCursor(273, 13);
33  tft.print(F("SIL"));
34}
35
36void setup() {
37  Serial.begin(9600);
38  pinMode(SD_CS, OUTPUT);
39  digitalWrite(SD_CS, HIGH);                      // SD kart hattı meşgul etmesin / keep the SD card off the bus
40  tft.begin();
41  tft.setRotation(1);                             // ekran yatay / display landscape
42  ts.begin();
43  ts.setRotation(1);                              // dokunmatik de aynı yönde / touch in the same orientation
44  tft.fillScreen(ILI9341_BLACK);
45  drawPalette();
46}
47
48void loop() {
49  if (!ts.touched()) return;                      // dokunma yok / no touch
50  TS_Point p = ts.getPoint();                     // ham x, y (0-4095) ve basınç z / raw x, y and pressure z
51  Serial.print(p.x); Serial.print(',');
52  Serial.print(p.y); Serial.print(',');
53  Serial.println(p.z);
54
55  int16_t x = constrain(map(p.x, TS_MINX, TS_MAXX, 0, 319), 0, 319);   // ekran koordinatı / screen coordinate
56  int16_t y = constrain(map(p.y, TS_MINY, TS_MAXY, 0, 239), 0, 239);
57
58  if (y < 40) {                                   // üst şerit: palet ve düğme / top strip: palette and button
59    if (x < 40)        brush = ILI9341_RED;
60    else if (x < 80)   brush = ILI9341_GREEN;
61    else if (x < 120)  brush = ILI9341_BLUE;
62    else if (x < 160)  brush = ILI9341_YELLOW;
63    else if (x >= 260) { tft.fillScreen(ILI9341_BLACK); drawPalette(); }
64  } else {
65    tft.fillCircle(x, y, 3, brush);               // parmağın altına nokta / dot under the finger
66  }
67}

I valori grezzi non sono 0 e 4095 proprio negli angoli; nella maggior parte dei moduli i bordi stanno più o meno tra 200–400 e 3700–3900. Per calibrare apri il Monitor seriale, tocca con un pennino l'angolo in alto a sinistra e quello in basso a destra e scrivi i valori x e y che vedi nelle costanti TS_MINX, TS_MAXX, TS_MINY e TS_MAXY. Se il punto appare specchiato rispetto al dito, scambia minimo e massimo di quell'asse in map(); se X e Y sono del tutto invertiti, prova i valori da 0 a 3 in ts.setRotation(). Un vero menu funziona allo stesso modo: disegni dei pulsanti e controlli in quale rettangolo cade il punto toccato. Lo strato resistivo risponde anche al dito, ma per i pulsanti piccoli una punta tipo pennino è più precisa.

Mostrare immagini BMP dalla scheda SD

Lo slot microSD sul retro del modulo ti permette di tenere loghi, sfondi e foto su una scheda e mostrarli sul display. Per preparare un'immagine riduci una foto a 320×240 pixel e salvala con Paint come Bitmap a 24 bit (.bmp). Poiché la libreria SD di Arduino lavora con nomi di file corti, usa un nome di massimo 8 caratteri come RESIM.BMP e formatta la scheda in FAT32. I dettagli sulla scheda e la soluzione all'errore initialization failed sono in Modulo scheda SD per Arduino. Ricorda che anche questo slot è a 3,3 V: sull'Uno anche le linee SD_CS, SD_MOSI e SD_SCK devono passare dal convertitore di livello.

C++ (Arduino IDE)
1#include <SPI.h>
2#include <SD.h>
3#include <Adafruit_GFX.h>
4#include <Adafruit_ILI9341.h>
5
6#define TFT_CS  10
7#define TFT_DC  9
8#define TFT_RST 8
9#define SD_CS   4
10#define T_CS    7
11#define CHUNK   20   // tek okumada 20 piksel (60 bayt) / 20 pixels (60 bytes) per read
12
13Adafruit_ILI9341 tft(TFT_CS, TFT_DC, TFT_RST);
14
15uint16_t read16(File &f) {                        // BMP sayıları küçük uçlu / BMP numbers are little-endian
16  uint16_t lo = f.read();
17  uint16_t hi = f.read();
18  return lo | (hi << 8);
19}
20
21uint32_t read32(File &f) {
22  uint32_t lo = read16(f);
23  uint32_t hi = read16(f);
24  return lo | (hi << 16);
25}
26
27bool drawBmp(const char *name, int16_t x, int16_t y) {
28  File f = SD.open(name);
29  if (!f) return false;                                   // dosya yok / file not found
30  if (read16(f) != 0x4D42) { f.close(); return false; }  // "BM" imzası / "BM" signature
31  read32(f);                                              // dosya boyutu / file size
32  read32(f);                                              // ayrılmış alan / reserved
33  uint32_t offset = read32(f);                            // piksel verisinin başı / start of pixel data
34  read32(f);                                              // başlık boyutu / header size
35  int32_t w = (int32_t)read32(f);
36  int32_t h = (int32_t)read32(f);
37  read16(f);                                              // düzlem sayısı / colour planes
38  uint16_t depth = read16(f);
39  uint32_t comp = read32(f);
40  if (depth != 24 || comp != 0) { f.close(); return false; }   // yalnız 24 bit, sıkıştırmasız / 24-bit uncompressed only
41
42  bool bottomUp = true;                                   // BMP satırları alttan üste / rows are stored bottom-up
43  if (h < 0) { h = -h; bottomUp = false; }
44  uint32_t rowSize = (w * 3 + 3) & ~3UL;                  // satırlar 4 baytın katı / rows padded to 4 bytes
45  int32_t drawW = w, drawH = h;
46  if (x + drawW > tft.width())  drawW = tft.width() - x;   // ekrana sığmayanı kırp / clip to the screen
47  if (y + drawH > tft.height()) drawH = tft.height() - y;
48
49  uint8_t sdBuf[CHUNK * 3];
50  uint16_t line[CHUNK];
51  for (int32_t row = 0; row < drawH; row++) {
52    uint32_t pos = offset + (bottomUp ? (h - 1 - row) : row) * rowSize;
53    f.seek(pos);                                          // satırın başına git / jump to the start of the row
54    for (int32_t col = 0; col < drawW; col += CHUNK) {
55      int16_t n = drawW - col;
56      if (n > CHUNK) n = CHUNK;
57      f.read(sdBuf, n * 3);
58      for (int16_t i = 0; i < n; i++) {                   // BGR'den RGB565'e / BGR to RGB565
59        line[i] = tft.color565(sdBuf[i * 3 + 2], sdBuf[i * 3 + 1], sdBuf[i * 3]);
60      }
61      tft.drawRGBBitmap(x + col, y + row, line, n, 1);    // parçayı ekrana bas / push the chunk to the screen
62    }
63  }
64  f.close();
65  return true;
66}
67
68void setup() {
69  Serial.begin(9600);
70  pinMode(T_CS, OUTPUT);
71  digitalWrite(T_CS, HIGH);                       // dokunmatik hattı meşgul etmesin / keep touch off the bus
72  tft.begin();
73  tft.setRotation(1);                             // 320x240 yatay / landscape
74  tft.fillScreen(ILI9341_BLACK);
75  tft.setTextSize(2);
76
77  if (!SD.begin(SD_CS)) {                         // kart başlatılamadı / card init failed
78    tft.setTextColor(ILI9341_RED);
79    tft.setCursor(10, 10);
80    tft.print(F("SD kart bulunamadi"));
81    return;
82  }
83  uint32_t t = millis();
84  if (!drawBmp("RESIM.BMP", 0, 0)) {
85    tft.setTextColor(ILI9341_YELLOW);
86    tft.setCursor(10, 10);
87    tft.print(F("RESIM.BMP okunamadi"));
88  }
89  Serial.print(F("Cizim suresi / Draw time (ms): "));
90  Serial.println(millis() - t);
91}
92
93void loop() {
94}

I primi 54 byte di un file BMP sono l'intestazione: lì si trovano la firma "BM", il punto in cui iniziano i dati dei pixel, la larghezza, l'altezza e la profondità di colore. I pixel sono salvati nell'ordine blu, verde, rosso (BGR) e normalmente dal basso verso l'alto, e ogni riga è completata fino a un multiplo di 4 byte. Per questo lo sketch salta nel punto giusto del file per ogni riga dello schermo, legge 20 pixel (60 byte) alla volta, li converte in RGB565 e li disegna con drawRGBBitmap(). Lavorare a piccoli pezzi tiene tutto nella RAM dell'Uno e permette alla scheda SD e al display di usare a turno lo stesso bus SPI. Il tempo di disegno viene scritto nel Monitor seriale; sull'Uno un'immagine a tutto schermo compare riga per riga in pochi secondi. Se vuoi mostrare PNG o JPEG e disegnare molto più velocemente, passa a un ESP32 con le librerie TFT_eSPI e TJpg_Decoder.

Disegno veloce sull'ESP32 con TFT_eSPI

Scheda di sviluppo ESP32
Grazie alla logica a 3,3 V, l'ESP32 si collega direttamente all'ILI9341 e pilota l'SPI a 40 MHz, disegnando molte volte più velocemente dell'Uno.

L'ESP32 lavora a 3,3 V e può portare l'SPI fino a 40 MHz: non serve un convertitore di livello e riempire tutto lo schermo scende in teoria a circa 31 millisecondi. Per sfruttare davvero questa velocità si usa di solito la libreria TFT_eSPI di Bodmer. Accede direttamente all'hardware SPI dell'ESP32, supporta font con bordi smussati e soprattutto buffer fuori schermo chiamati sprite. Disegni quanto vuoi in uno sprite nella RAM e invii il risultato allo schermo in un colpo solo, così nemmeno la grafica che cambia velocemente sfarfalla. La particolarità di TFT_eSPI è che i pin non si impostano nello sketch, ma nel file User_Setup.h dentro la cartella della libreria. Aprilo, commenta le righe dei pin ESP8266 (NodeMCU) attive di default e attiva queste:

C++ (Arduino IDE)
1// TFT_eSPI/User_Setup.h içinde yalnız bu satırlar açık kalsın / keep only these lines active in TFT_eSPI/User_Setup.h
2#define ILI9341_DRIVER
3
4#define TFT_MISO 19
5#define TFT_MOSI 23
6#define TFT_SCLK 18
7#define TFT_CS   15   // ekran seçme / chip select
8#define TFT_DC    2   // komut/veri / data/command
9#define TFT_RST   4   // sıfırlama / reset
10#define TOUCH_CS 21   // dokunmatik seçme (T_CS) / touch chip select (T_CS)
11
12#define LOAD_GLCD     // 1: 8 piksel yazı tipi / 8 px font
13#define LOAD_FONT2    // 2: 16 piksel / 16 px
14#define LOAD_FONT4    // 4: 26 piksel / 26 px
15#define LOAD_FONT7    // 7: 7 segment rakamlar / 7-segment digits
16#define LOAD_GFXFF    // Adafruit FreeFont'lar / Adafruit FreeFonts
17#define SMOOTH_FONT
18
19#define SPI_FREQUENCY       40000000   // kablolar uzunsa 27000000 / 27 MHz with long wires
20#define SPI_READ_FREQUENCY  20000000
21#define SPI_TOUCH_FREQUENCY  2500000
C++ (Arduino IDE)
1#include <SPI.h>
2#include <TFT_eSPI.h>                     // pinler User_Setup.h içinde / pins are set in User_Setup.h
3
4TFT_eSPI tft = TFT_eSPI();
5TFT_eSprite graph = TFT_eSprite(&tft);    // ekran dışı çizim alanı / off-screen canvas
6
7// Touch_calibrate örneğinin verdiği 5 sayıyla değiştir / replace with the 5 numbers from the Touch_calibrate example
8uint16_t calData[5] = {286, 3534, 283, 3600, 6};
9
10const int GW = 300, GH = 100;             // grafik boyutu / graph size
11uint8_t samples[GW];                      // son 300 ölçüm / last 300 readings
12uint32_t frames = 0, fps = 0, lastFps = 0;
13
14void setup() {
15  tft.init();
16  tft.setRotation(1);                     // yatay, 320x240 / landscape, 320x240
17  tft.setTouch(calData);
18  tft.fillScreen(TFT_BLACK);
19  tft.setTextColor(TFT_WHITE, TFT_BLACK);
20  tft.drawString("ESP32 + TFT_eSPI", 10, 8, 4);   // 4 numaralı yazı tipi, 26 px / font 4, 26 px
21  graph.createSprite(GW, GH);             // 300x100x2 bayt = 60 KB RAM / 60 KB of RAM
22}
23
24void loop() {
25  memmove(samples, samples + 1, GW - 1);                          // grafiği sola kaydır / scroll the graph left
26  samples[GW - 1] = map(analogRead(34), 0, 4095, 0, GH - 1);       // GPIO 34'teki potansiyometre / pot on GPIO 34
27
28  graph.fillSprite(TFT_BLACK);
29  for (int y = 0; y < GH; y += 25) graph.drawFastHLine(0, y, GW, TFT_DARKGREY);   // ızgara / grid
30  for (int x = 1; x < GW; x++) {
31    graph.drawLine(x - 1, GH - 1 - samples[x - 1], x, GH - 1 - samples[x], TFT_GREEN);
32  }
33  graph.setTextColor(TFT_YELLOW);
34  graph.drawString(String(fps) + " FPS", 4, 4, 2);
35  graph.pushSprite(10, 50);               // tek seferde ekrana gönder, titreme yok / push in one go, no flicker
36
37  uint16_t tx, ty;
38  if (tft.getTouch(&tx, &ty)) {           // dokunulduysa / if touched
39    tft.fillRect(10, 170, 300, 30, TFT_BLACK);
40    tft.setTextColor(TFT_CYAN, TFT_BLACK);
41    tft.drawString("Dokunma / Touch: " + String(tx) + ", " + String(ty), 10, 175, 2);
42  }
43
44  frames++;
45  if (millis() - lastFps >= 1000) {       // saniyede bir FPS hesapla / compute FPS once per second
46    fps = frames;
47    frames = 0;
48    lastFps = millis();
49  }
50}

Lo sketch disegna il valore di un potenziometro collegato al GPIO 34 come un grafico che scorre e mostra i fotogrammi al secondo (FPS) nell'angolo dello sprite. Uno sprite da 300×100 pixel a 16 bit occupa 60 KB di RAM; è circa 30 volte tutta la memoria dell'Uno, ma per l'ESP32 non è un problema. Nel touch, i pin T_CLK, T_DIN e T_DO si uniscono alle linee SCK, MOSI e MISO del display e solo T_CS (GPIO 21) resta separato. Per ottenere i tuoi valori di calibrazione, esegui una volta l'esempio Generic > Touch_calibrate di TFT_eSPI, tocca le frecce che compaiono negli angoli e copia nell'array calData i 5 numeri stampati nel Monitor seriale. La riga già pronta Setup42_ILI9341_ESP32.h in User_Setup_Select.h seleziona gli stessi pin del display, ma la riga TOUCH_CS devi aggiungerla tu. Se sei alle prime armi con l'ESP32, leggi prima Che cos'è l'ESP32.

Quando aggiorni TFT_eSPI dall'Arduino IDE, la cartella della libreria viene riscritta e le tue impostazioni in User_Setup.h si perdono; se un display che ieri funzionava oggi resta bianco, è la prima cosa da controllare, quindi tieni una copia del tuo file di configurazione. Se rosso e blu sono invertiti, attiva TFT_RGB_ORDER TFT_BGR; se i colori sembrano un negativo, attiva TFT_INVERSION_ON; alcuni pannelli funzionano meglio con ILI9341_2_DRIVER. TFT_eSPI 2.5.43 può andare in crash e riavviarsi all'avvio su alcune schede con le versioni 3.x del pacchetto esp32; in tal caso torna a una versione 2.0.x del pacchetto esp32 dal Gestore schede.

ILI9341 con Raspberry Pi Pico e MicroPython

Anche il Pico è una scheda a 3,3 V, quindi il display si collega direttamente. Il driver MicroPython più usato è la coppia di file ili9341.py e xpt2046.py del repository micropython-ili9341 di rdagger; basta copiarli entrambi sul Pico con Thonny. Nel codice seguente il display è sull'SPI0 a 40 MHz e il touch su un bus SPI1 separato a 1 MHz, così la differenza di velocità tra i due chip non crea problemi. Il codice disegna testi e forme e poi mette punti gialli dove tocchi, creando una lavagna semplice. Se usi Pico e Thonny per la prima volta, parti da Che cos'è il Raspberry Pi Pico.

MicroPython
1from machine import Pin, SPI
2from time import sleep_ms
3from ili9341 import Display, color565      # ili9341.py Pico'da olmalı / must be on the Pico
4from xpt2046 import Touch                  # xpt2046.py Pico'da olmalı / must be on the Pico
5
6# Ekran: SPI0, 40 MHz / Display: SPI0, 40 MHz
7spi_tft = SPI(0, baudrate=40000000, sck=Pin(18), mosi=Pin(19), miso=Pin(16))
8tft = Display(spi_tft, cs=Pin(17), dc=Pin(20), rst=Pin(21), width=240, height=320, rotation=0)
9
10# Dokunmatik: ayrı SPI1, 1 MHz / Touch: separate SPI1, 1 MHz
11spi_touch = SPI(1, baudrate=1000000, sck=Pin(10), mosi=Pin(11), miso=Pin(12))
12touch = Touch(spi_touch, cs=Pin(13), width=240, height=320)
13
14WHITE = color565(255, 255, 255)
15YELLOW = color565(255, 255, 0)
16
17tft.clear(color565(0, 0, 0))                                   # ekranı temizle / clear the screen
18tft.draw_text8x8(10, 10, "BlueGrays + Pico", WHITE)
19tft.fill_rectangle(10, 30, 100, 50, color565(255, 0, 0))       # dolu dikdörtgen / filled rectangle
20tft.draw_rectangle(130, 30, 100, 50, color565(0, 255, 0))      # çerçeve / outline
21tft.fill_circle(60, 130, 30, color565(0, 128, 255))            # dolu daire / filled circle
22tft.draw_line(0, 175, 239, 175, color565(255, 0, 255))         # çizgi / line
23tft.draw_text8x8(10, 185, "Ekrana dokun / Touch me", YELLOW)
24
25while True:
26    raw = touch.raw_touch()                # dokunma yoksa None / None when not touched
27    if raw is not None:
28        x, y = touch.normalize(*raw)       # ham değeri piksele çevir / raw value to pixels
29        y = 319 - y                        # eksen ters ise / if the axis is inverted
30        x = min(max(x, 3), 236)            # ekran dışına taşma / keep inside the screen
31        y = min(max(y, 3), 316)
32        tft.fill_circle(x, y, 3, YELLOW)
33    sleep_ms(20)

In verticale (rotation=0) la larghezza è 240 e l'altezza 320; per usare lo schermo in orizzontale passa width=320 e height=240 insieme a rotation=90. La calibrazione predefinita del touch (x_min=100, x_max=1962) potrebbe non andare bene per ogni modulo; se il punto è spostato, stampa i valori di raw_touch() e passa a Touch() i tuoi x_min, x_max, y_min e y_max. Per le immagini, la funzione draw_image() del driver legge file .raw convertiti in RGB565; lo script utils/img2rgb565.py del repository fa questa conversione sul tuo computer.

Schermo bianco: cause e soluzione

Il problema più famoso dell'ILI9341 è uno schermo completamente bianco con la retroilluminazione accesa. Lo schermo bianco in realtà è un indizio: alimentazione e retroilluminazione funzionano, ma il chip driver non è mai stato inizializzato. Quando il pannello non riceve comandi, i pixel lasciano passare la luce e lo schermo appare bianco. Quindi il problema è quasi sempre nella comunicazione. Controlla la tabella dall'alto verso il basso:

SintomoCausa probabileSoluzione
Schermo bianco, collegato direttamente all'UnoSegnali a 5 V senza convertitore di livelloUsa un 74HC4050 o dei partitori di tensione; se il chip è danneggiato sostituisci il modulo
Schermo bianco con i cavi collegatiCS e DC scambiati, o i pin nel codice non corrispondono al cablaggioConfronta una per una le definizioni TFT_CS, TFT_DC e TFT_RST con la tabella
Schermo bianco, RESET scollegatoRESET non collegato o sul pin sbagliatoCollega RESET al pin del codice o a 3,3 V; non lasciarlo mai flottante
Schermo bianco sull'ESP32 (TFT_eSPI)User_Setup.h non modificato o cancellato da un aggiornamentoDisattiva le righe ESP8266 e riscrivi i pin dell'ESP32 e ILI9341_DRIVER
Bianco a tratti, immagine spostata o disturbataCavetti lunghi, SPI troppo veloce, contatti allentati sulla breadboardTieni i cavi sotto i 10–15 cm; abbassa l'SPI a 20–27 MHz, o a 4 MHz sull'Uno
Bianco solo con touch o SD collegatiIl CS dell'altro dispositivo è flottante e blocca il busNel codice imposta ogni CS non usato come OUTPUT e mettilo a HIGH
Non funziona con nessun codiceIl display non è un ILI9341 (ST7789, ILI9488) oppure è uno shield paralleloLeggi la serigrafia sul retro; un 3,5 pollici da 320×480 è un ILI9488, uno shield richiede MCUFRIEND_kbv
Schermo bianco, retroilluminazione che sfarfallaAlimentazione insufficienteAlimenta VCC dai 5 V, prova un altro cavo USB e un altro alimentatore
Per isolare il guasto usa le righe di diagnosi del primo sketch. Se il Monitor seriale mostra Power Mode: 0x94 e Self Diagnostic: 0xC0, il display riceve i comandi e il problema è nel software (orientamento, colori o codice di disegno). Se i valori sono 0x0 o 0xFF, Arduino non riesce a comunicare con il display: controlla i cavi, il convertitore di livello e i pin CS e DC. Questa lettura funziona solo con la linea SDO (MISO) collegata.

Altri errori frequenti

  • Colori sbagliati: se il rosso appare blu, il pannello usa l'ordine BGR; cambia l'impostazione TFT_RGB_ORDER in TFT_eSPI. Se i colori sembrano un negativo, prova tft.invertDisplay(true).
  • Immagine capovolta o specchiata: cambia il valore di setRotation() tra 0 e 3 e regola di conseguenza gli assi del touch.
  • Il display funziona, ma touch o SD no: verifica che T_CS e SD_CS corrispondano ai pin del codice. Su alcuni moduli l'uscita SDO del display non libera il bus; in quel caso prova a scollegare il pin SDO del display, smetterà di funzionare solo la lettura di diagnosi.
  • Il BMP non compare: la scheda non è in FAT32, il nome del file supera gli 8 caratteri o l'immagine non è a 24 bit. Ricorda di scegliere 24 bit in Paint; questo sketch non disegna BMP a 16 e 32 bit.
  • Le lettere accentate non compaiono: il font predefinito di GFX non ha caratteri come à, è o ù. In TFT_eSPI puoi creare un tuo font smussato oppure usare un font GFX che contenga quei caratteri.
  • Il display è lento: sull'Uno un aggiornamento a tutto schermo richiede almeno 0,15 secondi. Per animazioni e giochi passa a un ESP32 o a un Pico e ridisegna solo la zona che cambia.
  • Il modulo scalda: forse ci sono 5 V su VCC con il ponticello J1 chiuso, oppure VCC e GND sono invertiti; togli subito l'alimentazione.

Idee di progetti con l'ILI9341

  • Pannello touch per la casa intelligente: controlla luci e relè con grandi pulsanti sullo schermo; trovi spunti in Progetto di casa intelligente con Arduino.
  • Display meteo a colori: mostra il meteo che l'ESP32 scarica da internet con icone e cifre grandi (Stazione meteo con ESP32).
  • Cruscotto dei sensori: disegna temperatura, umidità e pressione di un BME280 come strumenti a lancetta con il grafico delle ultime 24 ore.
  • Console di giochi retrò: gioca a Snake, Pong o Tetris a colori; aggiungi un modulo joystick per i comandi e cerca idee in Progetti di giochi con Arduino.
  • Cornice digitale: fai scorrere ogni pochi secondi le immagini BMP della scheda SD.
  • Mini oscilloscopio: disegna i valori di analogRead come un'onda fluida con uno sprite sull'ESP32.
  • Serratura touch con codice: disegna un tastierino numerico sullo schermo e apri un relè o un servo quando viene inserito il codice giusto.

L'ILI9341 è il modo più economico per dare ai tuoi progetti un'interfaccia touch a colori: parti con l'Uno per imparare le funzioni di disegno di base e passa all'ESP32 con TFT_eSPI quando ti servono velocità e animazioni fluide. Se preferisci iniziare con un display più piccolo, Display OLED (SSD1306) è un buon punto di partenza. Nell'app BlueGrays trovi il display meteo con ESP32, il registratore di temperatura, il sensore di parcheggio e progetti di giochi con display, con schemi elettrici e codice passo dopo passo.

Domande frequenti

Il display ILI9341 funziona a 5 V?

Il pin VCC del modulo accetta 3,3–5 V perché sulla scheda c'è un regolatore da 3,3 V. I pin di segnale come CS, DC, SCK e MOSI, però, sono solo a 3,3 V. Con un Arduino Uno devi mettere su queste linee un convertitore di livello, come un 74HC4050 o dei partitori di tensione.

Perché il mio ILI9341 resta bianco?

Lo schermo bianco indica che la retroilluminazione è accesa ma il chip driver non è stato inizializzato. Le cause più comuni sono un cablaggio sbagliato di CS, DC o RESET, l'assenza del convertitore di livello sull'Uno, un User_Setup.h non modificato in TFT_eSPI e un display che in realtà non è un ILI9341.

Quale libreria si usa per l'ILI9341?

Per Arduino Uno, Nano e Mega la scelta più semplice è Adafruit_ILI9341 con Adafruit GFX. Sulle schede ESP32, ESP8266 e RP2040 si preferisce TFT_eSPI, molto più veloce. Gli shield paralleli da 2,4 pollici che si innestano sull'Uno richiedono invece MCUFRIEND_kbv.

Come si calibra il touch dell'ILI9341?

Il controller touch XPT2046 restituisce valori grezzi da 0 a 4095. Annota i valori minimi e massimi che vedi nel Monitor seriale toccando gli angoli e convertili in coordinate dello schermo con map(). Se usi TFT_eSPI, l'esempio Touch_calibrate fa tutto da solo e ti dà un array di calibrazione pronto.

Che differenza c'è tra l'ILI9341 da 2,4 e da 2,8 pollici?

Entrambi hanno una risoluzione di 240×320 pixel e usano gli stessi pin e lo stesso codice. Il display da 2,8 pollici ha pixel un po' più grandi, quindi il testo si legge meglio ed è più facile premere i pulsanti touch. Il modulo da 2,4 pollici entra in contenitori più piccoli.

Si può usare l'ILI9341 con un Arduino Nano?

Sì. I pin SPI del Nano sono gli stessi dell'Uno: D13 SCK, D11 MOSI e D12 MISO. Anche il Nano lavora con logica a 5 V, quindi serve un convertitore di livello. I suoi 2 KB di RAM bastano per pilotare il display, ma non per tenere immagini grandi, che dovrai leggere a pezzi dalla scheda SD.

Vedi tutti i progetti
ESP32 HTTPClient + API meteo (con display OLED SSD1306)
#134Avanzato
Premium

ESP32 HTTPClient + API meteo (con display OLED SSD1306)

In questo progetto, utilizzando l'ESP32, effettuiamo una chiamata REST all'API meteo (wttr.in) tramite Internet utilizzando HTTPClient.h. A differenza della precedente versione con LCD I2C, qui utilizziamo un display OLED SSD1306 (128×64), che consente di utilizzare caratteri di grandi dimensioni, icone vettoriali e una ricca presentazione visiva su un unico schermo. Per le condizioni meteorologiche, 7 diverse icone vettoriali (soleggiato, parzialmente nuvoloso, nuvoloso, piovoso, nevoso, temp

4.3(10)
19
Data Logger di Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
#144Avanzato
Premium

Data Logger di Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)

Costruisci un data logger di temperatura con timestamp usando ESP32! Leggi temperatura/umidità dal DHT22 ogni minuto, ottieni l'ora reale dal DS1307 RTC e registra su scheda microSD in formato CSV. L'OLED mostra dal vivo temperatura (font grande), percentuale di umidità, timestamp e contatore di log. Il file /temp_log.csv sulla scheda SD si apre in Excel, Google Sheets o Python pandas per l'analisi — perfetto per il monitoraggio di serre, tracciamento della temperatura domestica, raccolta

4.7(7)
12
Lampada con miscelatore di colori ESP32 (3 potenziometri + LED RGB + OLED)
#138Avanzato
Premium

Lampada con miscelatore di colori ESP32 (3 potenziometri + LED RGB + OLED)

Una lampada mista colori intelligente che, ruotando i 3 potenziometri con l'ESP32, permette di miscelare il colore desiderato! Man mano che si ruotano i potenziometri rosso, verde e blu, il LED RGB a catodo comune cambia colore istantaneamente. Sul display OLED SSD1306 vengono visualizzati in tempo reale i valori compresi tra 0 e 255 per ogni colore, le barre di riempimento visive e il codice colore HEX (#FF8040, ad esempio). Un mini studio di colore professionale: insegna la teoria dei colori R

4.7(6)
10
Sensore di parcheggio ESP32 (HC-SR04 + barra a 5 LED + cicalino + OLED)
#142Avanzato
Premium

Sensore di parcheggio ESP32 (HC-SR04 + barra a 5 LED + cicalino + OLED)

La versione ESP32 del sensore di parcheggio per auto! Grazie al sensore a ultrasuoni HC-SR04 misuriamo la distanza dall'oggetto davanti al veicolo. Man mano che la distanza diminuisce, la barra composta da 5 LED si riempie (da verde → giallo → rosso) e l'intervallo tra i bip del cicalino si accorcia. Quando ci si avvicina troppo (meno di 10 cm), l'allarme suona ininterrottamente e tutti i LED si accendono. Sul display OLED SSD1306 vengono visualizzati in caratteri grandi il valore istantaneo in

0.0(0)
14
Gioco delle Racchette - SSD1306
#86Intermedio
Premium

Gioco delle Racchette - SSD1306

Una pallina, due racchette e tu: giochi a ping pong, uno dei primissimi videogiochi, su un piccolo display OLED. Con due pulsanti muovi su e giù la tua racchetta a destra, mentre il computer guida que

4.5(47)
65
OLED T-Rex Run: Gioco del dinosauro con Arduino
#87Avanzato
Premium

OLED T-Rex Run: Gioco del dinosauro con Arduino

Il gioco del dinosauro che compare quando salta internet, ora sulla tua scrivania: il dinosauro corre sul piccolo display OLED, i cactus gli vengono incontro e tu salti con un solo pulsante. Il punteg

4.7(33)
53
Schermo LCD I2C per ESP32 (16x2)
#119Intermedio
Premium

Schermo LCD I2C per ESP32 (16x2)

In questo progetto visualizziamo del testo collegando un display LCD a 16x2 caratteri all'ESP32 tramite il protocollo I2C. Grazie all'I2C possiamo controllare il display utilizzando solo 2 pin di dati (SDA e SCL); si elimina così lo spreco dei 6+ pin tipici del collegamento parallelo classico. Il codice stampa un messaggio fisso sulla prima riga e un contatore che aumenta ogni secondo sulla seconda riga. Inoltre, all'inizio, eseguendo lo scanner I2C, stampiamo l'indirizzo del display sul Serial

4.9(23)
40
Gioco runner su LCD con Arduino
#98Intermedio
Premium

Gioco runner su LCD con Arduino

Gioco endless runner a scorrimento laterale su schermo LCD a 16x2 caratteri. L'eroe corre automaticamente, il giocatore salta gli ostacoli premendo il pulsante. Sulla riga superiore e inferiore compaiono ostacoli casuali. Il cicalino passivo riproduce la melodia di apertura, il suono di salto, il suono di celebrazione dei 50 punti e la melodia di fine gioco. All'avvio viene visualizzata la schermata iniziale "BlueGrays - Arduino Projects".

4.6(32)
55