what's wrong with this this loop?

I have created a virtual key pad on 2.8" TFT Touch Screen by Adafruit using an Arduino Uno.

This is a copy of the code.

int x , y;

void loop()
{
   boolean  pressed = false;
   
   
  //==> check for press
  while(pressed == false) {  
    //==> retrieve the point  
    TS_Point point = screen.getPoint(); 
    //==> map the point
    x = map(point.x, screenminx, screenmaxx, 0, touch.width());
    y = map(point.y, screenminy, screenmaxy, 0, touch.height());
    
    pressed = true;
    
  } 



  if((x > one_fx) && (x < (one_fx + one_fw))) { // x > 0 && x < 80
      if((y > one_fy) && (y <= (one_fy + one_fh))) { // y > 83 && y < 143
      
        Serial.print("1: x= ");
        Serial.print(x);
        Serial.print(" y= ");
        Serial.print(y);
        Serial.print("\n");
        
        pressed = false; x = 0; y = 0;
    
      }else { pressed = false; x = 0; y = 0; }
  }
    
} //==> void loop end

The idea here was that whenever I press on the screen, the X and Y coordinates would be recorded to variables x and y ... and boolean pressed will be set to TRUE.

Thats what this chunk should do...

//==> check for press
  while(pressed == false) {  
    //==> retrieve the point  
    TS_Point point = screen.getPoint(); 
    //==> map the point
    x = map(point.x, screenminx, screenmaxx, 0, touch.width());
    y = map(point.y, screenminy, screenmaxy, 0, touch.height());
    
    pressed = true;
    
  }

Next in line is the if statement.. I plan on having one of these for each button. This is just one for the button number 1. Once I get this one working I plan on just doing same thing for other buttons. But I can not get it to run the way I want to.

  if((x > one_fx) && (x < (one_fx + one_fw))) { // x > 0 && x < 80
      if((y > one_fy) && (y <= (one_fy + one_fh))) { // y > 83 && y < 143
      
        Serial.print("1: x= ");
        Serial.print(x);
        Serial.print(" y= ");
        Serial.print(y);
        Serial.print("\n");
        
        pressed = false; x = 0; y = 0;
    
      }else { pressed = false; x = 0; y = 0; }
  }
    
} //==> void loop end

In order for the above code to execute those print statements 3 conditions must all be true.

1.) The X coordinate must be between 0 and 80.
2.) The Y coordinate must be between 83 and 143.

Both of the values above indicate that the position pressed on the screen is within button number 1.

3.) Boolean pressed must equal true.

If these 3 conditions are not true then the x and y coordinates are set to 0 and pressed is set to false. Which should put us back to the top of the loop waiting for the next X and Y coordinates to be recorded.

Unfortunately the program is not running like that. When I click number 1, it gets the x and y coordinates and sets pressed to true. It should only run once and reset x,y, and pressed to default values. However, it spams the Serial.print's until you click somewhere else on the screen outside of the number 1 range.

This lead me to believe that x, y, and pressed are not being set back to default value or that it is getting stuck in that if statement somehow? But how? It's an if statement and should only be run once if the conditions are all true.

What am I missing here? It's driving me nuts because i've been stuck on it for couple days now. I have tried moving

boolean pressed = false; int x = 0; int y = 0;

to the beginning of the void loop to ensure it is getting reset to default value before doing anything else in the loop again. I have also tried using do-while and while loops in different places but it always puts me back to the same spot no matter what I do.

for me the layout of the code is confusing.
I restyled it the way I used to and I see that there are problems with the else branches,
empty and not the right number of {}

with CTRL-T the IDE can auto format the code (if it cannot , the balance of {} is wrong )

void loop()
{
  boolean pressed = false;

  while (pressed == false)  // WILL RUN ONLY ONCE
  {
    TS_Point point = screen.getPoint();
    x = map(point.x, screenminx, screenmaxx, 0, touch.width());
    y = map(point.y, screenminy, screenmaxy, 0, touch.height());
    pressed = true;
  }

  if ((x > one_fx) && (x < (one_fx + one_fw)))
  {
    if ((y > one_fy) && (y <= (one_fy + one_fh)))
    {
      Serial.print("1: x= ");
      Serial.print(x);
      Serial.print(" y= ");
      Serial.print(y);
      Serial.print("\n");

      pressed = false;
      x = 0;
      y = 0;
    }
    else <<<<<<<<<<<<<<<< missing {  and unclear what the if else logic should be here.
    }
  else
  {
    pressed = false;
    x = 0;
    y = 0;
  }
}

}

