ESP32: TFT Touchscreen On/Off Button – 2.8 inch ILI9341 240×320 (Arduino IDE)

In this project, you’ll build a simple graphical user interface (GUI) with the ESP32 and a TFT Touchscreen with 2.8 inch display (240×320 px) that comes with the ILI9341 driver. The TFT display will have an ON and OFF button that you can use to control an output.

ESP32 TFT Touchscreen On and Off Buttons 2.8 inch ILI9341 240×320 Arduino IDE

We recommend an ESP32 board that has an on-board TFT display, read our guide ESP32 Touchscreen On/Off Button – Cheap Yellow Display (ESP32-2432S028R)

Introducing the TFT LCD Touchscreen Display

The display we’re using in this guide is the 2.8. inch TFT LCD that also comes with a touchscreen. The display communicates via SPI communication protocol and uses the ILI9341 driver. You can write text, draw shapes, and display images. The touchscreen also uses the SPI communication protocol.

The TFT LCD touchscreen also comes with an SD card interface if you need to load files for your specific project. This display is also available with different screen sizes.

Parts Required

For this project, you need to wire the TFT display and touchscreen pins to the ESP32. Here’s a list of parts you need:

Wiring TFT LCD Touchscreen display to ESP32

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

Wiring the TFT LCD Touchscreen Display to the ESP32 Board

Wiring the TFT LCD Touchscreen Display to the ESP32 Board

Wire the TFT LCD and touchscreen pins to the following ESP32 GPIOs (you must use these exact pins, otherwise the project will not work).

TFT LCD TouchscreenESP32
T_IRQGPIO 36
T_OUTGPIO 39
T_DINGPIO 32
T_CSGPIO 33
T_CLKGPIO 25
SDO(MISO)GPIO 16
LEDGPIO 21
SCKGPIO 14
SDI(MOSI)GPIO 13
D/CGPIO 2
RESETGPIO 12
CSGPIO 15
GNDGND
VCC5V (or 3.3V)*
* In the VCC pin, you can either use 5V or 3.3V depending if your J1 connection is open or closed (by default it’s usually open).

Prerequisites

The ESP32 communicates with the TFT Display and Touchscreen using SPI communication protocol. We’ll be using the TFT_eSPI and XPT2046_Touchscreen libraries. To properly use the TFT_eSPI library, you need a configuration file called User_Setup.h with the right definitions.

Code – Touchscreen with On/Off Button

With the following code, the TFT will display an ON/OFF button to control an output. When you press the touchscreen with your finger or pen, it should turn on/off the GPIO 16 (which can have an LED attached).

Copy the following code to the Arduino IDE and upload it to your board.

/*  Rui Santos & Sara Santos - Random Nerd Tutorials
    THIS EXAMPLE WAS TESTED WITH THE FOLLOWING HARDWARE:
      REGULAR ESP32 Dev Board + 2.8 inch 240x320 TFT Display: https://makeradvisor.com/tools/2-8-inch-ili9341-tft-240x320/ and https://makeradvisor.com/tools/esp32-dev-board-wi-fi-bluetooth/
      SET UP INSTRUCTIONS: https://RandomNerdTutorials.com/esp32-tft/
    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
    Complete project details: https://RandomNerdTutorials.com/esp32-tft-touchscreen-on-off-button-ili9341-arduino/
*/

#include <SPI.h>

/*  Install the "TFT_eSPI" library by Bodmer to interface with the TFT Display - https://github.com/Bodmer/TFT_eSPI
    *** IMPORTANT: User_Config.h available on the internet will probably NOT work with the examples available at Random Nerd Tutorials ***
    *** YOU MUST USE THE User_Config.h FILE PROVIDED IN THE LINK BELOW IN ORDER TO USE THE EXAMPLES FROM RANDOM NERD TUTORIALS ***
    FULL INSTRUCTIONS AVAILABLE ON HOW CONFIGURE THE LIBRARY: https://RandomNerdTutorials.com/esp32-tft/   */
#include <TFT_eSPI.h>

