Login Login
MORE

WIDGETS

Widgets

Wanted articles
Who is online?
Article tools

Domotica Arduino Integrazione Display TFT LCD

From Aino Wiki

Jump to: navigation, search

LCD TFT SPI - ILI9341 LCD with XPT2046 Touch

Il display da 3.2" con risoluzione è 240x320px ha due componenti fondamentali: il controller grafico ILI9341 e quello del touchscreen di tipo resistivo XPT2046 (di XPTek).
Occorrerebbe approfondire il protocollo di interfaccia seriale SPI (ideato inizialmente da Motorola) e che si contrappone all' I2C: elettronica-tech.it.

SPI 8-bit circular transfer.svg.png
Che nel caso ce ne siano altri diventa:
SPI Bus.jpg

IMPORTANTE come da specifiche del protocollo di interfaccia SPI il collegamento tra il display (slave) e Arduino (master) non può esser lungo, ad es. collegando un cavo maschio femmina da 20cm ho sperimentato che il display, per quanto acceso ed illuminato, non funzionasse! Display LCD TFT SPI - ILI9341 LCD with XPT2046 Touch acquistato su Temu a 13€:

L TLife 3.2 TFT SPI 240x320 v1.0.png

Progetto

NOTA quanto segue è una adattamento\copia di quanto suggerito qui (bytesnbits.co.uk).
Configurazione del bus SPI:
Display SPI 01.jpg

PS manca il collegamento giallo tra il Pin digitale 7 con la funzione di Slave Select sul touchscreen.
Tabella dei collegamenti:

Funzione collegamento Arduino TFT Touch
SCK

Serial Clock

Pin 13 SCK T_CLK
MISO

Master Input, Slave Output

Pin 12 SDO (MISO) T_DO

MOSI
Master Output, Slave Input

Pin 11 SDI (MOSI) T_DIN
SS

Slave Select

Pin 10 CS
DC

Data / Command

Pin 9 DC
RESET

Reset

Pin 8 RESET

SS
Slave Select (Touch)

Pin 7 T_CS

Tre collegamenti essenziali:

Display SPI 03 essential connections.jpg

NOTA, il display funziona con logica e tensione a 3.3V:

Display SPI 04 trasformazione a 3.3V.jpg

Dettaglio progetto:

Display SPI 05 schema progetto.jpg

Sistemazione su breadboard (design con Frizing):

Display SPI 06 progetto fritzing.jpg

Mia implementazione:

Mio prj TFT SPI 240x320 ILI9341 XPT2046 Touch.jpeg

Sketch per display

Sul fronte della programmazione, sketch, utilizzeremo la libreria Adafruit ILI9341 per gestire la comunicazione di basso livello con il pannello LCD.
Librerie da installare:

Usando VS Code e PatformIO le librerie ci sono e si ricercano ed aggiungono normalmente.
Sketch di esempio copiato (dalla libreria "Adafruit ILI9341") adattato in base al tutorial e corretto da un baco:

/***************************************************
  This is our GFX example for the Adafruit ILI9341 Breakout and Shield
  ----> http://www.adafruit.com/products/1651
  Written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/
#include <Arduino.h>
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
 
// For the Adafruit shield, these are the default.
#define TFT_RST 8 // Reset pin
#define TFT_DC 9  // Data/Command pin
#define TFT_CS 10 // Slave select o Chip Select (CS) pin
 
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
// If using the breakout, change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);
 
//Contratto funzioni locali
unsigned long testFillScreen(void);
unsigned long testText(void);
unsigned long testLines(uint16_t color);
unsigned long testFastLines(uint16_t color1, uint16_t color2);
unsigned long testRects(uint16_t color);
unsigned long testFilledRects(uint16_t color1, uint16_t color2);
unsigned long testFilledCircles(uint8_t radius, uint16_t color);
unsigned long testCircles(uint8_t radius, uint16_t color);
unsigned long testTriangles(void);
unsigned long testFilledTriangles(void);
unsigned long testRoundRects(void);
unsigned long testFilledRoundRects(void);
 
void setup() {
  Serial.begin(9600);
  Serial.println("ILI9341 Test!"); 
 
  // Si deselezionano tutti i dispositivi SPI
  pinMode(TFT_CS, OUTPUT);    // pin 10, Chip Select for TFT display
  pinMode(7, OUTPUT);         // Slave Select for second SPI device il touch screen
  digitalWrite(TFT_CS, HIGH); // pin 10, Chip Select for TFT display
  digitalWrite(7, HIGH);      // Slave Select for second SPI device il touch screen
 
  tft.begin();
 
  delay(4000); //Per darmi modo di aprire il monitor seriale e vedere quanto segue
  Serial.println(F("[Dalla funzione setup()] Starting..."));
 
  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(ILI9341_RDMODE);
  Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDMADCTL);
  Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDPIXFMT);
  Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDIMGFMT);
  Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDSELFDIAG);
  Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); 
 
  Serial.println(F("Benchmark                Time (microseconds)"));
  delay(10);
  Serial.print(F("Screen fill              "));
  Serial.println(testFillScreen());
  delay(500);
 
  Serial.print(F("Text                     "));
  Serial.println(testText());
  delay(3000);
 
  Serial.print(F("Lines                    "));
  Serial.println(testLines(ILI9341_CYAN));
  delay(500);
 
  Serial.print(F("Horiz/Vert Lines         "));
  Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE));
  delay(500);
 
  Serial.print(F("Rectangles (outline)     "));
  Serial.println(testRects(ILI9341_GREEN));
  delay(500);
 
  Serial.print(F("Rectangles (filled)      "));
  Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA));
  delay(500);
 
  Serial.print(F("Circles (filled)         "));
  Serial.println(testFilledCircles(10, ILI9341_MAGENTA));
 
  Serial.print(F("Circles (outline)        "));
  Serial.println(testCircles(10, ILI9341_WHITE));
  delay(500);
 
  Serial.print(F("Triangles (outline)      "));
  Serial.println(testTriangles());
  delay(500);
 
  Serial.print(F("Triangles (filled)       "));
  Serial.println(testFilledTriangles());
  delay(500);
 
  Serial.print(F("Rounded rects (outline)  "));
  Serial.println(testRoundRects());
  delay(500);
 
  Serial.print(F("Rounded rects (filled)   "));
  Serial.println(testFilledRoundRects());
  delay(500);
 
  Serial.println(F("[Dalla funzione setup()]  ... Done!"));
}
 
 
void loop(void) {
  for(uint8_t rotation=0; rotation<4; rotation++) {
    tft.setRotation(rotation);
    testText();
    delay(1000);
  }
}
 
unsigned long testFillScreen() {
  unsigned long start = micros();
  tft.fillScreen(ILI9341_BLACK);
  yield();
  tft.fillScreen(ILI9341_RED);
  yield();
  tft.fillScreen(ILI9341_GREEN);
  yield();
  tft.fillScreen(ILI9341_BLUE);
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
  return micros() - start;
}
 
unsigned long testText() {
  tft.fillScreen(ILI9341_BLACK);
  unsigned long start = micros();
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(1);
  tft.println("Ciao mondo cattivo!");
  tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
  tft.println(1234.56);
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(3);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(ILI9341_GREEN);
  tft.setTextSize(5);
  tft.println("Gruppo di dimensione 5");
  tft.setTextSize(2);
  tft.println("I implore thee,");
  tft.setTextSize(1);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  tft.println("......... fine della strana poesia......");
  return micros() - start;
}
 
unsigned long testLines(uint16_t color) {
  unsigned long start, t;
  int           x1, y1, x2, y2,
                w = tft.width(),
                h = tft.height();
 
  tft.fillScreen(ILI9341_BLACK);
  yield();
 
  x1 = y1 = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t     = micros() - start; // fillScreen doesn't count against timing
 
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
 
  x1    = w - 1;
  y1    = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;
 
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
 
  x1    = 0;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;
 
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
 
  x1    = w - 1;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
 
  yield();
  return micros() - start;
}
 
unsigned long testFastLines(uint16_t color1, uint16_t color2) {
  unsigned long start;
  int           x, y, w = tft.width(), h = tft.height();
 
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
  for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);
 
  return micros() - start;
}
 
unsigned long testRects(uint16_t color) {
  unsigned long start;
  int           n, i, i2,
                cx = tft.width()  / 2,
                cy = tft.height() / 2;
 
  tft.fillScreen(ILI9341_BLACK);
  n     = min(tft.width(), tft.height());
  start = micros();
  for(i=2; i<n; i+=6) {
    i2 = i / 2;
    tft.drawRect(cx-i2, cy-i2, i, i, color);
  }
 
  return micros() - start;
}
 
unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
  unsigned long start, t = 0;
  int           n, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  n = min(tft.width(), tft.height());
  for(i=n; i>0; i-=6) {
    i2    = i / 2;
    start = micros();
    tft.fillRect(cx-i2, cy-i2, i, i, color1);
    t    += micros() - start;
    // Outlines are not included in timing results
    tft.drawRect(cx-i2, cy-i2, i, i, color2);
    yield();
  }
 
  return t;
}
 
unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;
 
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(x=radius; x<w; x+=r2) {
    for(y=radius; y<h; y+=r2) {
      tft.fillCircle(x, y, radius, color);
    }
  }
 
  return micros() - start;
}
 
unsigned long testCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int           x, y, r2 = radius * 2,
                w = tft.width()  + radius,
                h = tft.height() + radius;
 
  // Screen is not cleared for this one -- this is
  // intentional and does not affect the reported time.
  start = micros();
  for(x=0; x<w; x+=r2) {
    for(y=0; y<h; y+=r2) {
      tft.drawCircle(x, y, radius, color);
    }
  }
 
  return micros() - start;
}
 
unsigned long testTriangles() {
  unsigned long start;
  int           n, i, cx = tft.width()  / 2 - 1,
                      cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  n     = min(cx, cy);
  start = micros();
  for(i=0; i<n; i+=5) {
    tft.drawTriangle(
      cx    , cy - i, // peak
      cx - i, cy + i, // bottom left
      cx + i, cy + i, // bottom right
      tft.color565(i, i, i));
  }
 
  return micros() - start;
}
 
unsigned long testFilledTriangles() {
  unsigned long start, t = 0;
  int           i, cx = tft.width()  / 2 - 1,
                   cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(i=min(cx,cy); i>10; i-=5) {
    start = micros();
    tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(0, i*10, i*10));
    t += micros() - start;
    tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(i*10, i*10, 0));
    yield();
  }
 
  return t;
}
 
unsigned long testRoundRects() {
  unsigned long start;
  int           w, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  w     = min(tft.width(), tft.height());
  start = micros();
  for(i=0; i<w; i+=6) {
    i2 = i / 2;
    tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0));
  }
 
  return micros() - start;
}
 
unsigned long testFilledRoundRects() {
  unsigned long start;
  int           i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(i=min(tft.width(), tft.height()); i>20; i-=6) {
    i2 = i / 2;
    tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
    yield();
  }
 
  return micros() - start;
}

Sketch per touchscreen

Per testare il touchscreen, si procede con un nuovo progetto, si installa la libreria:

  • XPT2046 library, al momento in elenco si trova con "XPT2046_Touchscreen" by Paul Stoffregen. GitHub: XPT2046_Touchscreen.

Si può usare il codice di esempio del file "TouchTestIRQ.ino" che si trova su GitHub della stessa libreria.
Questo programmino, semplicemente restituisce sul Serial Monitor: la pressione esercitata sullo schermo e le coordinate X ed Y in pixel della selezione sullo schermo!
NOTE

  • vanno fatte delle modifiche sullo sketch originale, si cambia il pin ChipSelect da 8 (assegnato al reset, vedasi cablatura sulla breadboard) a 7, nel setup si imposta l'uso dei PIN 10 e 7;
  • la velocità in bau della seriale deve essere impostata a 38400.
#include <Arduino.h>
#include <XPT2046_Touchscreen.h>
#include <SPI.h>
 
#define CS_PIN  7 //Chip select
// MOSI=11, MISO=12, SCK=13
 
// The TIRQ interrupt signal must be used for this example.
#define TIRQ_PIN  2
XPT2046_Touchscreen ts(CS_PIN);  // Param 2 - ULL - Ovvero no interrupts
//XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);  // Param 2 - Touch IRQ Pin - interrupt enabled polling
 
void setup() {
  Serial.begin(38400);
 
  // Deselect ALL SPI devices
  pinMode(10, OUTPUT);
  pinMode(7, OUTPUT);
  digitalWrite(10, HIGH);
  digitalWrite(7, HIGH);
 
  Serial.println("Premere lo schermo del Touchscreen si restituiranno: pressione e coordinate X e Y.");
 
  ts.begin();
  ts.setRotation(1);
  while (!Serial && (millis() <= 1000));
}
 
void loop() {
  // tirqTouched() is much faster than touched().  For projects where other SPI chips
  // or other time sensitive tasks are added to loop(), using tirqTouched() can greatly
  // reduce the delay added to loop() when the screen has not been touched.
  if (ts.tirqTouched()) {
    if (ts.touched()) {
      TS_Point p = ts.getPoint();
      Serial.print("Pressione = ");
      Serial.print(p.z);
      Serial.print(", x = ");
      Serial.print(p.x);
      Serial.print(", y = ");
      Serial.print(p.y);
      delay(30);
      Serial.println();
    }
  }
}

NOTA Per rilevare il tocco sullo schermo, si può usare direttamente la funzione ts.touched() (vedere lo sketch di sopra) ma non garantisce una corretta rilevazione e la libreria infatti suggerisce quanto segue:

    tirqTouched() is much faster than touched().  
    For projects where other SPI chips or other time sensitive tasks are added to loop(), using 
    tirqTouched() can greatly reduce the delay added to loop() when the screen has not been touched.


Output, come da VS Code e estensione SERIAL MONITOR:

Display SPI Touchscreen 01.jpg

Un gioco: Arcanoid

NOTA!!! Il codice del seguente gioco è di Bob, del sito Bytes N bits, ho fatto delle piccole correzioni ma sono GRATO PROFONDAMENTE a questo blogger che gratuitamente e generosamente ha condiviso con TUTTI.
Arduino Display touch e Arcanoid.jpeg

E' implementato usando VS Code con estensione PlatformIO, ho dovuto aggiungere le funzioni prototipo in testa e del codice di Debug... ATTENZIONE il bus che collega il display DEVE esser corto altrimenti lo schermo rimarrà BIANCO!
Articoli di riferimento (da Bytes N Bits):

Perchè si calibra

Per poter lavorare con le coordinate usate nell'applicazione occorrerà una calibrazione dello schermo ovvero calcoalre una corrispondenza approssimata tra quanto risulta al touchscreen resistivo e quanto risulta al display LCD, i due sono totalmente separati e non c'è corrispondenza esatta.
In parole povere questa necessità deriva dalla teconologia del touchscreen resistivo (indipendente dallo schermo LCD), il calcolo della posizione deriva da due numeri associato ad un coprischermo che quando vien toccato, questi due numeri sono la letture di due resistenze, una per le ascisse x del punto di contatto ed una per le ordinate y dello stesso punto.
Particolare della funzione di calibrazione:

#include <Arduino.h>
#include "SPI.h"
#include "Adafruit_ILI9341.h"
#include "XPT2046_Touchscreen.h"
 
Adafruit_ILI9341 m_tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
XPT2046_Touchscreen m_ts(TS_CS);
 
int16_t m_tftWidth = 0, m_tftHeight = 0; // Dimensioni schermo TFT
// Variabili calibrate per il touch screen:
float m_xCalM = 0.0, m_yCalM = 0.0;
float m_xCalC = 0.0, m_yCalC = 0.0;
 
void setup() {
	//...etc
	CalibrateTouchScreen();
	//...etc
}
 
void CalibrateTouchScreen(){
    TS_Point p;
    int16_t x1,y1,x2,y2; // Coordinate lette dal touchscreen in base ai valori dei RESISTORI!
    const int16_t c_whPlus = 20; // Ampiezza del + disegnato sullo schermo per la calibrazione
    if (m_isDebug) {}
    Serial.println("Calibrating touch screen...");
    Serial.print("Height: ");Serial.print(m_tftHeight);
    Serial.print(" x Width: ");Serial.println(m_tftWidth);
    Serial.println("Touch the corners as indicated to calibrate the touch screen...");
    m_tft.fillScreen(ILI9341_BLACK);
 
    while(m_ts.touched());                      // In realtà sembra inutile
    //Disegna un + in alto a SX
    m_tft.drawFastHLine(10,20,c_whPlus,ILI9341_RED); //Linea oriziontale del +
    m_tft.drawFastVLine(20,10,c_whPlus,ILI9341_RED); //Linea verticale   del +
    //Attende che l'utente tocchi lo schermo per poi prenderne la posizione
    while(!m_ts.touched());                      // !
    p = m_ts.getPoint();
    x1 = p.x; // Valore della resistenza sulle ascisse
    y1 = p.y; // Valore della resistenza sulle ascisse
    m_tft.drawFastHLine(10,20,c_whPlus,ILI9341_BLACK); // Cancella il +
    m_tft.drawFastVLine(20,10,c_whPlus,ILI9341_BLACK);
 
    Serial.println("Touch the corners bottom right on the screen...");
    delay(500);
    while(m_ts.touched());                      // In realtà sembra inutile
    //Disegna un + in basso a DX
    m_tft.drawFastHLine(m_tftWidth - 30,m_tftHeight - 20,c_whPlus,ILI9341_RED);
    m_tft.drawFastVLine(m_tftWidth - 20,m_tftHeight - 30,c_whPlus,ILI9341_RED);
    //Attende che l'utente tocchi lo schermo per poi prenderne la posizione
    while(!m_ts.touched());                      // !
    p = m_ts.getPoint();
    x2 = p.x;
    y2 = p.y;
    m_tft.drawFastHLine(m_tftWidth - 30,m_tftHeight - 20,c_whPlus,ILI9341_BLACK); // Cancella il +
    m_tft.drawFastVLine(m_tftWidth - 20,m_tftHeight - 30,c_whPlus,ILI9341_BLACK);
 
    // **********************************************************
    // !      Calcola i coefficienti di trasformazione          !
    // **********************************************************
    const int16_t c_BothXMargin = 40; //ex 40
    const int16_t c_BothYMargin = 40; //ex 40
    const float c_TouchXMargin = 20.0; // Ex 20.0 Margine in pixel da considerare sul touch screen
    const float c_TouchYMargin = 20.0; // Ex 20.0 Margine in pixel da considerare sul touch screen
 
    int16_t xDist = m_tftWidth - c_BothXMargin;
    int16_t yDist = m_tftHeight - c_BothYMargin;
    // translate in form pos = m x val + c
    // x
    m_xCalM = (float)xDist / (float)(x2 - x1);
    m_xCalC = c_TouchXMargin - ((float)x1 * m_xCalM);
    // y
    m_yCalM = (float)yDist / (float)(y2 - y1);
    m_yCalC = c_TouchYMargin - ((float)y1 * m_yCalM);
 
    Serial.print("(x1 = ");Serial.print(x1);
    Serial.print(", y1 = ");Serial.print(y1);
    Serial.print(") - (x2 = ");Serial.print(x2);
    Serial.print(", y2 = ");Serial.print(y2);Serial.println(")");
    Serial.print("m_xCalM = ");Serial.print(m_xCalM);
    Serial.print(", m_xCalC = ");Serial.print(m_xCalC);
    Serial.print("  -  m_yCalM = ");Serial.print(m_yCalM);
    Serial.print(", m_yCalC = ");Serial.println(m_yCalC);
 
    Serial.println("Calibration complete!");
}

Sketch

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include "XPT2046_Touchscreen.h"
#include "Math.h"
 
// function declarations
boolean checkCollision(int x1, int y1, int width1, int height1, int x2, int y2, int width2, int height2);
 
// For the Adafruit shield, these are the default.
#define TFT_CS 10
#define TFT_DC 9
#define TFT_MOSI 11
#define TFT_CLK 13
#define TFT_RST 8
#define TFT_MISO 12
 
#define TS_CS 7
 
#define ROTATION 3 // Landscape
 
// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC/RST
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
XPT2046_Touchscreen ts(TS_CS);
 
//Definizione dei prototipi delle funzioni
void drawLives();
void drawScore();
void drawLevel();
void initGameBoard();
void clearOldBallPos();
void moveBall();
void moveBat();
void checkHitBat();
void checkHitBlock();
boolean checkAllBlocksHit();
void newBall();
void initGame();
 
// Global variables
float xCalM = 0.0, yCalM = 0.0;
float xCalC = 0.0, yCalC = 0.0;
float xPos = 0.0, yPos = 0.0;
float xPosLast = 0.0, yPosLast = 0.0;
float xVel = 0.0, yVel = 0.0;
int8_t topBorder = 20;
int8_t batWidth = 30;
int8_t batHeight = 7;
int16_t batX = 0, batY = 0;
int8_t ballSize = 3;
int playerLives = 3;
int playerScore = 0;
int gameState = 1; // 1=start 2=playing 3=gameover
int level;
 
int16_t tftWidth = 0, tftHeight = 0;
 
class ScreenPoint {
  public:
    int16_t x;
    int16_t y;
 
  ScreenPoint(){
    // default contructor
  }
 
  ScreenPoint(int16_t xIn, int16_t yIn){
      x = xIn;
      y = yIn;
  }
};
 
class Block {
    public:
      int x;
      int y;
      int width;
      int height;
      int colour;
      int score;
      boolean isActive;
 
    // default constructor
    Block(){}
 
    Block(int xpos, int ypos, int bwidth, int bheight, int bcol, int bscore){
      x = xpos;
      y = ypos;
      width = bwidth;
      height = bheight;
      colour = bcol;
      score = bscore;
      isActive = true;
      drawBlock();
    }
 
  void drawBlock(){
    tft.fillRect(x,y,width,height,colour);
  }
 
  void removeBlock(){
    tft.fillRect(x,y,width,height,ILI9341_BLACK);
    isActive = false;
  }
 
  boolean isHit(float x1,float y1, int w1,int h1) {
    if (checkCollision((int)round(x1),(int)round(y1),w1,h1,x,y,width,height)) {
      return true;
    }
    else {
      return false;
    }
  }
};
 
Block blocks[5][16];
 
ScreenPoint getScreenCoords(int16_t x, int16_t y){
  int16_t xCoord = round((x * xCalM) + xCalC);
  int16_t yCoord = round((y * yCalM) + yCalC);
  if(xCoord < 0) xCoord = 0;
  if(xCoord >= tftWidth) xCoord = tftWidth - 1;
  if(yCoord < 0) yCoord = 0;
  if(yCoord >= tftHeight) yCoord = tftHeight - 1;
  return(ScreenPoint(xCoord, yCoord));
}
 
void calibrateTouchScreen(){
  TS_Point p;
  int16_t x1,y1,x2,y2;
 
  Serial.println("Calibrating touch screen...");
  Serial.print("Height: ");Serial.print(tftHeight);
  Serial.print(" x Width: ");Serial.println(tftWidth);
  Serial.println("Touch the corners as indicated to calibrate the touch screen...");
 
  tft.fillScreen(ILI9341_BLACK);
  // wait for no touch
  while(ts.touched());
  tft.drawFastHLine(10,20,20,ILI9341_RED);
  tft.drawFastVLine(20,10,20,ILI9341_RED);
  while(!ts.touched());
  p = ts.getPoint();
  x1 = p.x;
  y1 = p.y;
  tft.drawFastHLine(10,20,20,ILI9341_BLACK);
  tft.drawFastVLine(20,10,20,ILI9341_BLACK);
  delay(500);
  while(ts.touched());
  tft.drawFastHLine(tftWidth - 30,tftHeight - 20,20,ILI9341_RED);
  tft.drawFastVLine(tftWidth - 20,tftHeight - 30,20,ILI9341_RED);
  while(!ts.touched());
  p = ts.getPoint();
  x2 = p.x;
  y2 = p.y;
  tft.drawFastHLine(tftWidth - 30,tftHeight - 20,20,ILI9341_BLACK);
  tft.drawFastVLine(tftWidth - 20,tftHeight - 30,20,ILI9341_BLACK);
 
  int16_t xDist = tftWidth - 40;
  int16_t yDist = tftHeight - 40;
 
  // translate in form pos = m x val + c
  // x
  xCalM = (float)xDist / (float)(x2 - x1);
  xCalC = 20.0 - ((float)x1 * xCalM);
  // y
  yCalM = (float)yDist / (float)(y2 - y1);
  yCalC = 20.0 - ((float)y1 * yCalM);
 
  Serial.print("x1 = ");Serial.print(x1);
  Serial.print(", y1 = ");Serial.print(y1);
  Serial.print(" x2 = ");Serial.print(x2);
  Serial.print(", y2 = ");Serial.println(y2);
  Serial.print("xCalM = ");Serial.print(xCalM);
  Serial.print(", xCalC = ");Serial.print(xCalC);
  Serial.print(" yCalM = ");Serial.print(yCalM);
  Serial.print(", yCalC = ");Serial.println(yCalC);
 
  Serial.println("Calibration complete!");
}
 
 
void setup() {
  Serial.begin(9600);
 
  Serial.println(".............................^v^.........................");
  Serial.println("Game setup()");
  // avoid chip select contention
  pinMode(TS_CS, OUTPUT);
  digitalWrite(TS_CS, HIGH);
  pinMode(TFT_CS, OUTPUT);
  digitalWrite(TFT_CS, HIGH);
 
  tft.begin();
  tft.setRotation(ROTATION);
  tft.fillScreen(ILI9341_BLACK);
  tftWidth = tft.width();
  tftHeight = tft.height();
  ts.begin();
  ts.setRotation(ROTATION);
  calibrateTouchScreen();
 
  batY = tftHeight - batHeight -30;
  Serial.println("Setup complete...");
}
 
void initGame(){
  tft.fillScreen(ILI9341_BLACK);
  tft.drawFastHLine(0, topBorder-1, tftWidth, ILI9341_BLUE);
  tft.setCursor(0,5);
  tft.setTextSize(1);
  tft.setTextColor(ILI9341_WHITE);
  tft.print("SCORE :");
  tft.setCursor((tftWidth/2), 5);
  tft.print("LIVES :");
  tft.setCursor(tftWidth - 75, 5);
  tft.print("LEVEL :");
 
  batY = tftHeight - batHeight -30;
  playerLives = 3;
  playerScore = 0;
  level = 0;
 
  drawLives();
  drawScore();
  drawLevel();
 
  initGameBoard();
}
 
void initGameBoard() {
  int row, col;
  int colour, score;
  clearOldBallPos();
  xPosLast = xPos = 0;
  yPosLast = yPos = 90;
  xVel = 2;
  yVel = 2 + (level);
  gameState = 2;
 
  for(row=0; row < 5; row++){
    for (col=0; col < 16; col++){
      switch(row){
        case 0:
        case 1:
          colour = ILI9341_BLUE;
          score = 50;
        break;
        case 2:
        case 3:
          colour = ILI9341_MAGENTA;
          score = 30;
        break;
        case 4:
        case 5:
          colour = ILI9341_YELLOW;
          score = 10;
        break;
      }
      blocks[row][col] = Block(col*20, (row*10) + 30, 19, 9,colour,score);
    }
  }
}
 
void clearOldBallPos(){
  tft.fillCircle(round(xPosLast), round(yPosLast), ballSize, ILI9341_BLACK);
}
 
void moveBall(){
  float newX, newY;
  newX = xPos + xVel;
  newY = yPos + yVel;
  if (newX < (float)ballSize){
    newX = (float)ballSize;
    xVel = -xVel;
  }
  if (newX > (float)(tftWidth - ballSize - 1)){
    newX = (float)(tftWidth - ballSize - 1);
    xVel = -xVel;
  }
  if (newY < topBorder + (float)ballSize){
    newY = topBorder + (float)ballSize;
    yVel = -yVel;
  }
  if ((round(newX) != round(xPosLast)) || (round(newY) != round(yPosLast))){
    // draw ball
    clearOldBallPos();
    tft.fillCircle(round(newX), round(newY), ballSize, ILI9341_GREEN);
    xPosLast = newX;
    yPosLast = newY;
  }
  xPos = newX;
  yPos = newY;
}
 
void drawScore(){
  // clear old score
  tft.fillRect(50,5,25,10,ILI9341_BLACK);
  // print new score
  tft.setCursor(50,5);
  tft.setTextSize(1);
  tft.setTextColor(ILI9341_WHITE);
  tft.print(playerScore);
}
 
void drawLives(){
  // clear old lives
  tft.fillRect((tftWidth/2)+50,5,25,10,ILI9341_BLACK);
  // print new score
  tft.setCursor((tftWidth/2)+50,5);
  tft.setTextSize(1);
  tft.setTextColor(ILI9341_WHITE);
  tft.print(playerLives);
}
 
void drawLevel(){
  // clear old level
  tft.fillRect(tftWidth-25,5,25,10,ILI9341_BLACK);
  // print new score
  tft.setCursor(tftWidth-25,5);
  tft.setTextSize(1);
  tft.setTextColor(ILI9341_WHITE);
  tft.print(level + 1);
}
 
void newBall(){
  xPos = 0;
  yPos = 90;
  xVel = yVel = 2;
  moveBall();
  delay(1000);
}
 
boolean checkBallLost(){
  if (yPos > tftHeight + ballSize){
    return true;
  }
  else {
    return false;
  }
}
 
void moveBat(){
  int16_t newBatX;
  ScreenPoint sp = ScreenPoint(0,0);
  if (ts.touched()) {
    TS_Point p = ts.getPoint();
    sp = getScreenCoords(p.x, p.y);
    newBatX = sp.x - (batWidth / 2);
    if (newBatX < 0) newBatX = 0;
    if (newBatX >= (tftWidth - batWidth)) newBatX = tftWidth - 1 - batWidth;
  }
  if (abs(newBatX - batX) > 4){
    tft.fillRect(batX, batY, batWidth, batHeight,ILI9341_BLACK);
    batX = newBatX;
    tft.fillRect(batX, batY, batWidth, batHeight,ILI9341_RED);
  }
}
 
// bounding box collision detection
boolean checkCollision(int x1, int y1, int width1, int height1, int x2, int y2, int width2, int height2){
  boolean hit = false;
   if (
      (((x2 + width2) >= x1) && (x2 <= (x1 + width1)))
      && (((y2 + height2) >= y1) && (y2 <= (y1 + height1)))
      ) {
      hit = true;
    }
  return hit;
}
 
void checkHitBat(){
  // check bat and bottom half of ball
  float xInc;
  boolean hit = checkCollision(batX, batY, batWidth, batHeight, (int)round(xPos)-ballSize, (int)round(yPos), ballSize*2, ballSize);
  if (hit) {
      // reverse ball y direction but increase speed
      yVel += 0.05;
      if (yVel > 5){
      yVel = 5;
    }
    yVel = -yVel;
    // rounded bounce
    xInc = (xPos - (float)(batX + (batWidth / 2))) / (float)batWidth;
    xVel += 6 * xInc;
    if (abs(xVel) > 6){
      if (xVel < 0) {
        xVel = -6;
      }
      else {
        xVel = 6;
      }
    }
    // make sure ball not hitting bat
    yPos = (float)(batY - ballSize -1);
  }
}
 
void checkHitBlock(){
  int row, col;
  for (row=0; row<5; row++){
    for (col=0; col<16; col++){
      if (blocks[row][col].isActive && blocks[row][col].isHit(xPos,yPos, ballSize*2,ballSize*2)){
        blocks[row][col].removeBlock();
        playerScore += blocks[row][col].score;
        drawScore();
        yVel = -yVel;
        return;
      }
    }
  }
}
 
boolean checkAllBlocksHit(){
  int row, col, actives;
  actives = 0;
  for (row=0; row<5; row++){
      for (col=0; col<16; col++){
        if (blocks[row][col].isActive){
          return false;
      }
    }
  }
  return true; 
}
 
unsigned long lastFrame = millis();
 
void loop(void) {
  Serial.print("GameLoop state: ");Serial.println(gameState);
 
  // limit frame rate
  while((millis() - lastFrame) < 20);
  lastFrame = millis();
 
  switch(gameState){
    case 1: // start
      gameState = 11;
      break;
 
    case 11: // click to play
      tft.fillRect((tftWidth/2)-100,(tftHeight/2)-20,200,40,ILI9341_GREEN);
      tft.setCursor((tftWidth/2)-100+25,(tftHeight/2)-20+12);
      tft.setTextSize(2);
      tft.setTextColor(ILI9341_WHITE);
      tft.print("CLICK TO PLAY");
      gameState = 12;
      break;
 
    case 12: // wait for click to play
      if (ts.touched()) {
        TS_Point p = ts.getPoint();
        ScreenPoint sp = getScreenCoords(p.x, p.y);
        if (checkCollision(sp.x, sp.y,1,1,(tftWidth/2)-50,(tftHeight/2)-20,100,40)){
            initGame();
            gameState = 2;
        }
      }
      break;
 
    case 2: // play
 
      moveBall();
      moveBat();
      checkHitBat();
      checkHitBlock();
      if (checkBallLost()){
        playerLives --;
        drawLives();
        if (playerLives > 0){
          newBall();
        }
        else {
          gameState = 3; // end game
        }
      }
 
      if (checkAllBlocksHit()){
        gameState = 4;
      }
 
      break;
 
    case 4: // new blocks
      delay(1000);
      level ++;
      drawLevel();
      initGameBoard();
      break;
 
    case 3: // end
      tft.fillScreen(ILI9341_BLACK);
      tft.setCursor((tftWidth/2)-150,50);
      tft.setTextSize(3);
      tft.setTextColor(ILI9341_WHITE);
      tft.print("You Scored ");
      tft.print(playerScore);
      gameState = 11; // click to play
      break;
    }
}

Calcolatrice

Il seguente è un esempio dell'implementazione di pulsanti sullo schermo.... non è perfetto ma lo scopo non è creare una calcolatrice ma usare dei pulsanti sullo schermo.

Calcolatrice TFT.jpeg

Non ci sono modifiche hardware a quanto già fatto, lo sketch seguente è implementato in VS Code con estensione PlatformIO:

#include <Arduino.h>
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include "XPT2046_Touchscreen.h"
#include "Math.h"
// Usare #include <ArduinoExprEval.h>
 
// For the Adafruit shield, these are the default.
#define TS_CS 7
#define TFT_RST 8
#define TFT_DC 9
#define TFT_CS 10
#define TFT_MOSI 11
#define TFT_MISO 12
#define TFT_CLK 13
 
#define ROTATION 3 // Landscape
 
//-------------------CLASSI
class ScreenPoint {
  public:
    int16_t x;
    int16_t y;
 
  ScreenPoint(){
    // default contructor
  }
 
  ScreenPoint(int16_t xIn, int16_t yIn){
      x = xIn;
      y = yIn;
  }
};
 
class MyButton {
  public:
        int x;
        int y;
        int width;
        int height;
        String label;
 
    // Constructors
    MyButton(){}
    MyButton(int xPos, int yPos, int w, int h, String lab) {
      x = xPos;
      y = yPos;
      width = w;
      height = h;
      label = lab;
    }
};
//-------------------------
 
// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC/RST
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
XPT2046_Touchscreen ts(TS_CS);
 
MyButton m_Btns[16]; // Per comodità ci conserviamo i parametri di posizione di ogni bottone
 
//-- (Inizio) Definizione dei prototipi delle funzioni
void CalibrateTouchScreen();
ScreenPoint GetScreenCoords(int16_t x, int16_t y);
void PrintDisplayArea(String str);
void DrawAndSetCalculator();
void DebugPrint_ButtonsInfo();
boolean CheckCollision(int xTouchPoint, int yTouchPoint, int widthTP, int heightTP
                     , int xButton, int yButton, int widthB, int heightB);
//-- (Fine) Definizione dei prototipi delle funzioni
 
// Global variables
unsigned long lastFrame = millis();
const int c_leftMargin = 20;
const int c_rightMargin = 20;
const int c_topMargin  = 10;
int16_t m_tftWidth = 0, m_tftHeight = 0; // Dimensioni schermo TFT
// Variabili calibrate per il touch screen:
float m_xCalM = 0.0, m_yCalM = 0.0;
float m_xCalC = 0.0, m_yCalC = 0.0;
 
String m_stringaDisplay = "";
String m_stringNumber2 = "";
long m_number1 = 0;
long m_number2 = 0;
String m_CalcState = "";
 
void CalibrateTouchScreen(){
    TS_Point p;
    int16_t x1,y1,x2,y2; // Coordinate lette dal touch screen in base ai valori dei RESISTORI!
    Serial.println("Calibrating touch screen...");
    Serial.print("Height: ");Serial.print(m_tftHeight);
    Serial.print(" x Width: ");Serial.println(m_tftWidth);
    Serial.println("Touch the corners as indicated to calibrate the touch screen...");
    tft.fillScreen(ILI9341_BLACK);
 
    while(ts.touched());                      // In realtà sembra inutile
    //Disegna un + in alto a SX
    tft.drawFastHLine(10,20,20,ILI9341_RED);
    tft.drawFastVLine(20,10,20,ILI9341_RED);
    //Attende che l'utente tocchi lo schermo per poi prenderne la posizione
    while(!ts.touched());                      // !
    p = ts.getPoint();
    x1 = p.x; // Valore della resistenza sulle ascisse
    y1 = p.y; // Valore della resistenza sulle ascisse
    tft.drawFastHLine(10,20,20,ILI9341_BLACK); // Cancella il +
    tft.drawFastVLine(20,10,20,ILI9341_BLACK);
 
    Serial.println("Touch the corners bottom right on the screen...");
    delay(500);
    while(ts.touched());                      // In realtà sembra inutile
    //Disegna un + in basso a DX
    tft.drawFastHLine(m_tftWidth - 30,m_tftHeight - 20,20,ILI9341_RED);
    tft.drawFastVLine(m_tftWidth - 20,m_tftHeight - 30,20,ILI9341_RED);
    //Attende che l'utente tocchi lo schermo per poi prenderne la posizione
    while(!ts.touched());                      // !
    p = ts.getPoint();
    x2 = p.x;
    y2 = p.y;
    tft.drawFastHLine(m_tftWidth - 30,m_tftHeight - 20,20,ILI9341_BLACK); // Cancella il +
    tft.drawFastVLine(m_tftWidth - 20,m_tftHeight - 30,20,ILI9341_BLACK);
 
    // **********************************************************
    // !      Calcola i coefficienti di trasformazione          !
    // **********************************************************
    const int16_t c_BothXMargin = 40; //ex 40
    const int16_t c_BothYMargin = 40; //ex 40
    const float c_TouchXMargin = 20.0; // Ex 20.0 Margine in pixel da considerare sul touch screen
    const float c_TouchYMargin = 20.0; // Ex 20.0 Margine in pixel da considerare sul touch screen
 
    int16_t xDist = m_tftWidth - c_BothXMargin;
    int16_t yDist = m_tftHeight - c_BothYMargin;
    // translate in form pos = m x val + c
    // x
    m_xCalM = (float)xDist / (float)(x2 - x1);
    m_xCalC = c_TouchXMargin - ((float)x1 * m_xCalM);
    // y
    m_yCalM = (float)yDist / (float)(y2 - y1);
    m_yCalC = c_TouchYMargin - ((float)y1 * m_yCalM);
 
    Serial.print("(x1 = ");Serial.print(x1);
    Serial.print(", y1 = ");Serial.print(y1);
    Serial.print(") - (x2 = ");Serial.print(x2);
    Serial.print(", y2 = ");Serial.print(y2);Serial.println(")");
    Serial.print("m_xCalM = ");Serial.print(m_xCalM);
    Serial.print(", m_xCalC = ");Serial.print(m_xCalC);
    Serial.print("  -  m_yCalM = ");Serial.print(m_yCalM);
    Serial.print(", m_yCalC = ");Serial.println(m_yCalC);
 
    Serial.println("Calibration complete!");
}
 
// Converte le coordinate lette dal touch screen in coordinate dello schermo TFT
ScreenPoint GetScreenCoords(int16_t x, int16_t y){
  int16_t xCoord = round((x * m_xCalM) + m_xCalC);
  int16_t yCoord = round((y * m_yCalM) + m_yCalC);
  // Correzione se escono dai limiti dello schermo:
  if(xCoord < 0) 
    xCoord = 0;
  if(xCoord >= m_tftWidth) 
    xCoord = m_tftWidth - 1;
  if(yCoord < 0) 
    yCoord = 0;
  if(yCoord >= m_tftHeight) 
    yCoord = m_tftHeight - 1;
  return(ScreenPoint(xCoord, yCoord));
}
 
// Stampa l'area di display della calcolatrice
void PrintDisplayArea(String str){  
  tft.fillRect(c_leftMargin,c_topMargin, (m_tftWidth-c_leftMargin-c_rightMargin),24, ILI9341_PURPLE);
  tft.setCursor(c_leftMargin+5, c_topMargin+5);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE);
  tft.print(str);
}
 
// Disegna la calcolatrice e setta i bottoni
void DrawAndSetCalculator(){
  String btnLbl = " ";
  tft.fillScreen(ILI9341_BLACK);
  int c_buttonWH = 22;
  int c_buttonSpacing = 10;
 
  // Display dei calcoli:
  PrintDisplayArea("0"); // Reset display area
 
  // 5 Bottoni     0 1 2 3 4
  int buttonY = c_topMargin + 24 + 8; // =42
  int x = 0;
  for (int col=0; col<=4; col++){
      x = c_leftMargin + (col * (c_buttonWH + c_buttonSpacing));
 
      btnLbl = (String)col;
      m_Btns[col] = MyButton(x, buttonY, c_buttonWH, c_buttonWH, btnLbl);
 
      //           x,y      , w         ,h     , color
      tft.fillRect(x,buttonY, c_buttonWH,c_buttonWH, ILI9341_LIGHTGREY);
      tft.setCursor(x+5, buttonY+5);
      tft.setTextSize(2);
      tft.setTextColor(ILI9341_BLUE);
      tft.print(col);
   }
   // 5 Bottoni     5 6 7 8 9
   buttonY += c_buttonWH + c_buttonSpacing; // 42+22+10 =74
   for (int col=5; col<=9; col++){
      x = c_leftMargin + ((col-5) * (c_buttonWH + c_buttonSpacing));
 
      btnLbl = (String)col;
      m_Btns[col] = MyButton(x, buttonY, c_buttonWH, c_buttonWH, btnLbl);
      //           x,y      , w         , h        , color
      tft.fillRect(x,buttonY, c_buttonWH,c_buttonWH, ILI9341_LIGHTGREY);
      tft.setCursor(x+5, buttonY+5);
      tft.setTextSize(2);
      tft.setTextColor(ILI9341_BLUE);
      tft.print(col);
   }
 
  // 6 Bottoni    + - * / = C
  buttonY += c_buttonWH + c_buttonSpacing; // 74+22+10 =106
  for (int col=0; col<=5; col++){
      x = c_leftMargin + (col * (c_buttonWH + c_buttonSpacing));
      //           x,y      , w         ,h         , color
      tft.fillRect(x,buttonY, c_buttonWH,c_buttonWH, ILI9341_MAROON);
      tft.setCursor(x+5, buttonY+5);
      tft.setTextSize(2);
      tft.setTextColor(ILI9341_WHITE);
      switch (col)
      {
        case 0:
          btnLbl = "+";
          tft.print(btnLbl);
          break;
        case 1:
          btnLbl = "-";
          tft.print(btnLbl);
          break;
        case 2:
          btnLbl = "*";
          tft.print(btnLbl);
          break;
        case 3:
          btnLbl = "/";
          tft.print(btnLbl);
          break;
        case 4:
          btnLbl = "=";
          tft.print(btnLbl);
          break;
        case 5:
          btnLbl = "C";
          tft.print(btnLbl);
          break;
      }      
      m_Btns[10+col] = MyButton(x, buttonY, c_buttonWH, c_buttonWH, btnLbl); // Label da settare dopo
  }
}
 
void DebugPrint_ButtonsInfo(){
  Serial.println();
  Serial.println("Buttons info:");
 
  for (int i=0; i<=15; i++){
    Serial.print("Button ");
    Serial.print(i);
    Serial.print(" - x: ");
    Serial.print(m_Btns[i].x);
    Serial.print(", y: ");
    Serial.print(m_Btns[i].y);
    Serial.print(", w: ");
    Serial.print(m_Btns[i].width);
    Serial.print(", h: ");
    Serial.print(m_Btns[i].height);
    Serial.print(", label: ");
    Serial.print(m_Btns[i].label);
    Serial.println(".");
  }  
  Serial.println();
}
 
boolean CheckCollision(int xTouchPoint, int yTouchPoint, int widthTP, int heightTP
                     , int xButton, int yButton, int widthB, int heightB){
  boolean hit = false;
   if (
      (((xButton + widthB) >= xTouchPoint) && (xButton <= (xTouchPoint + widthTP)))
      && (((yButton + heightB) >= yTouchPoint) && (yButton <= (yTouchPoint + heightTP)))
      ) {
      hit = true;
    }
  return hit;
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Arduino setup and loop functions !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
void setup() {
    Serial.begin(9600);
    Serial.println("Test Calcolatrice");
    // avoid chip select contention
    pinMode(TS_CS, OUTPUT);
    digitalWrite(TS_CS, HIGH);
    pinMode(TFT_CS, OUTPUT);
    digitalWrite(TFT_CS, HIGH);
 
    tft.begin();
    tft.setRotation(ROTATION);
    tft.fillScreen(ILI9341_BLACK);
    m_tftWidth  = tft.width();
    m_tftHeight = tft.height();
    ts.begin();
    ts.setRotation(ROTATION);
 
    CalibrateTouchScreen();
 
    DrawAndSetCalculator();
 
    DebugPrint_ButtonsInfo();
}
 
void loop() {
    // Prosegue solo quando sono passati 20 ms dall'ultimo touch
    while((millis() - lastFrame) < 40);
    lastFrame = millis();
 
    if (ts.touched()) {
      TS_Point p = ts.getPoint();
      //delay(200); // debounce
      while(ts.touched()); // Attende che l'utente rilasci il touch, per evitare di scrivere ripetutamente lo stesso carattere
      ScreenPoint sp = GetScreenCoords(p.x, p.y);
      Serial.print("Hit pos. x="); Serial.print(sp.x); Serial.print(", y="); Serial.print(sp.y); Serial.print(".");
      Serial.print("  ~x="); Serial.print(p.x); Serial.print(", ~y="); Serial.println(p.y);
 
      for (int i=0; i<=15; i++){
        if (CheckCollision(sp.x       , sp.y       , 4              , 4, 
                           m_Btns[i].x, m_Btns[i].y, m_Btns[i].width, m_Btns[i].height)){
          Serial.print("--> Btn i="); Serial.print(i); Serial.print(" - lbl: "); Serial.print(m_Btns[i].label); Serial.println(".");  
 
          //m_stringaDisplay = m_stringaDisplay.replace("0",""); // Rimuove l'underscore di reset display area
          switch (i)
          {
            case 0:
              m_stringaDisplay += m_Btns[i].label; // Bottone 0
              PrintDisplayArea(m_stringaDisplay);
              if (m_CalcState == "OpSum"
                || m_CalcState == "OpSub"
                || m_CalcState == "OpMul" 
                || m_CalcState == "OpDiv") {
                m_stringNumber2 += m_Btns[i].label; // Bottone 0
              }              
              break;
            case 1:
              m_stringaDisplay += m_Btns[i].label; // Bottone 1
              PrintDisplayArea(m_stringaDisplay);
              if (m_CalcState == "OpSum"
                || m_CalcState == "OpSub"
                || m_CalcState == "OpMul" 
                || m_CalcState == "OpDiv"){
                m_stringNumber2 += m_Btns[i].label; // Bottone 1
              }              
              break;
            case 2:
              m_stringaDisplay += m_Btns[i].label; // Bottone 2
              PrintDisplayArea(m_stringaDisplay);
              if (m_CalcState == "OpSum"
                || m_CalcState == "OpSub"
                || m_CalcState == "OpMul" 
                || m_CalcState == "OpDiv"){
                m_stringNumber2 += m_Btns[i].label; // Bottone 2
              }              
              break;
            case 3:
              m_stringaDisplay += m_Btns[i].label; // Bottone 3
              PrintDisplayArea(m_stringaDisplay);
              if (m_CalcState == "OpSum"
                || m_CalcState == "OpSub"
                || m_CalcState == "OpMul" 
                || m_CalcState == "OpDiv"){
                m_stringNumber2 += m_Btns[i].label; // Bottone 3
              }              
              break;
            case 4:
              m_stringaDisplay += m_Btns[i].label; // Bottone 4
              PrintDisplayArea(m_stringaDisplay);
              if (m_CalcState == "OpSum"
                || m_CalcState == "OpSub"
                || m_CalcState == "OpMul" 
                || m_CalcState == "OpDiv") {
                m_stringNumber2 += m_Btns[i].label; // Bottone 4
              }              
              break;
            case 5:
              m_stringaDisplay += m_Btns[i].label; // Bottone 5
              PrintDisplayArea(m_stringaDisplay);
              if (m_CalcState == "OpSum"
                || m_CalcState == "OpSub"
                || m_CalcState == "OpMul" 
                || m_CalcState == "OpDiv") {
                m_stringNumber2 += m_Btns[i].label; // Bottone 5
              }              
              break;
            case 6:
              m_stringaDisplay += m_Btns[i].label; // Bottone 6
              PrintDisplayArea(m_stringaDisplay);
              if (m_CalcState == "OpSum"
                || m_CalcState == "OpSub"
                || m_CalcState == "OpMul" 
                || m_CalcState == "OpDiv"){
                m_stringNumber2 += m_Btns[i].label; // Bottone 6
              }              
              break;
            case 7:
              m_stringaDisplay += m_Btns[i].label; // Bottone 7
              PrintDisplayArea(m_stringaDisplay);
              if (m_CalcState == "OpSum"
                || m_CalcState == "OpSub"
                || m_CalcState == "OpMul" 
                || m_CalcState == "OpDiv"){
                m_stringNumber2 += m_Btns[i].label; // Bottone 7
              }              
              break;
            case 8:
              m_stringaDisplay += m_Btns[i].label; // Bottone 8
              PrintDisplayArea(m_stringaDisplay);
              if (m_CalcState == "OpSum"
                || m_CalcState == "OpSub"
                || m_CalcState == "OpMul" 
                || m_CalcState == "OpDiv") {
                m_stringNumber2 += m_Btns[i].label; // Bottone 8
              }              
              break;
            case 9:
              m_stringaDisplay += m_Btns[i].label; // Bottone 9
              PrintDisplayArea(m_stringaDisplay);
              if (m_CalcState == "OpSum"
                || m_CalcState == "OpSub"
                || m_CalcState == "OpMul" 
                || m_CalcState == "OpDiv"){
                m_stringNumber2 += m_Btns[i].label; // Bottone 9
              }              
              break;
            case 10:
              // Operazione +
              m_CalcState = "OpSum";
              m_number1 = m_stringaDisplay.toInt();
              m_stringaDisplay += m_Btns[i].label; // Bottone +
              PrintDisplayArea(m_stringaDisplay);
              break;
            case 11:
              // Operazione -
              m_CalcState = "OpSub";
              m_number1 = m_stringaDisplay.toInt();
              m_stringaDisplay += m_Btns[i].label; // Bottone -
              PrintDisplayArea(m_stringaDisplay);
              break;
            case 12:
              // Operazione *
              m_CalcState = "OpMul";
              m_number1 = m_stringaDisplay.toInt();
              m_stringaDisplay += m_Btns[i].label; // Bottone *
              PrintDisplayArea(m_stringaDisplay);
              break;
            case 13:
              // Operazione /
              m_CalcState = "OpDiv";
              m_number1 = m_stringaDisplay.toInt();
              m_stringaDisplay += m_Btns[i].label; // Bottone /
              PrintDisplayArea(m_stringaDisplay);
              break;
            case 14:
            {
              // Operatore =
              m_stringaDisplay += m_Btns[i].label; // Bottone =
              m_number2 = m_stringNumber2.toInt();
              long result = 0;
              if (m_CalcState == "OpSum"){
                result = m_number1 + m_number2;
              }
              else if (m_CalcState == "OpSub"){
                result = m_number1 - m_number2;
              }
              else if (m_CalcState == "OpMul"){
                result = m_number1 * m_number2;
              }
              else if (m_CalcState == "OpDiv"){
                if (m_number2 != 0){
                  result = m_number1 / m_number2;
                }
                else{
                  m_stringaDisplay = "Err:div0";
                  PrintDisplayArea(m_stringaDisplay);
                  break;
                }
              }
              m_stringaDisplay += String(result);
              PrintDisplayArea(m_stringaDisplay);
 
              m_CalcState = "";
              m_stringaDisplay = "";
              m_stringNumber2 = "";
              m_number1 = 0;
              m_number2 = 0;
              break;
            }
            case (int)15:
              // Operatore C , pulizia calcoli
              m_CalcState = "";
              m_stringaDisplay = "";
              m_stringNumber2 = "";
              m_number1 = 0;
              m_number2 = 0;
              PrintDisplayArea("0"); // Reset display area
              break;
          }
        }
    }
  }
}

Sketch utili

Scroll del testo

Copiato da GitHub BodManer

/*************************************************************
  This sketch implements a simple serial receive terminal
  program for monitoring serial debug messages from another
  board.
 
  Connect GND to target board GND
  Connect RX line to TX line of target board
  Make sure the target and terminal have the same baud rate
  and serial stettings!
 
  The sketch works with the ILI9341 TFT 240x320 display and
  the called up libraries.
 
  The sketch uses the hardware scrolling feature of the
  display. Modification of this sketch may lead to problems
  unless the ILI9341 data sheet has been understood!
 
  Updated by Bodmer 21/7/16 for TFT_ILI9341 library:
  https://github.com/Bodmer/TFT_ILI9341
 
  BSD license applies, all text above must be included in any
  redistribution
 *************************************************************/
 
