Come utilizzare un display TFT ILI9341 con Arduino

Ciao!

in questo post vedremo come utilizzare un display TFT ILI9341 da 2.8" interfacciandolo con una scheda basata su ESP8266 (NodeMcu).

questo tipo di display è piuttosto diffuso, io l'ho acquistato su Amazon dal fornitore HiLetgo

Il display arriva ben imballato e corredato di un pennino, utile per utilizzare la funzionalità touch del display (che vedremo prossimamente):










Vediamo come collegare il display alla nostra scheda NodeMcu, il display comunica in SPI e accetta un livello logico di 3.3v, quindi se utilizzate una scheda con uscite a 5v (Arduino Uno ad esempio) dovete interporre un level shifter.




Per poter visualizzare qualcosa sul display è necessario scaricare ed installare 2 librerie, 

A questo punto possiamo programmare il nostro NodeMcu, qui sotto trovate il codice, è l'esempio "graphicstest" della libreria "Adafruit_ILI9341" al quale ho modificato solamente i pin utilizzati nel micro.


  1. /***************************************************
  2.   This is our GFX example for the Adafruit ILI9341 Breakout and Shield
  3.   ----> http://www.adafruit.com/products/1651
  4.   Check out the links above for our tutorials and wiring diagrams
  5.   These displays use SPI to communicate, 4 or 5 pins are required to
  6.   interface (RST is optional)
  7.   Adafruit invests time and resources providing this open source code,
  8.   please support Adafruit and open-source hardware by purchasing
  9.   products from Adafruit!
  10.   Written by Limor Fried/Ladyada for Adafruit Industries.
  11.   MIT license, all text above must be included in any redistribution
  12.  ****************************************************/
  13. #include "SPI.h"
  14. #include "Adafruit_GFX.h"
  15. #include "Adafruit_ILI9341.h"
  16. // For the Adafruit shield, these are the default.
  17. #define TFT_CS    D2
  18. #define TFT_RST   D3
  19. #define TFT_DC    D4
  20. #define TFT_MOSI  D5
  21. #define TFT_CLK   D6
  22. #define TFT_MISO  D7
  23. // Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
  24. //Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
  25. // If using the breakout, change pins as desired
  26. Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);
  27. void setup() {
  28.   Serial.begin(9600);
  29.   Serial.println("ILI9341 Test!");
  30.   tft.begin();
  31.   // read diagnostics (optional but can help debug problems)
  32.   uint8_t x = tft.readcommand8(ILI9341_RDMODE);
  33.   Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  34.   x = tft.readcommand8(ILI9341_RDMADCTL);
  35.   Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  36.   x = tft.readcommand8(ILI9341_RDPIXFMT);
  37.   Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  38.   x = tft.readcommand8(ILI9341_RDIMGFMT);
  39.   Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  40.   x = tft.readcommand8(ILI9341_RDSELFDIAG);
  41.   Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
  42.   Serial.println(F("Benchmark                Time (microseconds)"));
  43.   delay(10);
  44.   Serial.print(F("Screen fill              "));
  45.   Serial.println(testFillScreen());
  46.   delay(500);
  47.   Serial.print(F("Text                     "));
  48.   Serial.println(testText());
  49.   delay(3000);
  50.   Serial.print(F("Lines                    "));
  51.   Serial.println(testLines(ILI9341_CYAN));
  52.   delay(500);
  53.   Serial.print(F("Horiz/Vert Lines         "));
  54.   Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE));
  55.   delay(500);
  56.   Serial.print(F("Rectangles (outline)     "));
  57.   Serial.println(testRects(ILI9341_GREEN));
  58.   delay(500);
  59.   Serial.print(F("Rectangles (filled)      "));
  60.   Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA));
  61.   delay(500);
  62.   Serial.print(F("Circles (filled)         "));
  63.   Serial.println(testFilledCircles(10, ILI9341_MAGENTA));
  64.   Serial.print(F("Circles (outline)        "));
  65.   Serial.println(testCircles(10, ILI9341_WHITE));
  66.   delay(500);
  67.   Serial.print(F("Triangles (outline)      "));
  68.   Serial.println(testTriangles());
  69.   delay(500);
  70.   Serial.print(F("Triangles (filled)       "));
  71.   Serial.println(testFilledTriangles());
  72.   delay(500);
  73.   Serial.print(F("Rounded rects (outline)  "));
  74.   Serial.println(testRoundRects());
  75.   delay(500);
  76.   Serial.print(F("Rounded rects (filled)   "));
  77.   Serial.println(testFilledRoundRects());
  78.   delay(500);
  79.   Serial.println(F("Done!"));
  80. }
  81. void loop(void) {
  82.   for(uint8_t rotation=0; rotation<4; rotation++) {
  83.     tft.setRotation(rotation);
  84.     testText();
  85.     delay(1000);
  86.   }
  87. }
  88. unsigned long testFillScreen() {
  89.   unsigned long start = micros();
  90.   tft.fillScreen(ILI9341_BLACK);
  91.   yield();
  92.   tft.fillScreen(ILI9341_RED);
  93.   yield();
  94.   tft.fillScreen(ILI9341_GREEN);
  95.   yield();
  96.   tft.fillScreen(ILI9341_BLUE);
  97.   yield();
  98.   tft.fillScreen(ILI9341_BLACK);
  99.   yield();
  100.   return micros() - start;
  101. }
  102. unsigned long testText() {
  103.   tft.fillScreen(ILI9341_BLACK);
  104.   unsigned long start = micros();
  105.   tft.setCursor(0, 0);
  106.   tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(1);
  107.   tft.println("Hello World!");
  108.   tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
  109.   tft.println(1234.56);
  110.   tft.setTextColor(ILI9341_RED);    tft.setTextSize(3);
  111.   tft.println(0xDEADBEEF, HEX);
  112.   tft.println();
  113.   tft.setTextColor(ILI9341_GREEN);
  114.   tft.setTextSize(5);
  115.   tft.println("Groop");
  116.   tft.setTextSize(2);
  117.   tft.println("I implore thee,");
  118.   tft.setTextSize(1);
  119.   tft.println("my foonting turlingdromes.");
  120.   tft.println("And hooptiously drangle me");
  121.   tft.println("with crinkly bindlewurdles,");
  122.   tft.println("Or I will rend thee");
  123.   tft.println("in the gobberwarts");
  124.   tft.println("with my blurglecruncheon,");
  125.   tft.println("see if I don't!");
  126.   return micros() - start;
  127. }
  128. unsigned long testLines(uint16_t color) {
  129.   unsigned long start, t;
  130.   int           x1, y1, x2, y2,
  131.                 w = tft.width(),
  132.                 h = tft.height();
  133.   tft.fillScreen(ILI9341_BLACK);
  134.   yield();
  135.   x1 = y1 = 0;
  136.   y2    = h - 1;
  137.   start = micros();
  138.   for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  139.   x2    = w - 1;
  140.   for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  141.   t     = micros() - start; // fillScreen doesn't count against timing
  142.   yield();
  143.   tft.fillScreen(ILI9341_BLACK);
  144.   yield();
  145.   x1    = w - 1;
  146.   y1    = 0;
  147.   y2    = h - 1;
  148.   start = micros();
  149.   for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  150.   x2    = 0;
  151.   for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  152.   t    += micros() - start;
  153.   yield();
  154.   tft.fillScreen(ILI9341_BLACK);
  155.   yield();
  156.   x1    = 0;
  157.   y1    = h - 1;
  158.   y2    = 0;
  159.   start = micros();
  160.   for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  161.   x2    = w - 1;
  162.   for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  163.   t    += micros() - start;
  164.   yield();
  165.   tft.fillScreen(ILI9341_BLACK);
  166.   yield();
  167.   x1    = w - 1;
  168.   y1    = h - 1;
  169.   y2    = 0;
  170.   start = micros();
  171.   for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  172.   x2    = 0;
  173.   for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  174.   yield();
  175.   return micros() - start;
  176. }
  177. unsigned long testFastLines(uint16_t color1, uint16_t color2) {
  178.   unsigned long start;
  179.   int           x, y, w = tft.width(), h = tft.height();
  180.   tft.fillScreen(ILI9341_BLACK);
  181.   start = micros();
  182.   for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
  183.   for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);
  184.   return micros() - start;
  185. }
  186. unsigned long testRects(uint16_t color) {
  187.   unsigned long start;
  188.   int           n, i, i2,
  189.                 cx = tft.width()  / 2,
  190.                 cy = tft.height() / 2;
  191.   tft.fillScreen(ILI9341_BLACK);
  192.   n     = min(tft.width(), tft.height());
  193.   start = micros();
  194.   for(i=2; i<n; i+=6) {
  195.     i2 = i / 2;
  196.     tft.drawRect(cx-i2, cy-i2, i, i, color);
  197.   }
  198.   return micros() - start;
  199. }
  200. unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
  201.   unsigned long start, t = 0;
  202.   int           n, i, i2,
  203.                 cx = tft.width()  / 2 - 1,
  204.                 cy = tft.height() / 2 - 1;
  205.   tft.fillScreen(ILI9341_BLACK);
  206.   n = min(tft.width(), tft.height());
  207.   for(i=n; i>0; i-=6) {
  208.     i2    = i / 2;
  209.     start = micros();
  210.     tft.fillRect(cx-i2, cy-i2, i, i, color1);
  211.     t    += micros() - start;
  212.     // Outlines are not included in timing results
  213.     tft.drawRect(cx-i2, cy-i2, i, i, color2);
  214.     yield();
  215.   }
  216.   return t;
  217. }
  218. unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
  219.   unsigned long start;
  220.   int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;
  221.   tft.fillScreen(ILI9341_BLACK);
  222.   start = micros();
  223.   for(x=radius; x<w; x+=r2) {
  224.     for(y=radius; y<h; y+=r2) {
  225.       tft.fillCircle(x, y, radius, color);
  226.     }
  227.   }
  228.   return micros() - start;
  229. }
  230. unsigned long testCircles(uint8_t radius, uint16_t color) {
  231.   unsigned long start;
  232.   int           x, y, r2 = radius * 2,
  233.                 w = tft.width()  + radius,
  234.                 h = tft.height() + radius;
  235.   // Screen is not cleared for this one -- this is
  236.   // intentional and does not affect the reported time.
  237.   start = micros();
  238.   for(x=0; x<w; x+=r2) {
  239.     for(y=0; y<h; y+=r2) {
  240.       tft.drawCircle(x, y, radius, color);
  241.     }
  242.   }
  243.   return micros() - start;
  244. }
  245. unsigned long testTriangles() {
  246.   unsigned long start;
  247.   int           n, i, cx = tft.width()  / 2 - 1,
  248.                       cy = tft.height() / 2 - 1;
  249.   tft.fillScreen(ILI9341_BLACK);
  250.   n     = min(cx, cy);
  251.   start = micros();
  252.   for(i=0; i<n; i+=5) {
  253.     tft.drawTriangle(
  254.       cx    , cy - i, // peak
  255.       cx - i, cy + i, // bottom left
  256.       cx + i, cy + i, // bottom right
  257.       tft.color565(i, i, i));
  258.   }
  259.   return micros() - start;
  260. }
  261. unsigned long testFilledTriangles() {
  262.   unsigned long start, t = 0;
  263.   int           i, cx = tft.width()  / 2 - 1,
  264.                    cy = tft.height() / 2 - 1;
  265.   tft.fillScreen(ILI9341_BLACK);
  266.   start = micros();
  267.   for(i=min(cx,cy); i>10; i-=5) {
  268.     start = micros();
  269.     tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
  270.       tft.color565(0, i*10, i*10));
  271.     t += micros() - start;
  272.     tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
  273.       tft.color565(i*10, i*10, 0));
  274.     yield();
  275.   }
  276.   return t;
  277. }
  278. unsigned long testRoundRects() {
  279.   unsigned long start;
  280.   int           w, i, i2,
  281.                 cx = tft.width()  / 2 - 1,
  282.                 cy = tft.height() / 2 - 1;
  283.   tft.fillScreen(ILI9341_BLACK);
  284.   w     = min(tft.width(), tft.height());
  285.   start = micros();
  286.   for(i=0; i<w; i+=6) {
  287.     i2 = i / 2;
  288.     tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0));
  289.   }
  290.   return micros() - start;
  291. }
  292. unsigned long testFilledRoundRects() {
  293.   unsigned long start;
  294.   int           i, i2,
  295.                 cx = tft.width()  / 2 - 1,
  296.                 cy = tft.height() / 2 - 1;
  297.   tft.fillScreen(ILI9341_BLACK);
  298.   start = micros();
  299.   for(i=min(tft.width(), tft.height()); i>20; i-=6) {
  300.     i2 = i / 2;
  301.     tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
  302.     yield();
  303.   }
  304.   return micros() - start;
  305. }