// Install the "XPT2046_Touchscreen" library by Paul Stoffregen to use the Touchscreen - https://github.com/PaulStoffregen/XPT2046_Touchscreen
// Note: this library doesn't require further configuration
#include <XPT2046_Touchscreen.h>

TFT_eSPI tft = TFT_eSPI();

// Touchscreen pins
#define XPT2046_IRQ 36   // T_IRQ
#define XPT2046_MOSI 32  // T_DIN
#define XPT2046_MISO 39  // T_OUT
#define XPT2046_CLK 25   // T_CLK
#define XPT2046_CS 33    // T_CS

SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);

#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#define FONT_SIZE 3

// Button position and size
#define FRAME_X 60
#define FRAME_Y 60
#define FRAME_W 200
#define FRAME_H 120

// Red zone size
#define REDBUTTON_X FRAME_X
#define REDBUTTON_Y FRAME_Y
#define REDBUTTON_W (FRAME_W / 2)
#define REDBUTTON_H FRAME_H

// Green zone size
#define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
#define GREENBUTTON_Y FRAME_Y
#define GREENBUTTON_W (FRAME_W / 2)
#define GREENBUTTON_H FRAME_H

// LED Pin
#define LED_GREEN 16

// Touchscreen coordinates: (x, y) and pressure (z)
int x, y, z;

// Stores current button state
bool buttonState = false;

// Print Touchscreen info about X, Y and Pressure (Z) on the Serial Monitor
void printTouchToSerial(int touchX, int touchY, int touchZ) {
  Serial.print("X = ");
  Serial.print(touchX);
  Serial.print(" | Y = ");
  Serial.print(touchY);
  Serial.print(" | Pressure = ");
  Serial.print(touchZ);
  Serial.println();
}

// Draw button frame
void drawFrame() {
  tft.drawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, TFT_BLACK);
}

// Draw a red button
void drawRedButton() {
  tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, TFT_RED);
  tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, TFT_WHITE);
  drawFrame();
  tft.setTextColor(TFT_BLACK);
  tft.setTextSize(FONT_SIZE);
  tft.setTextDatum(MC_DATUM);
  tft.drawString("ON", GREENBUTTON_X + (GREENBUTTON_W / 2), GREENBUTTON_Y + (GREENBUTTON_H / 2));
  buttonState = false;
}

// Draw a green button
void drawGreenButton() {
  tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, TFT_GREEN);
  tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, TFT_WHITE);
  drawFrame();
  tft.setTextColor(TFT_BLACK);
  tft.setTextSize(FONT_SIZE);
  tft.setTextDatum(MC_DATUM);
  tft.drawString("OFF", REDBUTTON_X + (REDBUTTON_W / 2) + 1, REDBUTTON_Y + (REDBUTTON_H / 2));
  buttonState = true;
}

void setup() {
  Serial.begin(115200);

  // Start the SPI for the touchscreen and init the touchscreen
  touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
  touchscreen.begin(touchscreenSPI);
  // Set the Touchscreen rotation in landscape mode
  // Note: in some displays, the touchscreen might be upside down, so you might need to set the rotation to 3: touchscreen.setRotation(3);
  touchscreen.setRotation(1);

  // Start the tft display
  tft.init();
  // Set the TFT display rotation in landscape mode
  tft.setRotation(1);

  // Clear the screen before writing to it
  tft.fillScreen(TFT_BLACK);

  // Draw button 
  drawGreenButton();

  pinMode(LED_GREEN, OUTPUT);
  digitalWrite(LED_GREEN, LOW);
}

