Letting a sensor value decay over a 3ms period

Hello fellas,

I’m at a project with a touch screen where I experience slight troubles: I want to program a ‘momentary hold’ function and I do this as follows (in order of time).

  1. I read the values of the touch screen
  2. I check if the hold switch boolean is true or false
  3. If it’s false, no problem, continue…
  4. If it’s true (i.e. we are now in momentary hold mode), check if the screen is pressed above a certain value. If it is, then I generate a clock signal which goes to a normalled minijack (so I can also feed ext. clocks into it) and then back into the Atmega again. Internally I handle this as a clock boolean.
  5. If there is a clock signal present on that pin I just continue reading the screen and writing the values.
  6. If the clock signal goes low, I lock up the value (simply stop reading the sensor) so therefore a hold mode is achieved.

I hope this is understandable. Now the problem is that the clock always goes low AFTER the touch screen isn’t touched anymore (because that’s the condition to make the clock high in the first place) so in 90% of the cases I end up with a 0 reading of the screen in that point of time. I can see on my Rigol that the clock goes low roughly 3ms after the sensor value decreases. Sometimes I have a lucky catch and it holds the value (for reasons unknown actually).

So now I think if I could make a tini tiny delay on my sensor reading, like 5ms, I could avoid this problem right? How would that work?
Or any other suggestions?

Thanks for your help!!

//edit:
Oh and here’s the (relevant) code pieces:

My main loop:

  int yout = Read_y();
 
  boolean lockmode = checkLockMode();
  boolean holdmodeX = checkHoldModeX();
  boolean holdmodeY = checkHoldModeY();
  
  TouchTest();


  
  //Y-HOLD Checking
  if (holdmodeY == true && lockmode == true) {
    //this is locked Y
    yhold = true;
    analogWrite(youtpin, yout);
  }
  
  else if (holdmodeY == true && lockmode == false) {
    //this is momentary Y
    analogWrite(youtpin, yout);
    
    clock = digitalRead(clockin);
    if (clock == true) {yhold = false;}
    else if (clock == false) {yhold = true;}
    
  }
  
  else if (holdmodeY == false && lockmode == true) {
    //free Y
    yhold = false;
    analogWrite(youtpin, yout);
  }   
  
  else if (holdmodeY == false && lockmode == false) {
    //free Y
    yhold = false;
    analogWrite(youtpin, yout);
  }

The sensor reading (pretty standard):

int Read_y() {
//  //Processing Y: To hold or not to hold - that is the question!
  if (yhold == true) {  
    return yout;
    }
    
  else if (yhold == false) {
    //Reading Y
    pinMode( A0, INPUT );
    pinMode( A2, INPUT );
    pinMode( A1, OUTPUT );
    digitalWrite( A1, LOW );
    pinMode( A3, OUTPUT );
    digitalWrite( A3, HIGH );


    yval = analogRead(0);
    yout = map(yval, 100, 800, 0, 255);
    if (yout < 0) {yout = 0;}
      else if(yout > 255) {yout = 255;};
      
    return yout;
  }
}

And this is the touch test:

int TouchTest(void) {
  pinMode(A1, OUTPUT);
  digitalWrite(A1, LOW);
  pinMode(A0, OUTPUT);
  digitalWrite(A0, HIGH); 
  
  digitalWrite(A3, LOW);
  pinMode(A3, INPUT);
  digitalWrite(A2, LOW);
  pinMode(A2, INPUT);
  
  int z1 = analogRead(A3);
  int z2 = analogRead(A2);

    boolean touch;
    float rtouch;
    rtouch = z2;
    rtouch /= z1;
    rtouch -= 1;
    rtouch *= Read_x();
    rtouch /= 1024;
    
    if (rtouch < 3) { //touched
      touch = true;
      digitalWrite(clockout, HIGH);
      }
      
     else { //untouched
       touch = false;
       digitalWrite(clockout, LOW);
       }
    return touch;
  
}

I left out the switch check, it is a simply boolean being slammed around by a pushbutton…

I can't deal with code fragments. Could you post the whole sketch?

Sure thang! It’s quite something though that’s why I stripped it down for you.

/*TODO:
- Manual Triggers/Gates und die Lengths according to the X and Y value
*/




int X_LED = 0;

int xholdbutton = 2;  //Pin for the X Hold Button
int HMholdbutton = 3; //Pin for Hold Mode Button
int yholdbutton = 4;  //Pin for the Y Hold Button

int xoutpin = 5;  //X-Out pin
int youtpin = 6;  //Y-Out pin

int clockout = 7;
int clockin = 8;

