Debounce tutorial with 2 buttons and 2 LEDs, need help

Trying to modify the debounce example sketch to incorporate 2 buttons and 2 LED's. Eventually, adding more... I am a newb, so be gentle... I am getting void loop previously defined here.... I'm lost...

Here is my modified code....

/*
Debounce

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).

The circuit:

  • LED attached from pin 13 to ground
  • pushbutton attached from pin 2 to +5V
  • 10K resistor attached from pin 2 to ground
  • LED attached from pin 12 to ground
  • pushbutton attached from pin 3 to +5V
  • 10K resistor attached from pin 3 to ground
    */

// set pin numbers:
int buttonPin2 = 2; // the number of the pushbutton pin
int ledPin13 = 13; // the number of the LED pin
int buttonPin3 = 3; // the number of the pushbutton pin
int ledPin12 = 12; // the number of the LED pin

// Variables will change:
int ledState = HIGH; // the current state of the output pin
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// 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 = 50; // the debounce time; increase if the output flickers

void setup() {
pinMode(buttonPin2, INPUT);
pinMode(ledPin13, OUTPUT);

// set initial LED state
digitalWrite(ledPin13, ledState);
}

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

// 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 ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:

// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;

// only toggle the LED if the new button state is HIGH
if (buttonState == HIGH) {
ledState = !ledState;
}
}
}

// set the LED:
digitalWrite(ledPin13, ledState);

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

void setup() {
pinMode(buttonPin3, INPUT);
pinMode(ledPin12, OUTPUT);

// set initial LED state
digitalWrite(ledPin12, ledState);
}

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

// 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 ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:

// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;

// only toggle the LED if the new button state is HIGH
if (buttonState == HIGH) {
ledState = !ledState;
}
}
}

// set the LED:
digitalWrite(ledPin12, ledState);

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

May I suggest that on the one hand, you go back to your first post here, and put all the code in "code" tags? As per the instructions for requesting help. Notably items 7 and 9.

So,

You are getting "void loop previously defined here" because you have two of them. That certainly isn't going to work!

May I offer a somewhat more sophisticated debounce and timing code designed to be immediately extensible to multiple pushbuttons and LEDs:

// Button toggle with extreme reliability!

const int ledpins[4] = {
  2, 3, 5, 6};
const int led1Pin =  13;    // LED pin number
const int buttons[2] =  {
  10, 11};

char bstates[2] = {
  0, 0};
char ledStates[2] = {
  0, 0};
unsigned long bcount[2] = {
  0, 0}; // button debounce timers.  Replicate as necessary.

// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check
// Routines by Paul__B of Arduino Forum
boolean timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) { 
    *marker += interval;    // move on ready for next interval
    return true;       
  } 
  else return false;
}

// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
// Routines by Paul__B of Arduino Forum
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
  switch (*butnstate) {               // Odd states if was pressed, >= 2 if debounce in progress
  case 0: // Button up so far, 
    if (button == HIGH) return false; // Nothing happening!
    else { 
      *butnstate = 2;                 // record that is now pressed
      *marker = millis();             // note when was pressed
      return false;                   // and move on
    }

  case 1: // Button down so far, 
    if (button == LOW) return false; // Nothing happening!
    else { 
      *butnstate = 3;                 // record that is now released
      *marker = millis();             // note when was released
      return false;                   // and move on
    }

  case 2: // Button was up, now down.
    if (button == HIGH) {
      *butnstate = 0;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 1;               // jackpot!  update the state
        return true;                  // because we have the desired event!
      }
      else 
        return false;                 // not done yet; just move on
    }

  case 3: // Button was down, now up.
    if (button == LOW) {
      *butnstate = 1;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 0;               // Debounced; update the state
        return false;                 // but it is not the event we want
      }
      else 
        return false;                 // not done yet; just move on
    }
  default:                            // Error; recover anyway
    {  
      *butnstate = 0;
      return false;                   // Definitely false!
    }
  }
}

void setup() {
  for (int i=0; i < 4; i++) pinMode(ledpins[i], OUTPUT);      
  for (int i=0; i < 2; i++) { 
    pinMode(buttons[i], INPUT);      
    digitalWrite(buttons[i],HIGH); // internal pullup all versions
  }        
}

void loop() {
  // Toggle LED if button debounced
  for (int i=0; i < 2; i++) {  
    if (butndown(digitalRead(buttons[i]), &bcount[i], &bstates[i], 10UL )) {
      if (ledStates[i] == LOW) {
        ledStates[i] = HIGH;
      }
      else {
        ledStates[i] = LOW; 
      } 
      digitalWrite(ledpins[i], ledStates[i]); 
    }
  } 
}

Note that only two buttons/ LEDs are implemented at this point, though it could just as easily be any reasonable number I have allocated an array for four LEDs. By adapting the loop() code, all sorts of interactions can be configured. The use of "timeout()" to flash LEDs is illustrated here:

// Blink without "delay()" - multi!

const int led1Pin =  13;    // LED pin number
const int led2Pin =  10;
const int led3Pin =  11;
const int button1 =  4;
int led1State = LOW;        // initialise the LED
int led2State = LOW;
int led3State = LOW;
char bstate1 = 0;
unsigned long count1 = 0;   // will store last time LED was updated
unsigned long count2 = 0;
unsigned long count3 = 0;
unsigned long bcount1 = 0; // button debounce timer.  Replicate as necessary.

// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check 
boolean timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) { 
    *marker += interval;    // move on ready for next interval
    return true;       
  } 
  else return false;
}

// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
  switch (*butnstate) {               // Odd states if was pressed, >= 2 if debounce in progress
  case 0: // Button up so far, 
    if (button == HIGH) return false; // Nothing happening!
    else { 
      *butnstate = 2;                 // record that is now pressed
      *marker = millis();             // note when was pressed
      return false;                   // and move on
    }

  case 1: // Button down so far, 
    if (button == LOW) return false; // Nothing happening!
    else { 
      *butnstate = 3;                 // record that is now released
      *marker = millis();             // note when was released
      return false;                   // and move on
    }

  case 2: // Button was up, now down.
    if (button == HIGH) {
      *butnstate = 0;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 1;               // jackpot!  update the state
        return true;                  // because we have the desired event!
      }
      else 
        return false;                 // not done yet; just move on
    }

  case 3: // Button was down, now up.
    if (button == LOW) {
      *butnstate = 1;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 0;               // Debounced; update the state
        return false;                 // but it is not the event we want
      }
      else 
        return false;                 // not done yet; just move on
    }
  default:                            // Error; recover anyway
    {  
      *butnstate = 0;
      return false;                   // Definitely false!
    }
  }
}

void setup() {
  pinMode(led1Pin, OUTPUT);      
  pinMode(led2Pin, OUTPUT);      
  pinMode(led3Pin, OUTPUT);      
  pinMode(button1, INPUT);      
  digitalWrite(button1,HIGH);        // internal pullup all versions
}

void loop() {
  // Toggle LED if button debounced
  if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) {
    if (led1State == LOW) {
      led1State = HIGH;
    }
    else {
      led1State = LOW; 
    } 
    digitalWrite(led1Pin, led1State);
  } 

  // Act if the latter time (ms) has now passed on this particular counter,
  if (timeout(&count2, 300UL )) {
    if (led2State == LOW) {
      led2State = HIGH;
    }
    else {
      led2State = LOW; 
    } 
    digitalWrite(led2Pin, led2State);
  } 

  if (timeout(&count3, 77UL )) {
    if (led3State == LOW) {
      led3State = HIGH;
    }
    else {
      led3State = LOW; 
    } 
    digitalWrite(led3Pin, led3State);
  } 
}

Note always that it is preferred to have the button connect from the input pin to ground and no pull-up resistor is required as we use the internal pull-up. (Those tutorials are badly written in this respect and confusing to beginners.)

Do try these out - putting in your own pin numbers, and go from there. :grin:

Thank you, we are trying this now. I was hoping to turn this into a tic tac toe game. We are realizing we only have 13 i/o pins and with 9 leds and 9 push buttons we need more.... this is frustrating