void loop() {
  // Checks if Touchscreen was touched, and prints X, Y and Pressure (Z) info on the TFT display and Serial Monitor
  if (touchscreen.tirqTouched() && touchscreen.touched()) {
    // Get Touchscreen points
    TS_Point p = touchscreen.getPoint();
    // Calibrate Touchscreen points with map function to the correct width and height
    x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
    y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
    z = p.z;

    printTouchToSerial(x, y, z);

    if (buttonState) {
      Serial.println("ON");
      if ((x > REDBUTTON_X) && (x < (REDBUTTON_X + REDBUTTON_W))) {
        if ((y > (REDBUTTON_Y)) && (y <= (REDBUTTON_Y + REDBUTTON_H))) {
          Serial.println("Red button pressed");
          drawRedButton();
          digitalWrite(LED_GREEN, HIGH);
        }
      }
    }
    else {
      Serial.println("OFF");
      if ((x > (GREENBUTTON_X)) && (x < (GREENBUTTON_X + GREENBUTTON_W))) {
        if ((y > (GREENBUTTON_Y)) && (y <= (GREENBUTTON_Y + GREENBUTTON_H))) {
          Serial.println("Green button pressed");
          drawGreenButton();
          digitalWrite(LED_GREEN, LOW);
        }
      }
    }
  }
}

View raw code

How the Code Works

Let’s take a quick look at the parts of the code that are relevant to this example.

Libraries

Include the SPI, TFT_eSPI and XPT2046_Touchscreen libraries.

#include <SPI.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>

Initialize TFT

Create a TFT_eSPI instance:

TFT_eSPI tft = TFT_eSPI();

Initialize Touchscreen

The following lines set the touchscreen pinout:

#define XPT2046_IRQ 36
#define XPT2046_MOSI 32
#define XPT2046_MISO 39
#define XPT2046_CLK 25
#define XPT2046_CS 33

Create a touchscreenSPI and touchscreen instances:

SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);

Other Variables

Set the screen width, screen height, and font size:

#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#define FONT_SIZE 3

These next variables have self-explanatory names, they are used to define the frame/button sizes and coordinates:

// Button position and size
#define FRAME_X 60
#define FRAME_Y 60
#define FRAME_W 200
#define FRAME_H 120

// Red zone size
#define REDBUTTON_X FRAME_X
#define REDBUTTON_Y FRAME_Y
#define REDBUTTON_W (FRAME_W / 2)
#define REDBUTTON_H FRAME_H

// Green zone size
#define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
#define GREENBUTTON_Y FRAME_Y
#define GREENBUTTON_W (FRAME_W / 2)
#define GREENBUTTON_H FRAME_H

In this example, we’ll only be controlling GPIO 16:

#define LED_GREEN 16

Variables to store the touch coordinates: (x, y) and pressure (z).

int x, y, z;

The switchState stores the current button state:

bool buttonState = false;

setup()

Start a serial communication with the Serial Monitor at a baud rate of 115200:

Serial.begin(115200);

Start the SPI for the touchscreen and initialize the touchscreen.

touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
touchscreen.begin(touchscreenSPI);
touchscreen.setRotation(1);

Note: in some displays, the touchscreen might be upside down, so you might need to set the rotation to 3: touchscreen.setRotation(3);

Start the TFT display and set the TFT display rotation in landscape mode.

tft.init();
tft.setRotation(1);

Set the TFT screen background to black.

tft.fillScreen(TFT_BLACK);

At the start, the LED is set to off, so draw the green button that will turn on the LED when pressed.

drawGreenButton();
pinMode(LED_GREEN, OUTPUT);
digitalWrite(LED_GREEN, LOW);

loop()

In the loop(), it constantly checks if the touchscreen was touched.