int Y_LED = 9;
int HM_LED = 10;

boolean xhold;
boolean yhold;
boolean HMhold = false;

int xval = 0;  //Variable for X-Axis reading
int yval = 0;  //Variable for Y-Axis reading

int xout = 0;  //Conditioned X-Output Value
int yout = 0;  //Conditioned Y-Output Value

//For X - Hold Pushbutton state changer:
int statex = LOW;      // the current state of the output pin
int readingx;           // the current reading from the input pin
int previousx = HIGH;    // the previous reading from the input pin

long timex = 0;         // the last time the output pin was toggled
long debouncex = 2000;   // the debounce time, increase if the output flickers

//For Y - Hold Pushbutton state changer:
int statey = LOW;      // the current state of the output pin
int readingy;           // the current reading from the input pin
int previousy = HIGH;    // the previous reading from the input pin

long timey = 0;         // the last time the output pin was toggled
long debouncey = 2000;   // the debounce time, increase if the output flickers

//And the Lock Mode Pushbutton state changer:
int stateHM = LOW;      // the current state of the output pin
int readingHM;           // the current reading from the input pin
int previousHM = HIGH;    // the previous reading from the input pin

long timeHM = 0;         // the last time the output pin was toggled
long debounceHM = 2000;   // the debounce time, increase if the output flickers

/* So, my Pins are like this:

.D0 - X-LED
.D1 - MIDI Out
.D2 - Hold Pushbutton für X
.D3 - Hold Mode Pushbutton
.D4 - Hold Pushbutton für Y
.D5 - Output X
.D6 - Output Y
.D7 - 'Internal' Clock Out
.D8 - Clock In
.D9 - Y-LED
.D10 - HM-LED
D11 - nix - kann PWM
D12 - nix
D13 - nix

.A0 - Touchscreen
.A1 - Touchscreen
.A2 - Touchscreen
.A3 - Touchscreen
A4 - nix
A5 - nix

*/

//TouchScreen ts = TouchScreen(A2, A3, A0, A1, 300);

void setup()
{
  //Serial.begin(57600); //MIDI: 31250
   
  pinMode(xoutpin, OUTPUT); //X Out
  pinMode(youtpin, OUTPUT); //Y Out
  pinMode(1, OUTPUT); //MIDI Out
  
  pinMode(xholdbutton, INPUT); //X Hold Button
  pinMode(yholdbutton, INPUT); //Y Hold Button
  pinMode(HMholdbutton, INPUT); //Hold-Mode Button
  
  pinMode(X_LED, OUTPUT);
  pinMode(Y_LED, OUTPUT);
  pinMode(HM_LED, OUTPUT);
  
  pinMode(clockout, OUTPUT);
  pinMode(clockin, INPUT);
  
  TCCR0B = TCCR0B & 0b11111000 | 0x01; //Clockdivider Clock0 = 1 -> Clockspeed = 62,5KHz
  TCCR1B = TCCR1B & 0b11111000 | 0x01; //Clockdivider Clock1 = 1 -> Clockspeed = 31,25KHz
  
}


void loop()
{ 
  //boolean touch = false;
  int yout = Read_y();
 
  boolean lockmode = checkLockMode();
  boolean holdmodeX = checkHoldModeX();
  boolean holdmodeY = checkHoldModeY();
  
  boolean clock = TouchTest();

  //X-HOLD Checking
  if (holdmodeX == true && lockmode == true) {
    //this is locked X
    xhold = true;
    analogWrite(xoutpin, xout);
  }
  
  else if (holdmodeX == true && lockmode == false) {
    //this is momentary X
    boolean clock = false;
    analogWrite(xoutpin, xout);
    
    clock = digitalRead(clockin);
    if (clock == true) {xhold = false;}
    else if (clock == false) {xhold = true;}
    
  }
  
  else if (holdmodeX == false && lockmode == true) {
    //free X
    xhold = false;
    analogWrite(xoutpin, xout);
  }   
  
  else if (holdmodeX == false && lockmode == false) {
    //free X
    xhold = false;
    analogWrite(xoutpin, xout);
  }
  
  
  //Y-HOLD Checking
  if (holdmodeY == true && lockmode == true) {
    //this is locked Y
    yhold = true;
    analogWrite(youtpin, yout);
  }
  
  else if (holdmodeY == true && lockmode == false) {
    //this is momentary Y
    boolean clock = false;
    analogWrite(youtpin, yout);
    
    clock = digitalRead(clockin);
    if (clock == true) {yhold = false;}
    else if (clock == false) {yhold = true;}
    
  }
  
  else if (holdmodeY == false && lockmode == true) {
    //free Y
    yhold = false;
    analogWrite(youtpin, yout);
  }   
  
  else if (holdmodeY == false && lockmode == false) {
    //free Y
    yhold = false;
    analogWrite(youtpin, yout);
  }



//  int lsb, msb = 0;
//  int pitchbend = 224;
//  MIDImessage(pitchbend, lsb, xout/2);

}

