Project tutorial
Button Switch Using An External Interrupt

Button Switch Using An External Interrupt

There are numerous examples of how to connect button switches via an external interrupt. This example offers an alternative approach.

  • 2 respects

Components and supplies

Apps and online services

About this project

Interrupt Driven Button Switch

If you are new to the idea of connecting up button switches and wiring up a simple circuit then see the tutorial Understanding and Using Button Switches - this will provide you with some of the fundamentals before looking next at an example implementation with an external interrupt. Conversely, if you know all there is to know about button switches, wiring them, inherent issues and external interrupts then you may also find this particular contribution of interest as it presents a different method of linking and processing button switches and their respective interrupts.

Design Considerations

Before we look at the offered method, we need to define our starting point as it has a bearing on the coded method.

Button circuit - The button switch circuit is configured as per Figure 1 (Circuit 1), below. This is a very common way to wire up a simple switch circuit. The circuit ensures that the digital input pin we declare and use as the interrupt pin is maintained at 0v when the switch is open (off), thereby removing spurious inputs arising from interference which would have the effect of falsely triggering the interrupt. When the switch is closed (on), the the digital pin rises to +5v and triggers the interrupt, as we require (see next section).

Interrupt mode - Next, we need to define the mode or type of interrupt trigger the digital pin will be sensitive to for firing the interrupt. As the circuit will cause the voltage to rise from 0v to +5v when the switch is closed, then the obvious choice of mode and respective parameter for attaching the interrupt is 'RISING'. For example, attachInterrupt(...,...,, RISING).

Switching style - Button switches are momentary switches, by which I mean that the switch's normal state is off until pressed when it is on until released when its state reverts back to off. So the switch is only on for the duration it is pressed. Obvious stuff, yes? Of course. However, the nature of mechanical button switches means that switching must go through the cycle of off-on and back to off before it can be said to have been fully pressed. Note also that the time it is kept pressed is variable too - I can keep my finger on the button for as long as I please.

If we also throw into the mix that switches are not perfect digital devices - they will invariably generate noise which can result in false triggering. The good news is that such noise can be accommodated through a technique known as 'debouncing'. Indeed, the offered sketch does incorporate this technique.

To understand what is going on, Figure 2 presents a simplified trace of a typical button switching cycle. It shows an example of noise as soon as the switch is pressed (point A) to being fully on (point B) and from the time it is released (point C) to being fully off (point D). The time the switch can be said to be reliably on is from B to C and this is a function for how long the switch is kept pressed. But, in truth, we need to account for false readings that may arise from noise at any point between A and D. So, things can be a bit messy - a switch interrupt can be triggered any time and we cant register that the switch has been pressed until we get to point D at the soonest. Quite a recipe of requirements!

Having said all that, there are numerous examples that do the job effectively. The method offered here, however, is straight forward, logical, concise and works - please do keep reading.

And The Solution Is...

The example solution is a sketch that addresses all of the above considerations and requirements in a simple, succinct and elegant way. Of note, and fundamental to its design, is that the method separates out switching initiation (the interrupt process) and switching completion (i.e. waiting for release and managing debounce).

It is also worthwhile mentioning that the switch reading process is non-exclusive (non-blocking), both when testing the digital input and when processing debounce. That is the approach allows the sketch to do other things even when the switch may be in transition.

Have a look at the sketch, load it up and try it out.

Further Investigation

If you are happy with the sketch and the way it operates, why not look at what changes may be necessary if you were to use a different switch circuit? For example, one that does not require a pull down resister. The circuit would look like Figure 3, below.

How would the sketch need to be altered?

Hint: the digital read pin would need to be at +5v (HIGH) as the button switch will cause current to flow from the digital pin to ground when pressed which will result in the triggering of the interrupt (switch would be wired up as per circuit_C2, above). Also, in setup(), this will require the switch pinMode call using the INPUTPULLUP parameter, rather than INPUT and an attachinterrupt call using the parameter 'FALLING', rather than 'RISING'.

Is that all? Not quite, because under open circuit conditions the digital pin will read HIGH which means the switch is open and LOW when the switch is closed - the reverse. See if you can work it out, but if not, have a look at the tutorial on button switches below which should help.

More Sophistication

If you have enjoyed looking and working through this article, then have a look at how we can use a single interrupt service routine (ISR) to handle any number of switches, virtually, without any additional wiring beyond the number of switches we wish to configure. The article is called "Multiple Switches, One Interrupt" and it makes use of the ez_switch_lib library (see below, Further Reading). The method is readily extensible to utilise any number of switches, button or toggle type and wired in either common wiring scheme.

Further Reading