if (touchscreen.tirqTouched() && touchscreen.touched()) {

When it detects that the touchscreen was touched, it will get the (x,y) coordinates and the pressure (z) from the point.

TS_Point p = touchscreen.getPoint();
// Calibrate Touchscreen points with map function to the correct width and height
x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
z = p.z;

Call the printTouchToSerial function to print the touchscreen info in the Serial Monitor for debugging purposes.

printTouchToSerial(x, y, z);

Based on the x and y coordinates detected by the touchscreen press, it will check if you pressed within the limits of the ON or OFF button coordinates. Then, it will turn the LED on or off accordingly and draw the right button to display by calling the drawRedButton() or drawGreenButton() functions.

if (buttonState)  {
  Serial.println("ON");
  if ((x > REDBUTTON_X) && (x < (REDBUTTON_X + REDBUTTON_W))) {
    if ((y > (REDBUTTON_Y)) && (y <= (REDBUTTON_Y + REDBUTTON_H))) {
      Serial.println("Red button pressed");
      drawRedButton();
      digitalWrite(LED_GREEN, HIGH);
    }
  }
}
else {
  Serial.println("OFF");
  if ((x > (GREENBUTTON_X)) && (x < (GREENBUTTON_X + GREENBUTTON_W))) {
    if ((y > (GREENBUTTON_Y)) && (y <= (GREENBUTTON_Y + GREENBUTTON_H))) {
      Serial.println("Green button pressed");
      drawGreenButton();
      digitalWrite(LED_GREEN, LOW);
    }
  }
}

printTouchToSerial()

The printTouchToSerial() function prints touchscreen info about X, Y, and Pressure (Z) on the Serial Monitor.

void printTouchToSerial(int touchX, int touchY, int touchZ) {
  Serial.print("X = ");
  Serial.print(touchX);
  Serial.print(" | Y = ");
  Serial.print(touchY);
  Serial.print(" | Pressure = ");
  Serial.print(touchZ);
  Serial.println();
}

Other Functions: drawFrame(), drawRedButton(), drawGreenButton()

The drawFrame() function draws a frame around the ON or OFF buttons.

// Draw button frame
void drawFrame() {
  tft.drawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, TFT_BLACK);
}

The drawRedButton() and drawGreenButton() functions create the ON and OFF buttons on the TFT display. It will draw and fill a rectangle based on the x and y coordinates defined at the start of the sketch, as well as writing the ON and OFF text labels.

// Draw a red button
void drawRedButton() {
  tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, TFT_RED);
  tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, TFT_WHITE);
  drawFrame();
  tft.setTextColor(TFT_BLACK);
  tft.setTextSize(FONT_SIZE);
  tft.setTextDatum(MC_DATUM);
  tft.drawString("ON", GREENBUTTON_X + (GREENBUTTON_W / 2), GREENBUTTON_Y + (GREENBUTTON_H / 2));
  buttonState = false;
}

// Draw a green button
void drawGreenButton() {
  tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, TFT_GREEN);
  tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, TFT_WHITE);
  drawFrame();
  tft.setTextColor(TFT_BLACK);
  tft.setTextSize(FONT_SIZE);
  tft.setTextDatum(MC_DATUM);
  tft.drawString("OFF", REDBUTTON_X + (REDBUTTON_W / 2) + 1, REDBUTTON_Y + (REDBUTTON_H / 2));
  buttonState = true;
}

Demonstration

Upload the code to your board. Go to Tools > Board and select ESP32 > ESP32 Dev Module. Then, select the right COM port in Tools > Port. Finally, click the upload button.

Arduino IDE 2 Upload Button

After uploading the code to your board, the TFT display should have an ON button that you can press with your finger.

TFT Touchscreen Press Off Button ESP32 Arduino IDE

Pressing the ON button turns on the green LED on GPIO 16. If the LED is on, the display should have the OFF button. You can click on it to turn the LED off.

ESP32 TFT LCD Touchscreen On Off Buttons Arduino IDE

The coordinates, pressure, and LED state are also printed on the Arduino IDE serial monitor for debugging purposes:

ESP32 TFT Touchscreen On Off Button Cheap Yellow Display Arduino IDE Serial Monitor

Wrapping Up

In this tutorial, you learned how to build a basic GUI for the ESP32 with a TFT Touchscreen display.

We also recommend reading our: Getting Started with ESP32 Cheap Yellow Display Board – CYD (ESP32-2432S028R)

To learn more about the ESP32, make sure to take a look at our resources:



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

6 thoughts on “ESP32: TFT Touchscreen On/Off Button – 2.8 inch ILI9341 240×320 (Arduino IDE)”

  1. Hi Rui,
    I really enjoyed this tutorial and the similar one on CYD. I’ve had these displays and the CYD displays for a couple of years and never understood how to use them. Now you have fired up my interest in them again.
    Thank you & Sarah for all your great tutorials & courses.
    Best regards,
    Joe

    Reply
  2. I had problem shoving changes on/off. Untill I changed (LED_GREEN 16) to (LED_GREEN 4) .Now the code works OK.
    /Jan-Olof

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.