Strange Behavior in If Statement

Hi All,

This is related to reading a touch screen but I'm posting here because the reading of the screen is going fine, my problem relates to some If statement code that is acting strangely.

Essentially, when I touch the screen I get good values but when the screen isn't touched I get erroneous values. This is to be expected, so it is recommended to first detect a touch and then read the values. So, you can see in the code below that I first arrange the pins to detect a touch, I look for a high or low value, and based on the value of the Touch variable I either (via an If statement) serial print the value and the string "no touch" or execute some more code to take readings of X and Y.

The weird thing is that with the code below, when the screen is not touched, it continues to report those original erroneous values... when I touch the screen I get good values. So, I figured that there was something wrong with the way I detect a touch. But when I remove the "else" section of code (commented out or deleted) the "if" section works correctly. To be specific: When the "else" section is gone and the screen is not touched the serial monitor reports a high value for Touch and prints the "no touch" line. If I touch the screen the serial prints stop as expected and the code loops indefinitely. When the "else" portion is re-inserted the code in the "if" section never runs regardless of contact with the screen.

Code that acts strangely:

//Brian Josephs Mar 29, 2015
//Pin arrangements based on...
//http://www.ti.com/lit/an/slaa384a/slaa384a.pdf

int YP = A4;
int XP = A5;
int YM =  3;
int XM =  2;
int XValue;
int YValue;
int Touch;

void setup() {

  Serial.begin(9600);

}

void loop() {

  //Detect Touch
  pinMode(YP, INPUT);
  pinMode(YM, INPUT);
  pinMode(XP, INPUT);
  pinMode(XM, OUTPUT);

  digitalWrite(YP, HIGH);
  digitalWrite(XM, LOW);
  Touch = digitalRead(YP);

  if (Touch == HIGH)
  {
    Serial.println(Touch);
    Serial.println("No Touch");
  }
  else
  {
    //READ X
    pinMode(YP, OUTPUT);
    pinMode(YM, OUTPUT);
    pinMode(XP, INPUT);
    pinMode(XM, INPUT);

    digitalWrite(YP, HIGH);
    digitalWrite(YM, LOW);
    XValue = analogRead(XP);

    //READ Y
    pinMode(YP, INPUT);
    pinMode(YM, INPUT);
    pinMode(XP, OUTPUT);
    pinMode(XM, OUTPUT);

    digitalWrite(XP, HIGH);
    digitalWrite(XM, LOW);
    YValue = analogRead(YP);

    Serial.print (XValue);
    Serial.print (", ");
    Serial.println(YValue);
  }
     delay(100);  
}

Code that acts normally but obviously fall short of its purpose:

//Brian Josephs Mar 29, 2015
//Pin arrangements based on...
//http://www.ti.com/lit/an/slaa384a/slaa384a.pdf

int YP = A4;
int XP = A5;
int YM =  3;
int XM =  2;
int XValue;
int YValue;
int Touch;

void setup() {

  Serial.begin(9600);

}

void loop() {

  //Detect Touch
  pinMode(YP, INPUT);
  pinMode(YM, INPUT);
  pinMode(XP, INPUT);
  pinMode(XM, OUTPUT);

  digitalWrite(YP, HIGH);
  digitalWrite(XM, LOW);
  Touch = digitalRead(YP);

  if (Touch == HIGH)
  {
    Serial.println(Touch);
    Serial.println("No Touch");
  }
//  else
//  {
//    //READ X
//    pinMode(YP, OUTPUT);
//    pinMode(YM, OUTPUT);
//    pinMode(XP, INPUT);
//    pinMode(XM, INPUT);
//
//    digitalWrite(YP, HIGH);
//    digitalWrite(YM, LOW);
//    XValue = analogRead(XP);
//
//    //READ Y
//    pinMode(YP, INPUT);
//    pinMode(YM, INPUT);
//    pinMode(XP, OUTPUT);
//    pinMode(XM, OUTPUT);
//
//    digitalWrite(XP, HIGH);
//    digitalWrite(XM, LOW);
//    YValue = analogRead(YP);
//
//    Serial.print (XValue);
//    Serial.print (", ");
//    Serial.println(YValue);
//  }
     delay(100);  
}

Another variant of code that "works"... touch and no touch report as expected:

//Brian Josephs Mar 29, 2015
//Pin arrangements based on...
//http://www.ti.com/lit/an/slaa384a/slaa384a.pdf

int YP = A4;
int XP = A5;
int YM =  3;
int XM =  2;
int XValue;
int YValue;
int Touch;

void setup() {

  Serial.begin(9600);

}

void loop() {

  //Detect Touch
  pinMode(YP, INPUT);
  pinMode(YM, INPUT);
  pinMode(XP, INPUT);
  pinMode(XM, OUTPUT);

  digitalWrite(YP, HIGH);
  digitalWrite(XM, LOW);
  Touch = digitalRead(YP);

  if (Touch == HIGH)
  {
    Serial.println(Touch);
    Serial.println("No Touch");
  }
  else
  {
Serial.println("Touch!");
  }
     delay(100);  
}

Post a link to the datasheet for the touchscreen you are using.

Why have you pinMode() within loop()

How is the touchscreen supposed to work?

...R

I am curious what the intent behind the following line just prior to the If statement is?

digitalWrite(YP, HIGH);

