Módulo shield pantalla TFT LCD 2.4'' Arduino

Publicado por Victor Arrieta en

 

Este  módulo  consta de una pantalla LCD que nos permitirá desplegar imágenes, programar gráficos, textos, colores y agregar funciones de visualización a nuestros proyectos con Arduino. También cuenta con un panel táctil sobre la LCD. El módulo está diseñado como un shield para ser montado sobre tu placa de Arduino de tal suerte que son poco probables los errores en la conexión y cuenta también con un espacio para instalar una memoria micro SD, desde la cual podrás leer imágenes y desplegarlas también en la pantalla.

Esta módulo LCD puede presentarse con diferentes chips controladores (9320, 9325, 9341,etc.), para los cuales te verás obligado a usar diferentes librerías, este tutorial se centra en las pantallas con chips 9320, 9325 y 9341.

 Las librerías que debes utilizar son las siguientes:

Librería Adafruit_GFX: Esta librería nos proporcionará el código necesario para la realización de gráficos en la pantalla.

Librería TouchScreen: Librería que se encarga de traducir e interpretar las coordenadas, para poder trabajar con el panel táctil resistivo. Descarga librería Touch.

La librería que se personaliza y que puede cambiar según el controlador es la siguiente:

Librería TFTLCD: Esta librería incluye drivers de varias pantallas con diferentes chips (ILI9320, ILI9341, etc) , por lo que debemos seleccionar el chip correcto en el código del sketch para poder visualizar texto, gráficos e imágenes en nuestra pantalla LCD.  Descarga de la librería.

 

PANEL TÁCTIL

La shield incluye sobre la pantalla un panel táctil resistivo de 4 hilos que nos permitirá obtener las coordenadas X e Y donde pulsemos sobre la pantalla, y por tanto, poder realizar acciones que van desde dibujar botones en nuestro LCD que al pulsar sobre ellos realicen una determinada acción hasta pintar sobre nuestro LCD como si fuera un “tablero de dibujo digital”. El panel táctil es resistivo y funciona midiendo la resistencia en el punto x,y que se ha tocado.

Una vez que tienes todas las librería en la carpeta correcta podrás usarlas para controlar tu pantalla, en e IDE Arduino ve a:

File > Examples > MCUFRIEND_kbv-master > Touch_Shield

// Para mejor precision de la presion realizada, es necesario
// medir la resistencia entre los pines X+ y X-.
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XM, YM, XP, YP, 400);
TSPoint tp;

Como medir esa resistencia?

La clave está en mirar esta parte del código:

// most mcufriend shields use these pins and Portrait mode:
uint8_t YP = A2; // must be an analog pin, use "An" notation!
uint8_t XM = A1; // must be an analog pin, use "An" notation!
uint8_t YM = 6; // can be a digital pin
uint8_t XP = 7; // can be a digital pin
uint8_t SwapXY = 0;

XP es X+ y XM es X-, que equivalen a los pines  7 y A1 del Arduino Uno que a su vez son los pines LCD_D7 y LCD_WR de la LCD, entonces mides con el multímetro la resistencia entre estos dos pines de la LCD.

Si cargamos el ejemplo podremos usar la pantalla como un tablero de dibujo. Pero antes se ejecutan ciertas funciones (tft.print) que muestran información sobre la LCD y también las coordenadas del punto presionando con la función  ts.getPoint().

 

Conexión

 

Sólo monta el shield sobre tu placa, es muy simple! Solo encaja de una manera.

 

Código Arduino

 

#include <Adafruit_GFX.h> // Core graphics library
//#include <Adafruit_TFTLCD.h> // Hardware-specific library
//Adafruit_TFTLCD tft(A3, A2, A1, A0, A4);
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft; // hard-wired for UNO shields anyway.
#include <TouchScreen.h>

#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif

// These are the pins for some typical shields!
// S6D0154: YP=A1, XM=A2, YM=7, XP=6
// ST7783 : YP=A2, XM=A1, YM=6, XP=7
// ILI9320: YP=A2, XM=A3, YM=8, XP=9
// ILI9325: YP=A2, XM=A1, YM=6, XP=7
// ILI9325BG: YP=A2, XM=A1, YM=6, XP=7
// ILI9341: YP=A2, XM=A1, YM=7, XP=6
// ILI9488: YP=A1, XM=A2, YM=7, XP=6
// R65109V: YP=A2, XM=A1, YM=6, XP=7

// most mcufriend shields use these pins and Portrait mode:
uint8_t YP = A2; // must be an analog pin, use "An" notation!
uint8_t XM = A1; // must be an analog pin, use "An" notation!
uint8_t YM = 6; // can be a digital pin
uint8_t XP = 7; // can be a digital pin
uint8_t SwapXY = 0;

uint16_t TS_LEFT = 920;
uint16_t TS_RT = 150;
uint16_t TS_TOP = 940;
uint16_t TS_BOT = 120;
char *name = "Unknown controller";

// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XM, YM, XP, YP, 400);
TSPoint tp;

#define MINPRESSURE 20
#define MAXPRESSURE 1000

#define SWAP(a, b) {uint16_t tmp = a; a = b; b = tmp;}

