Latched switch with delay

Hi all,
I'm just trying to work out some simple ideas before I get stuck into my first major Arduino project.

Starting out building a device that will monitor the state of a swtich;
if this switch is pressed, it will turn an output on;
once the switch is released, it will turn the output back off after a settable delay period.
if the switch is held down, the output is on, and the delay isn't triggered until the switch is released.

My first attempt at this is as follows;

const int ledPin =  13;      // LED mirrors output for visual testing purposes
const int buttonpin = 22;    // input from trigger switch
const int tbrakepin = 24;    // output 
int setting = 750;           // delay setting in milliseconds
int buttonstate = 0;          // is button depressed?

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode (buttonpin, INPUT);
  pinMode (tbrakepin, OUTPUT);
  digitalWrite (buttonpin, HIGH);
}

void loop()
{
  buttonstate = digitalRead(buttonpin);
  if (buttonstate == LOW) {
    digitalWrite (tbrakepin, HIGH);
    digitalWrite (ledPin, HIGH);
    buttonstate = digitalRead(buttonpin);
    if (buttonstate == HIGH) {
      delay(setting);
      digitalWrite (tbrakepin, LOW);
      digitalWrite (ledPin, LOW);
      delay(3000);
  }
}
}

I am still waiting on my Arduino board to get here to test it live, but does that look like it would work?
(The 3 second delay at the end is to prevent the re-activation of the output for a period as a protection for the device the output is driving)

I am still waiting on my Arduino board to get here to test it live, but does that look like it would work?
(The 3 second delay at the end is to prevent the re-activation of the output for a period as a protection for the device the output is driving)

Make a copy of the reference page. Use FrontPage or suitable html editor and remove the entry for delay(). Forget that it even exists.

Look at the blink without delay example to learn how to get along (better) without it.

You need two switch states - one for what the state is this time through loop(), and one for what the state was last time through loop().

That will allow you to detect transitions - the switch was not pressed but now is or the switch is not pressed but was.

Knowing whether this pass through loop represents a transition (from pressed to released or from released to pressed) will allow you to determine and handle the "not pressed", "just pressed", "still pressed", and "just released" states.

The states, along with the time that a state change occurred, and the current time are what you need to make this project work correctly.

Please, learn these concepts from the beginning. Then, you won't need to come back here and say stuff like "How do I do two things at once" or "I have to press my switch too many times to make stuff happen" or "How do I interrupt a delay".

PaulS:

I am still waiting on my Arduino board to get here to test it live, but does that look like it would work?
(The 3 second delay at the end is to prevent the re-activation of the output for a period as a protection for the device the output is driving)

Make a copy of the reference page. Use FrontPage or suitable html editor and remove the entry for delay(). Forget that it even exists.

Look at the blink without delay example to learn how to get along (better) without it.

You need two switch states - one for what the state is this time through loop(), and one for what the state was last time through loop().

That will allow you to detect transitions - the switch was not pressed but now is or the switch is not pressed but was.

Knowing whether this pass through loop represents a transition (from pressed to released or from released to pressed) will allow you to determine and handle the "not pressed", "just pressed", "still pressed", and "just released" states.

The states, along with the time that a state change occurred, and the current time are what you need to make this project work correctly.

Please, learn these concepts from the beginning. Then, you won't need to come back here and say stuff like "How do I do two things at once" or "I have to press my switch too many times to make stuff happen" or "How do I interrupt a delay".

Thanks!
That was my hope; to learn how to do it properly.
I see straight away the delay() is no good at all; whilever it's counting, nothing else will happen.

I'll study some more on the 'blinkwithoutdelay' example and see if i can use it in my situation.
Cheers!

OK;

const int ledpin =  13;      // LED mirrors output for visual testing purposes
const int buttonpin = 22;    // input from trigger switch
const int tbrakepin = 24;    // output to transbrake
int setting = 750;           // delay setting in milliseconds
int buttonstate = 0;         // current button state
int lastbuttonstate = HIGH;  // last button state

void setup() {
  pinMode(ledpin, OUTPUT);
  pinMode (buttonpin, INPUT);
  pinMode (tbrakepin, OUTPUT);
  digitalWrite (buttonpin, HIGH);
}