I am curious what the intent behind the following line just prior to the If statement is?

digitalWrite(YP, HIGH);

Hi BH72,

That line should set the input pull-up on the YP pin.

Brian

Post a link to the datasheet for the touchscreen you are using.

Why have you pinMode() within loop()

How is the touchscreen supposed to work?

...R

I didn't see a real datasheet, but here is a link to the item at Adafruit.

http://www.adafruit.com/products/1676?gclid=CMX1t8aSzsQCFUJk7AodnVEAtQ

The pin mode lines reconfigure the pins between readings. If you look at the TI app note that I link to in the code it explains why... some pins need to be outputs for reading Y and inputs for reading X and vice versa.

Thanks, Brian

Hi -

I'm a bit concerned, that you are using the same pin both as digital and analog input, and changing its status to a digital output. Is that in fact possible ?

I think this code that I wrote ages ago is for the same sort of touch screen.

void setup() {
  Serial.begin(9600);
}

void loop() {
  
  Serial.print("Ax ");
  Serial.print(readXpos());
  Serial.print(" Ay ");
  Serial.println(readYpos());
  delay(500);

}

int readXpos() {
  pinMode(A0, INPUT);
  pinMode(A1, OUTPUT);
  pinMode(A2, INPUT);
  pinMode(A3, OUTPUT);
  
  digitalWrite(A3, HIGH);
  digitalWrite(A1, LOW);
  
  int anX = analogRead(A0);
  anX = analogRead(A0);

  return(anX);

}

int readYpos() {
  
  pinMode(A0, OUTPUT);
  pinMode(A1, INPUT);
  pinMode(A2, OUTPUT);
  pinMode(A3, INPUT);
  
  digitalWrite(A2, HIGH);
  digitalWrite(A0, LOW);

  int anY = analogRead(A1);
  anY = analogRead(A1);

  return(anY);

}

Hope it helps

...R

Anders53: Hi -

I'm a bit concerned, that you are using the same pin both as digital and analog input, and changing its status to a digital output. Is that in fact possible ?

That is totally possible. All of the analog inputs can also serve as digital inputs or outputs.

Although I am unsure whether or not this is one of those cases where you should take two readings each time and throw the first one away. Sometimes switching pins like that can cause your first analogRead to be erroneous. Maybe someone else can expand.

Delta_G: That is totally possible. All of the analog inputs can also serve as digital inputs or outputs.

Although I am unsure whether or not this is one of those cases where you should take two readings each time and throw the first one away. Sometimes switching pins like that can cause your first analogRead to be erroneous. Maybe someone else can expand.

Looks like Robin2 has a point then, as he is using a much longer delay of 500mS, to let the analog input state settle after the status change.

Would be very easy though to simply read twice in a row, instead of more mcu sleeping.

I was also thinking along the lines of perhaps there not being enough time elapsed after setting pin mode to allow proper low to high transition, additionally resetting the pin mode to the basic "detect touch" state should only be required once a touch state is detected, perhaps an experiment if you have time..

int YP = A4;
int XP = A5;
int YM =  3;
int XM =  2;
int XValue;
int YValue;
int Touch;

void setup() {

  Serial.begin(9600);

  //set initial state
  pinMode(YP, INPUT);
  pinMode(YM, INPUT);
  pinMode(XP, INPUT);
  pinMode(XM, OUTPUT);
  digitalWrite(YP, HIGH);
  digitalWrite(XM, LOW);

}

void loop() {

  //Detect Touch

  Touch = digitalRead(YP);

  if (Touch == HIGH)
  {
    Serial.println(Touch);
    Serial.println("No Touch");
  }
  else
  {
    //READ X
    pinMode(YP, OUTPUT);
    pinMode(YM, OUTPUT);
    pinMode(XP, INPUT);
    pinMode(XM, INPUT);

    digitalWrite(YP, HIGH);
    digitalWrite(YM, LOW);
    XValue = analogRead(XP);

    //READ Y
    pinMode(YP, INPUT);
    pinMode(YM, INPUT);
    pinMode(XP, OUTPUT);
    pinMode(XM, OUTPUT);

    digitalWrite(XP, HIGH);
    digitalWrite(XM, LOW);
    YValue = analogRead(YP);

    Serial.print (XValue);
    Serial.print (", ");
    Serial.println(YValue);

 //set pinMode back to detect touch state

  pinMode(YP, INPUT);
  pinMode(YM, INPUT);
  pinMode(XP, INPUT);
  pinMode(XM, OUTPUT);

  digitalWrite(YP, HIGH);
  digitalWrite(XM, LOW);
  }
     delay(100);  
}

Anders53: Looks like Robin2 has a point then, as he is using a much longer delay of 500mS, to let the analog input state settle after the status change.

My code was just a quick and dirty test. I suspect the 500mS was chosen so the Serial Monitor was not overwhelmed. If the code works with 500mS then try shorter values until you find the minimum that works.

From reading the Atmel datasheet I think the mode of a pin should change in a single instruction - i.e. 62.5 nanosecs

...R

Hi All,

Thanks for all the insights. It turns out a small delay before the:

Touch = digitalRead(YP);

line was all that was needed. 200 microseconds does the trick. Anything shorter (or no delay at all) seems to result in a false "LOW" reading and the execution of the wrong branch of code.

Thanks, Brian