Multiple Input Debouncing + State Changes

Hello all,

I have a problem. I am a proud owner of the Arduino Uno, and I am working on a circuit that requires for two pushbuttons inputs to be continuously polled and debounced. Basically, every time pushbutton A is pressed, it is debounced (delay of 50 ms) and either turns on or turns off a red LED, and the same with pushbutton B, except with a green led. To do this, I combined the Debouncing example code with the State Change code, and changed the modulus at the end to 2 instead of 4.

The algorithm works for a single input, but when combining the two inputs codes, neither of them work. Is there any solution to this problem? Is there too much going for the Arduino to handle?

Thanks!

Certainly not too much for a Arduino to handle. It's more about your program structure and flow. A good solution is to use a standard library class that you can assign unique instances to as many unique buttons as you want. Check out this library:

http://www.arduino.cc/playground/Code/Debounce

Here is another that has fancier modes: Arduino Playground - Buttons

Otherwise if you would rather just fix what you wrote, you will have to post your sketch here and one of the software gurus can possible help you fix it.

Lefty

Thank you for your exceptionally quick and informative reply, retrolefty. I will check out those links now.

Hey lefty, I got it working, along with polling an Ultrasonic sensor that stops all activity when an object comes closer than 3 in.

Can you take a look at my code and see where I can optimize?
To clarify: prefix y_ refers to turning on the yellow (pin 13) led on the board, while g_ refers to the turning on of an external led. BUTTON is related to LED (y_) while SWITCH is related to gLED (g_).

Thank you!

// MP2 Deliverable

#include <Bounce.h>

#define PING 2
#define BUTTON 3
#define SWITCH 4
#define gLED 5
#define LED 13

// Variables will change:
int y_buttonPushCounter = 0;   // counter for the number of button presses
int y_buttonState;         // current state of the button
int y_lastButtonState = LOW;     // previous state of the button

int g_buttonPushCounter = 0;   // counter for the number of button presses
int g_buttonState;         // current state of the button
int g_lastButtonState = LOW;     // previous state of the butto

Bounce y_bouncer = Bounce( BUTTON, 50 ); 
Bounce g_bouncer = Bounce( SWITCH, 50 ); 

void setup() {
  pinMode(BUTTON,INPUT);
  pinMode(SWITCH, INPUT);
  pinMode(gLED,OUTPUT);
  pinMode(LED,OUTPUT);
  Serial.begin(9600);
  }


void loop() {
  
  PingTrigger();
    
  Button1();
      
  Button2();
  
  long duration, inches, cm;  
   
  duration = pulseIn(PING, HIGH);

  // convert the time into a distance
  inches = microsecondsToInches(duration);
  
  Serial.print(inches);
  Serial.print("in, ");
  Serial.println();
  
  ObstacleCheck(inches, duration);
 
  delay(100);

}

long microsecondsToInches(long microseconds)
{
    return microseconds / 74 / 2;
}

void ShutDown(){
    digitalWrite(LED, LOW);
    digitalWrite(gLED, LOW);
}

void Button1(){
  y_bouncer.update ( );
  y_buttonState = y_bouncer.read();
  
  if (y_buttonState != y_lastButtonState) {
        // if the state has changed, increment the counter
        if (y_buttonState == HIGH) {
          // if the current state is HIGH then the button
          // wend from off to on:
          y_buttonPushCounter++;
                } 
        else {}    
        // save the current state as the last state, 
        //for next time through the loop
        y_lastButtonState = y_buttonState;
      }
      
      if (y_buttonPushCounter % 2 == 0) {
        digitalWrite(LED, LOW);
      } else {
       digitalWrite(LED, HIGH);
      }
}

void Button2(){
  g_bouncer.update ( );
  g_buttonState = g_bouncer.read();
  
  if (g_buttonState != g_lastButtonState) {
        // if the state has changed, increment the counter
        if (g_buttonState == HIGH) {
          // if the current state is HIGH then the button
          // wend from off to on:
          g_buttonPushCounter++;
                } 
        else {}    
        // save the current state as the last state, 
        //for next time through the loop
        g_lastButtonState = g_buttonState;
      }
      
      if (g_buttonPushCounter % 2 == 0) {
        digitalWrite(gLED, LOW);
      } else {
       digitalWrite(gLED, HIGH);
      }
}

void PingTrigger(){
  pinMode(PING, OUTPUT);
  digitalWrite(PING, LOW);
  delayMicroseconds(2);
  digitalWrite(PING, HIGH);
  delayMicroseconds(5);
  digitalWrite(PING, LOW);
  pinMode(PING, INPUT);
}
  
void ObstacleCheck(long in, long dur){
  while (in < 3){
      ShutDown();
      dur = pulseIn(PING, HIGH);
      in = microsecondsToInches(dur);
      Serial.print(in);
      Serial.print("in, ");
      Serial.println();
      delay(100);
  }
}

Great that you got it working. I'm a hardware guy and probably the last guy to ask about optimizing a program. I'm happy if I can get a sketch to compile without writing a bunch of red crap in the output window. :wink:

Perhaps one of the many software gurus around here will be able to comment.

Lefty

I would suggest that PingTrigger() is not a very good function. The idea behind a function is that it does one thing, and it does that very well. Ping() that does everything that PingTrigger() does, plus waits for the return pulse, and returns a distance, would be a better function, in my opinion.

ObstacleCheck() expects that PingTrigger() has been called. But, loop() only calls PingTrigger() once, to cause a pulse to be sent. It has already ready the reply that PingTrigger() caused. So, ObstacleCheck() is going to wait for a return pulse that will not be coming, because one has not been sent.

Changing PingTrigger() to Ping(), making a complete function out of it, and calling Ping() in ObstacleCheck() will fix this problem.

PaulS, thank you, that is a very good point! I will work on that now, and tell you if I have succeeded!

EDIT:

It works! Thank you! With a bit of counter modification in ShutDown(), I have managed to make the LEDs stay off when you break the 3in barrier, so you need to press the button/flip the switch again to turn it on.