// In most cases characters don't get lost at 9600 baud but
// it is a good idea to increase the serial Rx buffer from 64
// to 512 or 1024 bytes especially if higher baud rates are
// used (this sketch does not need much RAM).
// The method described here works well:
// http://www.hobbytronics.co.uk/arduino-serial-buffer-size
//
 
#include <TFT_ILI9341.h> // Hardware-specific library
#include <SPI.h>
 
TFT_ILI9341 tft = TFT_ILI9341();       // Invoke custom library
 
// The scrolling area must be a integral multiple of TEXT_HEIGHT
#define TEXT_HEIGHT 16 // Height of text to be printed and scrolled
#define BOT_FIXED_AREA 0 // Number of lines in bottom fixed area (lines counted from bottom of screen)
#define TOP_FIXED_AREA 16 // Number of lines in top fixed area (lines counted from top of screen)
#define YMAX 320 // Bottom of screen area
 
// The initial y coordinate of the top of the scrolling area
uint16_t yStart = TOP_FIXED_AREA;
// yArea must be a integral multiple of TEXT_HEIGHT
uint16_t yArea = YMAX-TOP_FIXED_AREA-BOT_FIXED_AREA;
// The initial y coordinate of the top of the bottom text line
uint16_t yDraw = YMAX - BOT_FIXED_AREA - TEXT_HEIGHT;
 
