1

The code below is used for controlling a relay with an Arduino. Pressing the touch sensor connects and disconnects the relay.

If the user presses/touches/holds their finger on the touch sensor for longer than two seconds, how do I adjust the program to do something other than connecting or disconnecting the relay?

#define TouchSensor 9 // Pin for capactitive touch sensor

int relay = 2; 

boolean currentState = LOW;
boolean lastState = LOW;
boolean RelayState = LOW;

void setup() {
  Serial.begin(9600);
  pinMode(relay, OUTPUT);  
  pinMode(TouchSensor, INPUT);
}

void loop() {
  currentState = digitalRead(TouchSensor);
    if (currentState == HIGH && lastState == LOW){
    Serial.println("pressed");
    delay(1);

    if (RelayState == HIGH){
      digitalWrite(relay, LOW);
      RelayState = LOW;
    } else {
      digitalWrite(relay, HIGH);
      RelayState = HIGH;
    }
  }
  lastState = currentState;
}
1

You have to determine, how long a the sensor was pressed until released. When it is released you can take the corresponding steps. If the press was shorter than say 1.5s, you can switch the relay. Else you can do something else.

There are many ways to achieve this. You can program it yourself by using the millis() function. You would have to set a timestamp, when the state of the sensor changes to high, then wait for it to go low and substract the timestamp from the current value of millis(). This would give you the duration of press, which you can use in a corresponding if-statement.

Or you can use the Debounce library for it, which makes it a bit simpler (not a lot, but you should consider debouncing depending on the type of sensor you use). Look at the answer from VE7JRO to this question. The debouncer.update() function checks, if the state of the button changed. If so and the value was LOW (in your case this would has to be changed to HIGH), a timestamp is set with the value of millis(). When an update with LOW occurs, the time difference between the two events is calculated and the corresponding action are taken. I will add the code from the answer for reference here:

// Connect one end of a N.O. push button switch to GND and the other
// end to pin 4 of the Arduino.
// NOTE: If the button is held down for less than the debounce delay
//       time, the elapsed time will display the debounce delay time.
#include <Debounce.h>
const byte SWITCH = 4;
unsigned long startTime = 0;
unsigned long endTime = 0;
unsigned long elapsedTime = 0;
const byte debounceDelayTime = 50;

Debounce debouncer = Debounce(debounceDelayTime, SWITCH);

void setup(){
  Serial.begin(9600);
  pinMode(SWITCH, INPUT_PULLUP);
}

void loop(){
  if(debouncer.update()){
    if(debouncer.read() == 0){
      startTime = millis();
      Serial.println("Button Pressed");
    }
    else if(debouncer.read() == 1){
      endTime = millis();
      Serial.println("Button Released");
      elapsedTime = endTime - startTime;
      Serial.print("Button Held Down For ");
      Serial.print(elapsedTime);
      Serial.println(" ms.");
    }
  }
}
1

This sketch uses a millis() timer to add the concept of time to debouncing a button with the Bounce2 Library, (This library may be included with the current version of the Arduino IDE). This sketch does not contain any code to turn a relay on and off.

// Connect one end of a N.O. push button switch to GND
// and the other end to pin 4 of the Arduino.
#include <Bounce2.h>

byte buttonState = 0;
byte lastButtonState = 0;
const byte buttonPin = 4;
const byte debouncerInterval = 50;         // Time in ms.
unsigned long buttonHeldThreshold = 2000;  // Time in ms.
unsigned long buttonPressTimeStamp;

Bounce debouncer = Bounce();

void setup(){
  Serial.begin(9600);
  pinMode(buttonPin, INPUT_PULLUP);
  debouncer.attach(buttonPin);
  debouncer.interval(debouncerInterval);
}

void loop(){

  if(debouncer.update()){

    if(debouncer.read() == 0){
      buttonState = 1;
      buttonPressTimeStamp = millis();
      Serial.println("Button Pressed");
    }
    else if(debouncer.read() == 1){
      buttonState = 0;
      Serial.println("Button Released");
    }
  }

  if(buttonState == 1){
    if(millis() - buttonPressTimeStamp >= buttonHeldThreshold){
      buttonState = 2;
      Serial.println("Button Held for 2+ seconds");
    }
  }

  // Print out the contents of the buttonState variable only when it changes.
  if(buttonState != lastButtonState){
    Serial.print("Button state = ");
    Serial.println(buttonState);
    Serial.println();
    lastButtonState = buttonState;
  }
}

Keep in mind that this library has debouncer.rose() and debouncer.fell() functions that may be helpful to you. It's always a good idea to look at the *.h and *.cpp files in the libraries you install. There may be several functions that are not demonstrated in the library's examples. Sometimes the author(s) use code comments in the library which can help you to trouble shoot any issues that may arise.

1

For this kind of scenario "activation" of the button is never done when it is pressed. Yes, under "normal" circumstances you press a button, a circuit is made, and something happens.

However, if you need more than just that simple operation you never do anything just when it's pressed.

For example, if you click on a link on a web page, nothing really happens when you press the mouse button. Yes, the link is "selected", but that's all. Nothing active happens until you release the mouse button. It's the act of "press-then-release" that constitutes a "click" - and then only if the release happens within a certain time after the press.

That allows such other options to happen, such as "press-drag-release" for drag and drop, or "press-wait-release" for selecting without activating, etc.

So for your scenario you have two desired "triggering" options:

  • press-release
  • press-hold

As long as the "release" of the "press-release" happens in a shorter time than the "hold" time of the "press-hold" you can differentiate between them.

So your methodology would look something like this:

  • Button pressed - record the time
  • Either:
    • Button released and time elapsed < 2 seconds, or
    • Time elapsed >= 2 seconds

As code that may look something along the lines of:

static uint32_t ts = 0;
static uint8_t buttonState = HIGH;

uint8_t buttonValue = digitalRead(ButtonPin);

if (buttonValue != buttonState) { // The state has changed. 
    buttonState = buttonValue; // Record it
    if (buttonState == LOW) { // Button has been pressed
        ts = millis(); // Record the time
    } else if (ts > 0) { // Released - ts must have been set by a press
        if (millis() - ts < 2000) { // Less than 2 seconds have passed
            // Run your "press" routine
            ts = 0; // Clear our time stamp.
        }
    }
} else if (ts > 0) { // It hasn't changed state, but was pressed
    if (buttonState == LOW) { // It's held in. Not strictly necessary but can't hurt
        if (millis() - ts >= 2000) { // 2 seconds have passed
            // Run your "hold" routine
            ts = 0; // Clear our time stamp.
        }
    }
}

The time stamp variable ts is both used to record the time the button was pressed and also as a flag to indicate that we are currently in an "unactivated" state. That is, for the "held" state to indicate whether or not we still need to run our "held" routine or not. Without that check, after 2 seconds of holding the button the "held" routine would keep running over and over and over again until the button is released. It's kind of like implementing a "forced" release of the button after it has triggered the "held" routine. After that first triggering of "held" we no longer care what is done with the button. We ignore everything until the next time it is pressed when we set ts again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.