robtillaart:
for me the layout of the code is confusing.
I restyled it the way I used to and I see that there are problems with the else branches,
empty and not the right number of {}

with CTRL-T the IDE can auto format the code (if it cannot , the balance of {} is wrong )

void loop()

{
  boolean pressed = false;

while (pressed == false)  // WILL RUN ONLY ONCE
  {
    TS_Point point = screen.getPoint();
    x = map(point.x, screenminx, screenmaxx, 0, touch.width());
    y = map(point.y, screenminy, screenmaxy, 0, touch.height());
    pressed = true;
  }

if ((x > one_fx) && (x < (one_fx + one_fw)))
  {
    if ((y > one_fy) && (y <= (one_fy + one_fh)))
    {
      Serial.print("1: x= ");
      Serial.print(x);
      Serial.print(" y= ");
      Serial.print(y);
      Serial.print("\n");

pressed = false;
      x = 0;
      y = 0;
    }
    else <<<<<<<<<<<<<<<< missing {  and unclear what the if else logic should be here.
    }
  else
  {
    pressed = false;
    x = 0;
    y = 0;
  }
}

}

Thanks for the tip rob. That Ctrl+T will definitely make life a little easier in the future. I'll also be sure to hit Ctrl+T in the future when posting code to make it easier for people to help me out.

I removed the empty else. It now looks a lot prettier but still runs the same way. So I don't believe it was a format issue.

void loop()
{
  boolean pressed = false;

  while (pressed == false)  // WILL RUN ONLY ONCE
  {
    TS_Point point = screen.getPoint();
    x = map(point.x, screenminx, screenmaxx, 0, touch.width());
    y = map(point.y, screenminy, screenmaxy, 0, touch.height());
    pressed = true;
  }

  if ((x > one_fx) && (x < (one_fx + one_fw)))
  {
    if ((y > one_fy) && (y <= (one_fy + one_fh)))
    {
      Serial.print("1: x= ");
      Serial.print(x);
      Serial.print(" y= ");
      Serial.print(y);
      Serial.print("\n");

      pressed = false;
      x = 0;
      y = 0;
    }
    else
    {
      pressed = false;
      x = 0;
      y = 0;
    }
  }

}

Does the else belong to the right if statement?

note that this while loop will always be executed

  boolean pressed = false;

  while (pressed == false)  // WILL RUN ONLY ONCE
  {
    TS_Point point = screen.getPoint();
    x = map(point.x, screenminx, screenmaxx, 0, touch.width());
    y = map(point.y, screenminy, screenmaxy, 0, touch.height());
    pressed = true;
  }

thereby making pressed always true

think there is a logic flaw around that var.

robtillaart:
note that this while loop will always be executed

  boolean pressed = false;

while (pressed == false)  // WILL RUN ONLY ONCE
  {
    TS_Point point = screen.getPoint();
    x = map(point.x, screenminx, screenmaxx, 0, touch.width());
    y = map(point.y, screenminy, screenmaxy, 0, touch.height());
    pressed = true;
  }



thereby making pressed always true 

think there is a logic flaw around that var.

Yes but I need that part to execute every time to detect a touch on touch screen, that is where x and y values are coming from.

The part I dont want to execute every time is the if statement. And it shouldn't execute unless all 3 statements are true.

Yes but I need that part to execute every time to detect a touch on touch screen, that is where x and y values are coming from.

You most certainly do NOT. You need to ask the point object if a press occurred. If none occurred, then setting pressed to true is wrong.

PaulS:
You most certainly do NOT. You need to ask the point object if a press occurred. If none occurred, then setting pressed to true is wrong.

Ohhhhhhhhh, thanks for putting it that way.. helped me look at it a different way. Instead of checking for touch I changed it to check for a change in the x and y.

int x, y, ox, oy;