// Keep track of the drawing x coordinate
uint16_t xPos = 0;
 
// For the byte we read from the serial port
byte data = 0;
 
// A few test variables used during debugging
boolean change_colour = 1;
boolean selected = 1;
 
// We have to blank the top line each time the display is scrolled, but this takes up to 13 milliseconds
// for a full width line, meanwhile the serial buffer may be filling... and overflowing
// We can speed up scrolling of short text lines by just blanking the character we drew
int blank[19]; // We keep all the strings pixel lengths to optimise the speed of the top line blanking
 
void setup() {
  // Setup the TFT display
  tft.init();
  tft.setRotation(0); // Must be setRotation(0) for this sketch to work correctly
  tft.fillScreen(TFT_BLACK);
 
  // Setup baud rate and draw top banner
  Serial.begin(9600);
 
  tft.setTextColor(TFT_WHITE, TFT_BLUE);
  tft.fillRect(0,0,240,16, TFT_BLUE);
  tft.drawCentreString(" Serial Terminal - 9600 baud ",120,0,2);
 
  // Change colour for scrolling zone text
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
 
  // Setup scroll area
  setupScrollArea(TOP_FIXED_AREA, BOT_FIXED_AREA);
 
  // Zero the array
  for (byte i = 0; i<18; i++) blank[i]=0;
}
 
 
void loop(void) {
  //  These lines change the text colour when the serial buffer is emptied
  //  These are test lines to see if we may be losing characters
  //  Also uncomment the change_colour line below to try them
  //
  //  if (change_colour){
  //  change_colour = 0;
  //  if (selected == 1) {tft.setTextColor(TFT_CYAN, TFT_BLACK); selected = 0;}
  //  else {tft.setTextColor(TFT_MAGENTA, TFT_BLACK); selected = 1;}
  //}
 
  while (Serial.available()) {
    data = Serial.read();
    // If it is a CR or we are near end of line then scroll one line
    if (data == '\r' || xPos>231) {
      xPos = 0;
      yDraw = scroll_line(); // It can take 13ms to scroll and blank 16 pixel lines
    }
    if (data > 31 && data < 128) {
      xPos += tft.drawChar(data,xPos,yDraw,2);
      blank[(18+(yStart-TOP_FIXED_AREA)/TEXT_HEIGHT)%19]=xPos; // Keep a record of line lengths
    }
    //change_colour = 1; // Line to indicate buffer is being emptied
  }
}
 
