Domotica Arduino Integrazione Display TFT LCD
From Aino Wiki
Contents
LCD TFT SPI - ILI9341 LCD with XPT2046 Touch
- Tutorial fondamentale: bytesnbits.co.uk;
- Video diretto YT.
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.
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€:
Progetto
NOTA quanto segue è una adattamento\copia di quanto suggerito qui (bytesnbits.co.uk).Configurazione del bus SPI:
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 |
Pin 11 | SDI (MOSI) | T_DIN |
| SS Slave Select |
Pin 10 | CS | |
| DC Data / Command |
Pin 9 | DC | |
| RESET Reset |
Pin 8 | RESET | |
|
SS |
Pin 7 | T_CS |
Tre collegamenti essenziali:
NOTA, il display funziona con logica e tensione a 3.3V:
Dettaglio progetto:
Sistemazione su breadboard (design con Frizing):
Mia implementazione:
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:
- Adafruit ILI9341 (nel tutorial si parla della 1.5.6). GitHub: Adafruit_ILI9341
- Adafruit GFX Library (nel tutorial si parla della 1.10.1). GitHub: Adafruit-GFX-Library
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(); } } }
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.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.
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.
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!
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
- Videotutorial 1 Bytes N Bits
- Tutorial 1 Bytes N Bits
- Tutorial su adafruit-gfx-graphics-library
- Videotutorial 2 Bytes N Bits
- Tutorial 2 Bytes N Bits
#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:
