Double press button for on/off function with debounce

I have tried several examples and while some work well but have terrible predictability for single press vs double press while others that have great button use but no double click if you will. I need something that I can piggyback an existing momentary switch with that when it’s pressed once it does nothing and when pressed twice within 500ms, it will latch an output and when pressed twice again in quick succession, will unlatch the output. I’ve tried some of the multi switch examples without success. I thought about counting presses but I’m not having any success with it resetting after a second and then if it does work, the other part of it doesn’t.

Thanks in advance.

Try this sketch.

byte ButtonPin = 2; //digital pin 2

int button = LOW;
int lastButtonState = LOW;
int type,lastType=0;
long time=0;
int flagged = 0;
long newT=0;
int output = 0, lastOut;
int cnt=0;

long lastDebounceTime = 0;  
long debounceDelay = 50;



void setup() {
  //pinMode(LEDpin, OUTPUT);
  pinMode(ButtonPin, INPUT);
  Serial.begin(9600);
  Serial.println("ready");
}

void loop() {
  button = digitalRead(ButtonPin);
  if (button != lastButtonState) {
    lastDebounceTime = millis();
    lastButtonState = button;
    time = millis();
  }

  while( millis() - time < 1500){
    type = check(time);
  }

  if(type != lastType){
    lastType = type;
    //Serial.println(type);
    switch(type){
    case 0:  
      break;
    case 1: 
      Serial.println("pressed 1 time(s)"); 
      break;
    case 2: 
      Serial.println("pressed 2 time(s)"); 
      break;
    case 3: 
      Serial.println("pressed 3 time(s)"); 
      break;
    }
  }
  type = 0; 
}
  
int check(long time){
  newT=0; 
  if ((millis() - lastDebounceTime) > debounceDelay) {  // debounce button
    newT=(millis() - time);

    if(newT < 500) // check if button is pressed within half a second
    { 
      button = digitalRead(ButtonPin);

      if(button == HIGH)
      {
        if(!flagged) // latch + lockout  that prevents cnt to increase when button is held
        {
          cnt++; 
          flagged = 1;
          output = cnt;
        }
      }
      else {
        flagged = 0;
      }
    }
    else { 
      cnt=0;
      if(output != lastOut) // prevents continuous stream of values, and only when the value changes, display it. 
      {
        lastOut = output; 
        return output;//Serial.println(cnt);
      }
    }
  }
}

I played around with that sketch and made a few changes. I’m guessing that I will not be able just run a simple pin high/delay/low/delay to generate a frequency out so how would you recommend I continue. I tried to use the serial portion as well but the examples I’ve tried to combine are without success.

byte ButtonPin = 2; //digital pin 2
byte LEDpin = 13; //onboard LED
byte FREQpin = 10; //frequency output

int button = LOW;
int lastButtonState = LOW;
int type,lastType=0;
long time=0;
int flagged = 0;
long newT=0;
int output = 0, lastOut;
int cnt=0;

long lastDebounceTime = 0;  
long debounceDelay = 50;



void setup() {
  pinMode(ButtonPin, INPUT);
  pinMode(LEDpin, OUTPUT);
  pinMode(FREQpin, OUTPUT);
  //Serial.begin(9600);
  //Serial.println("ready");
}

void loop() {
  button = digitalRead(ButtonPin);
  if (button != lastButtonState) {
    lastDebounceTime = millis();
    lastButtonState = button;
    time = millis();
  }

  while( millis() - time < 1500){
    type = check(time);
  }

  if(type != lastType){
    lastType = type;
    //Serial.println(type);
    switch(type){
    case 0:  
      break;
    case 1: 
      //Serial.println("pressed 1 time(s)"); 
      break;
    case 2: 
      //Serial.println("pressed 2 time(s)"); 
      digitalWrite(13, !digitalRead(13));
      break;
    case 3: 
      //Serial.println("pressed 3 time(s)"); 
      break;
    }
  }
  type = 0; 
}
  
int check(long time){
  newT=0; 
  if ((millis() - lastDebounceTime) > debounceDelay) {  // debounce button
    newT=(millis() - time);

    if(newT < 500) // check if button is pressed within half a second
    { 
      button = digitalRead(ButtonPin);

      if(button == HIGH)
      {
        if(!flagged) // latch + lockout  that prevents cnt to increase when button is held
        {
          cnt++; 
          flagged = 1;
          output = cnt;
        }
      }
      else {
        flagged = 0;
      }
    }
    else { 
      cnt=0;
      if(output != lastOut) // prevents continuous stream of values, and only when the value changes, display it. 
      {
        lastOut = output; 
        return output;//Serial.println(cnt);
      }
    }
  }
}

Here is the sketch above with changes to change the LED state but I can’t figure out how to add in what I need it to do like the legacy circuit to generate the frequency such as http://goo.gl/qQB7zf

Thanks again

Take a screen shot of your circuit, I can't see it.

Here's a picture of the legacy circuit for the frequency generator.

I know I can make that circuit work with the arduino as it is right now by using the arduino to drive a relay that would supply current to the 555 timer but I'd like to try to get this to work without the legacy components if possible as I think it will make it much easier to adapt it to other applications in the future.

Code works, just had to change a few things.

byte ButtonPin = 2; //digital pin 2
byte LED = 6;

int button = LOW;
int lastButtonState = LOW;
int type,lastType=0;
long time=0;
int flagged = 0;
long newT=0;
int output = 0, lastOut;
int cnt=0;

long lastDebounceTime = 0;  
long debounceDelay = 50;



void setup() {
  pinMode(LED, OUTPUT);
  pinMode(ButtonPin, INPUT);
  Serial.begin(9600);
  Serial.println("ready");
}

void loop() {
  button = digitalRead(ButtonPin);
  if (button != lastButtonState) {
    lastDebounceTime = millis();
    lastButtonState = button;
    time = millis();
  }

  while( millis() - time < 1500){
    type = check(time);
  }

  if(type != lastType){
    lastType = type;
    Serial.println(type);
    if(type == 2) digitalWrite(LED, !digitalRead(LED)); 
  }
  type = 0;
} 

int check(long time){
  newT=0; //cnt = 0;
  if ((millis() - lastDebounceTime) > debounceDelay) {
    newT=(millis() - time);
    if(newT < 500){
      button = digitalRead(ButtonPin);

      if(button == HIGH)
      {
        if(!flagged){
          cnt++; 
          flagged = 1;
          output = cnt;
        }
      }
      else {
        flagged = 0;
      }
    }
    else { 
      cnt=0;
      if(output != lastOut){
        lastOut = output; 
        return output;//Serial.println(cnt);
      }
    }
  }
}

How do I add the frequency output to the code so it's generated by the arduino and not an external circuit?

Look at the example sketch Blink without delay.

Its quite simple. Just two while loops, comparing time to a set value. ( two if you want a duty cycle other than 50%)

Added: Even more simple 50% duty cycle 1Hz generator

 long time1 = 0;

void setup(){
pinMode(13,OUTPUT);
}

void loop() {
  if(millis() - time1 > 1000)  // 1 second = 1 Hz
  {
     time1 = millis();
    digitalWrite(13, !digitalRead(13));
  }
}

Another solution using my state machine library foud here:http://playground.arduino.cc/Code/SMlib
instruction for installing here: http://arduino.cc/en/Guide/Libraries

#include <SM.h>

//macro for detection of raising edge and debouncing
#define DRE(signal, state) (state=((state<<1)|(signal&1))&15)==8
const int buttonPin = 2;
int buttonState;

const int ledPin = 13;

SM timeSwitch(wait);

void setup(){
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
}//()

void loop(){
  EXEC(timeSwitch);
}//()

State wait(){
  if(DRE(digitalRead(buttonPin), buttonState)) timeSwitch.Set(delay500);
}//wait()

State delay500(){
  if(DRE(digitalRead(buttonPin), buttonState)) timeSwitch.Set(toggle);
  if(timeSwitch.Timeout(500)) timeSwitch.Set(wait);
}//delay500()

State toggle(){
  digitalWrite(ledPin, !digitalRead(ledPin));
  timeSwitch.Set(wait);
}//toggle()

That's the problem I'm having. When I add the second loop code, it will no longer verify.

I would tackle the problem in several parts, because you have several distinct algorithms to implement.

Firstly, debounce the raw switch state to get a clean switch state. The IDE comes with examples that demonstrate this.

Apply edge detection to the debounced signal to detect button presses.

Compare the time of the current click against the time of the preceding click to work out whether this press constitutes a double-click. if you want to handle single clicks too then I would implement this as a finite state machine (with two states) so that you can apply a timeout between clicks and infer a single click.

Use a boolean variable as a toggle that you can invert each time a double click is detected.

This doesn't require any looping control structures and everything you need to implement would be in loop(), or functions you define called from it.

Don't forget to: 1) use loads of unnecessary variables. 2) order and process everything numerically 3) { Use scope brackets a lot even when they are not needed on single line conditions } 4) Make code as initially unreadable as possible without scrolling up and down to see references.

@DGlen

Everyone else that has posted did so with the intent of trying to help me with this project but yours carries quite a negative vibe so please feel free to show everyone how you'd do what I'm trying to accomplish without doing any of what you posted in regards to.

The two codes I gave should work. The first one should toggle the LED when double clicked, and the second code shows you how to create a 1 Hz pulse @ 50% duty cycle.

Try the first code again, I added a new line that I forget to mention. Sorry about that. Make sure you button is wired properly so it's normally low then when pressed, goes high.