Add touch functionality to Waveshare 2.8 tft touch shield for Mega

Hey there,

I have a 2.8inch TFT Touch Shield as seen here. After lurking on this forum for awhile I was finally able to get some functionality with the help of this post. I am able to get graphics displaying perfectly, but the problem I'm having is that I cannot figure out how to how to add any touch functionality to my program.

I am trying to make a simple program that turns a rectangle green when I touch within its bounds. Note, this is for the Arduino Mega2560. The code I have so far is:

#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin

#include <SPI.h>          // f.k. for Arduino-1.5.2
#include "Adafruit_GFX.h"// Hardware-specific library
#include <HX8347D_kbv.h>

HX8347D_kbv tft;

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

uint16_t g_identifier;

void setup() {
    //Setup Serial Monitor
    Serial.begin(9600);
    g_identifier = tft.readID();
    tft.begin(g_identifier);  
    
    tft.setRotation(1);   //90 DEGREE ROTATION
    makeGUI();
}

void makeGUI() {
   tft.fillScreen(DARK_GREY);
      
   tft.setTextSize(2);
   tft.setCursor(130, 6);
   tft.println("My Box");
   
   tft.setTextSize(1);
   tft.setCursor(100, 28);
   tft.println("(Touch to turn green)");
   
   tft.fillRect(45, 40, tft.width()-90, tft.height()-100, WHITE);  //x-start, y-start, x-width, y-height
   tft.fillRect(50, 45, tft.width()-100, tft.height()-110, BLACK);
}

void loop() {

}

If you are able to help me add touch functionality to this I would be extremely grateful. I have been looking for a solution for awhile and nothing seems to work. Also, if you can help me set up the serial monitor to display the X and Y coordinates where I touch, I would very much appreciate it.

Thank you,

Jake

You have a Waveshare 2.8" SPI Display.
It came with some examples from Waveshare.

I posted a version of the Waveshare code as conventional Arduino library. But will work with the Wavshare examples using their unconventional methods.

I also posted an Arduino library that uses Adafruit_GFX methods. It should be able to do everything that the MCUFRIEND_kbv library can do (except for readID(), readReg(), readPixel() because Waveshare is not readable)

The Waveshare code comes with XPT2046 code for its Touch Controller.

There are many Arduino libraries for XPT2046 and similar Touch i.c.

Note that Henning Karlsen's UTouch / URTouch is not suitable. These libraries have no concept of using a hardware SPI bus.

It should be pretty straightforward to use the Adafruit_GFX_Button class with any of the XPT2046 libraries.

David.

I found the XPT2046_Touchscreen library in the Library Manager.
I have tidied up your code to do what you wanted:

jakeb_GFX.ino:

#include <SPI.h>          // f.k. for Arduino-1.5.2
#include "Adafruit_GFX.h"// Hardware-specific library
#include <HX8347D_kbv.h>
HX8347D_kbv tft;
#include <XPT2046_Touchscreen.h>

//edit begin() method in XPT2046_Touchscreen.cpp source code :
//        attachInterrupt( digitalPinToInterrupt(tirqPin), isrPin, FALLING );  //.kbv

#define XPT_CS  4
#define XPT_IRQ 255       //use 3 if you fix interrupts in library source code

#define TS_LEFT 3900    //The XPT2046_Touchscreen works in Landscape
#define TS_RT   300     //I would expect Touch in Portrait
#define TS_TOP  360
#define TS_BOT  3800

XPT2046_Touchscreen ts(XPT_CS, XPT_IRQ);

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

void setup()
{
    Serial.begin(9600);
    uint16_t ID = tft.readID(); //
    tft.begin(ID);
    tft.setRotation(1);   //LANDSCAPE

    makeGUI();

    ts.begin();            //.kbv XPT2046_Touchscreen needs to start
}

void makeGUI()
{
    tft.fillScreen(DARK_GREY);
    tft.setTextSize(2);
    tft.setCursor(130, 6);
    tft.println("My Box");
    tft.setTextSize(1);
    tft.setCursor(100, 28);
    tft.println("(Touch to turn green)");

    tft.fillRect(45, 40, tft.width() - 90, tft.height() - 100, WHITE); //x-start, y-start, x-width, y-height
    tft.fillRect(50, 45, tft.width() - 100, tft.height() - 110, BLACK);
}

void loop()
{
    if (ts.touched()) {
        TS_Point p = ts.getPoint(); //XPT_2046_touchscreen returns in Landscape
        uint16_t y = map(p.y, TS_TOP, TS_BOT, 0, tft.height());
        uint16_t x = map(p.x, TS_LEFT, TS_RT, 0, tft.width());
        uint16_t w = tft.width() - 100;
        uint16_t h = tft.height() - 110;
        uint16_t color;
        if ((x > 50 && x < 50 + w) && (y > 45 && y < 45 + h))
            color = GREEN;
        else color = BLACK;
        tft.fillRect(50, 45, w, h, color);
        //        Serial.println("x=" + String(x) + " y=" + String(y) + " z=" + String(p.z) + "   ");
    }
}

David.

And here is an example that uses Buttons:

phonecal_XPT2046.ino

#include <Adafruit_GFX.h>    // Core graphics library
#include <HX8347D_kbv.h>     // Hardware-specific library
#include <XPT2046_Touchscreen.h> // define pins, calibration, getPoint() is different

//edit begin() method in XPT2046_Touchscreen.cpp source code :
//        attachInterrupt( digitalPinToInterrupt(tirqPin), isrPin, FALLING );  //.kbv

#define XPT_CS  4
#define XPT_IRQ 255       //use 3 if you fix interrupts in library source code

#define TS_LEFT 3900    //The XPT2046_Touchscreen works in Landscape
#define TS_RT   300     //I would expect Touch in Portrait
#define TS_TOP  360
#define TS_BOT  3800

HX8347D_kbv tft;
XPT2046_Touchscreen ts(XPT_CS, XPT_IRQ);
Adafruit_GFX_Button buttons[15];

// Color definitions
#define TFT_BLACK       0x0000      /*   0,   0,   0 */
#define TFT_NAVY        0x000F      /*   0,   0, 128 */
#define TFT_DARKGREEN   0x03E0      /*   0, 128,   0 */
#define TFT_DARKCYAN    0x03EF      /*   0, 128, 128 */
#define TFT_MAROON      0x7800      /* 128,   0,   0 */
#define TFT_PURPLE      0x780F      /* 128,   0, 128 */
#define TFT_OLIVE       0x7BE0      /* 128, 128,   0 */
#define TFT_LIGHTGREY   0xC618      /* 192, 192, 192 */
#define TFT_DARKGREY    0x7BEF      /* 128, 128, 128 */
#define TFT_BLUE        0x001F      /*   0,   0, 255 */
#define TFT_GREEN       0x07E0      /*   0, 255,   0 */
#define TFT_CYAN        0x07FF      /*   0, 255, 255 */
#define TFT_RED         0xF800      /* 255,   0,   0 */
#define TFT_MAGENTA     0xF81F      /* 255,   0, 255 */
#define TFT_YELLOW      0xFFE0      /* 255, 255,   0 */
#define TFT_WHITE       0xFFFF      /* 255, 255, 255 */
#define TFT_ORANGE      0xFD20      /* 255, 165,   0 */
#define TFT_GREENYELLOW 0xAFE5      /* 173, 255,  47 */
#define TFT_PINK        0xF81F

/******************* UI details */
#define BUTTON_X 40
#define BUTTON_Y 100
#define BUTTON_W 60
#define BUTTON_H 30
#define BUTTON_SPACING_X 20
#define BUTTON_SPACING_Y 20
#define BUTTON_TEXTSIZE 2

// text box where numbers go
#define TEXT_X 10
#define TEXT_Y 10
#define TEXT_W 220
#define TEXT_H 50
#define TEXT_TSIZE 3
#define TEXT_TCOLOR TFT_MAGENTA
// the data (phone #) we store in the textfield
#define TEXT_LEN 12
char textfield[TEXT_LEN + 1] = "";
uint8_t textfield_i = 0;

// We have a status line for like, is FONA working
#define STATUS_X 10
#define STATUS_Y 65

/* create 15 buttons, in classic candybar phone style */
char buttonlabels[15][5] = {
    "Send", "Clr", "End", "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#"
};
uint16_t buttoncolors[15] = {
    TFT_DARKGREEN, TFT_DARKGREY, TFT_RED,
    TFT_BLUE, TFT_BLUE, TFT_BLUE,
    TFT_BLUE, TFT_BLUE, TFT_BLUE,
    TFT_BLUE, TFT_BLUE, TFT_BLUE,
    TFT_ORANGE, TFT_BLUE, TFT_ORANGE
};

void setup(void)
{
    Serial.begin(9600);
    Serial.println(F("TFT LCD test"));
    uint16_t ID = tft.readID();
    tft.begin(ID);
    tft.fillScreen(TFT_BLACK);
    ts.begin();            //.kbv XPT2046_Touchscreen needs to start
    // create buttons
    for (uint8_t row = 0; row < 5; row++) {
        for (uint8_t col = 0; col < 3; col++) {
            uint8_t n = col + row * 3;
            //                    &gfx, x, y, w, h, outline, fill, text, textsize
            buttons[n].initButton(&tft, BUTTON_X + col * (BUTTON_W + BUTTON_SPACING_X),
                                  BUTTON_Y + row * (BUTTON_H + BUTTON_SPACING_Y),
                                  BUTTON_W, BUTTON_H, TFT_WHITE, buttoncolors[n], TFT_WHITE,
                                  buttonlabels[n], BUTTON_TEXTSIZE);
            buttons[n].drawButton();
        }
    }

    // create 'text field'
    tft.drawRect(TEXT_X, TEXT_Y, TEXT_W, TEXT_H, TFT_WHITE);
}

// Print something in the mini status bar with either flashstring
void status(const __FlashStringHelper *msg)
{
    tft.fillRect(STATUS_X, STATUS_Y, 240, 8, TFT_BLACK);
    tft.setCursor(STATUS_X, STATUS_Y);
    tft.setTextColor(TFT_WHITE);
    tft.setTextSize(1);
    tft.print(msg);
}
// or charstring
void status(char *msg)
{
    tft.fillRect(STATUS_X, STATUS_Y, 240, 8, TFT_BLACK);
    tft.setCursor(STATUS_X, STATUS_Y);
    tft.setTextColor(TFT_WHITE);
    tft.setTextSize(1);
    tft.print(msg);
}

void loop(void)
{
    int x = -1, y = -1;   //regular pixel coordinates
    if (ts.touched()) {         //XPT2046_Touchscreen can use hardware
        TS_Point p = ts.getPoint(); //XPT_2046_touchscreen returns in Landscape
        x = map(p.y, TS_BOT, TS_TOP, 0, tft.width());
        y = map(p.x, TS_LEFT, TS_RT, 0, tft.height());
    }
    // go thru all the buttons, checking if they were pressed
    for (uint8_t b = 0; b < 15; b++) {
        bool down = buttons[b].contains(x, y);
        buttons[b].press(down);
    }

    // now we can ask the buttons if their state has changed
    for (uint8_t b = 0; b < 15; b++) {
        if (buttons[b].justReleased()) {
            // Serial.print("Released: "); Serial.println(b);
            buttons[b].drawButton();  // draw normal
        }

        if (buttons[b].justPressed()) {
            buttons[b].drawButton(true);  // draw invert!

            // if a numberpad button, append the relevant # to the textfield
            if (b >= 3) {
                if (textfield_i < TEXT_LEN) {
                    textfield[textfield_i] = buttonlabels[b][0];
                    textfield_i++;
                    textfield[textfield_i] = 0; // zero terminate
                    // fona.playDTMF(buttonlabels[b][0]);
                }
            }

            // clr button! delete char
            if (b == 1) {

                textfield[textfield_i] = 0;
                if (textfield > 0) {
                    textfield_i--;
                    textfield[textfield_i] = ' ';
                }
            }

            // update the current text field
            Serial.println(textfield);
            tft.setCursor(TEXT_X + 2, TEXT_Y + 10);
            tft.setTextColor(TEXT_TCOLOR, TFT_BLACK);
            tft.setTextSize(TEXT_TSIZE);
            tft.print(textfield);

            // its always OK to just hang up
            if (b == 2) {
                status(F("Hanging up"));
                Serial.println("Hanging up");
                delay(1000);
                tft.fillRect(TEXT_X + 1, TEXT_Y + 1, TEXT_W - 2, TEXT_H - 2, TFT_BLACK);
                textfield_i = 0;
            }
            // we dont really check that the text field makes sense
            // just try to call
            if (b == 0) {
                status(F("Calling"));
                Serial.print("Calling "); Serial.println(textfield);
                //fona.callPhone(textfield);
            }

            delay(100); // UI debouncing
        }
    }
}

