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();
    }
  }
}
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:

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;
 
 
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!");
}

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;
          }
        }
    }
  }
}

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() {
 
}

etc

 
 

(Mappa e Link)


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


C++ Info fondamentali | Dizionario Elettronica | Dizionario


Parole chiave:

Author