void MIDImessage(int command, int data1, int data2) {
  Serial.write(command);//send command byte
  Serial.write(data1);//send data byte #1
  Serial.write(data2);//send data byte #2
}

int Read_x() {
  //Processing X: To hold or not to hold - that is the question!
  if (xhold == true) {
    int holdxout = xout;
    return xout;
  }
  else {
    //Reading X
    pinMode( A1, INPUT );
    pinMode( A3, INPUT );
    pinMode( A0, OUTPUT );
    digitalWrite( A0, LOW );
    pinMode( A2, OUTPUT );
    digitalWrite( A2, HIGH );
  
//      int readings[10];
//      int i;
//        for(i=0; i<10; i++){
//          readings[i] = analogRead( 1 );
//        }
//
//      int xval = (readings[0] + readings[1] + readings[2] + readings[3] + readings[4] + readings[5] + readings[6])/7; 


    xval = analogRead(1);
    xout = map(xval, 160, 850, 0, 255); //will ich eigentlich noch weg - AA vs VA
    if (xout < 0) {xout = 0;}
      else if(xout > 255) {xout = 255;};
      
    return xout;
   }
}
  
  
  
int Read_y() {
//  //Processing Y: To hold or not to hold - that is the question!
  if (yhold == true) {  
    return yout;
    }
    
  else if (yhold == false) {
    //Reading Y
    pinMode( A0, INPUT );
    pinMode( A2, INPUT );
    pinMode( A1, OUTPUT );
    digitalWrite( A1, LOW );
    pinMode( A3, OUTPUT );
    digitalWrite( A3, HIGH );

//      int readings[7];
//      int i;
//        for(i=0; i<7; i++){
//          readings[i] = analogRead( 0 );
//        }
//
//      int yval = (readings[0] + readings[1] + readings[2] + readings[3] + readings[4] + readings[5] + readings[6])/7;


    yval = analogRead(0);
    yout = map(yval, 100, 800, 0, 255);
    if (yout < 0) {yout = 0;}
      else if(yout > 255) {yout = 255;};
      
    return yout;
  }
}
  
  
int TouchTest(void) {
  pinMode(A1, OUTPUT);
  digitalWrite(A1, LOW);
  pinMode(A0, OUTPUT);
  digitalWrite(A0, HIGH); 
  
  digitalWrite(A3, LOW);
  pinMode(A3, INPUT);
  digitalWrite(A2, LOW);
  pinMode(A2, INPUT);
  
  int z1 = analogRead(A3);
  int z2 = analogRead(A2);

    boolean touch;
    float rtouch;
    rtouch = z2;
    rtouch /= z1;
    rtouch -= 1;
    rtouch *= Read_x();
    rtouch /= 1024;
    
    if (rtouch < 3) { //touched
      touch = true;
      digitalWrite(clockout, HIGH);
      }
      
     else { //untouched
       touch = false;
       digitalWrite(clockout, LOW);
       }
    return touch;
  
}

boolean checkHoldModeX() {
  
  readingx = digitalRead(xholdbutton);
  
  if (readingx == HIGH && previousx == LOW && millis() - timex > debouncex) {
    if (statex == HIGH) {
      statex = LOW;
      digitalWrite(X_LED, LOW);
    }
    
    else {
      statex = HIGH;
      digitalWrite(X_LED, HIGH);
    }

    timex = millis();    
  }

  previousx = readingx;
  return statex;
}

boolean checkHoldModeY() {
  
  readingy = digitalRead(yholdbutton);
  
  if (readingy == HIGH && previousy == LOW && millis() - timey > debouncey) {
    if (statey == HIGH) {
      statey = LOW;
      digitalWrite(Y_LED, LOW);
    }
    
    else {
      statey = HIGH;
      digitalWrite(Y_LED, HIGH);
    }

    timey = millis();    
  }

  previousy = readingy;
  return statey;
}

boolean checkLockMode() {

  readingHM = digitalRead(HMholdbutton);

  if (readingHM == HIGH && previousHM == LOW && millis() - timeHM > debounceHM) {
    if (stateHM == HIGH) {
      stateHM = LOW;
      digitalWrite(HM_LED, LOW);
    }
    
    else {
      stateHM = HIGH;
      digitalWrite(HM_LED, HIGH);
    }

    timeHM = millis();    
  }

  previousHM = readingHM;
  return stateHM;
}

It's not easy to relate the sequence you describes to what the code does.

I see that you are setting clockout HIGH when the screen is touched and LOW when it stops being touched. I assume this results in clockin going LOW and then HIGH and hence yhold being set to true and then false. Presumably it is when it goes false that you want to capture the sensor value. But what is the sensor value you're trying to capture? Is it yout? When within this sequence do you want to capture the value, and what does 'capture' mean? The code currently looks as if it captures the value (does not change it) while the screen is touched and then stops holding it (returns to reading the sensor value) afterwards when yhold goes false. That doesn't seem unreasonable but presumably isn't what you want.

PeterH: It's not easy to relate the sequence you describes to what the code does.

Alright, if there's anything to make that clearer then please let me know how I can do it.

The code currently looks as if it captures the value (does not change it) while the screen is touched and then stops holding it (returns to reading the sensor value) afterwards when yhold goes false. That doesn't seem unreasonable but presumably isn't what you want.

What it does now is: The screen is being touched and TouchTest() checks that because it is checking if on the whole screen something is going on. If there is, it makes the clock go high. If in 'momentary' mode then Read_y() (resp. Read_x()) looks if the clock is high (screen is touched) and does what it does best: Process the data and send them out on a pin. But as soon as the clock goes low (finger left the screen), it stops checking for new data and simply sends out the last value that is still stored in yout (xout). Alright?

So what I want is that when you lift your finger of the TS the machine 'remembers' where you lift it of, so that it holds those last two variables, you understand? The problem is that I can only know that the finger is gone ... well ... when it's gone already :P So at that point the value always is zero! But if I could hold the X-Y variables for a very short (unnoticable) time AFTER the clock went low (finger gone!) then it would be perfect.

Because like I said, I can see on my oscilloscope that it takes ~3ms from the value that you had last until the clock goes low, i.e. the µC 'notices' that your finger is gone.

Do you understand? Any ideas?

Each time you read the current x,y values from the screen, hold them in global or static variables. That way the most recently read values will remain available subsequently even after the screen touch has ended.

Alright then! So, how do I do that? :stuck_out_tongue:
Call them static xout and static yout or what?

I’m sorry, I have never done that before… Thanks for your help, much appreciated!

To make them global, put the declarations outside your functions. Global variables are visible throughout the whole code, and persist for the life of your sketch.

To make them static, put the keyword 'static' in front of the declaration. This is only really sensible to do when the variable is local (i.e. declared within a function). Static local variables are only visible within the scope of the function they are declared in, but persist their value for the life of your sketch.

You can also declare global variables as static but it does not achieve anything useful in this context. Making them global OR static is enough for what you're trying to do.

Okay. Hey, I’m sorry but I don’t think this will solve my problem. I actually do specify them as global variables, no?

My main problem is that I can only sense the leaving of the finger, after it had happened. Of course, because the machine can’t look into the future. But then I would need to take the value that has been there like 5ms ago.

osterchrisi: I would need to take the value that has been there like 5ms ago.

It's not a matter of recovering the value that was there 5ms ago, it's a matter of [u]not overwriting[/u] the value you had 5ms ago in the process of discovering whether the user is still touching the screen.

Alright then. I think I need some more philosophy here though, I can't really make something out of your words. I could get it to work a bit better by changing the code as follows:

else if (holdmodeX == true && lockmode == false) {
    
    clock = digitalRead(clockin);
      if (clock == true) {xhold = false; analogWrite(xoutpin, xout); }
      else if (clock == false) {xhold = true;}
    
  }

But I don't know, that's maybe not what you meant. Do you think you could enlighten me? Thank you so much for time really!

I find it very difficult to follow what your holding and locking variables do so I'm not going to try to explain in terms of your code.

What I suggest you do is define a global variable for each parameter that you want to be able to 'hold', and update that variable with the current value each time you discover that the value is being held. When the conditions change so that the 'hold' ends, this variable now stores the last held value.

There probably are more elegant ways to solve the problem by changing the logic in your code so that the running values are not overwritten while they're applicable, but I don't follow your code well enough to tell you how to do that (and I'm not inclined to put in the time to figure out how).

Alright, hey I think I got it now in a short ‘Eureka’ moment yesterday. I don’t have the facilities to try it out right now but I will let you know, if I have success. I think I understood now what you want to tell me.
Thanks.