// ##############################################################################################
// Call this function to scroll the display one text line
// ##############################################################################################
int scroll_line() {
  int yTemp = yStart; // Store the old yStart, this is where we draw the next line
  // Use the record of line lengths to optimise the rectangle size we need to erase the top line
  tft.fillRect(0,yStart,blank[(yStart-TOP_FIXED_AREA)/TEXT_HEIGHT],TEXT_HEIGHT, TFT_BLACK);
 
  // Change the top of the scroll area
  yStart+=TEXT_HEIGHT;
  // The value must wrap around as the screen memory is a circular buffer
  if (yStart >= YMAX - BOT_FIXED_AREA) yStart = TOP_FIXED_AREA + (yStart - YMAX + BOT_FIXED_AREA);
  // Now we can scroll the display
  scrollAddress(yStart);
  return  yTemp;
}
 
// ##############################################################################################
// Setup a portion of the screen for vertical scrolling
// ##############################################################################################
// We are using a hardware feature of the display, so we can only scroll in portrait orientation
void setupScrollArea(uint16_t tfa, uint16_t bfa) {
  tft.writecommand(ILI9341_VSCRDEF); // Vertical scroll definition
  tft.writedata(tfa >> 8);           // Top Fixed Area line count
  tft.writedata(tfa);
  tft.writedata((YMAX-tfa-bfa)>>8);  // Vertical Scrolling Area line count
  tft.writedata(YMAX-tfa-bfa);
  tft.writedata(bfa >> 8);           // Bottom Fixed Area line count
  tft.writedata(bfa);
}
 