int16_t BOXSIZE;
int16_t PENRADIUS = 3;
uint16_t identifier, oldcolor, currentcolor;
uint8_t Orientation = 0; //PORTRAIT

// Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF

void show_Serial(void)
{
Serial.print(F("Found "));
Serial.print(name);
Serial.println(F(" LCD driver"));
Serial.print(F("ID=0x"));
Serial.println(identifier, HEX);
Serial.println("Screen is " + String(tft.width()) + "x" + String(tft.height()));
Serial.println("Calibration is: ");
Serial.println("LEFT = " + String(TS_LEFT) + " RT = " + String(TS_RT));
Serial.println("TOP = " + String(TS_TOP) + " BOT = " + String(TS_BOT));
Serial.print("Wiring is: ");
Serial.println(SwapXY ? "SWAPXY" : "PORTRAIT");
Serial.println("YP=" + String(YP) + " XM=" + String(XM));
Serial.println("YM=" + String(YM) + " XP=" + String(XP));
}

void show_tft(void)
{
tft.setCursor(0, 0);
tft.setTextSize(2);
tft.print(F("Found "));
tft.print(name);
tft.println(F(" LCD"));
tft.setTextSize(1);
tft.print(F("ID=0x"));
tft.println(identifier, HEX);
tft.println("Screen is " + String(tft.width()) + "x" + String(tft.height()));
tft.println("Calibration is: ");
tft.println("LEFT = " + String(TS_LEFT) + " RT = " + String(TS_RT));
tft.println("TOP = " + String(TS_TOP) + " BOT = " + String(TS_BOT));
tft.print("\nWiring is: ");
if (SwapXY) {
tft.setTextColor(CYAN);
tft.setTextSize(2);
}
tft.println(SwapXY ? "SWAPXY" : "PORTRAIT");
tft.println("YP=" + String(YP) + " XM=" + String(XM));
tft.println("YM=" + String(YM) + " XP=" + String(XP));
tft.setTextSize(2);
tft.setTextColor(RED);
tft.setCursor((tft.width() - 48) / 2, (tft.height() * 2) / 4);
tft.print("EXIT");
tft.setTextColor(YELLOW, BLACK);
tft.setCursor(0, (tft.height() * 6) / 8);
tft.print("Touch screen for loc");
while (1) {
tp = ts.getPoint();
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
pinMode(XP, OUTPUT);
pinMode(YM, OUTPUT);
if (tp.z < MINPRESSURE || tp.z > MAXPRESSURE) continue;
if (tp.x > 450 && tp.x < 570 && tp.y > 450 && tp.y < 570) break;
tft.setCursor(0, (tft.height() * 3) / 4);
tft.print("tp.x=" + String(tp.x) + " tp.y=" + String(tp.y) + " ");
}
}


void setup(void)
{
uint16_t tmp;
Serial.begin(9600);

tft.reset();
identifier = tft.readID();
// if (identifier == 0) identifier = 0x9341;
if (0) {
} else if (identifier == 0x0154) {
name = "S6D0154";
TS_LEFT = 914; TS_RT = 181; TS_TOP = 957; TS_BOT = 208;
} else if (identifier == 0x5408) { //thanks gazialankus
name = "SPFD5408";
TS_LEFT = 150; TS_RT = 960; TS_TOP = 155; TS_BOT = 925;
SwapXY = 1;
} else if (identifier == 0x7783) {
name = "ST7781";
TS_LEFT = 865; TS_RT = 155; TS_TOP = 942; TS_BOT = 153;
SwapXY = 1;
} else if (identifier == 0x7789) {
name = "ST7789V";
YP = A2; XM = A1; YM = 7; XP = 6;
TS_LEFT = 906; TS_RT = 169; TS_TOP = 161; TS_BOT = 919;
} else if (identifier == 0x9320) {
name = "ILI9320";
// YP = A3; XM = A2; YM = 9; XP = 8;
TS_LEFT = 137; TS_RT = 902; TS_TOP = 134; TS_BOT = 941;
} else if (identifier == 0x9325) {
name = "ILI9325";
TS_LEFT = 201; TS_RT = 871; TS_TOP = 168; TS_BOT = 897;
} else if (identifier == 0x9325) {
name = "ILI9325 Green Dog";
TS_LEFT = 900; TS_RT = 130; TS_TOP = 940; TS_BOT = 130;
} else if (identifier == 0x9327) {
name = "ILI9327";
TS_LEFT = 899; TS_RT = 135; TS_TOP = 935; TS_BOT = 79;
SwapXY = 1;
} else if (identifier == 0x9329) {
name = "ILI9329";
TS_LEFT = 143; TS_RT = 885; TS_TOP = 941; TS_BOT = 131;
SwapXY = 1;
} else if (identifier == 0x9341) {
name = "ILI9341 BLUE";
TS_LEFT = 920; TS_RT = 139; TS_TOP = 944; TS_BOT = 150;
SwapXY = 0;
} else if (identifier == 0) {
name = "ILI9341 DealExtreme";
TS_LEFT = 893; TS_RT = 145; TS_TOP = 930; TS_BOT = 135;
SwapXY = 1;
} else if (identifier == 0 || identifier == 0x9341) {
name = "ILI9341";
TS_LEFT = 128; TS_RT = 911; TS_TOP = 105; TS_BOT = 908;
SwapXY = 1;
} else if (identifier == 0x9486) {
name = "ILI9486";
TS_LEFT = 904; TS_RT = 170; TS_TOP = 950; TS_BOT = 158;
} else if (identifier == 0x9488) {
name = "ILI9488";
TS_LEFT = 904; TS_RT = 170; TS_TOP = 950; TS_BOT = 158;
} else if (identifier == 0xB509) {
name = "R61509V";
TS_LEFT = 889; TS_RT = 149; TS_TOP = 106; TS_BOT = 975;
SwapXY = 1;
} else {
name = "unknown";
}
switch (Orientation) { // adjust for different aspects
case 0: break; //no change, calibrated for PORTRAIT
case 1: tmp = TS_LEFT, TS_LEFT = TS_BOT, TS_BOT = TS_RT, TS_RT = TS_TOP, TS_TOP = tmp; break;
case 2: SWAP(TS_LEFT, TS_RT); SWAP(TS_TOP, TS_BOT); break;
case 3: tmp = TS_LEFT, TS_LEFT = TS_TOP, TS_TOP = TS_RT, TS_RT = TS_BOT, TS_BOT = tmp; break;
}

Serial.begin(9600);
ts = TouchScreen(XP, YP, XM, YM, 300); //call the constructor AGAIN with new values.
tft.begin(identifier);
show_Serial();
tft.setRotation(Orientation);
tft.fillScreen(BLACK);
show_tft();

BOXSIZE = tft.width() / 6;
tft.fillScreen(BLACK);

tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED);
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW);
tft.fillRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, GREEN);
tft.fillRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, CYAN);
tft.fillRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, BLUE);
tft.fillRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, MAGENTA);

tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
currentcolor = RED;
delay(1000);
}

void loop()
{
uint16_t xpos, ypos; //screen coordinates
tp = ts.getPoint(); //tp.x, tp.y are ADC values

// if sharing pins, you'll need to fix the directions of the touchscreen pins
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
pinMode(XP, OUTPUT);
pinMode(YM, OUTPUT);
// digitalWrite(XM, HIGH);
// digitalWrite(YP, HIGH);
// we have some minimum pressure we consider 'valid'
// pressure of 0 means no pressing!

if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) {
// is controller wired for Landscape ? or are we oriented in Landscape?
if (SwapXY != (Orientation & 1)) SWAP(tp.x, tp.y);
// scale from 0->1023 to tft.width i.e. left = 0, rt = width
// most mcufriend have touch (with icons) that extends below the TFT
// screens without icons need to reserve a space for "erase"
// scale the ADC values from ts.getPoint() to screen values e.g. 0-239
xpos = map(tp.x, TS_LEFT, TS_RT, 0, tft.width());
ypos = map(tp.y, TS_TOP, TS_BOT, 0, tft.height());

// are we in top color box area ?
if (ypos < BOXSIZE) { //draw white border on selected color box
oldcolor = currentcolor;

if (xpos < BOXSIZE) {
currentcolor = RED;
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (xpos < BOXSIZE * 2) {
currentcolor = YELLOW;
tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (xpos < BOXSIZE * 3) {
currentcolor = GREEN;
tft.drawRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (xpos < BOXSIZE * 4) {
currentcolor = CYAN;
tft.drawRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (xpos < BOXSIZE * 5) {
currentcolor = BLUE;
tft.drawRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (xpos < BOXSIZE * 6) {
currentcolor = MAGENTA;
tft.drawRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, WHITE);
}

if (oldcolor != currentcolor) { //rub out the previous white border
if (oldcolor == RED) tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED);
if (oldcolor == YELLOW) tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW);
if (oldcolor == GREEN) tft.fillRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, GREEN);
if (oldcolor == CYAN) tft.fillRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, CYAN);
if (oldcolor == BLUE) tft.fillRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, BLUE);
if (oldcolor == MAGENTA) tft.fillRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, MAGENTA);
}
}
// are we in drawing area ?
if (((ypos - PENRADIUS) > BOXSIZE) && ((ypos + PENRADIUS) < tft.height())) {
tft.fillCircle(xpos, ypos, PENRADIUS, currentcolor);
}
// are we in erase area ?
if (ypos > tft.height() - 10) {
// press the bottom of the screen to erase
tft.fillRect(0, BOXSIZE, tft.width(), tft.height() - BOXSIZE, BLACK);
}
}
}

 

Una vez subido el código y montado el shield sobre la placa de Arduino UNO podrás dibujar sobre la pantalla, acá una foto de lo que puedes hacer utilizando la paleta de colores:

 

 

 

 

 

La librería trae múltiples comandos de dibujo, con los cuales serás capaz de dibujar cualquier figura de una forma relativamente fácil, puedes aprender estos comandos mirando los múltiples ejemplos de la librería, pero el principio es básicamente el mismo.


Compartir esta publicación



← Publicación más antigua Publicación más reciente →