Pushbuttons and tilt sensors/switches: how they work and some Arduino usage examples

Last updated on Wed, 2010-07-21 06:35. Originally submitted by fabio on 2010-06-29 00:06.

In this blog post I describe two switching components available in the Arduino Base Workshop KIT: pushbuttons and tilt sensors. I'll briefly describe how they works, what's the theory behind them and how to create some simple circuits to use them with Arduino.

Pushbuttons

A pushbutton is a simple switch mechanism which permits user generated changes in the state of a circuit. Below you can see the pushbutton available in the Arduino Base Workshop KIT.

The Pushbutton Available in the Arduino Base Workshop KIT

Pushbutton usually comes with four legs. Anyway, as you can see from the picture below, legs are always connected in groups of two. When the pushbutton is pressed all the 4 legs are connected.

How pushbuttons legs works

A simple circuit using a pushbutton and the Arduino board

We can try how pushbuttons work by creating a simple circuit based on the Arduino board. Here is the circuit schematics:

Scheme of a simple circuit using a pushbutton on the Arduino board

The above circuit, once assembled on our breadboard and Arduino board, will looks like:

Picture of a simple circuit using a pushbutton on the Arduino board

How does it work? Well.. pretty simple. When we don't push the button, the circuit is open and no current flows in it so the LED remains off. When we push the button the circuit closes and current flows: the LED will be on. You can see this in the video below:

Tilt Sensors/Switches

Tilt Sensors or Tilt Switches are a pretty simple electronic component which consists of a small plastic case which contains a metal ball.

Picture of the tilt sensor available in the Arduino Base Workshop KIT

At the bottom of the sensor there are four legs which are disconnected. The ball inside the case is able to move: when you move the sensor with the legs at the bottom, the ball move to the bottom and connects the four legs. When the sensor is placed with the legs up, the ball moves to the top disconnectin the legs. You can understand the behaviour by having a look a the picture below:

What happens inside a tilt sensor/switch

So, you might already understood that a tilt sensor is basically a switch, just like a pushbutton. The difference between a tilt sensor and a pushbutton is how they mechanically change their open/close state: one by tilting, the other by pushing.

A simple circuit using a tilt sensor/switch and the Arduino board

Given the above considerations, we can use the same circuit used on the pushbutton example above. Obviously we will change the pushbutton with the tilt sensor. The circuit will looks like:

A simple circuit using a tilt sensor/switch and the Arduino board

What happens? If we place the circuit so that the tilt sensor is closed, we will see the LED on. Instead, if we reverse the orientation of the tilt sensor we will see the LED off. The video below shows you this:

Reading the state of a switch with Arduino board and a simple Arduino program: digitalRead()

The circuits we created above are really simple. We can't do much with them. Instead pushbuttons and tilt sensors might be really useful if we could get their on/off (closed/open) state as an input value to the Arduino board. We could use this value to trigger actions in an Arduino program. Well, this is actually not that complex. Let's see how.

We'll need to use the digitalRead() function available in the Arduino programming language. This function will return the constant HIGH when a voltage is applied to the digital input pin. Instead the function will return the constant LOW when there is no voltage applied: actually, as we'll see below, to ensure that the read value doesn't fluctuates we need to connect it to the ground.

So, we will need to give a current when our pushbutton is pressed. We could do that by simply connect the 5V power pin to a digital input pin with the pushbutton and a small resistor in series. Unfortunately this won't work: when the circuit is open (the pushbutton isn't pushed) we would get rubbish values from digitalRead(): the values would randomly between HIGH and LOw.

This is a consequence of how Arduino internal circuits works. To ensure that we always get a LOW value, we need to connect the pin to the Ground. So we would need a switch that connects the digital input pin to +5V when pressed while it connects to GND while not pressed. This is possible with 2 ways switches but they aren't available in the Arduino Base Workshop KIT.

We still can use our simple pushbutton. We just need a simple trick: a pulldown resistor! This is how our circuit will looks:

Scheme of the pushbutton digital read circuit with the pulldown resistor

The circuit above, once implemented on the Arduino board, will looks like:

Picture of the pushbutton digital read circuit with the pulldown resistor picture

How does this work? Well, this is explained pretty well in the ladyada.net Pushbutton tutorial:

Here's how to think of it: When you press the button and connect the 100Ω resistor to 5V, the button has a very small resistance (less than 1 Ω!), so it provides a strong pull to 5V.
The 10KΩ resistor is also connecting the 100Ω resistor to ground, but since the 10KΩ resistor has 10000 times more resistance than the button, its a very weak pull to ground and can't compete. The strong 5V connection overpowers the weak ground connection and the input pin reads HIGH.
However, when the switch is disconnected, there is no longer a strong pull to 5V. In fact, its let go completely. But there is still weak pull to ground. Despite being a weak connection, it's better than nothing and so the resistor pulls the input pin to LOW.

Program for reading the switch status using digitalRead()

Now that we know how to correctly connect a switch to get its status using the Arduino digital inputs we can write a little program which uses digitalRead() to do so. Our goal will be to light on an LED only if the pushbutton is pressed. If it's not the LED will be off. The following program does just that:

/**
* Turn on an LED connected to LEDPIN only when
* the value readed on INPIN is HIGH
*/

#define LEDPIN 13
#define INPIN 2


void setup() {
  pinMode(LEDPIN, OUTPUT);
  pinMode(INPIN, INPUT);
}

void loop() {
  if(digitalRead(INPIN) == HIGH){
    digitalWrite(LEDPIN, HIGH); // turns the LED on
  }
  else {
    digitalWrite(LEDPIN, LOW); // turns the LED off
  }
  delay(10); // debounces switch
}