You might also find these contributions interesting and useful, by the same author:

  • UnderstandIng and UsIng Button SwItches, the basIcs - button switches, a simple but often tricky piece of kit. The tutorial provides in ins and outs of implementing a simple button switch, with flexibility to explore differences in circuit design, different reading methods and debouncing.
  • External Interrupts, a generic framework supporting concurrent asynchronous multiple interrupts. Configure multiple external interrupts with different characteristics and add code to provide post-interrupt asynchronous processing.

Other Online Resources

Digital pins

Overview of Interrupts



Interrupt Handling for Button SwitchC/C++
An example sketch demonstrating an alternative approach to reading a button switch using an interrupt.
//  This example and code is in the public domain and may be used without restriction and
//  without warranty.
// Exmple sketch - Button Switch Using An External Interrupt
// '''''''''''''''''''''''''''''''''''''''''''''''''''''''''
// This sketch demonstrates the use of a simple button switch which is processed by
// an external interrupt process.  It presents a very different and alternative approach
// for associating a button switch to an interrupt.
// The sketch is designed such that button status is only flagged as 'switched' AFTER
// 1. button is pressed AND then released, AND
// 2. elapse of the debounce period AFTER release
// Note that the associated button interrupt handler function and the button_read()
// function work together - the interrupt handler starts the on/off process and the
// button_read() function completes/concludes it.  The interrupt handler can only restart AFTER
// button reading and debounce is complete.  This ensures that only one interrupt trigger is
// processed at a time.
// The button switch is wired in a standard configuration with a 10K ohm pull down resister which
// ensures the digital interrupt pin is kept LOW until the button switch is pressed and
// raises it to HIGH (+5v).
// Operation of the button is demonstrated by toggling the in built LED on and off.

#define LED                         LED_BUILTIN  // digital pin connected to LED, for testing of switch code only
bool    led_status =                        LOW; // start with LED off, for testing of switch code only

int     button_switch =                       2; // external interrupt pin

#define switched                            true // value if the button switch has been pressed
#define triggered                           true // controls interrupt handler
#define interrupt_trigger_type            RISING // interrupt triggered on a RISING input
#define debounce                              10 // time to wait in milli secs

volatile  bool interrupt_process_status = {
  !triggered                                     // start with no switch press pending, ie false (!triggered)
bool initialisation_complete =            false; // inhibit any interrupts until initialisation is complete

// ISR for handling interrupt triggers arising from associated button switch
void button_interrupt_handler()
  if (initialisation_complete == true)
  { //  all variables are initialised so we are okay to continue to process this interrupt
    if (interrupt_process_status == !triggered) {
      // new interrupt so okay start a new button read process -
      // now need to wait for button release plus debounce period to elapse
      // this will be done in the button_read function
      if (digitalRead(button_switch) == HIGH) {
        // button pressed, so we can start the read on/off + debounce cycle wich will
        // be completed by the button_read() function.
        interrupt_process_status = triggered;  // keep this ISR 'quiet' until button read fully completed
} // end of button_interrupt_handler

bool read_button() {
  int button_reading;
  // static variables because we need to retain old values between function calls
  static bool     switching_pending = false;
  static long int elapse_timer;
  if (interrupt_process_status == triggered) {
    // interrupt has been raised on this button so now need to complete
    // the button read process, ie wait until it has been released
    // and debounce time elapsed
    button_reading = digitalRead(button_switch);
    if (button_reading == HIGH) {
      // switch is pressed, so start/restart wait for button relealse, plus end of debounce process
      switching_pending = true;
      elapse_timer = millis(); // start elapse timing for debounce checking
    if (switching_pending && button_reading == LOW) {
      // switch was pressed, now released, so check if debounce time elapsed
      if (millis() - elapse_timer >= debounce) {
        // dounce time elapsed, so switch press cycle complete
        switching_pending = false;             // reset for next button press interrupt cycle
        interrupt_process_status = !triggered; // reopen ISR for business now button on/off/debounce cycle complete
        return switched;                       // advise that switch has been pressed
  return !switched; // either no press request or debounce period not elapsed
} // end of read_button function

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(button_switch, INPUT);
  initialisation_complete = true; // open interrupt processing for business
} // end of setup function

void loop() {
  // test buton switch and process if pressed
  if (read_button() == switched) {
    // button on/off cycle now complete, so flip LED between HIGH and LOW
    led_status = HIGH - led_status; // toggle state
    digitalWrite(LED, led_status);
  } else {
    // do other things....



Similar projects you might like

A Switch Library for Arduino

by ronbentley1

  • 1 comment
  • 7 respects

Understanding and Using Button Switches

by ronbentley1

  • 13 respects

10 Buttons Using 1 Interrupt

Project tutorial by Svizel_pritula

  • 87 respects

Arduino - Use Reset Button Like a Push Button

by RoHa

  • 13 respects

You've Been Using a Button Wrong this Whole Time

Project tutorial by SMM2

  • 8 respects
Add projectSign up / Login