void loop()
{
  boolean pressed = false;

  //==> retrieve the point
  TS_Point point = screen.getPoint();
  //==> map the point
  x = map(point.x, screenminx, screenmaxx, 0, touch.width());
  y = map(point.y, screenminy, screenmaxy, 0, touch.height());


  //==> check for new press
  if (ox != x && oy != y) {

    ox = map(point.x, screenminx, screenmaxx, 0, touch.width());
    oy = map(point.y, screenminy, screenmaxy, 0, touch.height());
    pressed = true;

  }

  if (pressed) {
    if ((x > one_fx) && (x < (one_fx + one_fw))) { // x > 0 && x < 80
      if ((y > one_fy) && (y <= (one_fy + one_fh))) { // y > 83 && y < 143

        Serial.print("[o] x= ");
        Serial.print(x);
        Serial.print(" y= ");
        Serial.print(y);
        Serial.print("\n");

      }
    }
  }

} //==> void loop end
Touchscreen started.
[o] x= 30 y= 99
[o] x= 31 y= 112
[o] x= 40 y= 90
[o] x= 39 y= 91
[o] x= 38 y= 89
[o] x= 39 y= 90
[o] x= 38 y= 89
[o] x= 39 y= 91
[o] x= 38 y= 90
[o] x= 39 y= 89
[o] x= 38 y= 93
[o] x= 39 y= 88
[o] x= 38 y= 102
[o] x= 39 y= 106
[o] x= 41 y= 102
[o] x= 43 y= 98
[o] x= 41 y= 106
[o] x= 40 y= 103
[o] x= 34 y= 106
[o] x= 35 y= 105
[o] x= 36 y= 95
[o] x= 37 y= 97
[o] x= 36 y= 96
[o] x= 35 y= 98
[o] x= 38 y= 99
[o] x= 41 y= 102
[o] x= 43 y= 101

Now it only prints if there is a change. I just need to change that if statement that checks for change to make it a little less sensitive. If your finger slides just 1 pixel over it will print again. Perhaps add a +/- 5 pixel cushion.

Thanks Paul!

P.S. Do the arduino uno or other boards ever freeze up? After running it for first time and working fine for a bit, it froze up after clicking or holding a few times after. I tried to replicate the event again by trying different combinations of clicks and holds but couldn't get it to freeze up again.

Instead of checking for touch I changed it to check for a change in the x and y.

How will you deal with the need to enter 100? Pressing 0 twice need not result in a change in x or y.

The TS_Point class has a method to tell you how much pressure is being applied. You can use that method and the information it returns to determine if a press is happening.

PaulS:
How will you deal with the need to enter 100? Pressing 0 twice need not result in a change in x or y.

The TS_Point class has a method to tell you how much pressure is being applied. You can use that method and the information it returns to determine if a press is happening.

Ah, I did not see mention of the point.z variable when I was looking through the examples that came with the library. I did see mention of it once I Google'ed TS_Point. Thanks for the hint.

First I tried to do this.

This puts me back to square one with the same problem I had when I first started the thread. I click on the button, and it spams the Serial.print's until you click somewhere else on the screen again.

The problem with this is that for some reason I can not reset the X. Y, and Z values to 0 after the Serial.print's.

I have tried using x = 0; y = 0; z = 0; and point.x = 0; point.y = 0; point.z = 0;. But neither of those work. The value of Z will not change unless you physically touch somewhere else on the screen.

So I tried this.

int x, y, z, oz;

void loop()
{

  //==> retrieve the point
  TS_Point point = screen.getPoint();
  //==> map the point
  x = map(point.x, screenminx, screenmaxx, 0, touch.width());
  y = map(point.y, screenminy, screenmaxy, 0, touch.height());
  z = point.z;
  

  if (z != oz) {
    if ((x > one_fx) && (x < (one_fx + one_fw))) { // x > 0 && x < 80
      if ((y > one_fy) && (y <= (one_fy + one_fh))) { // y > 83 && y < 143
  
        Serial.print("[o] x= ");
        Serial.print(x);
        Serial.print(" y= ");
        Serial.print(y);
        Serial.print(" z= ");
        Serial.print(z);
        Serial.print("\n");
  
      }
    }
    oz = point.z;
  }

} //==> void loop end

Since I could not reset X, Y, and Z.. I tried to look for change in Z (pressure) instead. But this caused the same sensitivity issue I had as above when I was checking for change in X and Y rather than Z.

I tried changing the sensitivity with this this IF statement..

if ( (z > (oz-3)) && (z < (oz+3)) )

instead of

if ( z != oz)

But now it does not print anything when clicked anywhere...

I don't think you want to compare z to oz. It is not a change in z that you want. It is a value of z that is greater than some threshold.

Skip trying to use the value of z for now. Create a sketch that just prints the value of z. Caress, stroke, touch, press, etc. See what absolute value you get for z. There is some value that you will consider pressed. Anything at or above that value means pressed. Anything below that means that a fly was walking across the touch screen, and should be ignored.

