Microcontroller Interfacing –  Part 6

Interfacing Switches


This section covers techniques to interface switches to a microcontroller.

Controlling Inputs with Switches

A microcontroller can’t make any decisions on controlling something in the outside world without sensing something about it.  The simplest thing for a microcontroller to check is the status of a switch. Is it open or closed?

Switches can be used as operator controls. They can sense if a door is open or closed. A limit switch can detect if a part of a machine has reached a certain position. Switches can be used for many purposes, but they can be in only one of two states: On (closed) or Off (open).

Figure 6-1 shows two common ways to interface switches to a microcontroller input.  Input P0 uses R1 as a pull up. If SW1 is open, P0 will be high, and read as a logical 1.  When SW1 is closed, pin P0 is shorted to ground, or 0V, and P0 will read as a logical 0.  

Figure 6-1

Note that some microcontrollers have internal pull up resistors that can be enabled under program controller.  You don’t need to wire up R1 if you use an internal pull up resistor.  If you use an external pull up resistor, tie the high end to the same voltage used to run the microcontroller. Using a higher voltage will damage the microcontroller, and a lower voltage may result the circuit not working. Part 5 discussed the use of pull up resistors in more detail.

P1 has R2 as a pull down resistor. When SW2 is open, P1 is pulled low, and read as a logical 0. Closing SW2 causes current to flow through R2, raising the voltage at P1 to the Vcc level. At that point P1 will read as a logical 1.

If you don’t have a pull up or pull down resistor, the input will float and when the switch is open the input will be very susceptible to noise causing false readings. Part 5 discusses this in more detail. Which of the two methods should you use? I usually use the pull up resistor. That is a habit gained when I did a lot of design with bipolar transistor TTL logic gates.  Pull down resistors are not recommended with that technology. With MOS microcontrollers there is no major advantage of one over another.  Use whatever you prefer.

Your program can check the states of the switches, and execute different code depending on the state of the switch.

Switch Bounce

An unfortunate characteristic of switches is that they don’t switch cleanly. The mechanical components of a switch vibrate back and forth making a number of momentary contacts before finally settling down to the final state. Figure 6-2 shows what an oscilloscope attached to P0 in Figure 6-1 would show when SW1 is closed.  P0 goes high and low a number of times when the switch is first closed.

A microcontroller operates thousands of times faster than a mechanical switch. It would see each of the short pulses as individual switch openings and closures. If the switch is used for counting events, the microcontroller count would be many times the true number of events. In another application the switch might be used to turn a light or motor on and off.  

Figure 6-2

Press the button and the light goes on. Press it again and it will go off.  If switch bounce is not accounted for, the user would think the switch or device is operating erratically.  When the button is pressed, sometimes the light will not go on, other times it will not turn it off when it was supposed to.  In reality the microcontroller is turning the light on and off several times, but too fast to observe. The final number of bounces the switch makes each time will determine if desired operation is achieved.

There are a number of ways of handling switch bounce. Simple cross couple logic gates forming flip-flops can be used, but debouncing switches is usually done in software.  Once developed, software is free. Hardware costs money each time another unit is manufactured.  Simple C-like pseudo code to debounce a switch is shown in Listing 6-1. It could be used with the configuration of P0 in Figure 6-1.

Listing 6-1 is a function that the program calls every time it needs to check the status of a switch attached to I/O pin P0. The function returns a byte with the value of 1 if the switch is closed, and a value of 0 if it is open.  It is assumed that the port pin has already been set up to act as an input.  The actual syntax of the statements for reading the state of a pin will depend on the compiler. The C language standards do not define syntax for how an input is read, so each compiler implements this differently.

The first statement inside the function checks if the port is reading low (switch closed).  If it is, wait 50 milliseconds and see if it is still closed.  If it is still closed, the function returns a value of 1 to indicate the switch is closed. If none of the conditions are met, the function returns a logical 0, indicating the switch is open.

The program must call this function frequently to ensure it catches every switch closure. This is especially true if the switch closure is going to be short, say for a user press of a momentary push button switch.  If the delay function is not in there, and the switch has bounce, the function could be called several times and get multiple readings of the switch being open and closed.  The delay prevents the function from being called multiple times during a debounce period.

