3 buttons with 5 functions... maybe?

I have three buttons - left, right, and pair.

I need when you press left something happens 3 seconds later I need when you press right something happens 3 seconds later I need when you press pair something happens 3 seconds later I have been implementing this through read button and then delay then trigger event. Simple even for me.

Bringing me to my next point. I also need if you press left then immediately right for it to trigger left action after 3 seconds and then right action after 3 more seconds (6 seconds total before right button action). Then visa versa for right the left.

Any suggestions on how to get the L>R or R>L feature?

Have you seen the Debounce example?
Maybe if you expanded on the Debounce example, Perhaps by adding a second timer when a button press is confirmed (debounced).
Just tossing out a loose idea here.

Mixing it with the debounce example:

long debounceDelay = 50;    // the debounce time; increase if the output flickers

int maxButtonPresses = 2; // double click (2 presses max).
unsigned long buttonTime[maxButtonPresses];  // Two presses to be debounced and timed after each other
unsigned long doubleClickTime = 200; // time limit to press another button 
int buttonPressNr = 0;
int doubleClick = 0; // flag to set if double clicked


void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // If no buttons were pressed within doubleClickTime, start a new cycle
  if (buttonTime[buttonPressNr] - millis() > doubleClickTime) buttonPressNr = 0;

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    buttonTime[buttonPressNr] = millis();
  } 

  if ((millis() -  buttonTime[buttonPressNr]) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
    if (buttonState)  // Assuming a press is logical high
    {
       buttonPressNr++; // Wait for next buttonpress
      // reset the debouncing timer
      buttonTime[buttonPressNr] = millis();
       if (buttonPressNr > maxButtonPresses) 
      {
         buttonPressNr = 0; // begin new cycle of button presses

         // Check for "doubleclick"
         if (buttonTime[1] - buttonTime[0] < doubleClickTime) doubleClick = 1; else doubleClick = 0; 
      }
    }
  }
  
 // Do something if doubleclicked
 if (doubleClick)
 {
  ...... some doubleclick action

 }

  // set the LED using the state of the button:
  digitalWrite(ledPin, buttonState);

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
}

Note: Untested code!
Note II: I haven’t slept for a long time, so I’m sure I made some basic errors…

Also, you would need to expand to cope for several buttons. Maybe simply letting the “reading” variable be a value depending on which button is pressed, adding up binary. 1,2,4, for the three buttons. Then check on the values which one is pressed, and you can add conditions for “doubleclicking” with different buttons after each other.

Again, just an idea I’m tossing out.

I just wanted to test my idea, and had to change it a little (of course) before it worked.

This is still not exactly what you are after though, you would have to expand for multiple buttons somehow. Also, there might be something in the playground regarding your use (I have a bad habit of not always checking the playground..).

Anyway, a simple double click code (3 functions for one button: on, off and blink). Shamelessly based on the Debounce example.

/* 
 Debounced Doubleclick

 Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
 press), the output pin is toggled from LOW to HIGH or HIGH to LOW.  There's
 a minimum delay between toggles to debounce the circuit (i.e. to ignore
 noise).

 If the input pin goes from LOW to HIGH twice within a set period, a
 doubleclick state is set.

 The circuit:
 * LED attached from pin 13 to ground
 * pushbutton attached from pin 2 to +5V
 * 10K resistor attached from pin 2 to ground

 * Note: On most Arduino boards, there is already an LED on the board
 connected to pin 13, so you don't need any extra components for this example.


 created 21 November 2006
 by David A. Mellis
 modified 3 Jul 2009
 by Limor Fried
 modified 22 May 2010
 by raron. Added doubleclick function.

 This example code is in the public domain.

 http://www.arduino.cc/en/Tutorial/Debounce
*/


// constants won't change
const int buttonPin = 2;           // the number of the pushbutton pin
const int maxButtonPresses = 2;    // no more than a double click (2 presses max).
const int ledPin =  13;            // the number of the LED pin


// Variables will change
int ledState = 0;                  // the current state of the output pin
int buttonState;                   // the current reading from the input pin
int lastButtonState = 0;           // the previous reading from the input pin
int buttonPressNr = 0;             // a counter that says which how many button presses has occurred.
int doubleClick = 0;               // used as a flag to set if double clicking occurred


// the following variables are long's because the time, measured in milliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;         // the last time the output pin was toggled
long debounceDelay = 20;           // the debounce time; increase if the output flickers
long doubleClickDelay = 500;       // time limit to double click



void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
}


void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  // If no buttons were pressed within doubleClickDelay miliseconds, start a new buttonpress cycle
  if ((millis() - lastDebounceTime) > doubleClickDelay) buttonPressNr = 0;

  // Check if a debounced, changed state has occured
  if ((millis() - lastDebounceTime) > debounceDelay && buttonState != lastButtonState) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
    
    // Check if the button is currently pressed down
    // Assuming the input is logical high, invert if not.
    if (buttonState) {
      // change the led state
      ledState++;
      if (ledState > 1) ledState = 0;
      // Wait for next buttonpress
      buttonPressNr++;
      // remove doubleclick state     
      doubleClick = 0;
      
      // Check to see if there has been multiple quick buttonpresses
      if (buttonPressNr >= maxButtonPresses) {
        // begin new cycle of button presses
        buttonPressNr = 0;
        // Set doubleclick state
        doubleClick = 1;
      }
    }
  }

  
  // Blink the led without delay() if doubleclicked
  if (doubleClick) ledState = (millis()/500)%2;

  // set the LED state
  digitalWrite(ledPin, ledState);

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
}

