Button pressed for more than x seconds

Hi guys,

I am currently programming a water level sensor which is a trigger switch for when the water reaches a certain level.

In my code i want to add a delay that will only register the switches action if its been HIGH or LOW for 10 consecutive seconds. (e.g if its been high for 8 seconds then goes low... do nothing).

I've tried a few methods from other forum posts but i havent been able to make it work..

Could someone please help me?

my current code simply stops the program once it detects a rising or falling edge but this doesnt work well since the surface of the water is very wavy.

const int inPin = 2;
const int outPin =  3;
int potPin = 2;    // select the input pin for the potentiometer
long val = 0;       // variable to store the value coming from the sensor
int limitState = 0;
int limitStateOld = 0;



void setup() {
  // initialize the LED pin as an output:
  pinMode(outPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(inPin, INPUT);
  digitalWrite(inPin, LOW);
  limitStateOld = limitState;
  Serial.begin(9600);
}

void loop() {
  val = analogRead(potPin);
  val = map(val, 0, 1023, 10, 120);
  Serial.print(val);

  limitState = digitalRead(inPin);

  if (limitStateOld != limitState)
  {
    if ((limitState == HIGH) && (limitStateOld == LOW))
    {
      Serial.print("Rising Edge Detected");
      Serial.print(val * 1000);
      delay(val * 1000);
      limitStateOld = limitState;
    }
    if ((limitState == LOW) && (limitStateOld == HIGH))
    {
      Serial.print("Falling Edge Detected");
      delay(10000);
      limitStateOld = limitState;
    }
  }

  if (limitState == HIGH)
  {
    digitalWrite(outPin, HIGH);
  }
  else
  {
    digitalWrite(outPin, LOW);
  }
  limitStateOld = limitState;
}

Op's image:

In my code i want to add a delay that will only register the switches action if its been HIGH or LOW for 10 consecutive seconds. (e.g if its been high for 8 seconds then goes low... do nothing).

Save the value of millis() to a variable as the start time when the input changes state. Each time through loop() check whether 10 seconds has elapsed by subtracting the start time from the current time. If 10 seconds has elapsed take the action that you want. You may want to introduce a boolean flag indicating that the action has occurred to prevent it happening again

Pseudo code:

void setup()
{
  //Serial.begin(9600);
}
void loop()
{
  static unsigned long timeKeeper = 0, timeout = 10000; // 10 sec
  unsigned long timing = millis() - timeKeeper;
  if(level < maxLevel)
  {
    timeKeeper = millis(); // resets timing
  }
  if(timing >= timeout) // timing is longer than 10 seconds
  {
    action = true;
  }
}

How is your switch wired?

Does your switch close or open when the water is at the trigger level ?

// Version    YY/MM/DD
//  1.00      20/04/01   Running code

#define TriggerState     LOW  // <------<<<<< HIGH or LOW as needed  N  O  T  E

//***********************************************************************
const byte inPin        = 2;
const byte outPin       = 3;
const byte heartbeatLED = 13;

const byte potPin       = A2;   //select the input pin for the potentiometer

byte limitState         = 0;
byte limitStateOld      = 0;

bool triggerFlag        = false;

//timing stuff
unsigned long heartbeatMillis;
unsigned long switchMillis;
unsigned long triggerMillis;

unsigned long triggerInterval;


//***********************************************************************
void setup()
{
  Serial.begin(9600);

  pinMode(heartbeatLED, OUTPUT);

  //initialize the LED pin as an output:
  pinMode(outPin, OUTPUT);

  //initialize the pushbutton pin as an input:
  pinMode(inPin, INPUT);

} //END of setup()

//***********************************************************************
void loop()
{
  //**************************
  //heartbeat LED will toggle as long as the sketch is non blocking
  if (millis() - heartbeatMillis >= 200)
  {
    //restart timer
    heartbeatMillis = millis();

    //toggle LED
    digitalWrite(heartbeatLED , !digitalRead(heartbeatLED));

  }

  //**************************
  //time to check our switches ?
  if (millis() - switchMillis >= 50)
  {
    //restart timer
    switchMillis = millis();

    checkSwitches();

  }

  //**************************
  //if at trigger level, has the timer timed out ?
  if (triggerFlag == true && millis() - triggerMillis >= triggerInterval)
  {
    digitalWrite(outPin, HIGH);

  }


} //END of loop()

//***********************************************************************
void checkSwitches()
{
  //set timeout interval
  triggerInterval = analogRead(potPin);
  triggerInterval = map(triggerInterval, 0, 1023, 10, 120);
  triggerInterval = triggerInterval * 1000ul;

  limitState = digitalRead(inPin);

  //have we changed state ?
  if (limitStateOld != limitState)
  {
    //update to the new state
    limitStateOld = limitState;

    if (limitState == TriggerState)
    {
      Serial.print("Interval = ");
      Serial.println(triggerInterval);

      Serial.println("Rising Edge Detected");

      //allow trigger time checking
      triggerFlag = true;

      //reset timer
      triggerMillis = millis();
    }

    else
    {
      //disable alarm time checking
      triggerFlag = false;

      digitalWrite(outPin, LOW);
    }
  }

  //**************************

} //END of checkSwitches()

















































//April Fools Gift

larryd:
How is your switch wired?

Does your switch close or open when the water is at the trigger level ?

The switch closes when water reaches the trigger level.

Ill give that code a shot now and hopefully it works (fingers crossed :))) )

@larryd, i tested your code and it worked well! all thats left to do is perform a similar action for the falling edge.

I tried to give it a shot but frankly i dont fully understand how the code works, could you explain it to me in a little more detail please? I'm really interested to learn how it works rather than just use it :slight_smile:

What, line by line? It's already commented! Just find the first line you don't understand and ask about it specifically.

i dont understand the section pertaining to triggermillis and the if statement that sets outpin to be high.

You subtract trigger millis from millis however when you set the flag to be true you also equate trigger millis and millis so shouldnt the result be 0?

so shouldnt the result be 0?

Initially it will be but don't forget that millis() returns the number of milliseconds since power up or reset, but the value saved when triggered does not change. So the difference between the two will get greater as time passes and can be tested. Eventually it will equal or exceed the required timing period and the program can do something at that time

Isaac258:
In my code i want to add a delay that will only register the switches action if its been HIGH or LOW for 10 consecutive seconds. (e.g if its been high for 8 seconds then goes low... do nothing)

If you want to check that a switch has been LOW for a period use code like this (which may seem upside-down at first glance)

switchState = digitalRead(switchPin);
if (switchState == HIGH) {
   lastTimeSwitchWasHigh = millis();
}

if (millis() - lastTimeSwitchWasHigh >= period) {
   // switch was LOW throughout the period
}

You can do the same sort of thing to check for a period when it is HIGH

...R