4
$\begingroup$

I am trying to use a push button in order to know and print number of time a push button is pressed using a counter.But everytime i press the button , counter get incremented to sometime 3 and sometime 5 and some time counter does start >100 and continue.

I had preferred the this link for wiring PUSH button with arduino.

and here is my code

const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status
int count = 0;
void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);   
  pinMode(buttonPin, INPUT); 
  Serial.begin(9600);
    buttonState = digitalRead(buttonPin);
  digitalWrite(ledPin,LOW);  
}

void loop(){
    // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {

    // turn LED on:    
    digitalWrite(ledPin, HIGH); 
    count = count + 1;  
    Serial.print(count);
  } 
  else {
    // turn LED off:
    digitalWrite(ledPin, LOW); 
  }
}

I dont know why count is coming absurdly and unevenly.

$\endgroup$
5
$\begingroup$

Chris is right, the problem is that the mechanical contact of the switch is bouncing. However, I disagree with his statement that the most elegant solution is polling. Polling is very inefficient for the task of counting how many times a button was pressed, and so I decided to post my own answer for clarification:

Interrupts are what you want. Polling is used when you want to constantly capture information, for example from a range sensor. Interrupts give you time sensitive control, and only performs processing at the exact time you need it.

For a more thorough answer...

This design problem is commonly referred to as "switch debouncing." As Chris correctly mentions, you can do this in hardware or software. The optimal method of implementation with respect to count accuracy and CPU load is to use hardware to smooth out the signal and connect your button to an interrupt pin on the Arduino. You can then use the built in attachInterrupt() function to eliminate the need to poll constantly. Polling is a waste of CPU power. The attachInterrupt() function will assign an interrupt handler that will be called whenever the interrupt pin sees a RISING or FALLING edge (this depends on how you have your switch electrically connected), or even more generally on a CHANGE. This would look similar to the following:

attachInterrupt(0, buttonHandler, RISING);

void buttonHandler() {
   // turn LED on:    
  digitalWrite(ledPin, HIGH); 
  count = count + 1;  
  Serial.print(count);
}

This page explains the problem of switch debouncing and shows some example hardware circuits you can easily implement: http://www.elexp.com/t_bounc.htm

Note: You probably won't be able to see the led go HIGH because it will be handled so quickly. This code will increment the count once every time the button is pressed or released, depending on whether you attach the interrupt to the rising or falling edge of the signal.

Edit for OP's comment: If you want the serial.print to say that the button is pressed the entire time, then add a while loop in the interrupt:

void buttonHandler() {
   // turn LED on:    
  digitalWrite(ledPin, HIGH); 
  count = count + 1;
  Serial.print(count);
  while(digitalRead(buttonPin)) //This will loop until the button is released
    Serial.print("ON");
}

Please note that this will cause your program to stay inside the interrupt handler, and your main function will not execute. In your main function, you can then have a Serial.print("OFF").

You may also be able to use a boolean that is set to true in your interrupt handler:

void buttonHandler() {
   // turn LED on:    
  digitalWrite(ledPin, HIGH); 
  count = count + 1;  
  Serial.print(count);
  buttonWasPressed = true;
}

That way, in your main you can have an if statement to prevent your code from having to loop in the interrupt handler:

void loop() {
  if(buttonWasPressed) {
    while(digitalRead(buttonPin)) {
      Serial.print("ON");
    }
    buttonWasPressed = false;
  }
  else
    Serial.print("OFF");
}
$\endgroup$
  • $\begingroup$ I should have also mentioned that it's typically bad form to include print statements in interrupt handlers, depending on your application. Print functions are infamously slow, and since interrupt handlers temporarily cause the main thread to pause, having lengthy print statements can slow your algorithm down dramatically. Fortunately for you, a human pressing a button isn't all that fast, and printing a single int should be fine. If you had an actuator pushing this button at 100Hz you might want to start thinking about how much time is sunk by the print statement. $\endgroup$ – Andrew Capodieci Nov 15 '13 at 16:41
  • $\begingroup$ Well i am looking for a interrupt that can measure any event between 40 mili seconds and send a varible ON or OFF through serial print.... $\endgroup$ – shailendra Nov 20 '13 at 7:01
  • $\begingroup$ I believe my updated answer should solve the problem posed in your comment...the last example using the buttonWasPressed boolean is what I would recommend, because it's generally bad form to do a lot of processing in an interrupt handler. $\endgroup$ – Andrew Capodieci Nov 20 '13 at 16:49
3
$\begingroup$

What your experiencing is known as "button bounce". When you push a standard pushbutton, it actually makes and breaks contact many times very quickly for a few microseconds, usually enough to make the processor detect between 10 and 100 pushes, or more. There are many different methods of "debouncing" a pushbutton. The easiest approach is to add a small delay in your code right after you check if the pushbutton is pressed:

if(buttonState == HIGH){
    delay(10);
    //turn the light on, etc. 
}

There are other methods, both hardware and software. The most elegant method which will not interrupt the running of other code is to have a timer that scans the pushbutton periodically (i.e. every 5 milliseconds or so), and sets a boolean variable to TRUE when it detects a push. You could also rig up a small capacitor to the button; the schematic is available on the internet.

$\endgroup$
  • $\begingroup$ Well Adding a delay of 400 mili seconds works fine for me $\endgroup$ – shailendra Nov 15 '13 at 6:25
1
$\begingroup$

A switch does not have a quick low to high or high to low transition, instead something like this. This is called switch bounce. enter image description here image source: piconix.com

Just to add to the answers here. There are two commonly used methods to avoid switch bouncing:

  1. Using a capacitor with the switch, called RC debouncing. The capacitor tries to smoothen the transition and so avoiding voltage spikes. This method works fine but still there are chances that some big spikes of voltages may still be sent to the Arduino and Arduino senses it as a button press(false button press). So it is not a 'sure' method to avoid bounce. Also additional hardware is required for this method.

  2. Software denouncing: It is better method using which you can almost entirely remove the problem of switch bounce. In software too there are two majorly used methods, one is called polling and other is interrupt method. As Chris wrote, polling with a delay of 10-50 ms (depending on the quality of switch you are using) can avoid switch bouce. Polling is used in simple projects where time is not a very crucial aspect of project functioning. Polling is easy to implement. On the other hand using interrupt can be a little painstaking for beginners but it is a better way because the normal functioning of the code is not haulted while the debouncing is done(unlike polling where where we use delay and stop the processor from doing anything in that duration of time) . There can be many ways to do so.

Here is a pseudo code that I often useuse to avoid switch bounce:

//If button is pressed an interrupt, say, INTERRUPT1 is triggered
//Following is the interrupt service routine for INTERRUPT1:
ISR(INTERRUPT1) {                                                                        
//do something you wanted to do on button press                  
disable INTERRUPT1 //so that other button spike don't trigger it
enable, say, INTERRUPT2 Timer
INTERRUPT2 Timer is set to interrupt after, say 10ms                   
}

//Following is the interrupt service routine for INTERRUPT2:
ISR(INTERRUPT2) {
disable INTERRUPT2 Timer  
enable INTERRUPT1 //button press can be recognized now after 10ms have been elapsed
}
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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