Once you have that threshold, the rest is easy.

PaulS:
I don't think you want to compare z to oz. It is not a change in z that you want. It is a value of z that is greater than some threshold.

Skip trying to use the value of z for now. Create a sketch that just prints the value of z. Caress, stroke, touch, press, etc. See what absolute value you get for z. There is some value that you will consider pressed. Anything at or above that value means pressed. Anything below that means that a fly was walking across the touch screen, and should be ignored.

Once you have that threshold, the rest is easy.

Z ranges from 0 to 255. But the problem is that once you touch somewhere on the screen and Z is set to lets say 83. Z will forever remain 83 until you touch the screen again. It does not revert back to 0. I have tried setting it back to zero using x = 0; y = 0; z = 0; and point.x = 0; point.y = 0; point.z = 0;. But neither of those work.

It would be very simple if Z reset by itself or I could reset it myself in the code.

I would much rather like to use (z > 0) instead of the use of z and oz but can not get z to go back to 0. It just loops over and over again with the value 83 until clicked again. Which is why it spams print until pressed again somewhere else.

IMG

Not knowing if you are using the resitive or capacitive touch screen, I looked at the AdaFruit's sample code for their touchpaint demo for both. Both of them use a method .touched() to check for a touch screen event. For example, in the resitive touch demo:

#include <Adafruit_GFX.h>    // Core graphics library
#include <SPI.h>
#include <Wire.h>      // this is needed even tho we aren't using it
#include <Adafruit_ILI9341.h>
#include <Adafruit_STMPE610.h>

// The STMPE610 uses hardware SPI on the shield, and #8
#define STMPE_CS 8
Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS);

[...]

void setup(void) {

[...]

  if (!ts.begin()) {
    Serial.println("Couldn't start touchscreen controller");
    while (1);
  }
  Serial.println("Touchscreen started");

[...]

}

void loop()
{
  // See if there's any  touch data for us
  if (ts.bufferEmpty()) {
    return;
  }
  /*
  // You can also wait for a touch
  if (! ts.touched()) {
    return;
  }
  */

  // Retrieve a point  
  TS_Point p = ts.getPoint();

[...]

}

(Yes, I know the above won't compile, It's just the snippets that deal with setting up and recognizing that a touch screen event has happened.)

The capacitive touch touchpaint demo uses similar code, but doesn't have the .bufferEmpty() method. It might exist and the demo just doesn't mention it, or they didn't implement that method for the capacitive touch library.

I haven't tried out any touch-screen code on my capacitive touch TFT from Adafruit beyond their provided examples, but hope to soon.

BTW, I've found a handy add-on if you have the TFT shield is to put one of their wing shields below. That way you can actually wire to a breadboard while using the TFT shield.

Sembazuru:
Not knowing if you are using the resitive or capacitive touch screen, I looked at the AdaFruit's sample code for their touchpaint demo for both. Both of them use a method .touched() to check for a touch screen event. For example, in the resitive touch demo:

#include <Adafruit_GFX.h>    // Core graphics library

#include <SPI.h>
#include <Wire.h>      // this is needed even tho we aren't using it
#include <Adafruit_ILI9341.h>
#include <Adafruit_STMPE610.h>

// The STMPE610 uses hardware SPI on the shield, and #8
#define STMPE_CS 8
Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS);

[...]

void setup(void) {

[...]

if (!ts.begin()) {
   Serial.println("Couldn't start touchscreen controller");
   while (1);
 }
 Serial.println("Touchscreen started");

[...]

}

void loop()
{
 // See if there's any  touch data for us
 if (ts.bufferEmpty()) {
   return;
 }
 /*
 // You can also wait for a touch
 if (! ts.touched()) {
   return;
 }
 */

// Retrieve a point  
 TS_Point p = ts.getPoint();

[...]

}




(Yes, I know the above won't compile, It's just the snippets that deal with setting up and recognizing that a touch screen event has happened.)

The capacitive touch touchpaint demo uses similar code, but doesn't have the `.bufferEmpty()` method. It might exist and the demo just doesn't mention it, or they didn't implement that method for the capacitive touch library.

I haven't tried out any touch-screen code on my capacitive touch TFT from Adafruit beyond their provided examples, but hope to soon.


BTW, I've found a handy add-on if you have the TFT shield is to put one of their wing shields below. That way you can actually wire to a breadboard while using the TFT shield.

That's the first thing I did when I got the lcd.

adafruit-2-8-tft-touch-shield-v2.pdf

I looked at the paint demo and then the button on/off demo and based everything I have off that. I originally started playing with those two functions and couldnt really figure out how to use them to produce the output I wanted. Both of those functions fully spam the print while being held or touched. At least with the use of Z I have been able to reduce the print spam to just when you move the finger a little.

[o] x= 52 y= 107 z= 59 oz= 60
[o] x= 51 y= 106 z= 60 oz= 59
[o] x= 51 y= 106 z= 58 oz= 60
[o] x= 51 y= 106 z= 60 oz= 58
[o] x= 52 y= 107 z= 60 oz= 60
[o] x= 51 y= 108 z= 60 oz= 60
[o] x= 51 y= 107 z= 60 oz= 60
[o] x= 51 y= 107 z= 60 oz= 60
[o] x= 51 y= 112 z= 59 oz= 60
[o] x= 51 y= 105 z= 61 oz= 59
[o] x= 51 y= 108 z= 60 oz= 61
[o] x= 51 y= 109 z= 61 oz= 60
[o] x= 51 y= 107 z= 61 oz= 61
[o] x= 51 y= 107 z= 61 oz= 61
[o] x= 51 y= 107 z= 61 oz= 61

See there is multiple prints with same data. Use of Z at least doesn't print same thing, only when your finger moves a little it give newer print.

If only I can somehow figure out how to reset the x y z variables at the end of the loop, OR, fine tune if(z != oz).. but my attempt.

I just want to be able to click the button once and it prints once. Not click once and have 2-3 prints, which is as far as I have been able to get with it.

Your last posted code contains:
if (z != oz)
{
if ((x > one_fx) && (x < (one_fx + one_fw)))
{ // x > 0 && x < 80
}
oz = point.z;
}
(When the curly braces are where they belong).

I'd be setting oz to z (not point.z) every time, not just when they are not the same.

I'm officially more confused than when I started the topic, lol.

what about the closing curly bracket in this section.
//==> check for press
while(pressed == false) {
//==> retrieve the point
TS_Point point = screen.getPoint();
//==> map the point
x = map(point.x, screenminx, screenmaxx, 0, touch.width());
y = map(point.y, screenminy, screenmaxy, 0, touch.height());

pressed = true;

I'm pretty sure missing a bracket would set some sort of compiler error. All the bracket are fine.

I have found the solution. I'll post it just in case someone else has trouble with this getting a tft touch screen to return 1 output after touching in specific area.

int x, y, z;

void loop()
{
  TS_Point point;
  // wait for a touch
  if (! screen.touched()) {
    return;
  }
  while (screen.touched()) {
    // Retrieve a point 
    TS_Point point = screen.getPoint();
    x = map(point.x, screenminx, screenmaxx, 0, touch.width());
    y = map(point.y, screenminy, screenmaxy, 0, touch.height());
    z = point.z;
 
  }
  //we will drop out of the while loop when the touch is released

  if (z > 10) 
  {
    if ((x > one_fx) && (x < (one_fx + one_fw))) 
    {
      if ((y > one_fy) && (y <= (one_fy + one_fh))) 
      {
        Serial.print("[o] x= ");
        Serial.print(x);
        Serial.print(" y= ");
        Serial.print(y);
        Serial.print(" z= ");
        Serial.print(z);
        Serial.print("\n");
      }
    }
  }
}

Full code (pastebin)
Adafruit 2.8" TFT Touch Screen ($34.95)
Libraries

Thank you for all the help everyone. Sent Karma every time I checked back to topic.

This kind of logic would normally be

boolean pressed = false;

loop() {
  TS_Point point = screen.getPoint();

  if( /* the screen is not currently being pressed */ ) {
    pressed == false;
  }
  // ok, at this point we know that the screen is being pressed
  else if(pressed) {
    // the screen is being pressed, but we have already delay with it previously. Do nothing
    ;
  }
  else {
    // the screen is being pressed, and it was not pressed last time this loop was run.
    // so let's do some stuff!

    /* do some stuff */

    pressed = true;
  }
}

Alternatively, you can rename that variable "readyToDealWithPress" and invert the sense of your checks. This might make things clearer.

  if( /* the screen is not currently being pressed */ ) {
    pressed == false;
  }

Really? Compare pressed to false, and discard the result. Why?