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
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
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
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 3 This flowchart displays the process for reading an all-pushbutton system. Only one button at a time should be pressed.
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.
As the MCU clocks the CD4017
every 1 msec and increments the counter
variable by 1 if its value is less than
9, the CD4017 output corresponding
to the counter-variable value goes to
logic high from logic low; that is, if
the counter-variable value is 2, then
the decoded 2 output of the
CD4017 (pin 4) is at logic
high while all other outputs
are at logic low. At this time,
if the user pressed pushbutton
S2, it would send a logic-high
signal to the external
interrupt pin of the MCU.
Pressing any other button
does not generate external
interrupts, because all other
outputs of the CD4017 are in
the logic-low state.
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.