Touchscreen Edge Detection

Hi guys.

I'm trying to get edge detection working with my touchscreen, so it will cause an action when finger is released from the screen.

Im getting random inputs from the button in Serial Monitor..

Im in a hurry with a school project, so I'd be happy if someone could tell me what I have to change.

Thanks in advance
Anxodia

Heres my code

#include <SD.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_HX8357.h>
#include <TouchScreen.h>
#define LCD_CS 47        // LCD CS Pin
#define LCD_DC 45        // LCD D/C Pin
#define SD_CS 46         // SD Card Pin
#define YP A2            // Touchscreen Y+ pin
#define XM A3            // Touchscreen X- pin
#define YM 48            // Touchscreen Y- pin
#define XP 49            // Touchscreen X+ pin

Adafruit_HX8357 display = Adafruit_HX8357(LCD_CS, LCD_DC);
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

bool touch_trigger = false;
bool touching;
bool touch_change;


void setup() {
Serial.begin(9600);
display.begin();
display.setRotation(1); 
display.fillScreen(HX8357_BLACK);
SD.begin(SD_CS);
bmpDraw("Back.bmp", 20, 20);
}

void loop() {
TSPoint p = ts.getPoint(); 
  touching = p.z > 75;       
  touch_change = false;      
  if (touch_trigger != touching)
  {
    touch_trigger = !touch_trigger;
    touch_change = true;
  }
if (20 <= p.x <= 100 && 20 <= p.y <= 100 && touch_change && !touching)
{
  Serial.println("back");
  }

}

Oops

Whats wrong with that?

Thats the range that my button is in. I dont know what that has to do with my not working edge detection.

Anxodia

What ever the value of p.x, the expression will always be true.

Ah got it... But I noticed something else;

I did
Serial.println(p.x);
and the values its returning are no way where they should be. My display is 480x320 so I would guess thats the range of x and y. Im getting values for x in range of 160 to 800...

Whats up with that?
Anxodia

What's that got to do with the touchscreen?

As I said, im guessing touchscreen return value for the pixel that its at? Can i somehow calibrate it?

How could it know that?

Putting my Yoda gown on, don't guess - know.

I think that would be an excellent idea.

You could store the calibration data in EEPROM.

I had a look at touchscreen.h and the examples but theres only calibration number for p.z when you measure Reistance in Ohm between X+ and X-

Display a block in each of the four corners of the display, and ask the user to press on them.
The X and Y values for each corner will provide the basis for your calibration.
You may find just two points on a diagonal are sufficient.

Have no clue what to do honestly.
Found this online

p.y = map(p.x, TS_LEFT, TS_RIGHT, 0, display.height());
p.x = map(p.y, TS_BOT, TS_TOP, 0, display.width());

...and did it work for you?

I dont know what to do with it.

I touched left, right, top and bottom of the screen and put theese values into TS_LEFT, TS_RIGHT etc.
Then I used that map function. Im having different reads now but still not what I expected. I have setRoataion(1) (Landscape) maybe that has something to do with it.

You said "don't guess - know"

But you have to understand that I wrote my first code lines a week ago, and the touchscreen is just a byproduct of my schoolproject. But it needs to work. Thats why im kinda stressed out atm and used forum to hopefully get a quick guide on what I need to do to get it working. But looks like its much more complicated than I initially tought.

You need to have a consistent, logical approach to working out what is going on.
Compare your expectations to your observations, and adjust accordingly, then retest.
See if touches correspond to the area of the screen that you expect

I don't have your hardware, and it is possible that someone who does won't find your question (I'd've posted in "sensors", not "displays")

Touchscreen.h returns ADC values i.e. in the range 0 to 1023.

You convert to x,y pixel coordinates by using map() function.
e.g. by interpolating between TS_LEFT and TS_RT.

David.

Alright I played around a bit and found that I can change it. So I could just fine tune the falues by myself.