That might be able to do it. Will try it out tonight.

the double press works almost. This doesnt allow for instance release when wanting only one.
This is what I tried but doesnt work and cant find the error.

       if (buttL < buttthres){                 // if button one is low then button was pushed
         while (delayCounter<3000){   // instead of using the delay, using a rolling counter to allow checking on right button
           delayCounter++;                 // increment counter  
           if (buttR < buttthres)              // check if buttonRIGHT has been pressed
             Report_Pair_LR;                   // if buttonRIGHT has been pressed go to function REPORT_PAIR_RL
           }      
         delay(delayPull);                     // delay before activating trap
         ++count;
         digitalWrite(relayL, HIGH);           // turn the relay on
         delay(relayon);                       // hold relay on to make sure trap launches
         digitalWrite(relayL, LOW);            // turn the relay off
         timer = 0;                            // Reset sleep timer
      }

and the report pair subroutine is:

// ----------------------| REPORT PAIR R>L |------------------------------
void Report_Pair_RL(){
  delay (delayPull);                  // wait until time has passed for 
  digitalWrite(relayR, HIGH);         // turn on relayR
  delay(relayon);                     // leave relay on for "relayon" seconds
  digitalWrite(relayR, LOW);          // turn off relayR
  delay (3000);                  // wait again to release second target
  digitalWrite(relayL, HIGH);         // turn on relayL
  delay(relayon);                     // leave relay on for "relayon" seconds
  digitalWrite(relayL, LOW);          // turn off relayL
  ++++count;                          // increment counter twice since throwing two targets
  return;                             // go to beginning of main loop, NOT where the code left off
}// -------------------------------------------------------------------

return; // go to beginning of main loop, NOT where the code left off

This will not go to the beginning of the main loop, but exactly to were the code left off. So if it executes the Report_Pair_LR, it will then go on with the left button stuff afterwards. Besides, you don’t actually read the right button state in the loop?

One could set a variable as a flag that the Report_Pair_LR routine has run, for instance, and then skip the rest of the left button stuff:

       if (buttL < buttthres){                 // if button one is low then button was pushed
        boolean LR_flag = 0;                 // reset flag
         while (delayCounter<3000){   // instead of using the delay, using a rolling counter to allow checking on right button
           delayCounter++;                 // increment counter  
           buttR = digitalRead(buttonRPin);  // read right button state
           if (buttR < buttthres) {            // check if buttonRIGHT has been pressed
             Report_Pair_LR;                   // if buttonRIGHT has been pressed go to function REPORT_PAIR_RL
             LR_flag = TRUE;                      // set the flag that this is done
           }
           if (LR_flag) break;                // break out of the while loop
         }
         if (!LR_flag)  {                      // If NOT pressed right button right after left button
           delay(delayPull);                     // delay before activating trap
           ++count;
           digitalWrite(relayL, HIGH);           // turn the relay on
           delay(relayon);                       // hold relay on to make sure trap launches
           digitalWrite(relayL, LOW);            // turn the relay off
        }
        timer = 0;                            // Reset sleep timer
      }

Or something like that.

I thought the return statement sent the program to the beginning of the code.

// ----------------------| REPORT PAIR R>L |------------------------------
void Report_Pair_RL(){
  delay (delayPull);                  // wait until time has passed for
  digitalWrite(relayR, HIGH);         // turn on relayR
  delay(relayon);                     // leave relay on for "relayon" seconds
  digitalWrite(relayR, LOW);          // turn off relayR
  delay (3000);                  // wait again to release second target
  digitalWrite(relayL, HIGH);         // turn on relayL
  delay(relayon);                     // leave relay on for "relayon" seconds
  digitalWrite(relayL, LOW);          // turn off relayL
  ++++count;                          // increment counter twice since throwing two targets
  [glow]return;                             // go to beginning of main loop, NOT where the code left off[/glow]
}// -------------------------------------------------------------------

Am I miss using the return function?

The return statement is optional in a function with a return type of void. If not present, the end of the block implies a return.

The return is to the point that the function was called, not to the beginning of the code.

The digitalWrite function, for instance, returns when it is done. You wouldn't want that to cause the Arduino to reset, would you?

no, wouldnt want it to reset the arduino. Is there a function that starts the code over? Not to the start of everything just the main loop? For example skip the void setup and just go back to void loop?

Just put a "return;" at the point in "loop" you want to restart. "loop" will return to "main" and be called again immediately.

so use the code raron provided "LR_flag = TRUE;" and then use a

if (LR_flag = TRUE){ return; }

else (){ // do other stuff }

I'm not quite sure if what groove talks about works (isn't there a saying that you should NEVER return from the "loop" function of a sketch?), but it might work?

Anyway, comparison operator is two ==.

if (LR_flag [glow]==[/glow] TRUE){ return; }

else {
// do other stuff
}

But, it being non-zero for TRUE, you could just use

if (LR_flag) { return; }

else {
// do other stuff
}

EDIT: Grammar...and stuff.