Take the 2-minute tour ×
Electrical Engineering Stack Exchange is a question and answer site for electronics and electrical engineering professionals, students, and enthusiasts. It's 100% free, no registration required.

I'm using analog pin 5 on Arduino to detect presses from 6 push-buttons. On the picture top-right button is number 1 and then from right to left they go as 2, 3, 4, 5, 6. Program should print 0 when none of the buttons is pressed and if one of them is presses, it should print its position as I mentioned before. Currently the problem is that if I press say second button, it will (instead only once) sometimes print 2 a couple of times. I guess it is because of the "noise" when button is pressed and that it should be debounced, but I don't know how to debounce analog pin.

My code:

int old_button = 0;
int button;
int pressed_button;
int z;

void setup () {
  Serial.begin(9600);
  pinMode(A5, INPUT);
}

void loop () {
  z = analogRead(5);
  if (z > 1021) button = 0;                                           
  else if (z > 511 && z < 514) button = 1;                     
  else if (z > 680 && z < 684) button = 2;                
  else if (z > 766 && z < 770) button = 3;                
  else if (z > 817 && z < 822) button = 4;             
  else if (z > 851 && z < 856) button = 5; 
  else if (z > 875 && z < 880) button = 6;
  else button = 0;                                                      

  if (old_button == button) {                                           
    old_button = button;                                              
    pressed_button = 0;                                               
  }  

  else {                                                                
    old_button = button;                                             
    pressed_button = button;                                        
  }
  Serial.println(pressed_button);
}

Circuit (2200 ohm resistors):

enter image description here

share|improve this question
1  
An electrical schematic would be better than a Fritzing diagram, in this specific case. Use the builtin schematic editor. –  Passerby Mar 2 at 1:06
1  
@Mate Just FYI. There is now an specialized Arduino stack: arduino.stackexchange.com –  Nick Alexeev Mar 2 at 19:08

3 Answers 3

When you detect a significant difference in ADC reading, wait 20 milliseconds and then average a few readings then make a decision. If one of the readings still looks badly quantifiable, wait another short period of time.

share|improve this answer
    
+1 for answer. hey Andy, is it wisely to ground a 104 capacitor from the buttons line(for debancing)? –  Roh Mar 1 at 16:45
    
@roh not wise if it means connecting a switch across a charged up 100nF cap because the current pulse could reset the MCU. Best to put 100 ohms in series with the switch. –  Andy aka Mar 1 at 17:03
    
@Andyaka: Could you please write me a pseudocode for your answer? –  Nick Mar 1 at 20:16
    
@Mate I'm a verbal sort of dude (well, most of the time and some of the time undecipherable!) and I haven't written pseudo code in millenia. It shouldn't be difficult to visualize what I'm saying - I like circuits but I didn't ask you to change that awful fritzing thing to one LOL –  Andy aka Mar 1 at 20:21
1  
@Andyaka The current pulse from a 100nF could reset the MCU?! What kind of worthless crap MCU is that?! Throw it out instantly, get a real one... –  Lundin Mar 4 at 9:25

Yes, it is debounce noise. You need to wait a bit (say 50 ms) and read the analog input again. If the result matches, then the button value can be considered valid. Something like this:

int old_button = 0;

int getButton()
{
  int i, z, sum
  int button;

  sum = 0;
  for (i=0; i < 4; i++)
  {
     sum += analogRead(5);
  }
  z = sum / 4;
  if (z > 1021) button = 0;                                           
  else if (z > 511 && z < 514) button = 1;                     
  else if (z > 680 && z < 684) button = 2;                
  else if (z > 766 && z < 770) button = 3;                
  else if (z > 817 && z < 822) button = 4;             
  else if (z > 851 && z < 856) button = 5; 
  else if (z > 875 && z < 880) button = 6;
  else button = 0;

  return button;
}


void loop ()
{
  int button, button2, pressed_button;  
  button = getButton();
  if (button != old_button)
  {
      delay(50);        // debounce
      button2 = getButton();

      if (botton == button2)
      {
         old_button = button;
         presed_button = button;
         Serial.println(pressed_button);
      }
   }
}

Since Andy didn't want to provide any code, I added some averaging when taking the ADC readings. So the averaging inside getButton accounts for any noise reading the analog line coming into the ADC, and the 50 ms delay takes care of detecting switch bounce.

share|improve this answer
    
@Mate I added he code for averaging out the ADC noise to my answer. Thanks to Andy aka for suggesting it, it was a good addition. –  tcrosley Mar 2 at 0:29

Many switches of the style you're using are hard to debounce well, and trying to use a resistive multiplexer won't make it easier. Still, if you can afford two port pins (one analog), I can offer a recipe for success which should work even if your switches are pretty lousy. I'd suggest moving the bus-bar resistor (ignore the bottom bus bar of the breadboard) to the left of your leftmost one, and wiring that to a the non-analog port pin. The common wire on the top should be connected to the analog port pin. The wire from the right-most resistor should connect to ground.

When your unit is "idle" [you don't think any buttons are pushed] set the common output to high and float the other one. It will read low when no buttons are pushed, and will read close to VDD when any button is pushed.

To find out which button is pushed, float the common wire and drive the left-side wire high. Briefly set the common wire high or low (see note) and float it again, then read the voltage on that pin a little while later (keeping the left-side wire high). Once the reading has been taken, you may if desired turn off power to the left-side wire (turn it on again before the next reading cycle).

While a button is pushed, the voltage on the common wire should be a nice fraction of VDD (if there are six buttons and seven resistors, the buttons should read 1/7, 2/7, 3/7, etc. up to 6/7); the voltage should not be overly affected by whether the common pin had been briefly pulsed high or low. If no button is pushed, readings after the pin had been pulsed high will be much higher than when after it had been pulsed low. This will indicate that the button has been released.

Once the button has been released, you may go back to the "idle" configuration. When the left resistor is driven high, the resistor string will draw current whether or not any buttons are pressed, but when the left pin is floated and the common wire is high, no current will be drawn until a button is pushed.

To get good results with cheap switches, you should delay long enough after each momentary "ground" or "VDD" pulse on your common wire that if the switch is making any contact at all it will yield a good reading (try putting a 100K resistor in parallel with a switch, and adjust the delay and sensitivity so that it "barely" registers the switch as being held). Cheap switches have a resistance of well over a meg when totally released, and less than 10 ohms when fully pressed, but their resistance can wander all over the place between those states, and conventional debounce timing won't help. What will help is having a circuit that won't detect a button press until the resistance gets fairly low, and will regard a button as held unless its resistance gets much higher. For the circuit I've described, the left-side button will be more "sensitive" to "new" button pushes than the right-side button, and "hold" sensitivity may be different for all six buttons, but you should have little trouble ensuring that every button's "hold" sensitivity is much higher than its "new push" sensitivity, which is the requirement for reliable debouncing.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.