The only problem thats I have now is that I do Serial.println(p.x);
and I swipe up and down on the touchscreen and it reads the y values.

So I need to swap X and Y coordinate.

I tried this already:

 p.y = map(p.x, TS_TOP, TS_BOT, 0, display.height());  
 p.x = map(p.y, TS_LEFT, TS_RIGHT, 0, display.width());

I swapped p.y and p.x at the beginning of the line. Didnt help. I also tried to swap display.height() and display.widht() with no success

It is a bit of a trip to be honest, partly because there are so many variants of TFT-touchscreens around.
You have to understand that most of them come from leftover parts, and one could consider them obsolete if you look at the amount of power they use compared to newer types.

I think here is where setOrientation() is used. Though on second thought that actually refers mainly to the TFT.
If that fails, try to swap p.x & p.y before the mapping. What you do now is for sure not going to work unless you create a new variable for the result of the map() function.

Let me provide you with my calibration sketch. Provided 'as is' and without support. (it's been several years since i wrote this)
The idea is that when you use a toothpick and slide to the edge, you will find the correct extreme value

/*  TFT Touchscreen Calibrateter

 */
#include <EEPROM.h>        // for storage of the settings
#include <Adafruit_GFX.h>    // Core graphics library

#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;       // hard-wired for UNO shields anyway.
#include <TouchScreen.h>

#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif


// most mcufriend shields use these pins and Portrait mode:
const uint8_t YP = A1;  // must be an analog pin, use "An" notation!
const uint8_t XM = A2;  // must be an analog pin, use "An" notation!
const uint8_t YM = 7;   // can be a digital pin
const uint8_t XP = 6;   // can be a digital pin


uint8_t SwapXY = 1; // depends on the TFT shield

uint16_t TS_LEFT = 930;
uint16_t TS_RT = 175;
uint16_t TS_TOP = 175;  // this is actually the usb end at the start of the program
uint16_t TS_BOT = 920;

volatile uint16_t TFT_X_RANGE = 240;  // making these variables volatile solves the issue that when changing
volatile uint16_t TFT_Y_RANGE = 320;  // their value (or even keeping it the same but writing to them)
                                      // caused an incorrect memory write with black area's on screen.


// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 455);
TSPoint tp;

#define MINPRESSURE 5
#define MAXPRESSURE 1000
#define RELEASECYCLES 200

#define EEPROM_OFFSET 448  // set this to a matching value in the program 
                          // depending on the calibrated values, do not use 
                          // the low Eeprom adddresses since the graphics library
                          // appears to be using them.

#define SWAP(a, b) {uint16_t tmp = a; a = b; b = tmp;}

uint16_t identifier;
uint8_t orientation = 0;    //Portrait



// 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


void setup() {
  tft.begin(9600);
  tft.reset();
  identifier = tft.readID();
  tft.begin(identifier);
  tft.setRotation(orientation);  // we use orientation here to set the TFT rotation

//  TS_Rotation(orientation);  
  ts = TouchScreen(XP, YP, XM, YM, 455);     //  call the constructor 
  while (!TitleScreen()) Change_TFTXY_Settings(); 
  CalibrationScreen();
}

void loop() {
}

void CalibrationScreen() {
  tft.fillScreen(BLUE);
  tft.setTextSize(2);
  tft.setTextColor(BLACK);
  const char * title = "TFT Calibrater";            // header text
  tft.setCursor((TFT_X_RANGE/2) - strlen(title)*6,20);
  tft.print(title);

  tft.setCursor((TFT_X_RANGE/2) - 54,40);
  tft.print(String(TFT_X_RANGE)+" X "+String(TFT_Y_RANGE));
  tft.fillRect(TFT_X_RANGE/4,TFT_Y_RANGE/4,TFT_X_RANGE/2,TFT_Y_RANGE/2,RED);
  tft.setTextSize(1);
  const char * order = "Press the red rectangle";
  tft.setCursor((TFT_X_RANGE/2) - strlen(order)*3,TFT_Y_RANGE-50);
  tft.print(order);
  tft.drawRect(2,2,TFT_X_RANGE-4,TFT_Y_RANGE-4,RED);
  WaitReleaseReadPress(true);
  tft.fillRect((TFT_X_RANGE/8)*3,(TFT_Y_RANGE/8)*3,TFT_X_RANGE/4,TFT_Y_RANGE/4,YELLOW);
  while (!ConfirmRelease());
  tft.fillRect((TFT_X_RANGE/8)*3,(TFT_Y_RANGE/8)*3,TFT_X_RANGE/4,TFT_Y_RANGE/4,RED);
  
  uint16_t minx=500,miny=500,maxx=500,maxy=500;
  uint8_t minxq=4,minyq=4,maxxq=4,maxyq=4,i=0;
  tft.drawRect(2,2,TFT_X_RANGE-4,TFT_Y_RANGE-4,BLUE);
  tft.fillRect(0,  0,  TFT_X_RANGE,  TFT_Y_RANGE/4,  BLUE);
  tft.fillRect(0,  (TFT_Y_RANGE/4)*3  ,TFT_X_RANGE,  TFT_Y_RANGE/4,  BLUE);
  tft.fillRect((TFT_X_RANGE/8),(TFT_Y_RANGE/8),(TFT_X_RANGE/4)*3,(TFT_Y_RANGE/4)*3,RED);
  EdgeLookText();
  WaitReleaseReadPress(true);
  tft.fillScreen(BLUE);
  tft.fillRect(TFT_X_RANGE/4,TFT_Y_RANGE/4,TFT_X_RANGE/2,TFT_Y_RANGE/2,RED);  
  
  DrawArrow(0);
  FillQuad(i,CYAN);

  while (i<4) {
    tp = ts.getPoint();
    ResetPins();
    if (tp.z < MINPRESSURE || tp.z > MAXPRESSURE) continue;

    tft.setTextColor(YELLOW,BLUE);
    tft.setTextSize(2);
    tft.setCursor((TFT_X_RANGE/4)+20,(TFT_Y_RANGE/4)*(3-(i/2)*3)+20);
    tft.print("tp.x=" + String(tp.x));
    tft.setCursor((TFT_X_RANGE/4)+20,(TFT_Y_RANGE/4)*(3-(i/2)*3)+50);
    tft.print("tp.y=" + String(tp.y));
    tft.setTextSize(1);
    
    if (tp.x>maxx) {
      maxx=tp.x;
      maxxq=i;
      tft.setCursor((TFT_X_RANGE/4)*3+10,40);
      tft.print("MaxX="+String(maxx));
    }
    if (tp.x<minx) {
      minx=tp.x;
      minxq=i;
      tft.setCursor(10,40);
      tft.print("MinX="+String(minx));
    }
    if (tp.y>maxy) {
      maxy=tp.y;
      maxyq=i;
      tft.setCursor((TFT_X_RANGE/4)*3+10,(TFT_Y_RANGE/4)*3+40);
      tft.print("MaxY="+String(maxy));
    }
    if (tp.y<miny) {
      miny=tp.y;
      minyq=i;
      tft.setCursor(10,(TFT_Y_RANGE/4)*3+40);
      tft.print("MinY="+String(miny));
    }
    if (tp.x > 450 && tp.x < 570  && tp.y > 450 && tp.y < 570) { // exit
      FillQuad(i,BLUE);
      i++;
      tft.fillRect((TFT_X_RANGE/8)*3,(TFT_Y_RANGE/8)*3,TFT_X_RANGE/4,TFT_Y_RANGE/4,YELLOW);
      while (!ConfirmRelease());
      tft.fillRect((TFT_X_RANGE/4),(TFT_Y_RANGE/4),TFT_X_RANGE/2,TFT_Y_RANGE/2,RED);
      DrawArrow(i);
      FillQuad(i,CYAN);
    }
  }
  tft.fillScreen(YELLOW);
  tft.fillRect((TFT_X_RANGE/4),(TFT_Y_RANGE/4),TFT_X_RANGE/2,TFT_Y_RANGE/2,BLUE);
  tft.setTextColor(BLACK,YELLOW);
  tft.setTextSize(2);
  SetCursorInQuad(minxq,0); 
  tft.print("MinX");
  SetCursorInQuad(minxq,2);
  tft.print(String(minx));
  SetCursorInQuad(maxxq,0); 
  tft.print("MaxX");
  SetCursorInQuad(maxxq,2);
  tft.print(String(maxx));
  SetCursorInQuad(minyq,0); 
  tft.print("MinY");
  SetCursorInQuad(minyq,2);
  tft.print(String(miny));
  SetCursorInQuad(maxyq,0); 
  tft.print("MaxY");
  SetCursorInQuad(maxyq,2);
  tft.print(String(maxy));

  EepromSaveScreen();
  WaitReleaseReadPress(true);
  StoreInVar(minxq,minx-3);
  StoreInVar(maxxq,maxx+3);
  StoreInVar(minyq,miny-3);
  StoreInVar(maxyq,maxy+3);
  StoreValues();
  ReadValues();
  PrintValues();
}

void StoreInVar(uint8_t side,uint16_t value) {
  switch(side) {
    case 0: 
      TS_TOP=value;
      break;
    case 1:
      TS_RT=value;
      break;
    case 2:
      TS_BOT=value;
      break;
    case 3:
      TS_LEFT=value;
      break;
  }
}

void EepromSaveScreen() {
  tft.setTextColor(YELLOW,BLUE);
  tft.setTextSize(1);
  const char * line1 = "The Values found";
  const char * line2 = "Will be stored in";
  const char * line3 = "The Eeprom as 16";
  const char * line4 = "bit U-integers";
  const char * line5 = "Press to continue";
  tft.setCursor((TFT_X_RANGE/2) - strlen(line1)*3,((TFT_Y_RANGE/2)-24));
  tft.print(line1);
  tft.setCursor((TFT_X_RANGE/2) - strlen(line2)*3,((TFT_Y_RANGE/2)-12));
  tft.print(line2);
  tft.setCursor((TFT_X_RANGE/2) - strlen(line3)*3,((TFT_Y_RANGE/2)));
  tft.print(line3);
  tft.setCursor((TFT_X_RANGE/2) - strlen(line4)*3,((TFT_Y_RANGE/2)+12));
  tft.print(line4);
  tft.setCursor((TFT_X_RANGE/2) - strlen(line5)*3,((TFT_Y_RANGE/2)+30));
  tft.print(line5); 
}

void StoreValues() {
  Write16bitEeprom(EEPROM_OFFSET,TFT_X_RANGE);
  Write16bitEeprom(EEPROM_OFFSET+2,TFT_Y_RANGE);
  Write16bitEeprom(EEPROM_OFFSET+4,TS_TOP);
  Write16bitEeprom(EEPROM_OFFSET+6,TS_RT);
  Write16bitEeprom(EEPROM_OFFSET+8,TS_BOT);
  Write16bitEeprom(EEPROM_OFFSET+10,TS_LEFT);
}

void Write16bitEeprom(uint16_t location, uint16_t uinteg) {
  EEPROM.write(location,lowByte(uinteg));
  EEPROM.write(location+1,highByte(uinteg));
}

void ReadValues() {     //copy the following 2 functions into your program
  TFT_X_RANGE=Read16bitEeprom(EEPROM_OFFSET);
  TFT_Y_RANGE=Read16bitEeprom(EEPROM_OFFSET+2);
  TS_TOP=Read16bitEeprom(EEPROM_OFFSET+4);
  TS_RT=Read16bitEeprom(EEPROM_OFFSET+6);
  TS_BOT=Read16bitEeprom(EEPROM_OFFSET+8);
  TS_LEFT=Read16bitEeprom(EEPROM_OFFSET+10);
}

uint16_t Read16bitEeprom(uint16_t location) {
  return( ((uint16_t) EEPROM.read(location+1)<<8) | (uint16_t) EEPROM.read(location));
}

void PrintValues() {
  tft.fillScreen(GREEN);
  tft.fillRect((TFT_X_RANGE/4),(TFT_Y_RANGE/4),TFT_X_RANGE/2,TFT_Y_RANGE/2,WHITE);
  tft.setTextColor(BLACK);
  tft.setTextSize(2);
  SetCursorInQuad(0,1); 
  tft.print(String(TS_TOP));
  SetCursorInQuad(1,1); 
  tft.print(String(TS_RT));
  SetCursorInQuad(2,1); 
  tft.print(String(TS_BOT));
  SetCursorInQuad(3,1); 
  tft.print(String(TS_LEFT));
  tft.setCursor(TFT_X_RANGE/2-15,TFT_Y_RANGE/2-24);
  tft.print(String(TFT_X_RANGE));
  tft.setCursor(TFT_X_RANGE/2-3,TFT_Y_RANGE/2-6);
  tft.print("X");
  tft.setCursor(TFT_X_RANGE/2-15,TFT_Y_RANGE/2+12);
  tft.print(String(TFT_Y_RANGE));
}


void SetCursorInQuad(uint8_t quad, uint8_t line) {
  switch(quad) {
    case 0:
      tft.setCursor((TFT_X_RANGE/8)*3+line*7,20+line*15);
      break;
    case 1:
      tft.setCursor((TFT_X_RANGE/4)*3+5+line*7,(TFT_Y_RANGE/8)*3+20+line*15);
      break;
    case 2:
      tft.setCursor((TFT_X_RANGE/8)*3+line*7,(TFT_Y_RANGE/4)*3+20+line*15);
      break;
    case 3:
      tft.setCursor(5+line*7,(TFT_Y_RANGE/8)*3+20+line*15);
      break;
  }
  return;
}


void FillQuad(uint8_t quad,uint16_t color) {
  switch (quad) {
    case 0:
      tft.fillRect(TFT_X_RANGE/4,0,TFT_X_RANGE/2,TFT_Y_RANGE/4,color);
      break;
    case 1:
      tft.fillRect((TFT_X_RANGE/4)*3,TFT_Y_RANGE/4,TFT_X_RANGE/4,TFT_Y_RANGE/2,color);
      break;
    case 2:
      tft.fillRect(TFT_X_RANGE/4,(TFT_Y_RANGE/4)*3,TFT_X_RANGE/2,TFT_Y_RANGE/4,color);
      break;
    case 3:
      tft.fillRect(0,TFT_Y_RANGE/4,TFT_X_RANGE/4,TFT_Y_RANGE/2,color);
  }
}


void DrawArrow(uint8_t direct) {
  if (direct>3) return;
  if (direct%2) {  // horizontal
    for (uint8_t i=0; i<10; i++) {
      if ((i) && (i<9))  tft.drawLine(TFT_X_RANGE/2-(TFT_X_RANGE/16)*3, TFT_Y_RANGE/2-5+i, 
                          TFT_X_RANGE/2+(TFT_X_RANGE/16)*3, TFT_Y_RANGE/2-5+i, BLACK);
      if (direct/2) { // to left
        tft.drawLine(TFT_X_RANGE/2-(TFT_X_RANGE/16)*3, TFT_Y_RANGE/2-5+i,
                    TFT_X_RANGE/2,    TFT_Y_RANGE/2-5+i-(TFT_Y_RANGE/16)*2,BLACK);
        tft.drawLine(TFT_X_RANGE/2-(TFT_X_RANGE/16)*3, TFT_Y_RANGE/2-5+i,
                    TFT_X_RANGE/2,    TFT_Y_RANGE/2-5+i+(TFT_Y_RANGE/16)*2,BLACK);                    
      }
      else {  // to right
        tft.drawLine(TFT_X_RANGE/2+(TFT_X_RANGE/16)*3, TFT_Y_RANGE/2-5+i,
                    TFT_X_RANGE/2,    TFT_Y_RANGE/2-5+i-(TFT_Y_RANGE/16)*2,BLACK);
        tft.drawLine(TFT_X_RANGE/2+(TFT_X_RANGE/16)*3, TFT_Y_RANGE/2-5+i,
                    TFT_X_RANGE/2,    TFT_Y_RANGE/2-5+i+(TFT_Y_RANGE/16)*2,BLACK);        
      }
    }
  }
  else {  // vertical
  for (uint8_t i=0; i<10; i++) {
    if ((i) && (i<9))  tft.drawLine(TFT_X_RANGE/2-5+i,  TFT_Y_RANGE/2-(TFT_Y_RANGE/16)*3,  
                          TFT_X_RANGE/2-5+i, TFT_Y_RANGE/2+(TFT_Y_RANGE/16)*3, BLACK);
      if (!(direct/2)) { // to Bottom
        tft.drawLine(TFT_X_RANGE/2-5+i, TFT_Y_RANGE/2-(TFT_Y_RANGE/16)*3, 
                    TFT_X_RANGE/2-5+i-(TFT_X_RANGE/16)*2,  TFT_Y_RANGE/2,    BLACK);
        tft.drawLine(TFT_X_RANGE/2-5+i,  TFT_Y_RANGE/2-(TFT_Y_RANGE/16)*3, 
                    TFT_X_RANGE/2-5+i+(TFT_X_RANGE/16)*2,  TFT_Y_RANGE/2,    BLACK);                    
      }
      else {  // to Top
        tft.drawLine(TFT_X_RANGE/2-5+i,  TFT_Y_RANGE/2+(TFT_Y_RANGE/16)*3, 
                    TFT_X_RANGE/2-5+i-(TFT_X_RANGE/16)*2,  TFT_Y_RANGE/2,    BLACK);
        tft.drawLine(TFT_X_RANGE/2-5+i,  TFT_Y_RANGE/2+(TFT_Y_RANGE/16)*3, 
                    TFT_X_RANGE/2-5+i+(TFT_X_RANGE/16)*2,  TFT_Y_RANGE/2,    BLACK);
      }        
    }
  }
}

void EdgeLookText() {
  tft.setTextColor(BLACK,RED);
  tft.setTextSize(1);
  const char * line1 = "Look for the edge's";
  const char * line2 = "extreme value in the";
  const char * line3 = "lightblue area, using";
  const char * line4 = "a toothpick, and when";
  const char * line5 = "done press the center";
  const char * line6 = "of this red square for";
  const char * line7 = "the next edge.";
  const char * line8 = "Press to continue";
  tft.setCursor((TFT_X_RANGE/2) - strlen(line1)*3,((TFT_Y_RANGE/2)-48));
  tft.print(line1);
  tft.setCursor((TFT_X_RANGE/2) - strlen(line2)*3,((TFT_Y_RANGE/2)-36));
  tft.print(line2);
  tft.setCursor((TFT_X_RANGE/2) - strlen(line3)*3,((TFT_Y_RANGE/2)-24));
  tft.print(line3);
  tft.setCursor((TFT_X_RANGE/2) - strlen(line4)*3,((TFT_Y_RANGE/2)-12));
  tft.print(line4);
  tft.setCursor((TFT_X_RANGE/2) - strlen(line5)*3,((TFT_Y_RANGE/2)));
  tft.print(line5); 
  tft.setCursor((TFT_X_RANGE/2) - strlen(line6)*3,((TFT_Y_RANGE/2)+12));
  tft.print(line6);  
  tft.setCursor((TFT_X_RANGE/2) - strlen(line7)*3,((TFT_Y_RANGE/2)+24));
  tft.print(line7);
  tft.setCursor((TFT_X_RANGE/2) - strlen(line8)*3,((TFT_Y_RANGE/2)+48));
  tft.print(line8);
}

bool TitleScreen() {
  tft.fillScreen(WHITE);
  tft.setTextSize(2);
  tft.setTextColor(BLACK);
  const char * title = "TFT Calibrater";
  tft.setCursor((TFT_X_RANGE/2) - strlen(title)*6,20);
  tft.print(title);
  delay(1000);
  tft.setTextSize(1);
  const char * story1 = "Your screen should be";
  const char * story2 = "in Portait mode, where";
  const char * story3 = "the USB-end is the top.";
  const char * story4 = "And this text should be";
  const char * story5 = "centered, left to right,";
  const char * story6 = "and top to bottom, with";
  const char * story7 = "a frame around it.";
  const char * story8 = "If so, press the screen,";
  const char * story9 = "if not, press and hold";
  const char * story10 = "for 3 seconds";
  tft.setCursor((TFT_X_RANGE/2) - strlen(story1)*3,((TFT_Y_RANGE/2)-54));
  tft.print(story1);
  tft.setCursor((TFT_X_RANGE/2) - strlen(story2)*3,((TFT_Y_RANGE/2)-42));
  tft.print(story2);
  tft.setCursor((TFT_X_RANGE/2) - strlen(story3)*3,((TFT_Y_RANGE/2)-30));
  tft.print(story3);
  tft.setCursor((TFT_X_RANGE/2) - strlen(story4)*3,((TFT_Y_RANGE/2)-18));
  tft.print(story4);
  tft.setCursor((TFT_X_RANGE/2) - strlen(story5)*3,((TFT_Y_RANGE/2)-6));
  tft.print(story5); 
  tft.setCursor((TFT_X_RANGE/2) - strlen(story6)*3,((TFT_Y_RANGE/2)+6));
  tft.print(story6);  
  tft.setCursor((TFT_X_RANGE/2) - strlen(story7)*3,((TFT_Y_RANGE/2)+18));
  tft.print(story7);
  tft.setCursor((TFT_X_RANGE/2) - strlen(story8)*3,((TFT_Y_RANGE/2)+30));
  tft.print(story8);
  tft.setCursor((TFT_X_RANGE/2) - strlen(story9)*3,((TFT_Y_RANGE/2)+42));
  tft.print(story9);
  tft.setCursor((TFT_X_RANGE/2) - strlen(story10)*3,((TFT_Y_RANGE/2)+54));
  tft.print(story10);
  tft.drawRect(2,2,TFT_X_RANGE-4,TFT_Y_RANGE-4,BLACK);
  WaitReleaseReadPress(true);
  uint32_t moment=millis();
  while (!ConfirmRelease()) if ((millis()-moment)>3000) return false;
  return true;
}

void Change_TFTXY_Settings() {
  tft.fillScreen(RED);
  delay(3000);
}

bool ConfirmRelease() {
  uint8_t prs=0;
  while (prs<RELEASECYCLES) {
    tp = ts.getPoint();
    ResetPins();
    if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) return false ;
    delay(1);
    prs++;
  }
  return true;
}

void WaitReleaseReadPress(bool waitrelease) {
  if (waitrelease) {
    while (!ConfirmRelease());
  }
  while (tp.z < MINPRESSURE || tp.z > MAXPRESSURE) {
    tp = ts.getPoint();
    ResetPins();
  }
  delay (100);
}

void ResetPins(){
  pinMode(XM, OUTPUT);  // reset the pins after use.
  pinMode(YP, OUTPUT);
  pinMode(XP, OUTPUT);
  pinMode(YM, OUTPUT);
}

Thank you!