Last Updated: 10/01/2022
ESP32 with GT911 Capacitive Touch Screen
Components >> ESP32 with GT911 Capacitive Touch Screen
ESP32 with GT911 Capacitive Touch Screen
Capacitative touch screens are found on modern mobile phones and car sat navs. They are capable of tracking multiple touches allowing gestures to be programmed.
However for this tutorial I will just be going through how to track the touches.
This is a support titorial for a DCC modular model railway controller.
The GT911 screens are available in a number of sizes, just type in GT911 touch screen into AliExpress
and you will see they are realily available and cheap.
Most of the ones for sale are being sold as replacement screens for in car Sat navs but they open up a world of opportunities to Arduino/ESP32 programmers.
WARNING
GT911 screen are 3.3V, so if you are using an Arduino you will need a 3.3v model such as an Arduino Due
Pins
GT911 screen only have 6 pins.
In this tutorial I will be using an ESP32 and the copnnections used are as follows.
RST > GPIO 15
VCC > 3.3v
GND > GND
INT > GPIO 2
SDA > SDA (GPIO 21)
SCL > SCL (GPIO 22)
Change the pins to suit your board.
To connect to the ribbon cable you will need a 2.54mm FFC FPC 6P adapter.
The cable plugs into the adapter and then connect the adapter to your board.
Prototype Model railway control panel built using 2 x GT911 touch screens and neopixels. The touch screens in this prototype are controlled by a single Arduino Due.
GT911 Libraries
There are a few GT911 libraries for Arduino/ESP32, however for my sketches I have not used one. All it requires is the "Wire.h"
The sketch I used is based on someone elses work, sadly I can't find where I got the sketch from but whoever wrote the original deserves credit for their work.
Despite it working well on an Arduino Due when I came to load it onto the ESP32 it came up with an error and eventually I tracked it down to a bug in the code that the arduino overlooks. I have corrected the bug in the scripts suppiled.
Although the touch screen is capable of tracking 5 touches at the same time my main use is for single touches as part of a model railway control panel.
As such I have included three scripts, a single touch version and a multi touch.
Then as a final script I have shown how to create virtual buttons for those building model railway control panels.
Example 1: GT911_ESP32v1.ino
Basic script to get a single X/Y touch co ordinate
Click to Download code: GT911_ESP32v1.ino
Simple test sketch, red background, white outline box and some text.
Touch points written to Serial monitor.
/* GT911_ESP32v1
* 05/04/2024
Bug fixed 05/04/2024
Working for single point touch
Screen > Pins Used ESP32 Dev Module
RST > GPIO 15
VCC > 3.3v
GND > GND
INT > GPIO 2
SDA > SDA (GPIO 21)
SCL > SCL (GPIO 22)
*/
#include "Wire.h"
//Screen address for GT911
uint8_t addr = 0x5d; //CTP IIC ADDRESS
//Pins
const int GT911_RESET = 15; //CTP RESET
const int GT911_INT = 2; //CTP INT
//I have included debounce as it makes the output easier to read and means it is set up for those building model railway control panels
unsigned long captouchbounce = 0;//like button bounce for touch
int captouched = 0;//1 means there has been a touch
//X and Y positions that will be used in further programming
int captouchx = 0;
int captouchy = 0;
int lastpixeltouched = 1000;//keeps track of the last touched pixel to prevent excess bounce
//This is some data that is needed to configure the GT911 touch screen...not my work.
unsigned char GTP_CFG_DATA[] =
{
0x5A, 0x20, 0x03, 0xE0, 0x01, 0x05, 0x0D, 0x00,
0x01, 0x08, 0x28, 0x08, 0x50, 0x32, 0x03, 0x05,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x88, 0x29, 0x0A, 0x35, 0x37,
0xD3, 0x07, 0x00, 0x00, 0x01, 0x81, 0x02, 0x1D,
0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x64, 0x32,
0x00, 0x00, 0x00, 0x28, 0x5A, 0x94, 0xC5, 0x02,
0x00, 0x00, 0x00, 0x00, 0x98, 0x2B, 0x00, 0x84,
0x33, 0x00, 0x74, 0x3C, 0x00, 0x67, 0x46, 0x00,
0x5C, 0x53, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
0x12, 0x14, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x04, 0x06, 0x08, 0x0F, 0x10, 0x12, 0x16, 0x18,
0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x25, 0x01
};
struct TouchLocation
{
uint16_t x;
uint16_t y;
};
//Various variables required for the GT911 screen
TouchLocation touchLocations[5];
void inttostr(uint16_t value, uint8_t *str);
uint8_t GT911_Send_Cfg(uint8_t * buf, uint16_t cfg_len);
void writeGT911TouchRegister( uint16_t regAddr, uint8_t *val, uint16_t cnt);
uint8_t readGT911TouchAddr( uint16_t regAddr, uint8_t * pBuf, uint8_t len );
uint8_t readGT911TouchLocation( TouchLocation * pLoc, uint8_t num );
uint32_t dist(const TouchLocation & loc);
uint32_t dist(const TouchLocation & loc1, const TouchLocation & loc2);
bool sameLoc( const TouchLocation & loc, const TouchLocation & loc2 );
uint8_t buf[80];
//Function to initialise the GT911 touch screen
void gt911setup() {
delay(300);
pinMode(GT911_RESET, OUTPUT);
pinMode (GT911_INT, OUTPUT);
digitalWrite(GT911_RESET, LOW);
delay(20);
digitalWrite(GT911_INT, LOW);
delay(50);
digitalWrite(GT911_RESET, HIGH);
delay(100);
pinMode (GT911_RESET, INPUT);
delay(100);
uint8_t re = GT911_Send_Cfg((uint8_t*)GTP_CFG_DATA, sizeof(GTP_CFG_DATA));
pinMode(GT911_RESET, OUTPUT);
pinMode (GT911_INT, OUTPUT);
digitalWrite(GT911_RESET, LOW);
delay(20);
digitalWrite(GT911_INT, LOW);
delay(50);
digitalWrite(GT911_RESET, HIGH);
delay(100);
pinMode (GT911_INT, INPUT);
delay(100);
re = GT911_Send_Cfg((uint8_t*)GTP_CFG_DATA, sizeof(GTP_CFG_DATA));
uint8_t bb[2];
readGT911TouchAddr(0x8047, bb, 2);
while (bb[1] != 32) {
Serial.println("Capacitive touch screen initialized failure");
pinMode(GT911_RESET, OUTPUT);
pinMode (GT911_INT, OUTPUT);
digitalWrite(GT911_RESET, LOW);
delay(20);
digitalWrite(GT911_INT, LOW);
delay(50);
digitalWrite(GT911_RESET, HIGH);
delay(100);
pinMode (GT911_INT, INPUT);
delay(100);
uint8_t re = GT911_Send_Cfg((uint8_t*)GTP_CFG_DATA, sizeof(GTP_CFG_DATA));
}
Serial.println("Capacitive touch screen initialized success");
}
//Not required, just in sketch to test connections
void scani2c() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for (address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address < 16)
Serial.print("0");
Serial.print(address, HEX);
Serial.println(" !");
nDevices++;
}
else if (error == 4)
{
Serial.print("Unknown error at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
}
uint8_t GT911_Send_Cfg(uint8_t * buf, uint16_t cfg_len)
{
uint8_t retry = 0;
for (retry = 0; retry < 5; retry++)
{
writeGT911TouchRegister(0x8047, buf, cfg_len);
//if(ret==0)break;
delay(10);
}
return retry;
}
//function that writes to the GT911...do not edit
void writeGT911TouchRegister( uint16_t regAddr, uint8_t *val, uint16_t cnt)
{
uint16_t i = 0;
Wire.beginTransmission(addr);
Wire.write( regAddr >> 8 ); // register 0
Wire.write( regAddr); // register 0
for (i = 0; i < cnt; i++, val++) //data
{
Wire.write( *val ); // value
}
uint8_t retVal = Wire.endTransmission();
}
//function that reads from the GT911...do not edit
uint8_t readGT911TouchAddr( uint16_t regAddr, uint8_t * pBuf, uint8_t len )
{
uint8_t i;
uint8_t returned;
uint8_t retVal;
Wire.beginTransmission(addr);
Wire.write( regAddr >> 8 ); // register 0
Wire.write( regAddr); // register 0
retVal = Wire.endTransmission();
returned = Wire.requestFrom(addr, len); // request 1 bytes from slave device #2
for (i = 0; (i < len) && Wire.available(); i++)
{
pBuf[i] = Wire.read();
}
return i;
}
////function that works out the touch coordinates for GT911...do not edit
uint8_t readGT911TouchLocation( TouchLocation * pLoc, uint8_t num )
{
uint8_t retVal;
uint8_t i;
uint8_t k;
uint8_t ss[1];
do
{
if (!pLoc) break; // must have a buffer
if (!num) break; // must be able to take at least one
ss[0] = 0;
readGT911TouchAddr( 0x814e, ss, 1);
uint8_t status = ss[0];
if ((status & 0x0f) == 0) break; // no points detected
uint8_t hitPoints = status & 0x0f;
//Serial.print("number of hit points = ");
// Serial.println( hitPoints );
uint8_t tbuf[40];//changed to 40 as that is number called for in readGT911TouchAddrTest( 0x8150, tbuf, 40);
uint8_t tbuf1[8];
readGT911TouchAddr( 0x8150, tbuf, 40);
readGT911TouchAddr( 0x8150 + 32, tbuf1, 8);
for (k = 0, i = 0; (i < 4 * 8) && (k < num); k++, i += 8)
{
pLoc[k].x = tbuf[i + 1] << 8 | tbuf[i + 0];
pLoc[k].y = tbuf[i + 3] << 8 | tbuf[i + 2];
}
pLoc[k].x = tbuf1[1] << 8 | tbuf1[0];
pLoc[k].y = tbuf1[3] << 8 | tbuf1[2];
retVal = hitPoints;
} while (0);
ss[0] = 0;
writeGT911TouchRegister( 0x814e, ss, 1);
delay(2);
return retVal;
}
//Function that uses the functions above to give a simple X/Y position to be used in your code
void checkfortouchscreen() {
captouched = 0;
pinMode (GT911_INT, INPUT);
uint8_t st = digitalRead(GT911_INT);
if (!st) //Hardware touch interrupt
{
//Serial.println("Touch: ");
//This line gives the number of touch points
//Screen can deal with 5 touches at once
uint8_t count = readGT911TouchLocation( touchLocations, 5 );
/*
if(count > 0){
Serial.print("Touches: ");
Serial.println(count);
}
*/
if (count) {
static TouchLocation caplastTouch = touchLocations[0];// only take single touch, not dealing with multitouch
caplastTouch = touchLocations[0];
if (millis() > captouchbounce) { //cuts out multitouch
captouchbounce = millis() + 250;//250 is the debounce, lower makes more sensitive but more false touches
//only using first touch for now
if (touchLocations[0].x > 0 && touchLocations[0].y > 0) { //only do something if there is an x and Y value
captouched = 1;
captouchx = touchLocations[0].x;
captouchy = touchLocations[0].y;
//X and Y positions sent to serial monitor
Serial.print(captouchx);
Serial.print(" : ");
Serial.println(captouchy);
}
}
}
}
}
void setup() {
Serial.begin(115200);
Serial.println("GT911_ESP32v1");
Wire.begin();
scani2c();//Not required, just in sketch to test connections
//set up the screen
gt911setup();
}
void loop() {
checkfortouchscreen();//keep looking for screen touches
}
Example 2: GT911_ESP32v2.ino
Basic script to get multiplee X/Y touch co ordinates
Click to Download code: GT911_ESP32v2.ino
/* GT911_ESP32v2
* 05/04/2024
Bug fixed effecting certain boards
Basic sketch to see if I ca get ESP32 to work with GT911 touch screen
working for multiple touch
Debounce needs to be removed for multiple touches but is included
to make the output easier to read
Screen > Pins Used ESP32 Dev Module
RST > GPIO 15
VCC > 3.3v
GND > GND
INT > GPIO 2
SDA > SDA (GPIO 21)
SCL > SCL (GPIO 22)
*/
//Used for GT911
#include "Wire.h"
uint8_t addr = 0x5d; //CTP IIC ADDRESS
const int GT911_RESET = 15; //CTP RESET
const int GT911_INT = 2; //CTP INT
unsigned long captouchbounce = 0;//like button bounce for touch
int captouched = 0;//1 means there has been a touch
int captouchx = 0;
int captouchy = 0;
int lastpixeltouched = 1000;//keeps track of the last touched pixel to prevent excess bounce
unsigned char GTP_CFG_DATA[] =
{
0x5A, 0x20, 0x03, 0xE0, 0x01, 0x05, 0x0D, 0x00,
0x01, 0x08, 0x28, 0x08, 0x50, 0x32, 0x03, 0x05,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x88, 0x29, 0x0A, 0x35, 0x37,
0xD3, 0x07, 0x00, 0x00, 0x01, 0x81, 0x02, 0x1D,
0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x64, 0x32,
0x00, 0x00, 0x00, 0x28, 0x5A, 0x94, 0xC5, 0x02,
0x00, 0x00, 0x00, 0x00, 0x98, 0x2B, 0x00, 0x84,
0x33, 0x00, 0x74, 0x3C, 0x00, 0x67, 0x46, 0x00,
0x5C, 0x53, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
0x12, 0x14, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x04, 0x06, 0x08, 0x0F, 0x10, 0x12, 0x16, 0x18,
0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x25, 0x01
};
struct TouchLocation
{
uint16_t x;
uint16_t y;
};
TouchLocation touchLocations[5];
void inttostr(uint16_t value, uint8_t *str);
uint8_t GT911_Send_Cfg(uint8_t * buf, uint16_t cfg_len);
void writeGT911TouchRegister( uint16_t regAddr, uint8_t *val, uint16_t cnt);
uint8_t readGT911TouchAddr( uint16_t regAddr, uint8_t * pBuf, uint8_t len );
uint8_t readGT911TouchLocation( TouchLocation * pLoc, uint8_t num );
uint32_t dist(const TouchLocation & loc);
uint32_t dist(const TouchLocation & loc1, const TouchLocation & loc2);
bool sameLoc( const TouchLocation & loc, const TouchLocation & loc2 );
uint8_t buf[80];
void gt911setup() {
delay(300);
pinMode(GT911_RESET, OUTPUT);
pinMode (GT911_INT, OUTPUT);
digitalWrite(GT911_RESET, LOW);
delay(20);
digitalWrite(GT911_INT, LOW);
delay(50);
digitalWrite(GT911_RESET, HIGH);
delay(100);
pinMode (GT911_RESET, INPUT);
delay(100);
uint8_t re = GT911_Send_Cfg((uint8_t*)GTP_CFG_DATA, sizeof(GTP_CFG_DATA));
pinMode(GT911_RESET, OUTPUT);
pinMode (GT911_INT, OUTPUT);
digitalWrite(GT911_RESET, LOW);
delay(20);
digitalWrite(GT911_INT, LOW);
delay(50);
digitalWrite(GT911_RESET, HIGH);
delay(100);
pinMode (GT911_INT, INPUT);
delay(100);
re = GT911_Send_Cfg((uint8_t*)GTP_CFG_DATA, sizeof(GTP_CFG_DATA));
uint8_t bb[2];
readGT911TouchAddr(0x8047, bb, 2);
while (bb[1] != 32) {
Serial.println("Capacitive touch screen initialized failure");
pinMode(GT911_RESET, OUTPUT);
pinMode (GT911_INT, OUTPUT);
digitalWrite(GT911_RESET, LOW);
delay(20);
digitalWrite(GT911_INT, LOW);
delay(50);
digitalWrite(GT911_RESET, HIGH);
delay(100);
pinMode (GT911_INT, INPUT);
delay(100);
uint8_t re = GT911_Send_Cfg((uint8_t*)GTP_CFG_DATA, sizeof(GTP_CFG_DATA));
}
Serial.println("Capacitive touch screen initialized success");
}
void scani2c() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for (address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address < 16)
Serial.print("0");
Serial.print(address, HEX);
Serial.println(" !");
nDevices++;
}
else if (error == 4)
{
Serial.print("Unknown error at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
}
uint8_t GT911_Send_Cfg(uint8_t * buf, uint16_t cfg_len)
{
uint8_t retry = 0;
for (retry = 0; retry < 5; retry++)
{
writeGT911TouchRegister(0x8047, buf, cfg_len);
//if(ret==0)break;
delay(10);
}
return retry;
}
void writeGT911TouchRegister( uint16_t regAddr, uint8_t *val, uint16_t cnt)
{
uint16_t i = 0;
Wire.beginTransmission(addr);
Wire.write( regAddr >> 8 ); // register 0
Wire.write( regAddr); // register 0
for (i = 0; i < cnt; i++, val++) //data
{
Wire.write( *val ); // value
}
uint8_t retVal = Wire.endTransmission();
}
uint8_t readGT911TouchAddr( uint16_t regAddr, uint8_t * pBuf, uint8_t len )
{
uint8_t i;
uint8_t returned;
uint8_t retVal;
Wire.beginTransmission(addr);
Wire.write( regAddr >> 8 ); // register 0
Wire.write( regAddr); // register 0
retVal = Wire.endTransmission();
returned = Wire.requestFrom(addr, len); // request 1 bytes from slave device #2
for (i = 0; (i < len) && Wire.available(); i++)
{
pBuf[i] = Wire.read();
}
return i;
}
uint8_t readGT911TouchLocation( TouchLocation * pLoc, uint8_t num )
{
uint8_t retVal;
uint8_t i;
uint8_t k;
uint8_t ss[1];
do
{
if (!pLoc) break; // must have a buffer
if (!num) break; // must be able to take at least one
ss[0] = 0;
readGT911TouchAddr( 0x814e, ss, 1);
uint8_t status = ss[0];
if ((status & 0x0f) == 0) break; // no points detected
uint8_t hitPoints = status & 0x0f;
//Serial.print("number of hit points = ");
// Serial.println( hitPoints );
//uint8_t tbuf[32];//original code, buffer is too small
uint8_t tbuf[40];//changed to 40 as that is number called for in readGT911TouchAddrTest( 0x8150, tbuf, 40);
uint8_t tbuf1[8];
readGT911TouchAddr( 0x8150, tbuf, 40);
readGT911TouchAddr( 0x8150 + 32, tbuf1, 8);
for (k = 0, i = 0; (i < 4 * 8) && (k < num); k++, i += 8)
{
pLoc[k].x = tbuf[i + 1] << 8 | tbuf[i + 0];
pLoc[k].y = tbuf[i + 3] << 8 | tbuf[i + 2];
}
pLoc[k].x = tbuf1[1] << 8 | tbuf1[0];
pLoc[k].y = tbuf1[3] << 8 | tbuf1[2];
retVal = hitPoints;
} while (0);
ss[0] = 0;
writeGT911TouchRegister( 0x814e, ss, 1);
delay(2);
return retVal;
}
void checkfortouchscreen() {
int q;
captouched = 0;
pinMode (GT911_INT, INPUT);
uint8_t st = digitalRead(GT911_INT);
if (!st) //Hardware touch interrupt
{
//Serial.println("Touch: ");
uint8_t count = readGT911TouchLocation( touchLocations, 5 );
if (count > 0) {
static TouchLocation caplastTouch = touchLocations[0];// only take single touch, not dealing with multitouch
caplastTouch = touchLocations[0];
if (millis() > captouchbounce) { //cuts out multitouch
captouchbounce = millis() + 250;//debounce value, probably best to remove when trying to capture multi touches
//as two fingers may touch at sligtly different timings.
//left in to make the output easier to read.
Serial.print("Touches: ");
Serial.println(count);
//works through the aray of x/y locations
//If touch gestures are being worked out you would need to store these values and compare with the next set.
//for gestures you will probably need to remove the debounce
for(q=0;q < count;q++){
captouched = 1;
captouchx = touchLocations[q].x;
captouchy = touchLocations[q].y;
Serial.print(captouchx);
Serial.print(" : ");
Serial.println(captouchy);
}
//only using first touch for now
/*
if (touchLocations[0].x > 0 && touchLocations[0].y > 0) { //only do somethng if there is an x and Y value
captouched = 1;
captouchx = touchLocations[0].x;
captouchy = touchLocations[0].y;
Serial.print(captouchx);
Serial.print(" : ");
Serial.println(captouchy);
}
*/
}
}
}
}
void setup() {
Serial.begin(115200);
Serial.println("GT911_ESP32v2 Multi Touch");
Wire.begin();
scani2c();
gt911setup();
}
void loop() {
checkfortouchscreen();
}
Example 3: GT911_ESP32v3.ino
Working with virtual buttons
I have created my buttons as shown in this photo.
Click to Download code: GT911_ESP32v3.ino
/* GT911_ESP32v3
05/04/2024 bug fix
Simple sketch showing how to use the GT911 as a control panel with virtual buttons.
Screen > Pins Used ESP32 Dev Module
RST > GPIO 15
VCC > 3.3v
GND > GND
INT > GPIO 2
SDA > SDA (GPIO 21)
SCL > SCL (GPIO 22)
*/
#include "Wire.h"
//Screen address for GT911
uint8_t addr = 0x5d; //CTP IIC ADDRESS
//Pins
const int GT911_RESET = 15; //CTP RESET
const int GT911_INT = 2; //CTP INT
//I have included debounce as it makes the output easier to read and means it is set up for those building model railway control panels
unsigned long captouchbounce = 0;//like button bounce for touch
int captouched = 0;//1 means there has been a touch
//X and Y positions that will be used in further programming
int captouchx = 0;
int captouchy = 0;
int lastpixeltouched = 1000;//keeps track of the last touched pixel to prevent excess bounce
int numButtons = 3;//Change this to the number of buttons you are using
int MyButtons[3][2] { //3 needs to match numButtons, x y
{191, 331}, //cordinates found by using GT911_ESP32v1 and pressing on virtual button
{398, 336},
{550, 350}
};
//This is some data that is needed to configure the GT911 touch screen...not my work.
unsigned char GTP_CFG_DATA[] =
{
0x5A, 0x20, 0x03, 0xE0, 0x01, 0x05, 0x0D, 0x00,
0x01, 0x08, 0x28, 0x08, 0x50, 0x32, 0x03, 0x05,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x88, 0x29, 0x0A, 0x35, 0x37,
0xD3, 0x07, 0x00, 0x00, 0x01, 0x81, 0x02, 0x1D,
0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x64, 0x32,
0x00, 0x00, 0x00, 0x28, 0x5A, 0x94, 0xC5, 0x02,
0x00, 0x00, 0x00, 0x00, 0x98, 0x2B, 0x00, 0x84,
0x33, 0x00, 0x74, 0x3C, 0x00, 0x67, 0x46, 0x00,
0x5C, 0x53, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
0x12, 0x14, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x04, 0x06, 0x08, 0x0F, 0x10, 0x12, 0x16, 0x18,
0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x25, 0x01
};
struct TouchLocation
{
uint16_t x;
uint16_t y;
};
//Various variables required for the GT911 screen
TouchLocation touchLocations[5];
void inttostr(uint16_t value, uint8_t *str);
uint8_t GT911_Send_Cfg(uint8_t * buf, uint16_t cfg_len);
void writeGT911TouchRegister( uint16_t regAddr, uint8_t *val, uint16_t cnt);
uint8_t readGT911TouchAddr( uint16_t regAddr, uint8_t * pBuf, uint8_t len );
uint8_t readGT911TouchLocation( TouchLocation * pLoc, uint8_t num );
uint32_t dist(const TouchLocation & loc);
uint32_t dist(const TouchLocation & loc1, const TouchLocation & loc2);
bool sameLoc( const TouchLocation & loc, const TouchLocation & loc2 );
uint8_t buf[80];
//Function to initialise the GT911 touch screen
void gt911setup() {
delay(300);
pinMode(GT911_RESET, OUTPUT);
pinMode (GT911_INT, OUTPUT);
digitalWrite(GT911_RESET, LOW);
delay(20);
digitalWrite(GT911_INT, LOW);
delay(50);
digitalWrite(GT911_RESET, HIGH);
delay(100);
pinMode (GT911_RESET, INPUT);
delay(100);
uint8_t re = GT911_Send_Cfg((uint8_t*)GTP_CFG_DATA, sizeof(GTP_CFG_DATA));
pinMode(GT911_RESET, OUTPUT);
pinMode (GT911_INT, OUTPUT);
digitalWrite(GT911_RESET, LOW);
delay(20);
digitalWrite(GT911_INT, LOW);
delay(50);
digitalWrite(GT911_RESET, HIGH);
delay(100);
pinMode (GT911_INT, INPUT);
delay(100);
re = GT911_Send_Cfg((uint8_t*)GTP_CFG_DATA, sizeof(GTP_CFG_DATA));
uint8_t bb[2];
readGT911TouchAddr(0x8047, bb, 2);
while (bb[1] != 32) {
Serial.println("Capacitive touch screen initialized failure");
pinMode(GT911_RESET, OUTPUT);
pinMode (GT911_INT, OUTPUT);
digitalWrite(GT911_RESET, LOW);
delay(20);
digitalWrite(GT911_INT, LOW);
delay(50);
digitalWrite(GT911_RESET, HIGH);
delay(100);
pinMode (GT911_INT, INPUT);
delay(100);
uint8_t re = GT911_Send_Cfg((uint8_t*)GTP_CFG_DATA, sizeof(GTP_CFG_DATA));
}
Serial.println("Capacitive touch screen initialized success");
}
//Not required, just in sketch to test connections
void scani2c() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for (address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address < 16)
Serial.print("0");
Serial.print(address, HEX);
Serial.println(" !");
nDevices++;
}
else if (error == 4)
{
Serial.print("Unknown error at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
}
uint8_t GT911_Send_Cfg(uint8_t * buf, uint16_t cfg_len)
{
uint8_t retry = 0;
for (retry = 0; retry < 5; retry++)
{
writeGT911TouchRegister(0x8047, buf, cfg_len);
//if(ret==0)break;
delay(10);
}
return retry;
}
//function that writes to the GT911...do not edit
void writeGT911TouchRegister( uint16_t regAddr, uint8_t *val, uint16_t cnt)
{
uint16_t i = 0;
Wire.beginTransmission(addr);
Wire.write( regAddr >> 8 ); // register 0
Wire.write( regAddr); // register 0
for (i = 0; i < cnt; i++, val++) //data
{
Wire.write( *val ); // value
}
uint8_t retVal = Wire.endTransmission();
}
//function that reads from the GT911...do not edit
uint8_t readGT911TouchAddr( uint16_t regAddr, uint8_t * pBuf, uint8_t len )
{
uint8_t i;
uint8_t returned;
uint8_t retVal;
Wire.beginTransmission(addr);
Wire.write( regAddr >> 8 ); // register 0
Wire.write( regAddr); // register 0
retVal = Wire.endTransmission();
returned = Wire.requestFrom(addr, len); // request 1 bytes from slave device #2
for (i = 0; (i < len) && Wire.available(); i++)
{
pBuf[i] = Wire.read();
}
return i;
}
////function that works out the touch coordinates for GT911...do not edit
uint8_t readGT911TouchLocation( TouchLocation * pLoc, uint8_t num )
{
uint8_t retVal;
uint8_t i;
uint8_t k;
uint8_t ss[1];
do
{
if (!pLoc) break; // must have a buffer
if (!num) break; // must be able to take at least one
ss[0] = 0;
readGT911TouchAddr( 0x814e, ss, 1);
uint8_t status = ss[0];
if ((status & 0x0f) == 0) break; // no points detected
uint8_t hitPoints = status & 0x0f;
//Serial.print("number of hit points = ");
// Serial.println( hitPoints );
uint8_t tbuf[40];//changed to 40 as that is number called for in readGT911TouchAddrTest( 0x8150, tbuf, 40);
uint8_t tbuf1[8];
readGT911TouchAddr( 0x8150, tbuf, 40);
readGT911TouchAddr( 0x8150 + 32, tbuf1, 8);
for (k = 0, i = 0; (i < 4 * 8) && (k < num); k++, i += 8)
{
pLoc[k].x = tbuf[i + 1] << 8 | tbuf[i + 0];
pLoc[k].y = tbuf[i + 3] << 8 | tbuf[i + 2];
}
pLoc[k].x = tbuf1[1] << 8 | tbuf1[0];
pLoc[k].y = tbuf1[3] << 8 | tbuf1[2];
retVal = hitPoints;
} while (0);
ss[0] = 0;
writeGT911TouchRegister( 0x814e, ss, 1);
delay(2);
return retVal;
}
//Function that uses the functions above to give a simple X/Y position to be used in your code
void checkfortouchscreen() {
captouched = 0;
pinMode (GT911_INT, INPUT);
uint8_t st = digitalRead(GT911_INT);
if (!st) //Hardware touch interrupt
{
//Serial.println("Touch: ");
//This line gives the number of touch points
//Screen can deal with 5 touches at once
uint8_t count = readGT911TouchLocation( touchLocations, 5 );
if(count > 0){
Serial.print("Touches: ");
Serial.println(count);
}
if (count) {
static TouchLocation caplastTouch = touchLocations[0];// only take single touch, not dealing with multitouch
caplastTouch = touchLocations[0];
if (millis() > captouchbounce) { //cuts out multitouch
captouchbounce = millis() + 250;//250 is the debounce, lower makes more sensitive but more false touches
//only using first touch for now
if (touchLocations[0].x > 0 && touchLocations[0].y > 0) { //only do something if there is an x and Y value
captouched = 1;
captouchx = touchLocations[0].x;
captouchy = touchLocations[0].y;
//X and Y positions sent to serial monitor
Serial.print(captouchx);
Serial.print(" : ");
Serial.println(captouchy);
ProcessButton(captouchx, captouchy); //function to see if a button has been pressed
}
}
}
}
}
//function that checks if a button has been touched
void ProcessButton(int myx,int myy) {
int q;
//my screen is 153mm wide and 1011 touch points wide (x far left to x far right)
//This works out at about 6.6 points per mm.
//I allow 5mm around the centre touch point so approx 33
int touchError = 33;
for (q = 0; q < numButtons; q++) {
//work through the array to see if a button has been touched
if (myx > (MyButtons[q][0] - touchError) && myx < (MyButtons[q][0] + touchError) && myy > (MyButtons[q][1] - touchError) && myy < (MyButtons[q][1] + touchError)) {
buttonAction(q);
}
}
}
//function that creates actions depending on the button pressed
//This could change an LED, send a DCC instruction etc.
void buttonAction(int q) {
switch (q) {
case 0:
Serial.println("button A pressed");
break;
case 1:
Serial.println("button B pressed");
break;
case 2:
Serial.println("button C pressed");
break;
default:
break;
}
}
void setup() {
Serial.begin(115200);
Serial.println("GT911_ESP32v1");
Wire.begin();
scani2c();//Not required, just in sketch to test connections
//set up the screen
gt911setup();
}
void loop() {
checkfortouchscreen();//keep looking for screen touches
}
Additional Resource Links
Comments
This site has been designed to be child friendly, this means that comments cannot be added to videos or directly to the site. To add a comment or ask a question please email the address in this image: and use ESP32 with GT911 Capacitive Touch Screen as a reference.