// ##############################################################################################
// Setup the vertical scrolling start address pointer
// ##############################################################################################
void scrollAddress(uint16_t vsp) {
  tft.writecommand(ILI9341_VSCRSADD); // Vertical scrolling pointer
  tft.writedata(vsp>>8);
  tft.writedata(vsp);
}

Paginazione del testo di log

Il seguente si presta alla scrittura del testo sul display come una sequenza di righe, come in una applicazione di logging o una chat, è tarato per la dimensione minima del testo ovvero 1, sono previste 30 righe e nel caso nel testo ci sia un riotrno accapo questo verrà considerato nel conteggio del rigo corrente. Quando il testo raggiunge il massimo rigo il display viene pulito e si riscrive sul primo rigo e così via.

#include <Arduino.h>
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
//---------------------Costanti per il display TFT---------------------
#define TS_CS 7   // Chip Select pin for the touch screen
#define TFT_RST 8 // Reset pin
#define TFT_DC 9  // Data/Command pin
#define TFT_CS 10 // Slave select o Chip Select (CS) pin
#define TFT_MOSI 11
#define TFT_MISO 12
#define TFT_CLK 13
 
const uint8_t m_rotationLandscapeInv = 3;   //Rotazione display landscape
const uint8_t m_maxRoxsTxt1 = 30;           //Numero massimo di righe di testo con dimensione 1
 