void loop()
{
 buttonstate = digitalRead(buttonpin);
  if (buttonstate == LOW && lastbuttonstate == HIGH) {
    digitalWrite(ledpin, HIGH);
    digitalWrite (tbrakepin, HIGH);
    lastbuttonstate = LOW;

That's my first test. .
"if the button wasn't pushed before, and now it is, then turn the output on".
Is that on the right track??

Not sure where to go after that though? I'm stuck on the release button one;
"button was pushed before, and now it's not, so wait 'interval' milliseconds then turn the output off, unless the button is pushed again in that time, in which case, just continue with the output on.

I like similar variables to have names that are distinguishable but similar. I would use currState and prevState. Same length, same format, but clearly different uses.

The previous button state should be set at the end of loop() to match the current state, regardless of whether the current state is HIGH, LOW, or blown up.

While we're on the subject of good habits to develop, buttons are for keeping shirts from flapping in the breeze. Switches are for controlling the flow of electrons. There are very few times one would reasonable connect a button to an Arduino pin, but there are lots of uses for switches connected to Arduino pins. (A pet peeve of mine...)

camelCase or PascalCase variables names are a good idea, too.

void loop()
{
  currState = digitalRead(switchPin);
  if(currState != prevState) // a transition has occurred
  {
    if(currState == LOW)
    {
       // switch is now pressed...
    }
  }
  prevState = currState;
}

See also my new Timer library as a way of avoiding the dreaded 'delay()'.

A physical switch won't behave as nicely as you would like - search the forum for debounce to get some examples of how to handle it.

A physical switch won't behave as nicely as you would like - search the forum for debounce to get some examples of how to handle it.

One step at a time...

Is this getting somewhere close??

const int ledpin =  13;          // LED mirrors output for visual testing purposes
const int switchpin = 22;        // input from trigger switch
const int tbrakepin = 24;        // output to transbrake
int setting = 750;               // delay setting in milliseconds
int currState = 0;               // current switch state
int prevState = HIGH;            // last switch state
unsigned long releasemillis = 0;          // value to store release point

void setup() {
  pinMode(ledpin, OUTPUT);
  pinMode (switchpin, INPUT);
  pinMode (tbrakepin, OUTPUT);
  digitalWrite (switchpin, HIGH);
}

void loop() {
  currState = digitalRead(switchpin);
  if(currState != prevState); // there has been a change
  {
    if(currState == LOW); // switch has been pressed
    {
      digitalWrite (ledpin, HIGH);
      digitalWrite (tbrakepin, HIGH); // activate output
    }
    if(currState == HIGH); // switch has been released after having been activated
    {
      releasemillis = millis();
    }
  }
  if(millis() - releasemillis >= setting);
  {
    digitalWrite (ledpin, LOW);
    digitalWrite (tbrakepin, LOW);
  }
  prevState = currState;

}

Thanks for the help. . hopefully I'll start to get a handle on this stuff soon!! :blush:

Looks OK to me.

However as someone else said, bounces will annoy you.

Added a reset of releasemillis to the 'switch pressed' routine. .
My attempt is to re-set the count and hold the output high if the switch is released but then re-pressed before the timer elapses. . the idea is if the operater releases but then re-presses the switch, nothing should happen to the outputs; they remain high and the counter doesn't start until the switch is released again.
Does that look like this??

const int ledpin =  13;              // LED mirrors output for visual testing purposes
const int switchpin = 22;            // input from trigger switch
const int tbrakepin = 24;            // output to transbrake
int setting = 750;                   // delay setting in milliseconds
int currState = 0;                   // current switch state
int prevState = HIGH;                // last switch state
unsigned long releasemillis = 0;     // value to store release point
unsigned long lockoutmillis = 0;     // value to store time to lockout re-activation

void setup() {
  pinMode(ledpin, OUTPUT);
  pinMode (switchpin, INPUT);
  pinMode (tbrakepin, OUTPUT);
  digitalWrite (switchpin, HIGH);
}

void loop() {
  currState = digitalRead(switchpin);
  if(currState != prevState);             // there has been a change
  {
    if(currState == LOW);                 // switch has been pressed
    {
      digitalWrite (ledpin, HIGH);
      digitalWrite (tbrakepin, HIGH);     // activate outputs
      releasemillis = 0;
    }
    if(currState == HIGH);                // switch has been released after having been activated
    {
      releasemillis = millis();           // store the current time
    }
  }
  if(millis() - releasemillis >= setting); // has the delay period elapsed?
  {
    digitalWrite (ledpin, LOW);
    digitalWrite (tbrakepin, LOW);        // turn outputs off
  }
  prevState = currState;

}

If the code is functionally right, my next issue is the debounce. How is that achieved?

Attempted added debounce;
is this close??

const int ledpin =  13;              // LED mirrors output for visual testing purposes
const int switchpin = 22;            // input from trigger switch
const int tbrakepin = 24;            // output to transbrake
int setting = 750;                   // delay setting in milliseconds
int currState = 0;                   // current switch state
int prevState = HIGH;                // last switch state
unsigned long releasemillis = 0;     // value to store release point
unsigned long debouncemillis = 50;   // debounce time in milliseconds
unsigned long lastdebouncetime = 0;  // last time debounce was true

void setup() {
  pinMode(ledpin, OUTPUT);
  pinMode (switchpin, INPUT);
  pinMode (tbrakepin, OUTPUT);
  digitalWrite (switchpin, HIGH);
}

void loop() {
  int reading = digitalRead(switchpin);
  if(reading != prevState) {
    lastdebouncetime = millis();
  }

  if((millis() - lastdebouncetime) > debouncemillis) {
    currState = reading;
  }

  // currState = digitalRead(switchpin); //commented out when added debounce
  if(currState != prevState);             // there has been a change
  {
    if(currState == LOW);                 // switch has been pressed
    {
      digitalWrite (ledpin, HIGH);
      digitalWrite (tbrakepin, HIGH);     // activate outputs
      releasemillis = 0;
    }
    if(currState == HIGH);                // switch has been released after having been activated
    {
      releasemillis = millis();           // store the current time
    }
  }
  if((millis() - releasemillis) >= setting); // has the delay period elapsed?
  {
    digitalWrite (ledpin, LOW);
    digitalWrite (tbrakepin, LOW);        // turn outputs off
  }
  prevState = currState;

}

Er, maybe. Perhaps you could test? My recent debounce looked like this:

const int debounceTime = 20;  // debounce in milliseconds

void deBounce ()
{
  unsigned long now = millis ();
  do
  {
    // on bounce, reset time-out
    if (digitalRead (buttonPin) == LOW)
      now = millis ();
  } 
  while (digitalRead (buttonPin) == LOW ||
    (millis () - now) <= debounceTime);

}  // end of deBounce

The objective here is to wait for 20 milliseconds after the last time the pin high (low being a press).