The delay function in Listing 6-1 sits in a loop until the period specified has elapsed. Your compiler may have a delay function as part of its library functions. Otherwise you will have to write your own. You will also need to write your own or find one on line if you program in assembly language.  The listing shows a delay of 50 milliseconds.  The actual delay you need will depend on the switch you are using.  This is usually done experimentally.  The value of 50 milliseconds works well for many switches and is a good starting point.

char Check_P0(void)   //returns 1 if switch attached to                                     //P0 is closed, 0 if switch is open


if(P0 == 0) //check if pin P0 is low, meaning switch is on


     delay_msec(50);  //wait 50 msec to allow any                                  //switch bounce to die out

      if(P0 == 0)return(1);   //the switch is really closed


return(0);  //the switch is open

}  /* end of Check_P0 function */


Listing 6-1

If your delay period is too short you risk reading multiple switch closures from a single actual switch closure. If your period is too long, you risk missing multiple real short period switch closures. Also, with simple program delay functions, you are just in a loop counting milliseconds. Unless you have a multitasking application with an appropriate delay function, your program is not doing any other useful things during the delay period. Fifty milliseconds is a very long time to a modern microcontroller.  This may or may not be important depending on your application.

There is one other programming consideration.  After it detects a switch closure, the program needs to verify the switch is then opened before assuming the value returned by the function is a new switch closure.


This section covered the basic methods of using a switch to indicate an external event.  Switched inputs need a pull up or pull down resistor to hold the input to a specific value when the switch is open.  The value of the resistor will have an effect on the power consumption of the circuit.

Switches do not switch cleanly, and some debounce method must be used to prevent multiple false readings.


Arduino Tips  

You can use the internal pull up resistor when connecting a switch to an Arduino pin.  Connect the other switch pin to ground like SW-1 in Figure 6-1.

You can enable the internal pull up resistor on an Arduino pin with the following instructions:  

pinMode(pin, INPUT);       // set pin to be an input

digitalWrite(pin, HIGH);    // turn on pin's pull up resistor

Gotcha Checklist

1. Use a pull up or pull down resistor to ensure the  pin state when the switch is open

2. Account for switch debounce to prevent detecting multiple false switch closures (or opens).

© 2009 - 2022 Gary C. Sutcliffe


Selecting Resistor Values

What value should be used for pull up (or pull down) resistors?  A lot depends on the demands of the application.  A big part of the decision is how much power the application can afford to use.

When a switch is closed, current will flow through the resistor.  The current will depend on the value of the resistor and the voltage used to power the circuit. The current can be determined with Ohm’s Law:

I = V/R

Similarly, the power consumed by using the formula:

P= V^2/R

With a 1000 (1K) ohm resistor and a 5V supply voltage, we get the following:

I = V/R = 5/1000 = .005 A or 5 ma   P= V^2/R = 5 * 5/1000 = .025W or 25 mw

With a 10,000 (10K) ohm resistor in the same circuit we get:

I = V/R = 5/10000 = .0005 A or .5 ma   P= V^2/R = 5 * 5/10000 = .0025W or 2.5 mw

Clearly using a higher value resistor uses less power, so why not just use very large resistors for switch pull ups?  The problem is that high resistor values make the circuit more sensitive to noise.  A small amount of noise current injected into a high impedance circuit could generate enough voltage to cause an incorrect reading.

Too high a resistance can also make a circuit sensitive to leakage from moisture or contamination on the circuit board.  I once designed a portable device with a PIC microcontroller. It had some input switches for operator control. Wanting to maximize battery life, I used 47K Ω pull up resistors.  Things worked fine until units started to get returned for erratic operation.  They all worked fine once they got back. The ones getting returned were coming back from Central America and Pacific islands.  It turned out that condensation from the high humidity was enough of a path to pull the input pins low.  After that the boards were given a conformal coating to keep moisture off the conductors.

The purpose of the switch will also determine how critical power consumption is, even in a battery application. If the switch is a push button type the user only presses occasionally for a fraction of second, the total power consumption will be low.  A slide or toggle switch that might be left in the closed position for long periods of time could cause significant battery drain.

As a practical matter, values greater than 1KΩ and less than 20KΩ will work pretty well. Unless I have some special needs I usually just use 10K resistors as a good compromise between power use and noise immunity.  A future section of this series will cover handling other ways of dealing with noise on input lines.  

Created with the QTH.com SiteBuilder.