long m_lastUpdateSmartPhone = 0;
int m_intCounter = 0;
String m_strCount = "";
String m_strMessage = "";
String m_strTmp = "";
int16_t m_tftWidth = 0, m_tftHeight = 0;    //Dimensioni schermo TFT, valorizzate in setup()
uint8_t m_currRow = 0;                      //Riga corrente per stampa testo, supponendo di dimensione 1, quindi max 30 righe (m_maxRoxsTxt1) per evitare di sovrascrivere il testo precedente
 
//Per il display TFT
Adafruit_ILI9341 m_tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
 
//---------------------- PROTOTIPI Funzioni globali ----------------------------
void Println(String text, byte textSize, uint16_t colorText);
void PrintTFT(int x, int y, const char* text, byte textSize, uint16_t colorText);
void PrintTFT(int x, int y, String text, byte textSize, uint16_t colorText);
void PrintTFTln(String text, byte textSize, uint16_t colorText);
//---------------------- END PROTOTIPI Funzioni globali ------------------------
 
 
void setup() {
  Serial.begin(9600);
 
  // Si deselezionano tutti i dispositivi SPI
  pinMode(TFT_CS, OUTPUT);    // pin 10, Chip Select for TFT display
  pinMode(7, OUTPUT);         // Slave Select for second SPI device il touch screen
  digitalWrite(TFT_CS, HIGH); // pin 10, Chip Select for TFT display
  digitalWrite(7, HIGH);      // Slave Select for second SPI device il touch screen
 
  m_tft.begin();
 
  m_tft.setRotation(m_rotationLandscapeInv);
  m_tft.fillScreen(ILI9341_BLACK);
  m_tftWidth  = m_tft.width();
  m_tftHeight = m_tft.height();
 
  //Si attende che la seriale sia pronta, con un timeout di 2 secondi
  //altrimenti se se ci fosse l'istruzione  while (!Serial) e non si avviasse 
  //il Monitor Seriale l'applicazione andrebbe in loop infinito
  unsigned long previousMillis = millis();
  unsigned long currentMillis = millis();
  while (!Serial 
    && (currentMillis - previousMillis <= 2000)) {	//timeout 2s per evitare di restare bloccati
      currentMillis = millis();
  }
 
  m_strMessage = "fine setup()";
  Println(m_strMessage, 1, ILI9341_PURPLE);
}
 
