loading
What's simpler and dumber than a button, you ask...

I say: behind a button, unexpected things can hide. And within a program that does various things, handling a button can be tricky. The nice thing is that interesting functions can be built with a simple dumb button.

This tutorial will address these aspects:
  • wiring and configuring pins, using pull-up/pull-down resistor,
  • deglitching,
  • detecting states versus events,
  • detecting long presses,
  • and some object-oriented programming.

The programming approach is based on polling, encouraged by the Arduino loop() principle, and which is perfectly acceptable for simple to moderately complex Arduino projects. We'll require the duration of each loop() execution to be "fairly" the same each time.

More advanced implementations, not covered here, may include the usage of interrupts and timers. They are more accurate, but also harder to understand.

This tutorial is intended to people with a basic first Arduino experience (i.e. with knowledge of the IDE, and of the compilation, flashing and running of sketches).

In the following ZIP file, the four sketches used in this tutorial can be found.

Step 1: Connecting the Button

The Button

This is a momentary switch, with one stable position (open) when no force is exerted, and conducting (closed) when pressed. It is one of the simplest electro-mechanical sensing device.

Connect the button like illustrated in the photo of this step.

(Don't be impressed by the size of my breadboard. A small one will be actually handier.)


The I/O Pin

The AVR (aka ATmega, i.e. the Atmel chip powering the Arduino board) has several I/O pins. I/O means that they can be freely configured by software as input or output.

Pin 2 will be a good choice for our example. It will be used to measure the state of the button: pressed or released.


Pull-up Resistor

The pin has to be connected to somewhere via the button. The question is: where.

A first idea would be to go to VCC. VCC is the usual denomination for the supply voltage, here 5V.
So when the button is pressed, the pin would be connected to VCC, and the software would read HIGH. But when the button is released, the pin is connected to nowhere, aka "floating", and will be exposed to noise, and the software will read HIGH and LOW in an erratic way.

So the solution is to use a so-called pull-up or pull-down resistor. Such a resistor ensures that the pin is always connected to GND or VCC, directly or via the resistor, depending on the button position.

Fortunately, the AVR chip has, internally, a 20 kOhm pull-up resistor that can be connected to the pin (internally). The pin must be configured as input, and its value, in this situation, tells whether the pull-up is connected (otherwise the value defines, when the pin is configured as output, its output state).

With this pull-up, we'll connect the pin to GND through the button, and have these situations when the button is released, respectively pressed:
  Button not pressed:

               VCC
                |
           20K | |
      internal | |
       pull-up |_|
                |
                |                 _____
      input ––––*––––––o–––––––––o     o––––– GND
                      pin       released
                                 button

Input is isolated from GND, so only connected to VCC via the resistor. No current flows.
Without the pull-up resistor, the input would be "floating".

  Button pressed:
	
               VCC
                |    :
           20K | |   :
      internal | |   :
       pull-up |_|   :  some current flows
                |     `- - - - - - - - - ->
                |
      input ––––*––––––o–––––––––o–––––o––––– GND
                      pin        pushed
                                 button

Input is now directly connected to GND. Some current flows through the resistor.

In both cases, we now have a clearly defined situation.


Consumption

When the button is pressed, the resistor gets a voltage difference equal to VCC, and a current I is flowing:

I = VCC / R
  = 5 / 20,000 = 0.25 mA

Corresponding to consuming the power P:

P = VCC2 / R
   = 52 / 20,000 = 1.25 mW

This is not much, and is consumed only when the button is pressed. Often, pull-up and pull-down resistors have even greater values, consuming hence less power. If you don't have particular reasons, use this handy 20k internal pull-up.


Polarity

Had we a pull-down at our disposal, we would have connected the pin to VCC instead of GND, and read HIGH upon press, which is more logical. But since we have a pull-up only, we'll have to reverse the polarity by software, at pin sampling.

For more about I/O pins, follow http://www.arduino.cc/en/Tutorial/DigitalPins.


Programming

The configuration of the AVR pin (as input and with pull-up enabled) is described in the code below.


Code

––––––––––8<––––––––––
#define BUTTON_PIN 2

void setup()
{
  ...
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(BUTTON_PIN, HIGH); // connect internal pull-up
  ...
}

void loop()
{
  ...
}
––––––––––>8––––––––––
    

Step 2: Sampling, Deglitching, and Reading States

Glitches

Buttons are like many things: imperfect. Even when they give a firm mechanical sensation, they generate a couple of oscillations when the button position changes.

These oscillations are called glitches or bounces. They can be eliminated by adding a capacitor (introducing some delay), or by software.


Filtering by Sampling

Often, your Arduino application is loop()-based, i.e. does something, then sleeps awhile, repeatedly. The button state sampling code can look like:
void loop()
{
  // handle button
  boolean button_pressed = read_button();

  // do other things
  do_stuff(button_pressed);

  // sleep a moment before next iteration
  delay(DELAY);
}
This means that at least DELAY milliseconds elapse between successive button samplings. Depending on DELAY, this will make us insensitive to the glitches. The responsiveness is not totally accurate, but largely sufficient: there will be some jitter in the magnitude of DELAY. It must be insured that the things we do during each loop take a "small" and comparable time for each iteration.

The first picture of this step shows the glitches and the periodic sampling (indicated in blue).


Reading the State

The code below shows how the periodic sampling is done. When the button is seen as not pressed, a dot is sent to the serial line; when the button is seen as pressed, a caret is sent.

The second picture of this step shows the serial output, for one long press followed by two short presses.


Programming

In the code below, note that I have chosen a variable name (button_pressed) representing a high level of abstraction (the button state), and not the electrical state (button, conducting or not, nor electrical value read on the pin), which would be confusing because of the fact that, due to the pull-up resistor, the pin reads HIGH when the button is released.


Pro/Cons

Very simple implementation. Suited for continuous control (e.g. break pedal).

Unsuited for incremental control (e.g. sound incremental volume control) -- which will be explained in the next step.


Code

––––––––––8<––––––––––
#define BUTTON_PIN        2  // Button
#define DELAY            20  // Delay per loop in ms

void setup()
{
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(BUTTON_PIN, HIGH); // pull-up
  Serial.begin(9600);
}

boolean handle_button()
{
  int button_pressed = !digitalRead(BUTTON_PIN); // pin low -> pressed
  return button_pressed;
}

void loop()
{
  // handle button
  boolean button_pressed = handle_button();

  // do other things
  Serial.print(button_pressed ? "^" : ".");

  // add newline sometimes
  static int counter = 0;
  if ((++counter & 0x3f) == 0)
    Serial.println();

  delay(DELAY);
}
––––––––––>8––––––––––
    

Step 3: Detecting Edges

Edges

When we want to catch edges or transitions, we need to slightly enhance the program of the previous step.

We introduce a global variable (button_was_pressed) that remembers the last read state, so that we can detect a state change.

In this example, we detect the transitions from not pressed to pressed, and will signal them by an event, as shown on the first picture of this step.


Programming

At each iteration, if we have an event, we'll send a caret to the serial line, otherwise a dot. See the second picture of this step. Again, for one long press and two short presses. Notice that the long press has generated only one event.

In the code below, also note that I have chosen variable names (button_now_pressed) representing a high level of abstraction (the button state), and not the electrical state (button, conducting or not, nor electrical value read on the pin).


Pro/Cons

Still simple implementation. The introduction of global variables starts to put the scalability of the program at risk. For one button, still quite okay though.


Code

––––––––––8<––––––––––
#define BUTTON_PIN        2  // Button
#define DELAY            20  // Delay per loop in ms

boolean button_was_pressed; // previous state

void setup()
{
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(BUTTON_PIN, HIGH); // pull-up
  Serial.begin(9600);
  button_was_pressed = false;
}

boolean handle_button()
{
  boolean event;
  int button_now_pressed = !digitalRead(BUTTON_PIN); // pin low -> pressed

  event = button_now_pressed && !button_was_pressed;
  button_was_pressed = button_now_pressed;
  return event;
}

void loop()
{
  // handle button
  boolean raising_edge = handle_button();

  // do other things
  Serial.print(raising_edge ? "^" : ".");

  // add newline sometimes
  static int counter = 0;
  if ((++counter & 0x3f) == 0)
    Serial.println();

  delay(DELAY);
}
––––––––––>8––––––––––
    

Step 4: Distinguishing Short From Long Presses

Pulse Length

Many devices with few controls (e.g. digital watches) pack multiple functions per button.

It is very useful, saving precious volume, but must be used wisely, otherwise the device may become unintuitive to use.

Distinguishing short from long presses is about measuring the pulse length.

The event is no longer emitted upon pressing the button, but upon releasing it. This can affect the feeling of responsiveness. But until non-causal devices can be purchased, we cannot predict the duration and must hence proceed so.

This is a combined event and state handling: we detect the state change (an event), and the duration that the resulting state is lasting.


Programming

So we have to introduce another global variable (button_pressed_counter). Note also that the event has no longer a boolean value (event present or not, like in the previous step), but three states. They are defined by an enum. (I had troubles defining an enum type; Arduino-specific issue? So I used enum to define constants).

The first picture of this step show a long press and a short press timing, with a long press threshold of 3 sampling periods (which is way too short, but suited to the drawing).

The second picture shows the serial output for one long press followed by two short presses.


Pro/Cons

Nicely enhances the button functionality (if used wisely, to insure good usability). But the code starts to grow, and get polluted by global variables... The next step shows the OO variant, made for scaling.


Code

––––––––––8<––––––––––
#define BUTTON_PIN        2  // Button

#define LONGPRESS_LEN    25  // Min nr of loops for a long press
#define DELAY            20  // Delay per loop in ms

enum { EV_NONE=0, EV_SHORTPRESS, EV_LONGPRESS };

boolean button_was_pressed; // previous state
int button_pressed_counter; // press running duration

void setup()
{
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(BUTTON_PIN, HIGH); // pull-up
  Serial.begin(9600);
  button_was_pressed = false;
  button_pressed_counter = 0;
}

int handle_button()
{
  int event;
  int button_now_pressed = !digitalRead(BUTTON_PIN); // pin low -> pressed

  if (!button_now_pressed && button_was_pressed) {
    if (button_pressed_counter < LONGPRESS_LEN)
      event = EV_SHORTPRESS;
    else
      event = EV_LONGPRESS;
  }
  else
    event = EV_NONE;

  if (button_now_pressed)
    ++button_pressed_counter;
  else
    button_pressed_counter = 0;

  button_was_pressed = button_now_pressed;
  return event;
}

void loop()
{
  // handle button
  boolean event = handle_button();

  // do other things
  switch (event) {
    case EV_NONE:
      Serial.print(".");
      break;
    case EV_SHORTPRESS:
      Serial.print("S");
      break;
    case EV_LONGPRESS:
      Serial.print("L");
      break;
  }

  // add newline sometimes
  static int counter = 0;
  if ((++counter & 0x3f) == 0)
    Serial.println();

  delay(DELAY);
}

––––––––––>8––––––––––
    

Step 5: Adding Buttons, and Going OO

Issues Scaling Up

As we saw in the previous step, it is becoming hard to scale up. There are global state variables, which are referred to by some functions. Imagine adding a 2nd button: the nightmare will begin; not speaking about a 3rd button...


Programming: Going OO (Object-Oriented)

Arduino uses the Processing language built on top of C++, so why not use some OO features?

We need to pack these global variables into structures that we can create at will. Such structures, with associated handling functions are called classes and methods in the OO world. A class is just the description of the object, whereas the effective memory allocated for each object is called the instance.

The first picture of this step shows that we have added a 2nd button. The second picture shows the now traditional long/short presses, working independently very nicely. The 2nd button has, by the way, a longer long-press threshold.


Pro/Cons

This code is getting more complex, which is normal because, when scaling, the complexity raises by one significant step. The good news is that it can then support any number of additional buttons at no complexity increase.

Processing sets some limitations (e.g. there is no dynamic creation: the new and delete operators are not available). Which is not bad, because we also don't want to get lost into some of the particularly gory sides of C++, that are (arguably) unnecessary in small embedded systems like Arduino.

Sure the same could be done in pure C, so if you need/prefer a C implementation, just ask me.


Code

––––––––––8<––––––––––
#define BUTTON1_PIN               2  // Button 1
#define BUTTON2_PIN               3  // Button 2

#define DEFAULT_LONGPRESS_LEN    25  // Min nr of loops for a long press
#define DELAY                    20  // Delay per loop in ms

//////////////////////////////////////////////////////////////////////////////

enum { EV_NONE=0, EV_SHORTPRESS, EV_LONGPRESS };

//////////////////////////////////////////////////////////////////////////////
// Class definition

class ButtonHandler {
  public:
    // Constructor
    ButtonHandler(int pin, int longpress_len=DEFAULT_LONGPRESS_LEN);

    // Initialization done after construction, to permit static instances
    void init();

    // Handler, to be called in the loop()
    int handle();

  protected:
    boolean was_pressed;     // previous state
    int pressed_counter;     // press running duration
    const int pin;           // pin to which button is connected
    const int longpress_len; // longpress duration
};

ButtonHandler::ButtonHandler(int p, int lp)
: pin(p), longpress_len(lp)
{
}

void ButtonHandler::init()
{
  pinMode(pin, INPUT);
  digitalWrite(pin, HIGH); // pull-up
  was_pressed = false;
  pressed_counter = 0;
}

int ButtonHandler::handle()
{
  int event;
  int now_pressed = !digitalRead(pin);

  if (!now_pressed && was_pressed) {
    // handle release event
    if (pressed_counter < longpress_len)
      event = EV_SHORTPRESS;
    else
      event = EV_LONGPRESS;
  }
  else
    event = EV_NONE;

  // update press running duration
  if (now_pressed)
    ++pressed_counter;
  else
    pressed_counter = 0;

  // remember state, and we're done
  was_pressed = now_pressed;
  return event;
}

//////////////////////////////////////////////////////////////////////////////

// Instantiate button objects
ButtonHandler button1(BUTTON1_PIN);
ButtonHandler button2(BUTTON2_PIN, DEFAULT_LONGPRESS_LEN*2);

void setup()
{
  Serial.begin(9600);

  // init buttons pins; I suppose it's best to do here
  button1.init();
  button2.init();
}

void print_event(const char* button_name, int event)
{
  if (event)
    Serial.print(button_name);
  Serial.print(".SL"[event]);
}

void loop()
{
  // handle button
  int event1 = button1.handle();
  int event2 = button2.handle();

  // do other things
  print_event("1", event1);
  print_event("2", event2);

  // add newline sometimes
  static int counter = 0;
  if ((++counter & 0x1f) == 0)
    Serial.println();

  delay(DELAY);
}

––––––––––>8––––––––––
    

Step 6: Conclusion

If you're new to programming and have read this tutorial so far, kudos! don't hesitate to study the provided code, be critical, and ask questions. The full code archive can be found in the intro step, and here is the link again: arduino--button_tut.zip

I hope you have enjoyed this small tutorial. Now get some buttons, program something awesome, and show us what you made!


Other Links
<p>I love this tutorial! Never knew the Arduino had build in pull up resistors: so much easier, projects with less components. Also love the interupt example: very educational.</p>
<p>i want to press the button for long time but i want to the led light 1 second</p>
<p>These are great tutorials! I think I must be too new though and I'm missing how to tell the system what to trigger. For example I have three buttons (A, B, C) and I want each button to generate a keystroke. I've been able to do that however if I hold down button A I don't want it to keep sending the signal to type A over and over. I only want the system to type one A. Your event code seems to be what I would use but I don't see where I tell it what keystroke to send. Thanks in advance for any assistance you can provide. If it helps I'm trying to set this up on a Trinket Pro.</p>
<p>awesome!!</p><p>But I want to do this</p><p>There are two switch . I want when the both switch are changed their states, a LED is on and again both switch are changed their states, a LED is off.</p><p>please Help me to code this </p>
<p>I have a solution in mind, but I need to know if, in addition to what you describe (both buttons pressed at the same time) you want to also perform other actions when they are separately pressed.</p>
Awesome !!<br><br>how to make one button ,3 mode selection?
<p>Thankyou, life savor</p>
<p>I was curious since I was new to this stuff; working on a project where I need a single button to loop a sound and make an LED blink while a button is held down and I needed to know what the program/wiring situation needed to look like.</p><p>Great tutorial too, really helps with the basics for me.</p>
Despite being dyslexic, I've just taken the plunge into the arduino environment and have started attempting to write my first sketch and your tutorial covers some the most useful button functions which are on my &quot;to learn&quot; list so it couldn't have been more perfect for me.<br><br>The subjects are really well explained and it has gone a long way in helping me understand what goes on under the hood.<br><br>Huge thank you for putting the time and effort into making and sharing it :D
<p>hello, how to code this on arduino.</p><p>3 input pulse - process for 3 sec. then output pulse should be = to the number of input pulse with a 30ms interval.</p>
<p>is it possible , if we press the push botton for 3 sec, then an LED should blink??</p>
<p>Hi Amritk2,</p><p>I guess this can be done by below pseudo </p><p>void loop(){</p><p>if(Val ==HIGH){</p><p>delay(3000);// delay for 3 seconds and check again if the button is still //HIGH or u can keep checking in between for different intervals until //3000ms if not break;</p><p>if(Val ==HIGH){</p><p>digital.Write(pinout,HIGH);</p><p>}</p><p>}</p><p>// you can reset giving the value to LOW after a certain delay</p><p>}</p>
<p>is it possible , if we press the push botton for 3 sec, then an LED should blink??</p>
<p>Great work explaining!!<br>Could work with Touchscreen buttons ?</p>
<p>i want code in which if button is pressed , led remains on for a minute</p>
<p>You just have to change the delay in the on/off state of the LED, like so:</p><blockquote>digitalWrite(LED_PIN, HIGH);<br>delay(60000);<br>digitalWrite(LED_PIN, LOW);</blockquote>
<p> // handle button </p><p> boolean event = handle_button();</p><p>Should be:</p><p>int event = handle_button();</p>
<p>How 'bout double press? I like to distinguish all three. --THANKS</p>
<p>Hi!</p><p>does </p><p>void setup() </p><p>{</p><p> pinMode(BUTTON_PIN, INPUT_PULLUP); </p><p>}</p><p>equals-&gt;</p><p>void setup() </p><p>{ pinMode(BUTTON_PIN, INPUT); </p><p>digitalWrite(BUTTON_PIN, HIGH); // connect internal pull-up <br>}</p><p>I don't understand why if not...</p><p>thanx</p>
<p>Yes, the two are the same. I am new to all this so didn't understand what that was doing.</p><p>I Googled &quot;digitalwrite input pin&quot; and there is info on the Arduino site. They recommend using the INPUT_PULLUP method, but the other does exactly the same. Using &quot;digitalWrite(inputPin, HIGH)&quot; will activate the pullup resistor.</p>
<p>Really great ible!</p><p>I'm trying to detect long / multiple clicks for a number of buttons *not* connected to Arduino pins but rather to an ioexpander which is read by the Arduino over the I2C port. e.g. you can read the state of 8 buttons into a byte.</p><p>So I want to be able to &quot;detect&quot; long / multiple clicks represented in a byte variable rather than through Arduino's IO pins.</p><p>I'm sure this is easy to some but it's stumping me right now, any pointers you could give me to start with (or lines of code I could digest myself and adapt) would be very much appreciated, thanks!</p>
<p>Hi MatS1!</p><p>do you find a coding solution about write/read the state of 8 different buttons into an EEPROM byte ?</p><p>It's stumping me too actually...</p><p>cheers</p>
<p>By the way, here's my FSM diagram for the button press logic</p>
<p>How does enum work in this case? For:</p><p>enum { EV_NONE=0, EV_SHORTPRESS, EV_LONGPRESS };</p><p>Shouldn't there be an enum definition afterwards? Such as:</p><p>enum States { EV_NONE=0, EV_SHORTPRESS, EV_LONGPRESS };</p>
<p>Thank you! I found this to be super helpful!</p><p>How many milliseconds do you recommend for the delay? I'm using 5 ms right now and it seems to be enough to iron out the button-press glitches, but do you usually make your delay longer or shorter than that? </p>
<p>This paper <a href="http://www.eng.utah.edu/~cs5780/debouncing.pdf" rel="nofollow"> http://www.eng.utah.edu/~cs5780/debouncing.pdf </a> tells us that it really depends on the switch, so it's hard to do a general recommendation.</p><p>50 ms should be still unnoticeable, so I would try 25 ms or even 5 ms, and see if it correctly de-bounces...</p>
<p>Hi, just passing to say thank you for this awesome ible... its goes from basic to more advanced, clear examples and an excelente presentation... !!! Keep Up... </p>
<p>You are welcome! Glad it helped.</p>
Hey - you recommend using OOP to cut down on global vars but aren't you doing so here: <br> <br>// Instantiate button objects <br>ButtonHandler button1(BUTTON1_PIN); <br>ButtonHandler button2(BUTTON2_PIN, DEFAULT_LONGPRESS_LEN*2); <br> <br>in the global scope anyway? <br> <br>Please explain. Thanks!
You are correct about the global scope.<br> In this step 5, and in comparison to the previous step 4, we have gathered the individual global variables (button_was_pressed, button_pressed_counter) inside a class that we can replicate at will.<br> <br> OOP is not the only way to do it; 'struct' can do the job too, but OOP allows to creates and initialize copies (aka instances) of button variables very elegantly: ButtonHandler buttonX(..parameter..);<br> <br> And they are still allocated in the global scope as you noted.<br> <br> I hope it helped.
Thank you! I am more java-based, so I'm wondering why it seems like you can create static instances just by including a separate init method, as opposed to the constructor. I have seen other Arduino OOP stuff where the obj-&gt;method syntax is used, but is it the case that in your static version, obj.method can be used instead?
<u>New vs auto:</u> In C and C++, unlike in Java, instances can be declared 'auto', i.e. without requiring 'new'. They have the advantage that the destructor is implicitly called, when leaving the declaration scope. Remember that there is no GC, so 'new' requires 'delete'. Not all small embedded environment offer the 'new' construct. Arduino does, but I really wouldn't use it. Note that both methods of creation (auto and new) call the constructor.<br> <br> <u>Heap vs stack:</u> Then, still for automatic instances, you can declare them either on the heap (by declaring them outside any class/method scope, or within a class/method with the 'static' qualifier), or on the stack (within method code). Using the heap for long-term data is better, because your memory requirements are checked at build time, and stack overflows are killers, especially in small systems.<br> <br> <u>Method calls:</u> Finally, yes you can do method calls on any object instance. In the loop() above, I called:&nbsp; <em>button1.handle();</em>&nbsp; With auto instances you use the dot operator. With instances created with the 'new' construct, since you keep track of the instance by a pointer, you use the dereference '-&gt;' operator.
About method calls, I would add that, regardless how the instance was created, you may use the dot or dereference operator within a function to which the instance was passed, depending on whether passed as pointer or as reference:<br> <br> void function1(class MyClass *c) // pass by pointer<br> {<br> &nbsp; c-&gt;method();<br> }<br> <br> void function2(class MyClass &amp;c) // pass by reference<br> {<br> &nbsp; c.method();<br> }<br> <br> main()<br> {<br> &nbsp; MyClass instance();&nbsp; // instantiate<br> &nbsp; function1(&amp;instance); // pass address if instance<br> &nbsp; function2(instance);&nbsp; // instance passed as ref<br> }<br> <br> Under the hood and in the above case, the compiler produces similar machine code for both functions.
This is very interesting and well written. I am trying to use a button for dual function and need the short ( Mute toggle) and long ( start system power down) duration that you demonstrate. <br>I am also using the IRremote , SoftwareSerial and Button libraries in the same sketch...do you foresee and conflicts ? <br>Do you see any issue with a button press length of between 3 and 5 seconds? <br>This is the most complex sketch I have wrote thus far with my limited experience. <br>Thanks again for the tutorial! <br>Build_it_Bob
I do not know the IRremote and SoftwareSerial libraries, so I cannot say anything about potential conflicts.&nbsp; If these libs deal with distinct resources and I/Os, it should be OK, but one never knows...<br> <br> I suggest that you progressively add your usage of these libs, and do regression tests after each addition.<br> <br> Good luck! Post something about your project when completed!
I have changed code to lit led and display serial communication something different but when i press button, it just stops displaying 1 and displays blank till i keep pressed button. What is wrong i'm doing i can't get it.<br> <br> ////////////////////////////////////////////////////////////////////////////// // Arduino button tutorial 1. // // Demonstrates: // - detection of pressing state // // Push-button must be connected as follows: // __,__ // Pin2 ------o o------ GND // // (C) 2011 By P. Bauermeister // This example code is in the public domain. // ////////////////////////////////////////////////////////////////////////////// // Adapt these to your board and application timings: #define BUTTON_PIN 2 // Button #define DELAY 1000 // Delay per loop in ms #define LED_PIN 7 ////////////////////////////////////////////////////////////////////////////// void setup() { pinMode(BUTTON_PIN, INPUT); pinMode(LED_PIN, OUTPUT); digitalWrite(BUTTON_PIN, HIGH); // pull-up Serial.begin(9600); } boolean handle_button() { int button_pressed = !digitalRead(BUTTON_PIN); // pin low -&gt; pressed return button_pressed; } void loop() { // handle button boolean button_pressed = handle_button(); // do other things if (button_pressed==0) { Serial.print(&quot;1&quot;); digitalWrite(LED_PIN, HIGH); } else { digitalWrite(LED_PIN, LOW); Serial.print(&quot;2&quot;); } //Serial.print(button_pressed ? &quot;0&quot; : &quot;1&quot;); // add newline sometimes static int counter = 0; if ((++counter &amp; 0x3f) == 0) Serial.println(); delay(DELAY); }
Inspired!
Great work explaining and demonstrating switch bounce. Good work showing how to program around it. For those who don't want to have to include all the extra code there is an arduino library you can include in your sketch which does the same thing. I am using it in a sketch currently.<br><br>http://www.arduino.cc/playground/Code/Bounce
Thank you for the link. It uses millis(), which is much better than my code. I might update mine to use millis().<br><br>But it does not handle the long press (which my initial goal, the debounce being just an extra bonus).<br><br>So if one just needs debouncing and edge detection, one should definitely use the bounce lib.<br><br>Thanks.
Great information. Thanks especially for the introduction to OO programming. I ran right over to the Wiki and read up. I was initially skeptical about using a delay loop instead of a debounce function, but after seeing how you used it as a prescaler for your long press counter, it totally makes sense. Yay Arduino! If I had not read this article, I wouldn't have been aware that you could take it to this level.<br> <br> <a href="http://www.thelumberlab.com">David</a>

About This Instructable

223,815views

292favorites

License:

Bio: So many things to learn and make, so little time! I like things that are cool, useful, efficient, well crafted. Subscribe to me! If I ... More »
More by laxap:Stylish Concrete Phone Stands Easy Stylish Concrete Phone Stand Retrofit a LED Ring to a Stereo Microscope 
Add instructable to: