Interfacing Waveshare 2.8 Inch Capacitive Touch LCD with Arduino
Learn how to interface the beautiful 2.8 inch capacitive touch LCD panel from Waveshare to Arduino microcontroller boards.

When blinking LEDs are not enough to display information, we switch to LCDs. In fact you are staring at one right now. They are so ubiquitous and there are so many types of them. Have you ever wondered how you can control one yourself? If you have worked with Arduino boards before, we assume you have. We recently got our hands on a beautiful 2.8 Inch Capacitive Touch LCD screen from Waveshare. It is a bit costlier than the typical non-name LCDs you can buy from the market, but Waveshare products have their standards when it comes to quality. This time also, it is not different. The LCD comes with 320 x 240 TFT panel with rich colors and large viewing angles, and an integrated capacitive touch panel. The PCB has two types of connectors and four metallic standoff mounting points. This makes it extremely easy to interface with any of your microcontroller boards and even integrate into your product designs. In this post, we will take a closer look at the LCD and learn how to interface it with your favourite Arduino-supported microcontroller boards.
Features
- 240 × 320 resolution TFT panel with 8-bit, 262K colors.
- Capacitive touch panel with 5 point simultaneous touch tracking.
- ST7789T3 LCD driver and fast SPI port for interfacing with external microcontroller.
- CST328 touch panel controller and fast I2C interface.
- Dual 13-pin JST-GH and 18-pin FFC for easy interconnection. Cables provided.
- Onboard voltage translator for both 3.3V and 5V signal interfaces.
- Four metal standoff mounting points.


The Waveshare 2.8 inch capacitive touch LCD with SKU ID 27579 has a 320 x 240 TFT (Thin-Film Transistor) panel. This is a regular TFT panel with 8-bit color support and therefore 262 thousand colors . This is not best compared to IPS (In-Plane Switching) or OLED. But for most use cases, this panel will work just fine. In fact, the TFT used in the Waveshare display module is significantly better at color reproduction and viewing angles compared to the very cheap ones. The 2.8 inch (5.28 cm) indicates the diagonal size of the display. Check the dimensional drawing of the module for other dimensions.
The display panel is driven by the ST7789T3 driver from Sitronix. This controller supports parallel, RGB and SPI interfaces. The display module breaks out only the SPI port. The touch panel is a separate thing glued on top of the TFT panel. A capacitive touch panel is a better alternative to the inferior resistive touch panels. A capacitive panel does not bend or flex when touched and is much accurate. The touch panel on the Waveshare display module is controlled by CST328 from Hynitron Microelectronics. This controller has an I2C interface. The touch panel can detect and track up to 5 touches simultaneously.
The display comes with a 13-pin JST-GH to 2.54 mm pin sockets (female) and one 18-pin, 0.5 mm pitch and 200 mm long FPC/FFC cable (same sided). The display can be directly connected to Waveshare’s own ESP32 boards using the FFC. One JST-GH cable, and one 15 cm, 18-pin same-sided FFC are also included in the product package.

The display can be powered by either a 3.3V or 5V supply. There is an internal 3.3V regulator (ME6217C33M5G) that converts the VCC input to 3.3V. Additionally, the display has a voltage translator (TXS0108EPWR) that converts 3.3V/5V interface signals to 3.3V bidirectionally. This means, you can interface the display with both 3.3V and 5v microcontroller boards without worries. Exceeding the specified voltages will damage your display permanently. You can buy the Waveshare 2.8 inch capacitive LCD module from places like Robu for INR 1600 if you are in India.
Specifications
Specification | Value |
---|---|
Operating Voltage | 3.3V / 5V |
Display Driver | ST7789T3 |
Display Interface | 4-wire SPI |
Display Panel | TFT |
Pixel Pitch | 0.18 × 0.18 mm |
Display Size | 43.20 × 57.60 mm |
Resolution | 240 × 320 pixels |
Touch Driver | CST328 |
Touch Interface | I2C |
Touch Type | Capacitive |
Touch Points | 5-point touch |
Module Size | 50.54 × 73.06 mm |
Dimensions

Schematic
Waveshare has provided the schematic for the display module. This makes it easy to find the pinouts and design your project around it. The main voltage regulator is ME6217C33M5G with an input voltage range of 2~6.5V and maximum output current of 800 mA. NDC7002N is a dual N-Channel Mosfet for reset controls. TXS0108EPWR is an 8-channel bidirectional voltage translator. This converts 3.3V signals from and to 5V signals.

Pinout

Signal | Description | 13-Pin JST # | 18-Pin FFC # |
---|---|---|---|
VCC | Power (3.3V / 5V input) | 1 | 1 |
GND | Ground | 2 | 3 |
MISO | SPI MISO pin | 3 | 6 |
MOSI | SPI MOSI pin | 4 | 5 |
SCLK | SPI CLK pin | 5 | 4 |
LCD_CS | LCD Chip Selection, low active | 6 | 9 |
LCD_DC | LCD Data/Command selection (high for data, low for command) | 7 | 7 |
LCD_RST | LCD Reset pin, low active | 8 | 8 |
LCD_BL | LCD Backlight pin | 9 | 2 |
TP_SDA | Touch panel Data pin | 10 | 14 |
TP_SCL | Touch panel Clock pin | 11 | 13 |
TP_INT | Touch panel Interrupt pin | 12 | 15 |
TP_RST | Touch panel Reset pin, low active | 13 | 12 |
The unused pins of the FFC are not shown in the table. You can leave them unconnected.
Wiring
There are two connectors on the display module; a 13-pin JST-GH and 18-pin FFC connector. Both of them can be used to interface the display with external microcontroller boards. You can use the cables found in the product box for this. The JST-GH cable has 2.54 mm header sockets (female) on the other end. This means you can plug the wires into any boards with similar 2.54 mm header pins. If you have header sockets on the board instead, you will have to use extra jumper cables. We also suggest to keep the wire lengths as short as possible. The JST-GH connector has a locking mechanism which prevents it from getting accidentally disconnected. Make sure you unlock it before removing it. The following image shows how we connected the display module with a FireBeetle-ESP32E board from DFRobot.


The FFC is the easiest to use since it is thin and flexible. A 15 cm cable is already provided in the package. You can use this cable to connect the display to development boards from Waveshare. We accidentally found out that the GDI (General Display Interface) of the FireBeetle-ESP32E is similar to the FFC on the Waveshare display module. When we checked the pinouts of both, they were identical as you can see from the table below. Bothe connectors have 18 pins and 0.5 mm pitch.
LCD Pin # | LCD Signal | FireBeetle Pin # | FireBeetle Signal |
---|---|---|---|
1 | VCC | 18 | 3.3V |
2 | LCD_BL | 17 | IO12 /D13 |
3 | GND | 16 | GND |
4 | LCD_SCLK | 15 | IO18 /SCK |
5 | LCD_MOSI | 14 | IO23 /MOSI |
6 | LCD_MISO | 13 | IO19 /MISO |
7 | LCD_DC | 12 | IO25 /D2 |
8 | LCD_RST | 11 | IO26 /D3 |
9 | LCD_CS | 10 | IO14 /D6 |
10 | x | 9 | IO13 /D7 |
11 | x | 8 | IO0 /D5 |
12 | TP_RST | 7 | IO4 /D12 |
13 | TP_SCL | 6 | IO22 /SCL |
14 | TP_SDA | 5 | IO21 /SDA |
15 | TP_INT | 4 | IO16 /D11 |
16 | x | 3 | IO17 /D10 |
17 | x | 2 | IO1 |
18 | x | 1 | IO2 |
This means you can directly connect the Waveshare display module with the FireBeetle-ESP32E board. There is one small problem though. The pin ordering of the GDI connector are in reverse order. That means we can not use the provided same-sided cable to connect the display. Therefore we purchased new 18-pin, 0.5 mm pitch, 100 mm long FCC cables with reverse-sided faces from Mangalam Electronics, Mumbai. As expected, the cable worked perfectly. The following images shows the orientation of the cable.

Libraries
We will take a look at all of the libraries we are going to be using in our example interface codes. You have to make sure you install and configure all of these libraries before you can try out the example codes provided here.
TFT_eSPI
TFT_eSPI is a popular Arduino and PlatformIO IDE compatible LCD graphics library optimised for the RP2040, STM32, ESP8266 and ESP32 microcontrollers. The library is highly customizable and supports many different types LCD drivers and interfaces. The open-source library is written and published by Bodmer. Following is the list of interfaces supported.
Processor | 4 wire SPI | 8-bit parallel | 16-bit parallel | DMA support |
---|---|---|---|---|
RP2040 | Yes | Yes | Yes | Yes (all) |
ESP32 | Yes | Yes | No | Yes (SPI only) |
ESP32 C3 | Yes | No | No | No |
ESP32 S2 | Yes | No | No | No |
ESP32 S3 | Yes | Yes | No | Yes (SPI only) |
ESP8266 | Yes | No | No | No |
STM32Fxxx | Yes | Yes | No | Yes (SPI only) |
Other | Yes | No | No | No |
Following is a list of supported LCD controllers.
- GC9A01
- ILI9163
- ILI9225
- ILI9341
- ILI9342
- ILI9481 (DMA not supported with SPI)
- ILI9486 (DMA not supported with SPI)
- ILI9488 (DMA not supported with SPI)
- HX8357B (16-bit parallel tested with RP2040)
- HX8357C (16-bit parallel tested with RP2040)
- HX8357D
- R61581
- RM68120 (support files added but untested)
- RM68140
- S6D02A1
- SSD1351
- SSD1963 (this controller only has a parallel interface option)
- ST7735
- ST7789
- ST7796
We will use the ESP32 processor target and the 4-wire SPI port for interfacing the display module with the FireBeetle-ESP32E board. But you are free to use any other supported microcontrollers and the respective wiring.
CSE_CST328
Since the TFT_eSPI library does not support all types of touch controllers, we had to develop a new library for the CST328 touch controller. The CSE_CST328 is a touch controller library from CIRCUITSTATE Electronics. Using this library, you can easily interface any touch panels with CST328 controller with any Arduino-compatible boards. You can use this library in conjunction with the TFT_eSPI library.
CSE_Touch
CSE_Touch is a unified touch support library from CIRCUITSTATE Electronics. This unifies multiple touch drivers into a single software interface that you can use in your applications. The advantage of this is that you can change the touch driver without changing your main application code, allowing you to use different types of touch panels. The CSE_CST328 library is already supported by CSE_Touch.
CSE_UI
CSE_UI is yet another open-source Arduino library from CIRCUITSTATE Electronics. This is a Graphical User Interface (GUI) library built on top of the TFT_eSPI library. That means you can run the CSE_UI applications on any displays that are supported by TFT_eSPI library. The touch functions will be provided by the CSE_Touch library. Following are the main features of the CSE_UI library.
Arduino Code
To demonstrate the capabilities of the display module and our libraries, we have created a PlatformIO project for the Arduino platform. As said earlier, we are using the FireBeetle-ESP32E board from DFRobot. Since this is a PlatformIO project, you can easily change the target platform and the target microcontroller board. We have three examples present in this single project. We have uploaded the project to our GitHub.
To compile and upload an example, choose the PlatformIO environment configuration from the bottom bar of Visual Studio Code (VS Code). If you are new to VS Code and PlatformIO, we have great tutorials to help you get started.
Following is the main platformio.ini configuration file.
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
;------------------------------------------------------------------------------------;
; PlatformIO default environment
[platformio]
default_envs = LCD_Test
;------------------------------------------------------------------------------------;
; Common settings shared between environments
[env]
platform = espressif32
board = dfrobot_firebeetle2_esp32e
framework = arduino
; upload_protocol = esp-prog
debug_tool = esp-prog
lib_deps = bodmer/TFT_eSPI @ ^2.5.30
build_flags =
-D USER_SETUP_LOADED=1
-D ST7789_DRIVER=1
-D TFT_INVERSION_ON=0
-D TFT_RGB_ORDER=0
-D TFT_WIDTH=240
-D TFT_HEIGHT=320
-D LOAD_GLCD=1
-D LOAD_FONT2=1
-D LOAD_FONT4=1
-D LOAD_FONT6=1
-D LOAD_FONT7=1
-D LOAD_GFXFF=1
-D SMOOTH_FONT=1
-D SPI_FREQUENCY=80000000
-D SPI_READ_FREQUENCY=2500000
; Pinouts for the FFC
-D TFT_CS=14
-D TFT_DC=25
-D TFT_RST=26
-D TFT_MOSI=23
-D TFT_MISO=19
-D TFT_SCLK=18
-D TFT_BL=12
; -D TFT_TOUCH_SDA=21
; -D TFT_TOUCH_SCL=22
; -D TFT_TOUCH_INT=16
; ; Pinouts for the Molex connector
; -D TFT_CS=17
; -D TFT_DC=25
; -D TFT_RST=26
; -D TFT_MOSI=23
; -D TFT_MISO=19
; -D TFT_SCLK=18
; -D TFT_BL=2
; ; -D TFT_TOUCH_SDA=21
; ; -D TFT_TOUCH_SCL=22
; ; -D TFT_TOUCH_INT=25
;------------------------------------------------------------------------------------;
; For testing the LCD
[env:LCD_Test]
build_src_filter = +<LCD_Test/>
lib_deps =
${env.lib_deps} ; Inherit common dependencies
; CSE_MillisTimer=symlink://D:\Code\Arduino\libraries\CSE_MillisTimer
;------------------------------------------------------------------------------------;
; For testing the touch panel
[env:Touch_Test]
build_src_filter = +<Touch_Test/>
lib_deps =
${env.lib_deps} ; Inherit common dependencies
CSE_CST328=symlink://D:/Code/Arduino/libraries/CSE_CST328
CSE_Touch=symlink://D:/Code/Arduino/libraries/CSE_Touch
build_flags =
${env.build_flags}
-D ENABLE_CST328=1
;------------------------------------------------------------------------------------;
; For testing UI using CSE_UI library
[env:UI_Test]
build_src_filter = +<UI_Test/>
lib_deps =
${env.lib_deps} ; Inherit common dependencies
CSE_UI=symlink://D:\Code\Arduino\libraries\CSE_UI
CSE_Touch=symlink://D:/Code/Arduino/libraries/CSE_Touch
CSE_CST328=symlink://D:/Code/Arduino/libraries/CSE_CST328
CSE_MillisTimer=symlink://D:\Code\Arduino\libraries\CSE_MillisTimer
build_flags =
${env.build_flags}
-D ENABLE_CST328=1
;------------------------------------------------------------------------------------;
platformio.iniLCD Test

This example tests the basic functionalities of the LCD module and prints information about on the serial monitor. You can find this example under the LCD_Test
environment. Following is the main code.
//============================================================================================//
/*
Filename: main.cpp [Waveshare-2.8-Inch-LCD -> LCD_Test]
Description: Main source file for the LCD_Test example.
Framework: Arduino, PlatformIO
Author: Vishnu Mohanan (@vishnumaiea, @vizmohanan)
Maintainer: CIRCUITSTATE Electronics (@circuitstate)
Version: 0.1
License: MIT
Source: https://github.com/CIRCUITSTATE/CSE_CST328
Last Modified: +05:30 17:48:12 PM 20-02-2025, Thursday
*/
//============================================================================================//
#include <SPI.h>
#include <TFT_eSPI.h> // TFT LCD library
#include <Wire.h>
//============================================================================================//
// Globals
TFT_eSPI LCD = TFT_eSPI(); // Create a new TFT driver instance
// The library defines the type "setup_t" as a struct.
// Calling LCD.getSetup(user) populates it with the settings.
setup_t user;
//============================================================================================//
// Forward Declarations
void setup (void);
void loop (void);
void printDriverInfo (void);
void printProcessorName (void);
int8_t getPinName (int8_t pin);
bool initWire (void);
bool initLCD (void);
//============================================================================================//
/**
* @brief Setup runs once.
*
*/
void setup() {
Serial.begin (115200);
delay (1000);
Serial.println();
Serial.println (F("=== Waveshare 2.8 Inch LCD - LCD Test ==="));
// Initialize everything.
initWire();
initLCD();
Serial.println (F("setup [INFO]: System initialization complete."));
Serial.println();
delay (1000);
}
//============================================================================================//
/**
* @brief Infinite loop.
*
*/
void loop() {
LCD.fillScreen (TFT_BLACK);
LCD.setTextSize (2);
LCD.setTextColor (TFT_YELLOW);
LCD.setCursor (20, 50);
LCD.print ("Hello World");
printDriverInfo();
delay (1000);
}
//============================================================================================//
/**
* @brief Initialize the I2C/Wire interface.
*
* @return true Initialization successful.
* @return false Initialization failed.
*/
bool initWire (void) {
Serial.print (F("initWire [INFO]: Initializing I2C.. "));
Wire.begin();
// Wire.setSCL (PIN_I2C_SCL);
// Wire.setSDA (PIN_I2C_SDA);
// Wire.setClock (100000); // 100 kHz
// Wire.begin (I2C_PERIPHERAL_ADDR); // Initialize I2C as peripheral
Serial.println (F("Done."));
return true;
}
//============================================================================================//
/**
* @brief Initializes the LCD.
*
* @return true Initialization successful.
* @return false Initialization failed.
*/
bool initLCD (void) {
Serial.print (F("initLCD [INFO]: Initializing LCD.. "));
pinMode (TFT_BL, OUTPUT);
digitalWrite (TFT_BL, LOW); // Turn off the backlight
LCD.begin();
LCD.setRotation (3);
LCD.setFreeFont();
LCD.fillScreen (TFT_BLACK); // Clear the screen
delay (50);
Serial.println (F("Done."));
Serial.println (F("initLCD [INFO]: You should see \"Hello World\" printed in yellow color on the screen."));
digitalWrite (TFT_BL, HIGH); // Turn on the backlight
return true;
}
//============================================================================================//
/**
* @brief Prints the TFT_eSPI driver information.
*
*/
void printDriverInfo (void) {
LCD.getSetup (user); //
Serial.print ("\n[code]\n");
Serial.print ("TFT_eSPI ver = "); Serial.println(user.version);
printProcessorName();
#if defined (ESP32) || defined (ESP8266)
if (user.esp < 0x32F000 || user.esp > 0x32FFFF) { Serial.print("Frequency = "); Serial.print(ESP.getCpuFreqMHz());Serial.println("MHz"); }
#endif
#ifdef ESP8266
Serial.print("Voltage = "); Serial.print(ESP.getVcc() / 918.0); Serial.println("V"); // 918 empirically determined
#endif
Serial.print("Transactions = "); Serial.println((user.trans == 1) ? "Yes" : "No");
Serial.print("Interface = "); Serial.println((user.serial == 1) ? "SPI" : "Parallel");
#ifdef ESP8266
if (user.serial == 1){ Serial.print("SPI overlap = "); Serial.println((user.overlap == 1) ? "Yes\n" : "No\n"); }
#endif
if (user.tft_driver != 0xE9D) // For ePaper displays the size is defined in the sketch
{
Serial.print("Display driver = "); Serial.println(user.tft_driver, HEX); // Hexadecimal code
Serial.print("Display width = "); Serial.println(user.tft_width); // Rotation 0 width and height
Serial.print("Display height = "); Serial.println(user.tft_height);
Serial.println();
}
else if (user.tft_driver == 0xE9D) Serial.println("Display driver = ePaper\n");
if (user.r0_x_offset != 0) { Serial.print("R0 x offset = "); Serial.println(user.r0_x_offset); } // Offsets, not all used yet
if (user.r0_y_offset != 0) { Serial.print("R0 y offset = "); Serial.println(user.r0_y_offset); }
if (user.r1_x_offset != 0) { Serial.print("R1 x offset = "); Serial.println(user.r1_x_offset); }
if (user.r1_y_offset != 0) { Serial.print("R1 y offset = "); Serial.println(user.r1_y_offset); }
if (user.r2_x_offset != 0) { Serial.print("R2 x offset = "); Serial.println(user.r2_x_offset); }
if (user.r2_y_offset != 0) { Serial.print("R2 y offset = "); Serial.println(user.r2_y_offset); }
if (user.r3_x_offset != 0) { Serial.print("R3 x offset = "); Serial.println(user.r3_x_offset); }
if (user.r3_y_offset != 0) { Serial.print("R3 y offset = "); Serial.println(user.r3_y_offset); }
if (user.pin_tft_mosi != -1) { Serial.print("MOSI = "); Serial.print("GPIO "); Serial.println(getPinName(user.pin_tft_mosi)); }
if (user.pin_tft_miso != -1) { Serial.print("MISO = "); Serial.print("GPIO "); Serial.println(getPinName(user.pin_tft_miso)); }
if (user.pin_tft_clk != -1) { Serial.print("SCK = "); Serial.print("GPIO "); Serial.println(getPinName(user.pin_tft_clk)); }
#ifdef ESP8266
if (user.overlap == true)
{
Serial.println("Overlap selected, following pins MUST be used:");
Serial.println("MOSI = SD1 (GPIO 8)");
Serial.println("MISO = SD0 (GPIO 7)");
Serial.println("SCK = CLK (GPIO 6)");
Serial.println("TFT_CS = D3 (GPIO 0)\n");
Serial.println("TFT_DC and TFT_RST pins can be user defined");
}
#endif
String pinNameRef = "GPIO ";
#ifdef ESP8266
pinNameRef = "PIN_D";
#endif
if (user.esp == 0x32F) {
Serial.println("\n>>>>> Note: STM32 pin references above D15 may not reflect board markings <<<<<");
pinNameRef = "D";
}
if (user.pin_tft_cs != -1) { Serial.print("TFT_CS = " + pinNameRef); Serial.println(getPinName(user.pin_tft_cs)); }
if (user.pin_tft_dc != -1) { Serial.print("TFT_DC = " + pinNameRef); Serial.println(getPinName(user.pin_tft_dc)); }
if (user.pin_tft_rst!= -1) { Serial.print("TFT_RST = " + pinNameRef); Serial.println(getPinName(user.pin_tft_rst)); }
if (user.pin_tch_cs != -1) { Serial.print("TOUCH_CS = " + pinNameRef); Serial.println(getPinName(user.pin_tch_cs)); }
if (user.pin_tft_wr != -1) { Serial.print("TFT_WR = " + pinNameRef); Serial.println(getPinName(user.pin_tft_wr)); }
if (user.pin_tft_rd != -1) { Serial.print("TFT_RD = " + pinNameRef); Serial.println(getPinName(user.pin_tft_rd)); }
if (user.pin_tft_d0 != -1) { Serial.print("\nTFT_D0 = " + pinNameRef); Serial.println(getPinName(user.pin_tft_d0)); }
if (user.pin_tft_d1 != -1) { Serial.print("TFT_D1 = " + pinNameRef); Serial.println(getPinName(user.pin_tft_d1)); }
if (user.pin_tft_d2 != -1) { Serial.print("TFT_D2 = " + pinNameRef); Serial.println(getPinName(user.pin_tft_d2)); }
if (user.pin_tft_d3 != -1) { Serial.print("TFT_D3 = " + pinNameRef); Serial.println(getPinName(user.pin_tft_d3)); }
if (user.pin_tft_d4 != -1) { Serial.print("TFT_D4 = " + pinNameRef); Serial.println(getPinName(user.pin_tft_d4)); }
if (user.pin_tft_d5 != -1) { Serial.print("TFT_D5 = " + pinNameRef); Serial.println(getPinName(user.pin_tft_d5)); }
if (user.pin_tft_d6 != -1) { Serial.print("TFT_D6 = " + pinNameRef); Serial.println(getPinName(user.pin_tft_d6)); }
if (user.pin_tft_d7 != -1) { Serial.print("TFT_D7 = " + pinNameRef); Serial.println(getPinName(user.pin_tft_d7)); }
#if defined (TFT_BL)
Serial.print("\nTFT_BL = " + pinNameRef); Serial.println(getPinName(user.pin_tft_led));
#if defined (TFT_BACKLIGHT_ON)
Serial.print("TFT_BACKLIGHT_ON = "); Serial.println(user.pin_tft_led_on == HIGH ? "HIGH" : "LOW");
#endif
#endif
Serial.println();
uint16_t fonts = LCD.fontsLoaded();
if (fonts & (1 << 1)) Serial.print("Font GLCD loaded\n");
if (fonts & (1 << 2)) Serial.print("Font 2 loaded\n");
if (fonts & (1 << 4)) Serial.print("Font 4 loaded\n");
if (fonts & (1 << 6)) Serial.print("Font 6 loaded\n");
if (fonts & (1 << 7)) Serial.print("Font 7 loaded\n");
if (fonts & (1 << 9)) Serial.print("Font 8N loaded\n");
else
if (fonts & (1 << 8)) Serial.print("Font 8 loaded\n");
if (fonts & (1 << 15)) Serial.print("Smooth font enabled\n");
Serial.print("\n");
if (user.serial==1) { Serial.print("Display SPI frequency = "); Serial.println(user.tft_spi_freq/10.0); }
if (user.pin_tch_cs != -1) { Serial.print("Touch SPI frequency = "); Serial.println(user.tch_spi_freq/10.0); }
Serial.println("[/code]");
delay(3000);
}
//============================================================================================//
/**
* @brief Gets the name of the processor.
*
*/
void printProcessorName (void) {
Serial.print("Processor = ");
if ( user.esp == 0x8266) Serial.println("ESP8266");
if ( user.esp == 0x32) Serial.println("ESP32");
if ( user.esp == 0x32F) Serial.println("STM32");
if ( user.esp == 0x2040) Serial.println("RP2040");
if ( user.esp == 0x0000) Serial.println("Generic");
}
//============================================================================================//
/**
* @brief Gets the names of the pins used by the processor.
*
* @param pin
* @return int8_t
*/
int8_t getPinName (int8_t pin) {
// For ESP32 and RP2040 pin labels on boards use the GPIO number
if (user.esp == 0x32 || user.esp == 0x2040) return pin;
if (user.esp == 0x8266) {
// For ESP8266 the pin labels are not the same as the GPIO number
// These are for the NodeMCU pin definitions:
// GPIO Dxx
if (pin == 16) return 0;
if (pin == 5) return 1;
if (pin == 4) return 2;
if (pin == 0) return 3;
if (pin == 2) return 4;
if (pin == 14) return 5;
if (pin == 12) return 6;
if (pin == 13) return 7;
if (pin == 15) return 8;
if (pin == 3) return 9;
if (pin == 1) return 10;
if (pin == 9) return 11;
if (pin == 10) return 12;
}
if (user.esp == 0x32F) return pin;
return -1; // Invalid pin
}
//============================================================================================//
main.cppAfter choosing the target, you can compile and upload the code to your microcontroller board. Following is the compilation and upload log.
* Executing task: C:\PIO\penv\Scripts\platformio.exe run --target upload --environment LCD_Test
Processing LCD_Test (platform: espressif32; board: dfrobot_firebeetle2_esp32e; framework: arduino)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/dfrobot_firebeetle2_esp32e.html
PLATFORM: Espressif 32 (6.10.0) > DFRobot Firebeetle 2 ESP32-E
HARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash
DEBUG: Current (esp-prog) External (cmsis-dap, esp-bridge, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES:
- framework-arduinoespressif32 @ 3.20017.241212+sha.dcc1105b
- tool-esptoolpy @ 1.40501.0 (4.5.1)
- tool-mkfatfs @ 2.0.1
- tool-mklittlefs @ 1.203.210628 (2.3)
- tool-mkspiffs @ 2.230.0 (2.30)
- toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch5
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 34 compatible libraries
Scanning dependencies...
Dependency Graph
|-- TFT_eSPI @ 2.5.43
|-- SPI @ 2.0.0
|-- Wire @ 2.0.0
Building in release mode
Compiling .pio\build\LCD_Test\src\LCD_Test\main.cpp.o
Building .pio\build\LCD_Test\bootloader.bin
Generating partitions .pio\build\LCD_Test\partitions.bin
esptool.py v4.5.1
Creating esp32 image...
Merged 1 ELF section
Successfully created esp32 image.
Compiling .pio\build\LCD_Test\lib2bb\SPI\SPI.cpp.o
Compiling .pio\build\LCD_Test\liba1d\FS\FS.cpp.o
Compiling .pio\build\LCD_Test\liba1d\FS\vfs_api.cpp.o
Compiling .pio\build\LCD_Test\libb83\SPIFFS\SPIFFS.cpp.o
Compiling .pio\build\LCD_Test\lib194\LittleFS\LittleFS.cpp.o
In file included from src/LCD_Test/main.cpp:17:
.pio/libdeps/LCD_Test/TFT_eSPI/TFT_eSPI.h:973:8: warning: #warning >>>>------>> TOUCH_CS pin not defined, TFT_eSPI touch functions will not be available! [-Wcpp]
#warning >>>>------>> TOUCH_CS pin not defined, TFT_eSPI touch functions will not be available!
^~~~~~~
Compiling .pio\build\LCD_Test\lib94e\TFT_eSPI\TFT_eSPI.cpp.o
Compiling .pio\build\LCD_Test\lib265\Wire\Wire.cpp.o
Archiving .pio\build\LCD_Test\lib2bb\libSPI.a
Indexing .pio\build\LCD_Test\lib2bb\libSPI.a
Compiling .pio\build\LCD_Test\FrameworkArduino\Esp.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\FirmwareMSC.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\FunctionalInterrupt.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\HWCDC.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\HardwareSerial.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\IPAddress.cpp.o
Archiving .pio\build\LCD_Test\liba1d\libFS.a
Compiling .pio\build\LCD_Test\FrameworkArduino\IPv6Address.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\MD5Builder.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\Print.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\Stream.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\StreamString.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\Tone.cpp.o
Indexing .pio\build\LCD_Test\liba1d\libFS.a
Compiling .pio\build\LCD_Test\FrameworkArduino\USB.cpp.o
Archiving .pio\build\LCD_Test\libb83\libSPIFFS.a
Compiling .pio\build\LCD_Test\FrameworkArduino\USBCDC.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\USBMSC.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\WMath.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\WString.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\base64.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\cbuf.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-adc.c.o
Indexing .pio\build\LCD_Test\libb83\libSPIFFS.a
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-bt.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-cpu.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-dac.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-gpio.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-i2c-slave.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-i2c.c.o
In file included from .pio/libdeps/LCD_Test/TFT_eSPI/TFT_eSPI.cpp:16:
.pio/libdeps/LCD_Test/TFT_eSPI/TFT_eSPI.h:973:8: warning: #warning >>>>------>> TOUCH_CS pin not defined, TFT_eSPI touch functions will not be available! [-Wcpp]
#warning >>>>------>> TOUCH_CS pin not defined, TFT_eSPI touch functions will not be available!
^~~~~~~
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-ledc.c.o
Archiving .pio\build\LCD_Test\lib194\libLittleFS.a
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-matrix.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-misc.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-psram.c.o
Indexing .pio\build\LCD_Test\lib194\libLittleFS.a
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-rgb-led.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-rmt.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-sigmadelta.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-spi.c.o
Archiving .pio\build\LCD_Test\lib265\libWire.a
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-time.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-timer.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-tinyusb.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-touch.c.o
Indexing .pio\build\LCD_Test\lib265\libWire.a
Compiling .pio\build\LCD_Test\FrameworkArduino\esp32-hal-uart.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\firmware_msc_fat.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\libb64\cdecode.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\libb64\cencode.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\main.cpp.o
Compiling .pio\build\LCD_Test\FrameworkArduino\stdlib_noniso.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\wiring_pulse.c.o
Compiling .pio\build\LCD_Test\FrameworkArduino\wiring_shift.c.o
Archiving .pio\build\LCD_Test\libFrameworkArduino.a
Indexing .pio\build\LCD_Test\libFrameworkArduino.a
Archiving .pio\build\LCD_Test\lib94e\libTFT_eSPI.a
Indexing .pio\build\LCD_Test\lib94e\libTFT_eSPI.a
Linking .pio\build\LCD_Test\firmware.elf
Retrieving maximum program size .pio\build\LCD_Test\firmware.elf
Checking size .pio\build\LCD_Test\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM: [= ] 6.8% (used 22284 bytes from 327680 bytes)
Flash: [=== ] 25.3% (used 332197 bytes from 1310720 bytes)
Building .pio\build\LCD_Test\firmware.bin
esptool.py v4.5.1
Creating esp32 image...
Merged 2 ELF sections
Successfully created esp32 image.
Configuring upload protocol...
AVAILABLE: cmsis-dap, esp-bridge, esp-prog, espota, esptool, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa
CURRENT: upload_protocol = esptool
Looking for upload port...
Auto-detected: COM8
Uploading .pio\build\LCD_Test\firmware.bin
esptool.py v4.5.1
Serial port COM8
Connecting.....
Chip is ESP32-D0WD-V3 (revision v3.0)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: e0:5a:1b:55:d1:bc
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Flash will be erased from 0x00001000 to 0x00005fff...
Flash will be erased from 0x00008000 to 0x00008fff...
Flash will be erased from 0x0000e000 to 0x0000ffff...
Flash will be erased from 0x00010000 to 0x00061fff...
Compressed 17536 bytes to 12202...
Writing at 0x00001000... (100 %)
Wrote 17536 bytes (12202 compressed) at 0x00001000 in 0.6 seconds (effective 228.3 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 146...
Writing at 0x00008000... (100 %)
Wrote 3072 bytes (146 compressed) at 0x00008000 in 0.1 seconds (effective 355.0 kbit/s)...
Hash of data verified.
Compressed 8192 bytes to 47...
Writing at 0x0000e000... (100 %)
Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.1 seconds (effective 452.7 kbit/s)...
Hash of data verified.
Compressed 332560 bytes to 184137...
Writing at 0x00010000... (8 %)
Writing at 0x0001b092... (16 %)
Writing at 0x000294d1... (25 %)
Writing at 0x0002e83b... (33 %)
Writing at 0x000343b6... (41 %)
Writing at 0x00039930... (50 %)
Writing at 0x0003eddd... (58 %)
Writing at 0x000444da... (66 %)
Writing at 0x000499de... (75 %)
Writing at 0x00051bff... (83 %)
Writing at 0x0005a4d2... (91 %)
Writing at 0x0005fd46... (100 %)
Wrote 332560 bytes (184137 compressed) at 0x00010000 in 4.6 seconds (effective 572.8 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
======================================================================================== [SUCCESS] Took 14.30 seconds ========================================================================================
Environment Status Duration
------------- -------- ------------
LCD_Test SUCCESS 00:00:14.297
========================================================================================= 1 succeeded in 00:00:14.297 =========================================================================================
* Terminal will be reused by tasks, press any key to close it.
TerminalIf you open the serial monitor after uploading the code, you will see something like below printed to it. You will also see a “Hello World” message printed on the LCD in yellow color and black background. If you are not seeing it, then something is wrong. Check your wiring and pin configurations and try again.
ets Jul 29 2019 12:21:46
rst:0x1 (POWERON_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:1184
load:0x40078000,len:13232
load:0x40080400,len:3028
entry 0x400805e4
=== Waveshare 2.8 Inch LCD - LCD Test ===
initWire [INFO]: Initializing I2C.. Done.
initLCD [INFO]: Initializing LCD.. Done.
initLCD [INFO]: You should see "Hello World" printed in yellow color on the screen.
setup [INFO]: System initialization complete.
[code]
TFT_eSPI ver = 2.5.43
Processor = ESP32
Frequency = 240MHz
Transactions = Yes
Interface = SPI
Display driver = 7789
Display width = 240
Display height = 320
MOSI = GPIO 23
MISO = GPIO 19
SCK = GPIO 18
TFT_CS = GPIO 14
TFT_DC = GPIO 25
TFT_RST = GPIO 26
TFT_BL = GPIO 12
Font GLCD loaded
Font 2 loaded
Font 4 loaded
Font 6 loaded
Font 7 loaded
Smooth font enabled
Display SPI frequency = 80.00
[/code]
Serial MonitorTouch Test

This example checks the touch functionality of the LCD module. It draws a yellow XY crosshair on the point you touch. A small red square is also drawn on the origin of the display. This will help you visually determine where the origin of the LCD is. If the LCD origin does not match the touch panel origin, you can try changing the rotations to one of the other three values. One of the rotations should work.
You can find this example under the Touch_Test
environment. Following is the main code.
//============================================================================================//
/*
Filename: main.cpp [Waveshare-2.8-Inch-LCD -> Touch_Test]
Description: Main source file for the Touch_Test example.
Framework: Arduino, PlatformIO
Author: Vishnu Mohanan (@vishnumaiea, @vizmohanan)
Maintainer: CIRCUITSTATE Electronics (@circuitstate)
Version: 0.1
License: MIT
Source: https://github.com/CIRCUITSTATE/CSE_CST328
Last Modified: +05:30 22:15:35 PM 10-03-2025, Monday
*/
//============================================================================================//
#include <SPI.h>
#include <TFT_eSPI.h> // TFT LCD library
#include <Wire.h>
#include <CSE_CST328.h>
//============================================================================================//
// Macros and constants.
#define CST328_PIN_RST 4
#define CST328_PIN_INT 16
#define LCD_ROTATION 0 // The LCD panel rotation
#define TS_ROTATION 0 // The touch panel rotation
//============================================================================================//
// Globals
TFT_eSPI LCD = TFT_eSPI(); // Create a new TFT driver instance
// Create a new instance of the CST328 class.
// Parameters: Width, Height, &Wire, Reset pin, Interrupt pin
CSE_CST328 tsPanel = CSE_CST328 (240, 320, &Wire, CST328_PIN_RST, CST328_PIN_INT);
bool intReceived = false; // Flag to indicate that an interrupt has been received
CSE_TouchPoint point;
//============================================================================================//
// Forward Declarations
void setup (void);
void loop (void);
void readTouch (void);
bool initWire (void);
bool initLCD (void);
bool initTouch (void);
void touchISR (void);
void drawCrosshair (void);
//============================================================================================//
/**
* @brief Setup runs once.
*
*/
void setup() {
Serial.begin (115200);
delay (2000);
Serial.println();
Serial.println (F("=== Waveshare 2.8 Inch LCD - Touch Test ==="));
// Initialize everything.
initWire();
initTouch();
initLCD();
Serial.println (F("setup [INFO]: System initialization complete."));
Serial.println();
delay (1000);
}
//============================================================================================//
/**
* @brief Infinite loop.
*
*/
void loop() {
if (intReceived) {
tsPanel.fastReadData (0); // Read the touch point once.
LCD.drawRect (0, 0, 10, 10, TFT_RED); // Draw a small rectangle to indicate the origin of the display and the touch panel.
readTouch(); // Print touch point info.
drawCrosshair(); // Draw a cross hair.
intReceived = false;
attachInterrupt (digitalPinToInterrupt (CST328_PIN_INT), touchISR, FALLING);
}
}
//============================================================================================//
/**
* @brief Initializes the touch panel.
*
* @return true Initialization successful.
* @return false Initialization failed.
*/
bool initTouch (void) {
Serial.print (F("initTouch [INFO]: Initializing touch panel.."));
tsPanel.begin();
tsPanel.setRotation (TS_ROTATION);
// Attach the interrupt function.
attachInterrupt (digitalPinToInterrupt (CST328_PIN_INT), touchISR, FALLING);
Serial.println (F("Done."));
return true;
}
//============================================================================================//
/**
* @brief Initialize the I2C/Wire interface.
*
* @return true Initialization successful.
* @return false Initialization failed.
*/
bool initWire (void) {
Serial.print (F("initWire [INFO]: Initializing I2C.. "));
Wire.begin();
Serial.println (F("Done."));
return true;
}
//============================================================================================//
/**
* @brief Initializes the LCD.
*
* @return true Initialization successful.
* @return false Initialization failed.
*/
bool initLCD (void) {
Serial.print (F("initLCD [INFO]: Initializing LCD.. "));
pinMode (TFT_BL, OUTPUT);
digitalWrite (TFT_BL, LOW); // Turn off the backlight
LCD.begin();
LCD.setRotation (LCD_ROTATION);
LCD.setFreeFont();
LCD.fillScreen (TFT_BLACK); // Clear the screen
delay (50);
Serial.println (F("Done."));
digitalWrite (TFT_BL, HIGH); // Turn on the backlight
return true;
}
//============================================================================================//
/**
* @brief Reads a single touch point from the panel and print their info to the serial monitor.
*
*/
void readTouch() {
if (1) {
uint8_t i = 0;
Serial.print ("Touch ID: ");
Serial.print (i);
Serial.print (", X: ");
Serial.print (tsPanel.getPoint (i).x);
Serial.print (", Y: ");
Serial.print (tsPanel.getPoint (i).y);
Serial.print (", Z: ");
Serial.print (tsPanel.getPoint (i).z);
Serial.print (", State: ");
Serial.print (tsPanel.getPoint (i).state);
Serial.print (", W: ");
Serial.print (tsPanel.getWidth());
Serial.print (", H: ");
Serial.println (tsPanel.getHeight());
}
else {
Serial.println ("No touches detected");
}
}
//============================================================================================//
/**
* @brief The touch interrupt service routine.
*
*/
void touchISR() {
// Detach the interrupt to prevent multiple interrupts
detachInterrupt (digitalPinToInterrupt (CST328_PIN_INT));
intReceived = true;
}
//============================================================================================//
void drawCrosshair() {
static CSE_TouchPoint prevPoint; // Previous touch point (non-calibrated)
// tsPanel.fastReadData (0);
point = tsPanel.getPoint();
// Return if the point is the same as the previous point, or invalid.
if ((point.x == prevPoint.x) || (point.y == prevPoint.y) || (point.x == -1) || (point.y == -1)) {
return;
}
// LCD.drawRect (prevPoint.x, prevPoint.y, 10, 10, TFT_BLACK);
// LCD.drawRect (point.x, point.y, 10, 10, TFT_YELLOW);
// Clear the previous cursor with background color
LCD.drawLine (prevPoint.x, 0, prevPoint.x, tsPanel.height, TFT_BLACK);
LCD.drawLine (0, prevPoint.y, tsPanel.width, prevPoint.y, TFT_BLACK);
// Draw the new cursor with foreground color
LCD.drawLine (point.x, 0, point.x, tsPanel.height, TFT_YELLOW);
LCD.drawLine (0, point.y, tsPanel.width, point.y, TFT_YELLOW);
// Save the points
prevPoint = point;
}
//============================================================================================//
main.cppIf you open the serial monitor after uploading the code, you will see messages printed like the following. Try touching the display and you will see new touch point information.
ets Jul 29 2019 12:21:46
rst:0x1 (POWERON_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:1184
load:0x40078000,len:13232
load:0x40080400,len:3028
entry 0x400805e4
=== Waveshare 2.8 Inch LCD - Touch Test ===
initWire [INFO]: Initializing I2C.. Done.
initTouch [INFO]: Initializing touch panel..Done.
initLCD [INFO]: Initializing LCD.. Done.
setup [INFO]: System initialization complete.
Touch ID: 0, X: 115, Y: 151, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 115, Y: 151, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 115, Y: 151, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 115, Y: 151, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 115, Y: 151, Z: 0, State: 0, W: 240, H: 320
Touch ID: 0, X: 154, Y: 142, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 154, Y: 142, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 154, Y: 142, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 154, Y: 142, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 154, Y: 142, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 154, Y: 142, Z: 0, State: 0, W: 240, H: 320
Touch ID: 0, X: 97, Y: 216, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 97, Y: 216, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 97, Y: 216, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 97, Y: 216, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 97, Y: 216, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 97, Y: 216, Z: 0, State: 0, W: 240, H: 320
Touch ID: 0, X: 124, Y: 66, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 124, Y: 66, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 124, Y: 66, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 124, Y: 66, Z: 0, State: 1, W: 240, H: 320
Touch ID: 0, X: 124, Y: 66, Z: 0, State: 0, W: 240, H: 320
Serial MonitorUI Test
This example demonstrates some of the capabilities of the CSE_UI library. You can find this example under the UI_Test
environment. Following is the main code.
//============================================================================================//
/*
Filename: main.cpp [Waveshare-2.8-Inch-LCD -> UI_Test]
Description: Main source file for the UI_Test example.
Framework: Arduino, PlatformIO
Author: Vishnu Mohanan (@vishnumaiea, @vizmohanan)
Maintainer: CIRCUITSTATE Electronics (@circuitstate)
Version: 0.1
License: MIT
Source: https://github.com/CIRCUITSTATE/CSE_CST328
Last Modified: +05:30 15:50:11 PM 01-03-2025, Saturday
*/
//============================================================================================//
#include <SPI.h>
#include <TFT_eSPI.h> // TFT LCD library
#include <Wire.h>
#include <CSE_CST328.h>
#include <CSE_UI.h>
// #include "NotoSans-Bold-15.h"
// #include "FiraSans-Regular-15.h"
#include "FiraSans-Medium-15.h"
// #include "Roboto-Regular-15.h"
#include "NotoSans-Bold-28.h"
#include "NotoSans-Bold-36.h"
// #include "forkawesome-36.h"
// #include "forkawesome-32.h"
#include "forkawesome-30.h"
// Include the header files that contain the icons
#include "Alert.h"
#include "Close.h"
#include "Info.h"
//============================================================================================//
// Macros and constants.
#define CST328_PIN_RST 4
#define CST328_PIN_INT 16
#define LCD_ROTATION 3 // The LCD panel rotation
#define TS_ROTATION 3 // The touch panel rotation
// Fonts
// #define AA_FONT_SMALL NotoSansBold15
// #define AA_FONT_SMALL FiraSansRegular15
#define AA_FONT_SMALL FiraSansMedium15
// #define AA_FONT_SMALL RobotoRegular15
#define AA_FONT_LARGE NotoSansBold36
//============================================================================================//
// Globals
TFT_eSPI LCD = TFT_eSPI(); // Create a new TFT driver instance
// Create a new instance of the CST328 class.
// Parameters: Width, Height, &Wire, Reset pin, Interrupt pin
CSE_Touch* tsPanel = CSE_Touch_Driver:: createDriver (CSE_TOUCH_CST328, 240, 320, &Wire, TFT_RST);
// UI objects.
CSE_UI myui (&LCD, tsPanel);
// Pages
pageClass home_Page (&myui, 0);
// Buttons
buttonClass home_mainTitle (&myui);
buttonClass home_timeDateString (&myui);
buttonClass home_Button_A (&myui);
buttonClass home_Button_B (&myui);
buttonClass home_Button_C (&myui);
buttonClass home_Button_D (&myui);
buttonClass home_oxygenLabel (&myui);
buttonClass home_oxygenValue (&myui);
buttonClass home_feLabel (&myui);
buttonClass home_feValue (&myui);
buttonClass home_fgtLabel (&myui);
buttonClass home_fgtValue (&myui);
buttonClass home_atLabel (&myui);
buttonClass home_atValue (&myui);
bool intReceived = false; // Flag to indicate that an interrupt has been received
//============================================================================================//
// Forward Declarations
void setup (void);
void loop (void);
void readTouch (void);
bool initWire (void);
bool initLCD (void);
bool initTouch (void);
void home_Page_Init (void);
void home_Page_Draw (void);
//============================================================================================//
/**
* @brief Setup runs once.
*
*/
void setup() {
Serial.begin (115200);
delay (2000);
Serial.println();
Serial.println (F("=== Waveshare 2.8 Inch LCD - Touch Test ==="));
// Initialize everything.
initWire();
initTouch();
initLCD();
Serial.println (F("setup [INFO]: System initialization complete."));
Serial.println();
delay (1000);
}
//============================================================================================//
/**
* @brief Infinite loop.
*
*/
void loop() {
// readTouch();
home_Page.draw();
delay (50);
}
//============================================================================================//
/**
* @brief Initializes the touch panel.
*
* @return true Initialization successful.
* @return false Initialization failed.
*/
bool initTouch (void) {
Serial.print (F("initTouch [INFO]: Initializing touch panel.."));
tsPanel->begin();
tsPanel->setRotation (TS_ROTATION);
// Attach the interrupt function.
// attachInterrupt (digitalPinToInterrupt (CST328_PIN_INT), touchISR, FALLING);
Serial.println (F("Done."));
return true;
}
//============================================================================================//
/**
* @brief Initialize the I2C/Wire interface.
*
* @return true Initialization successful.
* @return false Initialization failed.
*/
bool initWire (void) {
Serial.print (F("initWire [INFO]: Initializing I2C.. "));
Wire.begin();
Serial.println (F("Done."));
return true;
}
//============================================================================================//
/**
* @brief Initializes the LCD.
*
* @return true Initialization successful.
* @return false Initialization failed.
*/
bool initLCD (void) {
Serial.print (F("initLCD [INFO]: Initializing LCD.. "));
pinMode (TFT_BL, OUTPUT);
digitalWrite (TFT_BL, LOW); // Turn off the backlight
LCD.begin();
LCD.setRotation (LCD_ROTATION);
LCD.setFreeFont();
LCD.fillScreen (TFT_BLACK); // Clear the screen
delay (50);
home_Page.setInitFunction (home_Page_Init);
home_Page.setDrawFunction (home_Page_Draw);
home_Page.init();
home_Page.setActive();
Serial.println (F("Done."));
digitalWrite (TFT_BL, HIGH); // Turn on the backlight
return true;
}
//============================================================================================//
void home_Page_Init() {
home_mainTitle.initialize (10, 10, 235, 25, TFT_BLUE, TFT_WHITE, "AIR QUALITY MONITORING");
home_mainTitle.radius = 0;
home_mainTitle.labelOffsetY = 2;
home_timeDateString.initialize (10, 205, 235, 25, TFT_DARKCYAN, TFT_WHITE, "08:24 PM, Wed, 24-06-2023");
home_timeDateString.radius = 0;
home_timeDateString.labelOffsetY = 2;
home_oxygenLabel.initialize (10, 95, 110, 20, 0x9edf, TFT_BLACK, "PM 1.0 ug/m3");
home_oxygenLabel.radius = 0;
home_oxygenLabel.labelOffsetY = 2;
home_oxygenValue.initialize (10, 45, 110, 50, TFT_BLUE, TFT_WHITE, "110");
home_oxygenValue.radius = 0;
home_oxygenValue.labelOffsetY = 2;
home_feLabel.initialize (135, 95, 110, 20, 0xfea8, TFT_BLACK, "PM 2.5 ug/m3");
home_feLabel.radius = 0;
home_feLabel.labelOffsetY = 2;
home_feValue.initialize (135, 45, 110, 50, TFT_BLUE, TFT_WHITE, "230");
home_feValue.radius = 0;
home_feValue.labelOffsetY = 2;
home_fgtLabel.initialize (10, 175, 110, 20, 0xe61e, TFT_BLACK, "PM 10 ug/m3");
home_fgtLabel.radius = 0;
home_fgtLabel.labelOffsetY = 2;
home_fgtValue.initialize (10, 125, 110, 50, TFT_BLUE, TFT_WHITE, "190");
home_fgtValue.radius = 0;
home_fgtValue.labelOffsetY = 2;
home_atLabel.initialize (135, 175, 110, 20, TFT_GREEN, TFT_BLACK, "TEMP °C");
home_atLabel.radius = 0;
home_atLabel.labelOffsetY = 2;
home_atValue.initialize (135, 125, 110, 50, TFT_BLUE, TFT_WHITE, "32.68");
home_atValue.radius = 0;
home_atValue.labelOffsetY = 2;
home_Button_A.initialize (267, 10, 44, 40, TFT_BLUE, TFT_WHITE, "\uF05A");
home_Button_B.initialize (267, 70, 44, 40, TFT_BLUE, TFT_WHITE, "\uF046");
home_Button_C.initialize (267, 130, 44, 40, TFT_BLUE, TFT_WHITE, "\uF071");
home_Button_D.initialize (267, 190, 44, 40, TFT_BLUE, TFT_WHITE, "\uF013");
}
//============================================================================================//
void home_Page_Draw() {
if (home_Page.isActive()) {
if (myui.prevPage != home_Page.pageNum) {
home_Page.uiParent->lcdParent->fillScreen (TFT_WHITE);
myui.currentPage = home_Page.pageNum;
myui.prevPage = home_Page.pageNum;
}
LCD.loadFont (AA_FONT_SMALL);
home_timeDateString.draw();
home_mainTitle.draw();
home_oxygenLabel.draw();
home_feLabel.draw();
home_atLabel.draw();
home_fgtLabel.draw();
LCD.loadFont (NotoSansBold28);
home_fgtValue.draw();
LCD.loadFont (AA_FONT_LARGE);
home_oxygenValue.draw();
home_feValue.draw();
home_atValue.draw();
LCD.loadFont (forkawesome30);
home_Button_A.draw();
home_Button_B.draw();
home_Button_C.draw();
home_Button_D.draw();
// bool buttonA = home_Button_A.isPressed();
// bool buttonB = home_Button_B.isPressed();
// bool buttonC = home_Button_C.isPressed();
// bool buttonD = home_Button_D.isPressed();
// if (buttonA || buttonB || buttonC || buttonD) {
// home_Page.setInactive();
// home_timeDateString.reset();
// home_mainTitle.reset();
// home_oxygenLabel.reset();
// home_feLabel.reset();
// home_atLabel.reset();
// home_fgtLabel.reset();
// home_fgtValue.reset();
// home_oxygenValue.reset();
// home_feValue.reset();
// home_atValue.reset();
// home_Button_A.reset();
// home_Button_B.reset();
// home_Button_C.reset();
// home_Button_D.reset();
// if (buttonA) {
// // dataAndInfo_Page.setActive();
// }
// else if (buttonB) {
// // tasks_Page.setActive();
// }
// else if (buttonC) {
// // errorsAndAlarms_Page.setActive();
// }
// else if (buttonD) {
// // settings_Page.setActive();
// }
// }
}
}
//============================================================================================//
/**
* @brief Reads a single touch point from the panel and print their info to the serial monitor.
*
*/
void readTouch() {
if (tsPanel->isTouched (0)) {
uint8_t i = 0;
Serial.print ("Touch ID: ");
Serial.print (i);
Serial.print (", X: ");
Serial.print (tsPanel->getPoint (i).x);
Serial.print (", Y: ");
Serial.print (tsPanel->getPoint (i).y);
Serial.print (", Z: ");
Serial.print (tsPanel->getPoint (i).z);
Serial.print (", State: ");
Serial.print (tsPanel->getPoint (i).state);
Serial.print (", W: ");
Serial.print (tsPanel->getWidth());
Serial.print (", H: ");
Serial.println (tsPanel->getHeight());
}
// else {
// Serial.println ("No touches detected");
// }
}
//============================================================================================//
main.cppAfter uploading the code, you will a UI mock up that will show multiple text boxes, labels and buttons. You can touch the buttons and they will change colors when you do. You can also attach different functionalities to the touches.
Links
- Waveshare 2.8 Inch Capacitive Touch LCD – Product Page
- Waveshare 2.8 Inch Capacitive Touch LCD – Wiki
- Buy Waveshare 2.8 Inch Capacitive Touch LCD – Robu
- Buy Waveshare 2.8 Inch Capacitive Touch LCD – Hubtronics
- Mangalam Electronics – Mumbai – Buy FFC/FPC
- TFT_eSPI Arduino Library – GitHub
- CSE_CST328 Arduino Library – GitHub
- CSE_Touch Arduino Library – GitHub
- CSE_UI Arduino Library – GitHub
- Waveshare-2.8-Inch-LCD – PlatformIO Project Example – GitHub
- Buy FireBeetle-ESP32E – Robu
Short Link
- A short URL to this page – https://www.circuitstate.com/wav28lcd