Delay an action, while waiting for another input

Hi, I have a question..
I have a push button, and I now have it doing 3 different things depending on the number of times pressed, it does have to perform every action one by one though..

So I was thinking, is it possible to do a delay while at the same time waiting for another input? And if the button get's pressed again, it performs a return?

Can I use millis() for that instead of delay?

You need a variable (or maybe more than 1) to keep track of the state of the system. Maybe the variable could hold values 1 or 2 or 3 to reflect 3 different states.

Then some action can be allowed to happen only if (say) the state is 3 - something like

void doSomething() {
   if (systemState == 3) {
      // code to do stuff
   }
}

The value in the variable systemState might be updated for each press of the button.

You should also look at the demo Several Things at a Time

...R
Edit to add (following Reply #1) - under no circumstances use the delay() function. I had inferred from your Original Post that you were using the word "delay" in the sense of "wait" for an indefinite period while other things continued.

Robin2:
You need a variable (or maybe more than 1) to keep track of the state of the system. Maybe the variable could hold values 1 or 2 or 3 to reflect 3 different states.

Then some action can be allowed to happen only if (say) the state is 3 - something like

void doSomething() {

if (systemState == 3) {
     // code to do stuff
  }
}




The value in the variable systemState might be updated for each press of the button.

You should also look at the demo [Several Things at a Time](http://forum.arduino.cc/index.php?topic=223286.0)

...R
Edit to add (following Reply #1) - under no circumstances use the delay() function. I had inferred from your Original Post that you were using the word "delay" in the sense of "wait" for an indefinite period while other things continued.

What I have so far is this, but it’s not really working…
Any ideas on what I’m missing or doing wrong? I can’t figure it out

#include <KEY.h>

const int pin = 2;
int count = 0;
int state = 0;
int last = 0;
int skip = 0;
int time = 0;
int interval = 2000;

void setup(){
 pinMode(pin, INPUT_PULLUP);
}

void loop(){
 state = digitalRead(pin);
 if (state != last){
   if (state == LOW){
     time = millis();
     count++;
   }
   delay(50);
 }
 last = state;

while (time + interval < millis()){
 if(digitalRead(pin) == LOW){
   count++;
 }
 delay(50);
}

 if (count == 1 && skip < 1) {
   KEY.delay(300);
   KEY.Stroke(r, GUI);
   KEY.delay(1500);
   KEY.print("cmd");
   KEY.delay(300);
   KEY.Stroke(ENTER);
   KEY.delay(3000);
   KEY.print("mkdir C:\Once")
   KEY.Stroke(ENTER);
   KEY.delay(1500);
   KEY.print("exit");
   KEY.Stroke(ENTER);
 }

 if (count == 2 && skip < 2) {
   KEY.delay(300);
   KEY.Stroke(r, GUI);
   KEY.delay(1500);
   KEY.print("cmd");
   KEY.delay(300);
   KEY.Stroke(ENTER);
   KEY.delay(3000);
   KEY.print("mkdir C:\Twice")
   KEY.Stroke(ENTER);
   KEY.delay(1500);
   KEY.print("exit");
   KEY.Stroke(ENTER);
   return;
 }
 }

I’m gonna read up on that topic you mentioned now

What I have so far is this, but it's not really working..

It does something. You failed to say what it does.

You expect it to do something. You failed to say what you expect.

"It doesn't work" is the lamest possible thing you can say here.

PaulS:
It does something. You failed to say what it does.

You expect it to do something. You failed to say what you expect.

“It doesn’t work” is the lamest possible thing you can say here.

Ah okay, well this code I had at first works fine if I just leave it as I had it, so waiting for the second buttonpress after the first action (if the button has been pressed once) is finished, like this:

#include <KEY.h>

const int pin = 2;
int count = 0;
int state = 0;
int last = 0;
int skip = 0;

void setup(){
 pinMode(pin, INPUT_PULLUP);
}

void(* resetFunc) (void) = 0;

void loop(){
 state = digitalRead(pin);
 if (state != last){
   if (state == LOW){
     time = millis();
     count++;
   }
   delay(50);
 }
 last = state;


 if (count == 1 && skip < 1) {
   KEY.delay(300);
   KEY.Stroke(r, GUI);
   KEY.delay(1500);
   KEY.print("cmd");
   KEY.delay(300);
   KEY.Stroke(ENTER);
   KEY.delay(3000);
   KEY.print("mkdir C:\Once")
   KEY.Stroke(ENTER);
   KEY.delay(1500);
   KEY.print("exit");
   KEY.Stroke(ENTER);
 }

 if (count == 2 && skip < 2) {
   KEY.delay(300);
   KEY.Stroke(r, GUI);
   KEY.delay(1500);
   KEY.print("cmd");
   KEY.delay(300);
   KEY.Stroke(ENTER);
   KEY.delay(3000);
   KEY.print("mkdir C:\Twice")
   KEY.Stroke(ENTER);
   KEY.delay(1500);
   KEY.print("exit");
   KEY.Stroke(ENTER);
   resetFunc();

 }
 }

However the thing I had in mind, was using millis() in a while loop to compare how much time has passed since the first buttonpress, and wait for a second buttonpress within that time, to then skip the first action if the second buttonpress occurs.
What I had in mind though for that, doesn’t work, if I then push the button once or twice (doesn’t matter), is doesn’t do anything at all, performs no actions at all…
Like this:

#include <KEY.h>

const int pin = 2;
int count = 0;
int state = 0;
int last = 0;
int skip = 0;
int time = 0;
int interval = 2000;

void setup(){
 pinMode(pin, INPUT_PULLUP);
}

void(* resetFunc) (void) = 0;

void loop(){
 state = digitalRead(pin);
 if (state != last){
   if (state == LOW){
     time = millis();
     count++;
   }
   delay(50);
 }
 last = state;

while (time + interval < millis()){
 if(digitalRead(pin) == LOW){
   count++;
 }
 delay(50);
}

 if (count == 1 && skip < 1) {
   KEY.delay(300);
   KEY.Stroke(r, GUI);
   KEY.delay(1500);
   KEY.print("cmd");
   KEY.delay(300);
   KEY.Stroke(ENTER);
   KEY.delay(3000);
   KEY.print("mkdir C:\Once")
   KEY.Stroke(ENTER);
   KEY.delay(1500);
   KEY.print("exit");
   KEY.Stroke(ENTER);
 }

 if (count == 2 && skip < 2) {
   KEY.delay(300);
   KEY.Stroke(r, GUI);
   KEY.delay(1500);
   KEY.print("cmd");
   KEY.delay(300);
   KEY.Stroke(ENTER);
   KEY.delay(3000);
   KEY.print("mkdir C:\Twice")
   KEY.Stroke(ENTER);
   KEY.delay(1500);
   KEY.print("exit");
   KEY.Stroke(ENTER);
   resetFunc();

 }
 }

Get rid of resetFunc(), post a link to the KEY library, and explain what the code ACTUALLY does (adding Serial.print() statements as required, so you KNOW what it does), and we'll talk.

so you want to do something like this:

if pushed one, do function1
if pushed twice, do function1 then function2
if pushed thrice, do function1 then function2 then function3

is that right?

Lastofthetukkers:
However the thing I had in mind, was using millis() in a while loop to compare how much time has passed since the first buttonpress, and wait for a second buttonpress within that time, to then skip the first action if the second buttonpress occurs.

I don’t understand what you want to happen? Is it the case that you want to ignore the second button press if it does not happen within some period after the first button press?

You are using millis() all wrong. The last thing you want is a WHILE which blocks everything else.

You have a variable called “skip” with a value or 0 and in two different places you test if it <1 and <2 - well of course it will be. There seems to be no point in having the variable or those tests.

…R
PS. I wrote Reply #2 thinking that you wanted to do what @BulldogLowell describes in Reply #7. But the piece I have quoted here makes me think you want to do something different.

BulldogLowell:
so you want to do something like this:

if pushed one, do function1
if pushed twice, do function1 then function2
if pushed thrice, do function1 then function2 then function3

is that right?

Almost, I’m trying to get it to do this:
if pushed once, do function1
in pushed again (so twice) within 2000ms after the first push, skip function1 and go do function2

@PaulS The KEY library just kinda does the same thing as acting as a keyboard, a hid
Also removing the resetFunc() made no apparant difference, in the working state or non working state

@Robin2 No, I’m sorry if I’m having trouble explaining, what I meant was I want it to ignore the first function and go straight to the second function if the button has been pressed again within 2 seconds of the first press.
Which is why I have the skip variable, so that (which I thought at the time) if the button gets pressed again it will skip the first function, but it’s not working out so far

so try using this approach:

#include "SimplePress.h"

SimpleButton button1(7, 2000);          // two second capture for multi-presses; uses default 200ms debounce
//SimpleButton button2(8, 500, 300);   // or specify custom debounce time in ms

void setup() 
{
  Serial.begin(9600);
  button1.begin();
}

void loop() 
{
  if(int pressCount = button1.pressed())
  {
    switch(pressCount)
    {
      case 1:
        Serial.println("one Press");
        break;
      case 2:
        Serial.println("two Presses");
        break;
      case 3:
        Serial.println("three Press");
        break;
      default:
        Serial.println("invalid entry");
        break;
    }
  }
}

with this library called SimplePress.h in your sketch’s directory:

#ifndef SIMPLEPRESS_H
#define SIMPLEPRESS_H

#include <Arduino.h>

class SimpleButton{
  public:
    SimpleButton(int _pin, uint32_t _pressInterval, uint32_t _debouncePeriod = 200);
    bool begin();
    byte pressed();

  private:
    byte pressCount;
    byte lastState;
    byte pin;
    uint32_t lastMillis;
    uint32_t debouncePeriod;
    uint32_t pressInterval;
};

SimpleButton::SimpleButton(int _pin, uint32_t _pressInterval, uint32_t _debouncePeriod)
{
  pin = _pin;
  debouncePeriod = _debouncePeriod;
  pressInterval = _pressInterval;
}

bool SimpleButton::begin()
{
  pinMode(pin, INPUT_PULLUP);
  lastState = HIGH;
  return true;
}

byte SimpleButton::pressed()
{
  byte nowState = digitalRead(pin);
  if(nowState != lastState)
  {
    if(millis() - lastMillis < debouncePeriod) return false;
    if(nowState == LOW)
    {
      lastMillis = millis();
      pressCount++;
    }
  }
  if(pressCount != 0)
  {
    if(millis() - lastMillis > pressInterval)
    {
      int presses = pressCount;
      pressCount = 0;
      return presses;
    }
  }
  return 0;
}


#endif

you should be able to tell if something like this will work for you.

Lastofthetukkers:
@Robin2 No, I'm sorry if I'm having trouble explaining, what I meant was I want it to ignore the first function and go straight to the second function if the button has been pressed again within 2 seconds of the first press.

What I was hoping you would tell me is what you want to happen if the second button press happens after more than 2 seconds.

The impression I had from your Original Post (and as set out in Reply #7) was that the only thing that matters is the order of events, not their timing.

The suggestion I made in Reply #2 should deal with a succession of button presses where time is not relevant.

And time can only be relevant if something (which you have not yet specified) is to happen when the time is exceeded. When we know how the time should affect things we can suggest a solution.

...R