Multiple buttons on one pin with an Arduino

Here is a circuit that allows you to use five buttons; up, down, left, right and select, on one analogue pin with the Arduino. It is a adaptation of one used on this LCD shield manufactured by DF Robot. I have used a 10K pull-up resistor and added a 100nF capacitor to help with debounce. The downside is that this can only detect one button press at a time, the button with the lowest resistor value is returned, and the output varies when different voltages are used to power it requiring an update to your software.

In this post I am looking to explore the effect of the existing resistor values, and how to choose your own resistors. This kind of circuit is called a multiple voltage divider or voltage ladder where each rung of the ladder, the switches in the diagram above, produces a different output voltage. Pressing one of the buttons on our circuit changes the output to the analogue port from 5V to a lower one determined by the number of resistors (R1 to R4) in series before the button, as you go down the ladder the output voltage to the pin increases. Here is a short sketch I used to test the circuit and show the voltage reading for each button:

The results from this are shown in the chart below, for the power I used the regulated 5V and 3.3V outputs on the Ardunio Uno, if you run this set-up yourself you may notice an anomalous reading when you release the button, more about this later. Note that a button press drops the power down to the recorded value, the pin is normally high (5V/3.3V) through the 10K resistor.

Resistance1 at 5v at 3v3
Btn Value Meter reading2 volt reading2 volt
S1 none 0 0V 0 0V
S2 330Ω 334Ω 31 0.15V 19 0.10V
S3 950Ω 964Ω 88 0.43V 57 0.29V
S4 1950Ω 1948Ω 166 0.81V 108 0.53V
S5 5250Ω 5270Ω 352 1.72V 230 1.14V
1: Total value of the resistors in series at the button. 2: this is an average, the actual reading can vary.

There are two columns for the resistance, the value marked on the resistors and the multimeter reading. It is best to use 1% tolerance resistors for this circuit to reduce the chances of the readings drifting close to the next. A good spread of output voltages ensures accurate switching.

All this works very well, but what to do if you wish to add more buttons, or have different output voltages? Looking at the circuit, each button can be seen as a voltage divider, such as shown in the diagram on the left. Where R1 is the 10K pull-up resistor and R2 is the sum of the resistors for the button being pressed.

With this simplified model we can calculate any missing value, but for now there are a couple of things to do; calculate the output voltage for the given input voltage and resistance and more usefully for us, work out a value for R2 to give us the desired output voltage.

Calculating the Output Voltage

Using Switch 2 in our existing circuit for example, with 5 volt power:

    \[ Vout = Vin \times \frac{R_2}{R_1 + R_2} \hspace{15 mm}with\ numbers:\hspace{4 mm} 5 \times \frac{330}{10,000 + 330} = 0.16V \]

And again with Switch 4. This has three resistors in series so the value for R2 in the voltage divider is: 330R + 620R + 1K = 1950 ohm:

    \[5 \times \frac{1,950}{10,000 + 1,950} = 0.82V \]

its rather satisfying when your calculations closely agree with the real world readings.

Setting the output Voltage

So, lets try working out some resistors based on the following specification: powered at 5V with five buttons, each 0.20V apart; S1: 0V, S2: 0.20V, S3: 0.40V etc. We know the input voltage, output voltage, and resistor R1, but not R2, here is the formula for finding the resistance of R2:

    \[ R_2 = Vout \times \frac{R_1}{Vin - Vout} \]

    \[ S2: 0.20 \times \frac{10,000}{5 - 0.20} = 417\X\Omega \hspace{5 mm} S3: 0.40 \times \frac{10,000}{5 - 0.40} = 870\X\Omega \hspace{5 mm} S4: 0.60 \times \frac{10,000}{5 - 0.60} = 1364\X\Omega \hspace{5 mm} S5: 0.80 \times \frac{10,000}{5 - 0.80} = 1905\X\Omega\]

These values show the resistance required for each switch and to find the resistor the previous resistance value needs to be deducted. As these values probably won’t be in the E24 Standard Value range and won’t be available in the shops I have the nearest available value in the Standard Resistor column:

