How to reset time delay for "If.. " statement after first loop

My problem is -
I have two if statements, simply put – if touch is detected → execute “A” ( light LED & print “Disarm”)
– if no touch is detected >= 30 seconds → execute “B” (turn off LED and print “Arm”)

The code works fine for the first run, but after “B” is executed, the timing doesn’t restart, so “A” only executes while the sensor is high (as opposed to high & for 30 seconds after) … which also means that “B” immediately executes after without waiting 30 seconds.
I want there to be a 30-second delay after the sensor goes low before “B” becomes true, every time

I have tried searching here and Google, and I’ve tried incorporating “while” as well as using millis() (which was a good thing to learn about) and state changes, but I end up with the same problem.

Basically, what I’m asking is, how do I reset the time for an if statement after the first loop/after “A” becomes true again?

I have a feeling this involves defining the time period (30 seconds) and using it rather than using millis(), but I’m unsure how to implement it and when I search, I either find people looking to do the opposite of what I’m doing, or not related to time resets.

int ledPin = 13;                // Connect LED on pin 13, or use the onboard one
int KEY = 2;                 // Connect Touch sensor on Digital Pin 2
// int buttonState = 0;
//int lastState = 0;
//int currentState = 0;
unsigned long currentMillis = 0;


void setup() {
  // put your setup code here, to run once:
  pinMode(ledPin, OUTPUT);      // Set ledPin to output mode
  pinMode(KEY, INPUT);       //Set touch sensor pin to input mode
  Serial.begin(9600);
}
const unsigned long event_1 = 30000;


void loop() {


  currentMillis = millis();
  // int buttonState = digitalRead(KEY); //tried using state changes, same result


  // put your main code here, to run repeatedly:
  if (digitalRead(KEY) == HIGH)  //if touch detected:
  { digitalWrite(ledPin, LOW);   
    Serial.println("Hand is on bar, disarm");        //print "disarm" when touch is detected
    while (digitalRead(KEY) == HIGH);
  }


  if (digitalRead(KEY) == LOW && millis() >= event_1)  //if no touch detected & 30 seconds pass:
  { digitalWrite(ledPin, HIGH);    // LED
    Serial.println("No touch detected for 30 seconds, ARM alarm");  //print "arm" on serial monitor
    while (digitalRead(KEY) == LOW);
  }
}

You could try it like this… (Using libraries) You’ll need LC_baseTools from the library manager to compile it.

#include <mechButton.h>

#define LED_PIN   13

mechButton  ourButton(2);
timeObj     ourTimer(3000,false);

void setup() {
   
   Serial.begin(57600);                // Fire up our serial monitor thing.
   pinMode(LED_PIN,OUTPUT);            // Set up the LED pin for output.
   digitalWrite(LED_PIN,LOW);          // LED Off.
   ourButton.setCallback(buttonClick);   // Set up our callback. (Also calls hookup() for idling.)
}


void buttonClick(void) {

   if (!ourButton.trueFalse()) {       // If the button was grounded.. (clicked)
      digitalWrite(LED_PIN,HIGH);      // LED on.
      Serial.println("Disarm");        // Say it..
      ourTimer.start();                // Start our timer.
   }    
}


void loop(void) {
   
   idle();                       // Let backgorund things do their thing.
   if (ourTimer.ding()) {        // If the timer has expired..
      digitalWrite(LED_PIN,LOW); // LED Off.
      Serial.println("Arm");    // Say it.
      ourTimer.reset();         // Reset the timer.
   }
}

-jim lee

jimLee:
You could try it like this… (Using libraries) You’ll need LC_baseTools from the library manager to compile it.

#include <mechButton.h>

#define LED_PIN   13

mechButton  ourButton(2);
timeObj     ourTimer(3000,false);

void setup() {
 
  Serial.begin(57600);                // Fire up our serial monitor thing.
  pinMode(LED_PIN,OUTPUT);            // Set up the LED pin for output.
  digitalWrite(LED_PIN,LOW);          // LED Off.
  ourButton.setCallback(buttonClick);   // Set up our callback. (Also calls hookup() for idling.)
}

void buttonClick(void) {

if (!ourButton.trueFalse()) {       // If the button was grounded… (clicked)
     digitalWrite(LED_PIN,HIGH);      // LED on.
     Serial.println(“Disarm”);        // Say it…
     ourTimer.start();                // Start our timer.
  }    
}

void loop(void) {
 
  idle();                       // Let backgorund things do their thing.
  if (ourTimer.ding()) {        // If the timer has expired…
     digitalWrite(LED_PIN,LOW); // LED Off.
     Serial.println(“Arm”);    // Say it.
     ourTimer.reset();         // Reset the timer.
  }
}




-jim lee

Thanks, that actually works exactly as I intended.
I see that the mechbutton class uses debouncing, which I thought may be the key to doing this properly. Thanks for the suggestion (and creating it! It looks like a very useful library to have).

Cool! You are very welcome!

-jim lee

The traditional way to re-start a timer is:

  if (digitalRead(KEY) == HIGH)  //if touch detected:
  {
    TimeOfLastTouch = millis();  //  Start the timer
    digitalWrite(ledPin, LOW);
    Serial.println("Hand is on bar, disarm");        //print "disarm" when touch is detected
    while (digitalRead(KEY) == HIGH);
  }


  if (digitalRead(KEY) == LOW && millis() - TimeOfLastTouch >= event_1)  //if no touch detected & 30 seconds pass:
  {
    digitalWrite(ledPin, HIGH);    // LED
    Serial.println("No touch detected for 30 seconds, ARM alarm");  //print "arm" on serial monitor
    while (digitalRead(KEY) == LOW);
  }

Make 'TimeOfLastTouch' a global 'unsigned long' varaible.

johnwasser:
The traditional way to re-start a timer is:

  if (digitalRead(KEY) == HIGH)  //if touch detected:

{
    TimeOfLastTouch = millis();  //  Start the timer
    digitalWrite(ledPin, LOW);
    Serial.println(“Hand is on bar, disarm”);        //print “disarm” when touch is detected
    while (digitalRead(KEY) == HIGH);
  }

if (digitalRead(KEY) == LOW && millis() - TimeOfLastTouch >= event_1)  //if no touch detected & 30 seconds pass:
  {
    digitalWrite(ledPin, HIGH);    // LED
    Serial.println(“No touch detected for 30 seconds, ARM alarm”);  //print “arm” on serial monitor
    while (digitalRead(KEY) == LOW);
  }





Make 'TimeOfLastTouch' a global 'unsigned long' varaible.

That might work differently than intended. You’re capturing the time before the blocking wait for disarming, so if you hold the bar for 30 seconds then release it, the alarm will be armed immediately. If you want to arm 30 seconds after release, you need to grab the time after the blocking while loop.

My How to write Timers and Delays in Arduino tutorial, has a millisDelay class that has start(), stop(), restart() methods that could be useful here.

Jiggy-Ninja:

Quote from: Jiggy-Ninja
That might work differently than intended. You're capturing the time before the blocking wait for disarming, so if you hold the bar for 30 seconds then release it, the alarm will be armed immediately. If you want to arm 30 seconds after release, you need to grab the time after the blocking while loop.

You're right. I just noticed that myself. Move the line down a bit:

  if (digitalRead(KEY) == HIGH)  //if touch detected:
  {
    digitalWrite(ledPin, LOW);
    Serial.println("Hand is on bar, disarm");        //print "disarm" when touch is detected
    while (digitalRead(KEY) == HIGH);
    TimeOfLastTouch = millis();  //  Start the timer
  }