Dopo aver caricato il codice, sul display inizierete a vedere una dimostrazione grafica.



Questo è tutto!
per qualsiasi domanda lascia pure un commento, risponderò appena possibile.

Seguimi sulle mie pagine per rimanere sempre aggiornato sui nuovi post!

14 commenti:

  1. HELP!

    Ero riuscito a far funzionare questo ILI9341 cinese (identico a quello delle tue foto) in modalità SPI hardware che risulta essere almeno 4 volte più veloce, con il seguente costruttore:

    #define CS 10 //PIN3
    #define RST 8 //PIN4
    #define DC 9 //PIN5


    #define MOSI 11 //PIN6
    #define CLK 13 //PIN7
    #define MISO 12 //PIN9


    Adafruit_ILI9341 tft = Adafruit_ILI9341(CS, DC, RST);

    Dopo una reinstallazione dell'IDE di Arduino, alla riapertura dello stesso identico sketch salvato in precedenza, il display rimane bianco.

    Con il costruttore completo come da codice originale Adafruit (che dovrebbe essere la configurazione SPI Software):

    Adafruit_ILI9341 tft = Adafruit_ILI9341(CS, DC, MOSI, CLK, RST, MISO);

    la demo funziona ma è paurosamente lenta.


    Non ho cambiato nulla, resistori da 10K in serie ai PIN dati (tranne per il MISO) e sempre sullo stesso Arduino Nano V3.

    Sbaglio io? Mi sfugge qualcosa?

    Ho provato a fare il downgrade delle Adafruit_GFX, BusIO e ILI9341, pensando che un aggiornamento possa aver scombinato le cose, ma niente da fare.

    Qualche idea? :(

    RispondiElimina
  2. Risolto!

    10K sono troppi, valori ottimali sono 3.3K per i dati e 47 Ohm per la retroilluminazione.

    il tempo impiegato da fillScreen() passa da 28742796µs a 1496900, 19 volte più veloce! Provare per credere :D

    RispondiElimina
  3. Risposte
    1. Ciao Janux,
      scusa il distrubo.
      Io ho un problema credo simile al tuo.
      IL9341 ed un IL9488. (Hanno stesso Pinout identici, solo che uno e' 2,8" e l'altro 3,5")
      Gli ho collegati ad un Arduino Mega2560.
      Pin che so a memoria e fatti e rifgatti 30000 volte.
      Non ho usato resistenze ma i pin collegati direttamente. (5 V)
      Qualsisi test faccia, il display mi appare sempre Bianco.
      Idee ?
      Grazie mille

      Elimina
    2. Ciao Leonardo, non si può collegare i pin digitali del display direttamente ai pin di arduino in quanto il display funziona a 3,3V e invece i pin di Arduino usano il livello TTL (0-5V).
      Per questo motivo il display diventa bianco.
      Bisogna inserire sui pin digitali "in ingresso al display" dei partitori di tensione composti da 2 resistenze per pin. Quindi i pin 3,4,5,6,7 vanno collegati a ad arduino tramite 5 restitenze da 3,3K e lato arduino altre 5 resistenze verso massa da 6,8K. La stessa cosa va fatta con gli altri pin el caso tu voglia usare il touch screen o il lettore SD.

      Qui trovi lo schema elettrico: https://www.dropbox.com/s/9gwm2jqth2hlp0k/Adapter%20Schematic.jpg?dl=0

      Elimina
    3. Ah... dimenticavo, se alimenti il display da Arduino ricorda di inserire in serie al PIN 8 (LED) una resistenza da 33 o 47 ohm altrimenti si rischia di bruciare il led della retroilluminazione.

      Elimina
  4. Nel caso volessi aggiornare il tuo cablaggio Fritzing con il display oggetto dell'articolo anzichè quello Adafruit il componente ILI9341 lo trovi qui: https://forum.fritzing.org/uploads/short-url/fp9ng4DGVCqAPCNCAmoozHnU3BK.fzpz

    Ciao e grazie a te per tutto.

    RispondiElimina
    Risposte
    1. Si lo avevo visto, ma ho preferito quello attuale perchè indicava il nome del pin.
      Grazie mille comunque

      Elimina
    2. Grande Janux, Stasera provo e ti faccio sapere. Grazie davvero.

      Elimina
    3. Ciao Janux, ti confermo che funziona tutto perfettamente . !!! Grazie mille di nuovo.

      Elimina
  5. Questo commento è stato eliminato da un amministratore del blog.

    RispondiElimina
  6. Sono ricapitato per puro caso su questa pagina e rileggendo il mio commento del 18 luglio ho notato che avevo scritto una fesseria: le parole "lato arduino" vanno modificate in "lato display".
    Chiedo scusa.

    Ne approfitto per aggiungere questo:

    il partitore di tensione le prevede, tuttavia ho notato che il display funziona anche omettendo le resistenze da 6,8K verso GND, in quanto già da sole, quelle da 3,3K in serie ai PIN creano comunque una leggera caduta di tensione, che evidentemente basta a evitare la saturazione degli ingressi, quindi il display bianco.

    Lo schema del link dropbox è corretto.
    Ciao

    RispondiElimina

Lascia un commento qui sotto, ti risponderò il prima possibile!

Altri Post