Btn Resistance Resistor Standard
Resistor
S1 none
S2 417Ω 417Ω R1: 390Ω
S3 870Ω 453Ω R2: 430Ω
S4 1364Ω 494Ω R3: 560Ω1
S5 1905Ω 541Ω R4: 560Ω
1: actually the nearest is 510Ω, but 560Ω was the closest I had

Obviously, we will need to get this onto breadboard for testing.

Using the same sketch as before I re-ran the tests with the new resistor values, the results are shown below; I have also included an Expected column to show the calculated voltage using the method shown earlier.

at 5v at 3v3
btn Resistor Resistance expected reading volt expected reading volt
S1 none 0 0V 0 0V
S2 R1 390Ω 390Ω 0.19V 39 0.19V 0.12V 25 0.12V
S3 R2 430Ω 820Ω 0.38V 76 0.37V 0.25V 50 0.25V
S4 R3 560Ω 1380Ω 0.61V 122 0.60V 0.40V 81 0.40V
S5 R4 560Ω 1940Ω 0.81V 165 0.81V 0.53V 108 0.53V

That, to me, looks close enough to the 0.20V separation at 5V specified to provide some stable hardware. Here is a short sketch to demonstrate the use of analogue buttons, it returns a number corresponding to the button pressed. When you release a button its resistance changes momentarily to give the Arduino a false reading, to fix this I have added de-bounce functionality to this program:

With this substitution on R3, changing the desired 510 ohm resistor for a 560 ohm, It may be interesting to see what kind of tolerance range we may be able to use. So, for the 0.60V output the optimal resistor would be 494 ohm but we only have Standard Resistor values available and to find the resistance value for our calculation to find the output voltage we need to add 820 ohm (R1 + R2) to R3:

Resistor Resistance Volts
430Ω 1250Ω 0.5556V
470Ω 1290Ω 0.5713V
510Ω 1330Ω 0.5869V
560Ω 1380Ω 0.6063V
620Ω 14400Ω 0.6294V

Clearly, using four decimal places shows is that a 510 ohm resistor is rounded up to 0.60V, while the 560 ohm rounds up to 0.61V, so for our purposes both are suitable. The other resistors will be outside the specification.

Finding the Power Consumption

We also need to look at how much power our circuit is consuming, this is for two reasons: to ensure that our resistors are properly rated and that the power supply can supply enough power. The Ardunio Uno provides a regulated supply of 20mA at 5V and 50mA at 3.3V. The calculation is done with Ohms law:

    \[ I = \frac{V}{R} \]

So, in the original circuit the shortest path to ground is through Switch 1 and the 10K resistor:

    \[\frac{5}{10,000} = 0.0005A \times 1000 = 0.5mA \]

a very low current, this is the maximum the circuit can use. Optionally, to work out the power use for another button add up all the resistors before the switch, for example in the original circuit Switch 5 comes to: 15250 ohm

    \[\frac{5}{15,250} = 0.00034A \times 1000 = 0.34mA \]

Voltage Divider Calculations

Just to round things off, here are four formulae for finding any resistor and voltage in the divider circuit:

    \[find\ resistor\ value: R_1 = \frac{Vin \times R_2}{Vout}-R_2 \hspace{20 mm} R_2 = Vout \times \frac{R_1}{Vin - Vout}\]

    \[find\ the\ voltage: Vin = \frac{Vout \times (R_1 + R_2)}{R_2} \hspace{20 mm} Vout = Vin \times \frac{R_2}{R_1 + R_2}\]

Links and Sources

2 thoughts on “Multiple buttons on one pin with an Arduino”

  1. Hello,

    I already have a ladder circuit but I couldn’t create nor find the code to debounce. Your code will do it hopefully, however I think there’s a mistake in this part:

    if (buttonOut != lastButton && lastBtnPress > millis()) {
    out = 0;
    }
    The “out” variable was not declared anywhere. What’s its purpose?

    Thank you in advance.

Leave a Reply

Your email address will not be published. Required fields are marked *