Well, the program above it's pretty simple. When digitalRead(INPIN) is HIGH we turn the LED on. If it's LOW we turn the LED off.

The only peculiar part of this program is the delay(10) call. This is needed to debounces the switch. What does that mean? Well, everytime a pushbutton (or any other switching component) changes state there is really small period of time in which the value readed is instable: it would bounces between HIGH and LOW. This is a consequence of how mechanically the button changes state. The delay(10) helps to prevent reading bouncing values and only read stable values.

Use Interrupts instead of digitalRead()

Interrupts are a really useful features of microprocessors. As an example, they are pretty crucial in the design of operating systems. Have a look at wikipedia Interrupt page for more informations.

The Arduino Duemilanove board and its internal microporcessor (ATMEGA 328) support interrupts. Digital pins 2 and 3 can be set as interrupt inputs so that once the value read on them changes (or becomes LOW or is RISING - LOW to HIGH - or FALLING - HIGH to LOW) specific functions, called interrupt service routine, are executed, no matter what the board was executing.

The programming language has a function, attachInterrupt(interrupt, function, mode), which permits making a function as a interrupt service routine on a given mode.

Using interrupts is demonstrated in the following little program:

/**
* Turn on an LED connected to LEDPIN only when the input 
* readed on INTERRUPTPIN (0 is Pin 2) changes its value
*/

#define LEDPIN 13
#define INTERRUPTPIN 0

volatile boolean state = LOW;

void setup() {
  pinMode(LEDPIN, OUTPUT);
  attachInterrupt(INTERRUPTPIN, buttonChange, CHANGE);
}

void loop() {
  digitalWrite(LEDPIN, state);
}

void buttonChange()
{
  state = !state;
}

The above code does just the same of the other program but it does using interrupts. With this little example the importance of interrupts is still to be shown but imagine this example: your Arduino board controls an assembly line where workers assemble pieces of cars. Somehow one of the worker drops under one of the machines and he's in danger. Fortunately you programmed an emergency routine which stops the assembly line: obviously you used a pushbutton to trigger an interrupt which had attached the emergency routine. Cool, uh?

NOTE: Unfortunately the above code isn't bounces safe. You will notice this when somehow it reverse the switch pressed/unpressed and LED on/off associations. Unfortunately I've not been able to fix this. If you have ideas please leave a comment below.

Conclusions

With this experiments I understood how to correctly use switching components: buttons and tilt sensors should be pretty known now. As usual there are really many usages one could imagine of those basic components. I'm pretty sure we'll do a lot of use of them.

Another really cool feature are interrupts which are pretty simple to use in Arduino, I'm looking forward to make cool uses of them!

References

  1. Pushbutton on Wikipedia
  2. Pushbuttons Arduino tutorial on ladyada.net
  3. Getting Started with Arduino by Massimo Banzi - Chapter 5 "advanced input output"
  4. Interrupts on Wikipedia
  5. Interrupts reference at arduino.cc

Hardware Debounce

Submitted by Ahmed (not verified) on Thu, 2013-06-20 23:57.

you can add an Capacitor and a Schmitt trigger Inverter just like this video min ~4.20

https://www.youtube.com/watch?v=CRJUdf5TTQQ

:D

Such an interesting

Submitted by nelly (not verified) on Mon, 2013-02-18 11:01.

Such an interesting technique! I wonder how many car owners are familiar with it, I own a car but when it comes to knowing the parts and the mechanisms in it I don't know too much thus I can be easily tricked.

Multiple Buttons

Submitted by Paul Sieradzki (not verified) on Thu, 2012-11-22 22:33.

Hello,

I found your guide after days of frustration attempting to simply connect 5V -> button -> PIN. I purchased an 8-button array from a website and made 8 resistor circuits for each button. Each works perfectly independently. Being that the Arduino doesn't have 8 ground pins, I wired all of the ground pins from the 8 buttons to 1 wire and connected that to Arduino. Now the light no longer blinks when there is a button press, just a slight change in brightness. Connecting any of the buttons only one at a time works like a charm, though.

Any ideas as to why? Or how I can fix this?

You probably have something

Submitted by fabio on Fri, 2012-11-23 00:08.

You probably have something wrong somewhere in your circuit.. It's hard to know where..

Anyways, do you know about internal pullups and how they can be used to simplify the connections of buttons? Check out my thesis, page 60.

debouncing a pushbutton interrupt

Submitted by Anonymous (not verified) on Fri, 2010-11-12 07:30.

to debounce the interrupt version of the switch program, couldn't you just change


void buttonChange(){
state = !state;
}

to:


void buttonChange(){
delay(10);
state = !state;
}

??

Also, I tried to use code tags to make the above nicer, but the formatting was seriously screwed up and unreadable... dunno why, just thought I'd let you know

It's not that easy...

Submitted by fabio on Fri, 2010-11-12 10:09.

Nope. delay() isn't available in interrupt handling functions.

From http://www.arduino.cc/en/Reference/AttachInterrupt :

Inside the attached function, delay() won't work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function.

I still don't know a software only debounce solution for interrupts handling. Anyone has ideas?

BTW, thanks for reporting the issue with the code tag. It should be fixed now.

Post new comment

The content of this field is kept private and will not be shown publicly.
If you have a personal or company website insert its address in the form http://www.example.com/ .
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <pre> <small> <del> <img> <h2> <h3> <h4> <b> <video> <sub> <sup>
  • Lines and paragraphs break automatically.
  • Images can be added to this post.
  • You may use [inline:xx] tags to display uploaded files or images inline.
  • You may insert videos with [video:URL]
  • Each email address will be obfuscated in a human readable fashion or (if JavaScript is enabled) replaced with a spamproof clickable link.

More information about formatting options