Coding a Touchscreen Menu

Here is a practical application example for the Touchscreen PCB.

First, a couple of caveats:

  • I use GPIO13 to power the led on the ILI9341 screens. It’s typical to wire the led (backlight) to Vcc, but this works for me.
  • My example uses arrays to position screen elements and to define touch area coordinates.
  • A complete version of this application would likely include wifi, OTA upgrading, HTTP client so that you can access pHp servers etc and control things.
  • Note that I have included Touch coordinates to suit the ST7789 displays that I also use. This might help someone…. (Refer to A Tale of two Screens for a more complete discussion.)
  • The actual coordinates will vary according to different displays / resolutions and screen rotation!

Arduino code for Touch Menu

/*
   ILI9341 and ESP32 Lolin demo http://www.lecity.edu.au
  Credit to Bodmer's TFT_eSPI library https://github.com/Bodmer/TFT_eSPI
*/

#include "LittleFS.h" // LittleFS 
#include "Free_Fonts.h" // Include the header file
#include <SPI.h>
#include <TFT_eSPI.h> // see https://github.com/Bodmer/TFT_eSPI Config in libraries User_Setup.h
#include <TJpg_Decoder.h>
#include <elapsedMillis.h>

TFT_eSPI tft = TFT_eSPI();

int Bx[15] =  {0, 80, 160, 0, 80, 160, 0, 80, 160, 0, 80, 160, 0, 80, 160}; // Arrays for buttons drawing starts at 0
int By[15] =  {0, 0, 0, 64, 64, 64, 128, 128, 128, 192, 192, 192, 256, 256, 256};
int tBx[15] = {0, 100, 200, 0, 100, 200, 0, 100, 200, 0, 100, 200, 0, 100, 200}; // Arrays for button touch coordinates
int tBy[15] = {0, 0, 0, 48, 48, 48, 96, 96, 96, 144, 144, 144, 192, 192, 192};
int pressed;
uint32_t keyStart, keyDelay = 500; //  milliseconds betwen keypresses avoid bounce

bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
  if ( y >= tft.height() ) return 0;
  tft.pushImage(x, y, w, h, bitmap);
  return 1;
}
String swVersion = (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__);

void setup(void) {
  Serial.begin(115200);
  if (!LittleFS.begin()) {
    Serial.println("LittleFS initialisation failed!");
  }
  pinMode(13, OUTPUT);  // The  pin needs to set to Output : HIGH screen on / LOW screen off  //
  digitalWrite(13, HIGH); // ILI9341's LED is driven from GPIO 13

  tft.begin();
  tft.setRotation(0);
  tft.fillScreen(TFT_BLACK);
  tft.drawRect(5, 5, 235, 315, TFT_YELLOW);
  tft.drawRect(8, 8, 227, 307, TFT_GREEN);
  tft.setFreeFont(FSS12);
  tft.setCursor(20, 35);
  tft.setTextColor(TFT_YELLOW);
  Serial.println("Loading the splash screen");
  tft.setCursor(20, 70);
  tft.println("TFT Touch Menu");
  tft.setCursor(20, 100);
  tft.setTextColor(TFT_WHITE);
  tft.setFreeFont(FSS9);
  tft.println(swVersion);
  ///  Put Wifi, MQTT, httpGet , OTA init, EEPROM etc things in here too.
  TJpgDec.setSwapBytes(true);
  TJpgDec.setCallback(tft_output);
  delay(1000);
  mainMenu();
}
///////////////////////////////// Main Loop //////////////////////////////////////
void loop() {
  uint16_t x, y; // Init touch
  if (tft.getTouch(&x, &y) && millis() >= keyStart + keyDelay) {
    getButton(x, y); // Evaluate press
    Serial.println("Pressed: " + String(pressed));
    if (pressed == 1) {  //Button 1
      mainMenu();
    }
    if (pressed == 2) {  //Button 2
      tft.fillScreen(TFT_BLACK);
      // doAirCon things.....
      tft.setCursor(20, 70);
      tft.setTextColor(TFT_WHITE);
      tft.println("Air Con menu etc");
      delay(3000);
      mainMenu();
    }
    if (pressed == 3) {  //Button 3
      tft.fillScreen(TFT_BLACK);
      TJpgDec.drawFsJpg(0, 0, "/Picture.jpg", LittleFS);
      delay(5000);
      mainMenu();
    }
    keyStart = millis();
  }
}

void mainMenu() {
  tft.fillScreen(TFT_BLACK);
  drawButton(1, "MAIN", TFT_YELLOW, TFT_GREEN);
  drawButton(2, "AirCon", TFT_WHITE, TFT_GREEN);
  drawButton(3, "Picture", TFT_WHITE, TFT_GREEN);
  drawButton(4, "4", TFT_WHITE, TFT_GREEN);
  drawButton(5, "5", TFT_WHITE, TFT_GREEN);
  drawButton(6, "6", TFT_WHITE, TFT_GREEN);
  drawButton(7, "7", TFT_WHITE, TFT_GREEN);
  drawButton(8, "8", TFT_WHITE, TFT_GREEN);
  drawButton(9, "9", TFT_WHITE, TFT_GREEN);
  drawButton(10, "etc", TFT_WHITE, TFT_GREEN);
}

/////// Draw any of 15 Outline buttons  /////
void drawButton(int buttonnumber, const String& textlabel, uint16_t fontColor, uint16_t background)  {
  tft.setFreeFont(FSS9);
  tft.drawRoundRect(Bx[buttonnumber - 1], By[buttonnumber - 1], 79, 63, 6, background);
  tft.setTextColor(fontColor);
  tft.setCursor(Bx[buttonnumber - 1] + 8, By[buttonnumber - 1] + 32);
  tft.print(textlabel);
}

uint16_t getButton(int x, int y) {
  pressed = 0;
  int vy = x, vx = 300 - y;
  //  if  (displayType == "ST7789") {vy = 240 - x;} else {vy = x;}  //vy=x for ILI9341  OR vy=240-x for ST7789

  Serial.print("vx/vy:");
  Serial.print(vx);
  Serial.print("*");
  Serial.println(vy);
  for (int n = 0; n < 15; n++) {
    if  (vx > tBx[n]   && vx < tBx[n] + 100 && vy > tBy[n] && vy < tBy[n] + 48) {
      pressed = n + 1   ;
    }
  }
  Serial.println(pressed);
  return pressed;
}