Read 10 or more switches using only two I/O pins of a microcontroller
Aruna Rubasinghe - February 28, 2013
| Click here to download a PDF |
There are several ways to read multiple switch inputs using a reduced number of microcontroller-unit (MCU) pins. For example, you can use an analog MCU pin to read multiple switches by assigning a unique voltage to each switch through a resistor network, or you can use a one-wire device, such as the Maxim DS2408 8-channel addressable switch.
The first method has several disadvantages: The MCU has to have an ADC function, debounce wait times reduce the polling rate, and an error results if the switch is opened during the ADC sampling time. The second method also has the drawback of comparatively low speed; it uses 1-wire communication, which requires continuous polling; and each poll generates an 8-bit data sequence relevant to switch positions.
This Design Idea describes a method for reading multiple pushbuttons or open/closed switches using only two digital I/O pins and a timer interrupt of the MCU (Figure 1). Optionally, a third I/O pin can be assigned to periodically reset the CD4017 (a cascadable decoded 1-of-10 Johnson counter) for reliable operation should an EMI or ESD event occur that could falsely clock the counter, or you can use the circuit shown in Figure 2 and retain the two-pin feature. The diodes isolate the counter outputs in the event that two or more switches are closed at the same time. You can increase the number of switches connected by cascading multiple CD4017 ICs using a carry-out signal (pin 12) and a clock signal (pin 14).

Figure 1 You can easily expand this circuit to many more than 10 switches, yet still use only two MCU I/O pins, by cascading multiple CD4017 counters through their carry-outs to the following enables.
Reliable operation following the initial power-up reset depends on the CD4017 counter’s remaining synchronized with the MCU counter. This synchronization can be upset by an ESD or EMI event such as a nearby cell phone, so it would be wise to include in the firmware a periodic hardware reset to the CD4017 to keep the counts synchronized. Figure 2 shows how you can do this without having to use a third MCU pin.

Figure 2 You can add three resistors and a transistor to implement the occasional synchronizing reset without using a third I/O pin.
For this function, you use the MCU’s ability to keep its I/O pin in three different states: high, low, and, by temporarily changing the pin to an input, high impedance.
In the logic-high state, transistor Q1 turns on through R4, making the voltage on V1 logic high and the voltage on V2 below the logic-low level. This sets the clock pin to a logic high while keeping the reset pin at a logic low.
In the logic-low state, transistor Q1 turns off, making the voltage on V1 logic low and the voltage on V2 above the logic-high level. This sets the reset pin to logic high while keeping the clock in the logic-low state.
In the idle high-impedance state,
transistor Q1 is turned on through R3
and R4, making the voltage on V1 and
V2 below the logic-low level. This sets
both the clock and reset pins of the
CD4017 to a logic-low state.
To send a clock edge, therefore, change the state in the following manner: high impedance > logic high > high impedance. Likewise, to reset the CD4017, change the state as follows: high impedance > logic low > high impedance.
The flowchart in Figure 3 is for an all-pushbutton system and functions as follows: At the start, the MCU sets a counter variable to 0 and starts an interrupt-enabled timer, which is set to overflow and interrupt at 1-msec intervals. In the timer-interrupt routine, several tasks are carried out: External interrupts are disabled; the counter variable is incremented by 1; a 10-μsec clock pulse is sent to the CD4017; and the external interrupt is enabled.
Figure 2 The electronic signals to the controller chip embedded in most character displays includes a data bus, read/write, clock, backlight control, contrast control, and a signal to put the display into command mode.
![]() Figure 4 When non-momentary toggle switches are used, you can decode multiple combinations of switch closures by checking the state of the interrupt input. |
When the MCU receives the external interrupt, it gets the current counter-variable value (which is 2) from its memory, identifies the pressed button as S2, and thus carries out the functions relevant to S2. When the counter variable reaches 9, it is set to 0 through the software, as the CD4017 also resets automatically at the 10th pulse.
Note that only one button at a time should be pressed; if two consecutive buttons are pressed together, there may not be enough dropout time between successive counter states for the interrupt edge to register. You can resolve this issue by using the flowchart shown in Figure 4.
Read 10 or more switches using only two I/O pins of a microcontroller
Special Report: Top 25 global electronics component distributors
A circuit simplification for AC power supply surge protection devices
High-Voltage Silicon MOSFETs, GaN, and SiC: All have a place
PCB layout considerations for non-isolated switching power supplies
Build an op amp with three discrete transistors
Coupling a supercapacitor with a small energy-harvesting source
Power Tip #49: Avoid these common MLCC pitfalls
Component obsolescence: Is your process up to the challenge? (Part 2)
Using a power transformer at a frequency it wasn't designed for