void loop() {
	//Scrive il contatore ogni secondo
    if (millis() - m_lastUpdateSmartPhone > 1000) {
        m_lastUpdateSmartPhone = millis();
        m_intCounter++;
        m_strCount = String(m_intCounter);
        m_strMessage = "Conteggio: " + m_strCount;
        Println(m_strMessage, 1, ILI9341_GREEN);
    }
}
 
void Println(String text, byte textSize, uint16_t colorText) {
  PrintTFTln(text, textSize, colorText);
  if (Serial) {
    Serial.println(text);
  }
}
 
void PrintTFT(int x, int y, const char* text, byte textSize, uint16_t colorText) {
	m_tft.setCursor(x, y); 
	m_tft.setTextColor(colorText); 
	m_tft.setTextSize(textSize);
	m_tft.print(text);
}
 
void PrintTFT(int x, int y, String text, byte textSize, uint16_t colorText) {
  if (x == -1 && y == -1) {
    m_tft.setCursor(x, y);
  }
  m_tft.setTextColor(colorText);
  m_tft.setTextSize(textSize);
  m_tft.print(text);
}
 
void PrintTFTln(String text, byte textSize, uint16_t colorText) { 
  if (text.indexOf('\n') != -1) {
    m_currRow++;
  }
  m_tft.setTextColor(colorText);
  m_tft.setTextSize(textSize);
  m_tft.println(text);
  m_currRow++;
  if (m_currRow >= m_maxRoxsTxt1) {
    m_currRow = 0;
    m_tft.fillScreen(ILI9341_BLACK); // Pulisce lo schermo quando si raggiunge il numero massimo di righe
    m_tft.setCursor(0, 0); // Torna alla prima riga dopo aver pulito lo schermo
  }
}

Lettore SSD

Questo particolare display consente persino la lettura di una scheda di memoria SSD!
Il materiale per studiare ed implementare è sul sito Bytes N Bits, attualmente solo un video ma esaustivo. Sarà necessario uno switch di corrente come già visto, allo scopo si suggerisce qui l'uso di "level shifter" (ce ne sono di bidirezionali da 5V a 3.3 e viceversa).
La libreria da utilizzare è quella standard di Arduino "SD Library", il file system supportato è FAT32 (purtroppo i nomi dei files devono essere nel formato corto 8.3 ed i files da referenziare DEVONO essere nella root!), per info arduino.cc.

Display TFT CardsReader 01.jpg

Riporto l'immagine da Bytes N Bits, il display è sempre lo stesso e la cablatura anche, prestare solo attenzione ai cavi che puntano al lato corto del display in quanto sono quelli per la lettura delle SD. ATTENZIONE non dare corrente con la scheda SD inserita ma spegnere, aggiungere la scheda e poi dare corrente ad Arduino Uno!

Display TFT CardsReader 02.jpg

ScritturaLettura di un file

#include <Arduino.h>
#include "SPI.h"
#include "SD.h"
 
#define SD_CLK 13
#define SD_MISO 12
#define SD_MOSI 11
#define SD_CS 6     // Chip Select pin for SD card module
 
int m_maxLoops = 50;
 
void setup() {
  Serial.begin(115200);
 
  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);
 
  if (!SD.begin(SD_CS)) {
    Serial.println("SD card failed, or not present");
    int i = 0;
    bool lopCondition = i < m_maxLoops;
    while (lopCondition){
      /* code */
      i++;
      delay(200);
    }    
    return;
  }
  else {
    Serial.println("SD card initialized.");
  }
 
  // Si crea un file
  File myFile = SD.open("myFile1.txt", FILE_WRITE);
 
  if (myFile) {
    myFile.println("Contenuto di esempio scritto su SD (rigo1).");
    myFile.println("Contenuto di esempio scritto su SD (rigo2).");
    myFile.close();
 
    Serial.println("File myFile1.txt creato e dato scritto.");
  } 
  else {
    Serial.println("Errore nell'apertura del file myFile1.txt");
  }
 
  // Legge il file appena creato
  myFile = SD.open("myFile1.txt");
  if (myFile) {
    Serial.println("Contenuto di myFile1.txt:");
 
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    myFile.close();
  } 
  else {
    Serial.println("Errore nell'apertura del file myFile1.txt");
  }
 
}
 
void loop() {
 
}

Lettura file immagine

TFT touchscreen Image reader 01.jpg
#include "SPI.h"
#include "Adafruit_GFX.h" // Core graphics library
#include "Adafruit_ILI9341.h" // Hardware-specific library
#include "SdFat.h" // SD card & FAT filesystem library
#include "Adafruit_ImageReader.h" // Image-reading functions
#include "XPT2046_Touchscreen.h"
 
 
#define TFT_CS 10
#define TFT_DC 9
#define TFT_MOSI 11
#define TFT_CLK 13
#define TFT_RST 8
#define TFT_MISO 12
 
#define TS_CS 7
#define SD_CS 6     // Chip Select pin for SD card module
 
#define ROTATION 3
 
 
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
XPT2046_Touchscreen ts(TS_CS);
 
int tft_width, tft_height;
SdFat SD; // SD card filesystem
Adafruit_ImageReader reader; // Create an image reader object
 
 
void setup() {
  Serial.begin(115200);
 
  pinMode(TS_CS, OUTPUT);
  digitalWrite(TS_CS, HIGH);
  pinMode(TFT_CS, OUTPUT);
  digitalWrite(TFT_CS, HIGH);
  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);
 
  tft.begin();
  tft.setRotation(ROTATION);
  tft_width = tft.width();
  tft_height = tft.height();
  ts.begin();
  ts.setRotation(ROTATION);
 
  Serial.println("TFT initialized");
 
  if (!SD.begin(SD_CS)) {
    Serial.println("SD card initialization failed!");
    return;
  }
 
  Serial.println("SD card initialized.");
  ImageReturnCode stat;
  stat = reader.drawBMP("test.bmp", tft, 0, 0); // Draw BMP at (0,0)
 
}
 
void loop() {
 
}

Con Arduino Uno R3 - Nano 33 IoT - Nano ESP32

Le due implementazioni a confronto:
SPI TFT Display ILI9341 XPT2046 ArduinoUnoR3 Nano33Iot.jpg

Nel mio caso, con uno sketch complesso con elaborazione di grafica e testo integrato con funzionalità del touch screen (usando le librerie prima citate) pur conservando esattamente gli stessi riferimenti ai pin, non c'è stato alcun problema, ha compilato al primo colpo.
Il vantaggio con Arduino Nano 33 IoT/ESP32 è quello di lavorare direttamente con una tensione da 3.3V e non usare le resistenze per abbattere la tensione.
NOTE

  • su Nano 33 IoT non ho potuto usare il pin 12 chiamato VUSB o +5V poiché contrariamente dalle attese non passa tensione (0V) che invece ho potuto trovare sul pin VIN che è in posizione 15.
  • La configurazione per Nano ESP 32 invece usa l'allaccio della tensione a 5V sul pin 12 chiamato VUSB o +5V.

(Mappa e Link)


Arduino indice | Arduino | Integrazioni tipiche | Arduino Progetti | Arduino C++


C++ Info fondamentali | Dizionario Elettronica | Dizionario


Parole chiave:

Author Giuseppe AINO