David.

Thank you so much! This looks like exactly what I was looking for. I'm away from school for a few days now but I will test it out as soon as I return.

Hello,
I' try to applay the following code (see top):

#include <SPI.h>          // f.k. for Arduino-1.5.2
#include "Adafruit_GFX.h"// Hardware-specific library
#include <HX8347D_kbv.h>
HX8347D_kbv tft;
#include <XPT2046_Touchscreen.h>

//edit begin() method in XPT2046_Touchscreen.cpp source code :
//        attachInterrupt( digitalPinToInterrupt(tirqPin), isrPin, FALLING );  //.kbv

#define XPT_CS  4
#define XPT_IRQ 255       //use 3 if you fix interrupts in library source code

#define TS_LEFT 3900    //The XPT2046_Touchscreen works in Landscape
#define TS_RT   300     //I would expect Touch in Portrait
#define TS_TOP  360
#define TS_BOT  3800

XPT2046_Touchscreen ts(XPT_CS, XPT_IRQ);

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

void setup()
{
   Serial.begin(9600);
   uint16_t ID = tft.readID(); //
   tft.begin(ID);
   tft.setRotation(1);   //LANDSCAPE

   makeGUI();

   ts.begin();            //.kbv XPT2046_Touchscreen needs to start
}

void makeGUI()
{
   tft.fillScreen(DARK_GREY);
   tft.setTextSize(2);
   tft.setCursor(130, 6);
   tft.println("My Box");
   tft.setTextSize(1);
   tft.setCursor(100, 28);
   tft.println("(Touch to turn green)");

   tft.fillRect(45, 40, tft.width() - 90, tft.height() - 100, WHITE); //x-start, y-start, x-width, y-height
   tft.fillRect(50, 45, tft.width() - 100, tft.height() - 110, BLACK);
}

void loop()
{
   if (ts.touched()) {
       TS_Point p = ts.getPoint(); //XPT_2046_touchscreen returns in Landscape
       uint16_t y = map(p.y, TS_TOP, TS_BOT, 0, tft.height());
       uint16_t x = map(p.x, TS_LEFT, TS_RT, 0, tft.width());
       uint16_t w = tft.width() - 100;
       uint16_t h = tft.height() - 110;
       uint16_t color;
       if ((x > 50 && x < 50 + w) && (y > 45 && y < 45 + h))
           color = GREEN;
       else color = BLACK;
       tft.fillRect(50, 45, w, h, color);
       //        Serial.println("x=" + String(x) + " y=" + String(y) + " z=" + String(p.z) + "   ");
   }
}

I have also uploaded the libraries Adafruit-GFX-Library-master, Waveshare_HX8347D_kbv-master and XPT2046_Touchscreen-master.
The programm unfortunately but not works- have problems with the compiler... :confused:
Error Message: "#include <HX8347D_kbv.h> ^ compilation terminated."

So I have change the #include <HX8347D_kbv.h> into #include <HX8347D.h> because in the installed libraries I have found only there Headerfile.
The next error message: "'HX8347D_kbv' does not name a type"...

Someone can help my to resolve the problem.
Thank you in advance!

Hello,
Can anybody help me... :sob:

Well, I copied your code. I already have Adafruit_GFX, HX8347D_kbv, XPT2046_Touchscreen libraries.

The sketch built and ran on a Uno. So I built and ran it on a Mega.

What does your Library Manager say about those libraries. Mine says:
Adafruit_GFX: v1.2.2
HX8347D_kbv: version unknown
XPT2046_Touchscreen: v1.2.0

David.

Hello David,
thank you for your fast answer.
Now I have checked the librarie:
-Adafruit_GFX: v1.2.2

I have notificated that in the librarie "Waveshare_HX8347D_kbv" I don't have a file like "HX8347D_kbv.h"...

Look in the ZIP file.

I will post it again if your zip is corrupt.

David.

Edit. I have posted library on GitHub
Click Green button to Download ZIP to your PC. Install Library from ZIP.

Wow, thank you so much!!! Now it works 8) 8) 8)
Nice weekend David!