How to Access 5 Buttons Through 1 Arduino Input

Using this method, I'll show you how you can access 5 (or even more) inputs through 1 Arduino pin. These buttons will only be read correctly if only one is pushed at any time though.

As we go through it I'll explain whatever background info you need to know, so as long as you can blink a button, read a switch and read an analog input, you'll be fine. If you can't do any of these, I'll point you in the right direction in the relevant steps as well.

Step 1: Parts List

This is pretty simple:

1 x Arduino (Obviously)
1 x 100K Resistor (Brown Black Yellow)
1 x 1K Resistor (Brown Black Red)
1 x 10K Resistor (Brown Black Orange)
1 x 33K Resistor (Orange Orange Orange)
1 x 68K Resistor (Blue Gray Orange)
4 x Push button switches
Some wires to connect it all

You can use any push buttons you might have lying around, and the resistor values are not critical. More on this later.

Step 2: The Theory - How Buttons Are Normally Read.

Lets first look at how you would normally read a button. In its simplest form, you would connect your button like the circuit shown.

As you can see, you need 1 Input pin and 1 resistor per button, and then you can check the state in your Arduino sketch using this:
buttonState = digitalRead(buttonPin);
I'm not showing all the setup etc... Obviously you need to declare everything and set the pin as an input, etc. You can see the full example on the Arduino website.

This is fine if you are only using 1 or 2 buttons, but what if you need 10? That leaves very little IO pins for anything else you might want to do.

Step 3: The Theory - Multiple Buttons on One Pin

So how do you put multiple buttons on one pin?

You cheat! The secret to this is using an analog input pin, not digital.

You can read about how the analog input works by going through this Arduino tutorial. Essentially, what you need to know though is that when there is 0V on the analog pin, analogRead() returns a value of 0 and if there is 5V, analogRead will return a value of 1023. For any voltage between 0V and 5V, analogRead will return a number proportional to the voltage.

We can't actually change the voltage that is supplied to the pin (Not easily at any rate, and I'm lazy, so easy is important), but if you remember from Ohms law, V=IR. The current (I) is fixed, which means that we just need to add a resistor between the supply voltage and the analog pin to change the voltage.

For those of you that were getting excited about all the maths that's necessary to calculate the voltages, I'm going to have to disappoint you... I'm lazy, so I don't need maths.

Let's get a bit more practical, and I'll show you why we don't care about the maths. We know that the analog pin reads voltages and we know that we can change those voltages by adding a resistor between it and the supply voltage. We also know that we've gone this far because we want to be able to read switches, so we should probably toss some switches in too.

Now, for those that are interested, To design this, you start with what you know. I know how to connect a single switch to a single input. I wanted 5 buttons, so I duplicated it 5 times. I then simplified it by having a single pull down resister connected to all the buttons, and then simply put resistors between the buttons and the supply voltage and tied all the inputs together.

If you connect each button to the supply voltage through a different value resistor, depending on which button is pushed, the value returned by analogRead would be different, and you can use a bunch of if statements to see which button was pressed. The reason we don't need maths is because we just connect it all up, push the buttons and print the returned values to the serial port.

Step 4: At Last We Can Breadboard It.

Using the previous circuit, build it on a breadboard. I'll show you how I did it, but this is very dependent on which buttons you use, so you'll need to use your imagination. I used micro buttons from old computer mice. I also only had 4 buttons (that worked properly at any rate), so I decided to only do 4 buttons, but the code is set up to handle a 5th button.

Once the circuit is built, you can hook up the GND and 5V to the Arduino, and connect the buttons to analog pin 0 (You can change it, just remember to change it in the sketch).

Remember that I said we don't need the maths? I prefer trial and error. For your resistor values, you should pick values that are fairly evenly spread between an arbitrary lower and higher range. I found that values spread between about 1K and 100K work best. For my resistors, I happened to have 1K, 10K, 33K and 68K lying around, so I used those. If I had a fifth button, i would add a 47K resistor between 33K and 68K.

After I built it, I realize now that the 1K resistor is probably not needed. One of your buttons could be connected directly to 5V, so you need one resistor less than buttons (and the one pull down resistor shared by all the buttons). If one of your buttons is connected to 5V it should always return a value of 1023. So if you want to save a couple of cents, leave out the resistor on button 1.

Step 5: Testing It

Download the attached sketch and upload it to your Arduino. Once it is uploaded, open the serial monitor as well. to test it, watch the serial monitor and then hold down button 1. You will see that the values returned will fluctuate for a bit before settling down in a small band of numbers. Write down the biggest and smallest numbers.

Using the 1K resistor with my button, I got values ranging between 988 and 1011.

After repeating this for all the buttons, I got the following values:
Using the 1K resistor with my button, I got values ranging between 988 and 1011.
Using the 10K resistor with my button, I got values ranging between 910 and 929.
Using the 33K resistor with my button, I got values ranging between 767 and 768.
Using the 68K resistor with my button, I got values ranging between 400 and 609.

The first thing that is clear is that the range is bigger for some buttons. I retested several times with consistent results. I actually replaced the second button because I was getting all kinds of results. I was getting numbers ranging from about 510 all the way through 910, so if you get a huge range of numbers, try a different button.

Once you have these values, you can create a sketch that will read the state of a specific button.

Step 6: Coding It.

To code it, I simply took the debounced button example and modified that to set a state based on which button was pressed rather than just a simple HIGH or LOW state.

You can download the attached sketch. It is actually quite simple. The first section sets up all the variables and constants we'll use.

const int buttonPin = 0;     // the number of the pushbuttons pin
const int ledPin =  13;      // the number of the LED pin for testing

 
The above just sets up the pins used. Then you need to set up each button and the range of values for that button:

 const int BUTTON1 = 1;
...
 const int BUTTON1LOW = 970;
 const int BUTTON1HIGH = 1024;
...

In the setup, we simply set the pin states and start the serial port (which button is pressed will be written to the serial output):

pinMode(buttonPin, INPUT);
   pinMode(ledPin, OUTPUT);
   Serial.begin(9600);


Then we get to the interesting part. The first part of the program loop is where the magic actually happens, but it simply checks which button was read based on the value we got from analogRead():

int reading = analogRead(buttonPin);
   int tmpButtonState = LOW;             // the current reading from the input pin
  
   if(reading>BUTTON5LOW && reading     //Read switch 5
     tmpButtonState = BUTTON5;
   }else if(reading>BUTTON4LOW && reading     //Read switch 4
     tmpButtonState = BUTTON4;
   }else if
....
   }else{
     //No button is pressed;
     tmpButtonState = LOW;
   }


The next part just debounces the button press. Basically, without this, pressing the button once would appear to the code as multiple presses. Usually this would allow you to use the button as a toggle switch as well, but I'm not doing that.

I'm planning on using the buttons as reset buttons, so I just need to detect when they are pushed and reset a specific variable.

   if (tmpButtonState != lastButtonState) {
     lastDebounceTime = millis();
   }

   if ((millis() - lastDebounceTime) > debounceDelay) {
     buttonState = tmpButtonState;
   }
   lastButtonState = tmpButtonState;


The last part of the program is just a switch statement that executes different code based on which button was pressed. For testing, they all just switch on the built in LED on pin 13.

switch(buttonState){
     case LOW:
     digitalWrite(ledPin, LOW);
     break;
     case BUTTON1:
     digitalWrite(ledPin, HIGH);
     break;
...
}


And that is in essence how easy it is to control multiple buttons. I haven't implemented this into my project yet, so I might do a library for it at some stage if I need to.

Step 7: Improving It

As with all projects, as soon as I'm done, I start thinking about how I can improve it... Here's some thoughts I had:

1. The consistency of the value returned by analogRead is determined by a couple of things:
   - The power supply. The value could vary dramatically if your power is not well regulated. On a regulated supply, maybe a capacitor could smooth the supply some more?
   - The button. I'm not sure why this would be. One thing I noticed is that the values jump around most right as the state changes. My best guess is that it could be caused by the back emf generated when the button is pressed / released. Maybe a diode across the button could clean it up a bit.

Of course, you might be wondering why we need to improve it. After all, it works fine.

If you could get the range of values for each button down to a minimum, you would be able to put a lot more buttons on each analog pin.

For example, if you could get the values for each button within about 60 points, you could easily put 12 buttons on a pin and use each value resistor in the E12 range between 10K and 100K (10k, 12k, 15k, 18k, 22k, 27k, 33k, 39k, 47k, 56k, 68k, 82k and 100k)

You would probably need to use more accurate resistors (or just measure them and use the ones that are close enough to the target value), and you might need to pick your buttons carefully, but the fact that my third button is always in a range of 2 points proves that you should be able to do this.

The second reason is to get it to work with multiple buttons.

Why shouldn't it work with multiple buttons? Once again, I'm not actually going to do the maths (Turns out I'm still lazy), but I am pretty sure that by choosing your resistors carefully, you could figure out which buttons were pressed even if it was more than one.

If you look at the circuit, you can see that by pressing 2 buttons at the same time, you are essentially putting their 2 resistors in parallel. By calling on uncle Ohm again, you have a formula for determining the total resistance for parallel resistors.

For example, if I pressed my second and third buttons, you can see that a 10K resistor in parallel with a 33K resistor gives you a total resistance of  7.6744K (Nope, I googled it - still no maths). This would be easy to pick up in the code. If however I pushed button 1 and 2 though, the resistance for a parallel 1K and 10K resistor would be 900 Ohms, so now we are in the same range as for button 1.

Of course, if you left out the 1K resistor, there would be no way to detect if button 1 was pressed with any other button. Since I don't need to detect multiple button presses, I 'm not going into more details (At this stage at any rate).

Step 8: Final Thoughts

Thanks for reading!  I hope you found this useful. It is my first Instructable, so any feedback - or ratings, wink, wink :) would be appreciated.

Please take the time to vote for me in the Arduino contest if you found this helpful.

This is the first part of a pretty big project. Look out for my next instructables on running lots of LED's on a small amount of pins and running lots of 7 segment displays on a few pins. Once that is done I'm going to have to put it all together.

Hint: I'm planning on running 4 buttons, 20 Led's 4 seven segment displays and an RGB orb on one Arduino. Then I'm going to need to write some software to control it all from my laptop.

If anybody wants me to document all of it, please let me know in the comments.

3 People Made This Project!

Recommendations

  • Make it Glow Contest 2018

    Make it Glow Contest 2018
  • Plastics Contest

    Plastics Contest
  • Optics Contest

    Optics Contest

37 Discussions

0
None
dwaynez

9 months ago

Good job. I used your work here as I have 3 nanos and I needed to uniquely identify the board (using the same sketch on each). I used have a different resistor value on each nano and I have my unique id by measuring the analog value. I don't have the problem you were having with varying values.

0
None
pk.jimoc

1 year ago

what happens if you press two or three buttons together?

0
None
Stuka39

1 year ago

That's very nice, but what if you wanted to add an indicator LED to every switch (which turns on when flipping it), how would you do that? And not using any pins on the Arduino... Now that would be extra cool.

0
None
AndersB28

1 year ago

I'm using the 1 wire keyboard calculator from: www.rau-deaver.org/Electronics

It works like a charm for me with an array of 4 x 4 buttons. The program also generates the c-code but with an small error in the #defines - Just remove the equal char to make it running.

/Anders

0
None
Jphifi

2 years ago

I want to thank you for such a well documented instructable!

It was very easy to read and understand, if only more people would put the time and effort like you have.

I look forward to reading more of your instructables.

0
None
MaximilianoV

2 years ago

This is amazing. Thank you so much! You've just saved me a lot of time and headaches :)

0
None
DanS167

2 years ago

Calculate the resistor:

it<= 40mA

vt= 5v

.

It = (i1+i2+i3+i4+i5+i6+...+in) <= 40mA

.

i1 >= (i2+...+in)

i1 >= it/2;

i1 >= 20mA R1= 5v/20mA = 0,25*10^3 = 250;

.

i2 >= (i3+...+in)

i2 >= i1/2

i2 >= 10mA R2= 5v/10mA = 0,5.10^3 = 500; (R1*2)

.

i3 >= (i4+...+in)

i3 >= i2/2

i3 >= 5mA R3 = 5v/5mA = 1*10^3 = 1k; (R2*2) => (R1*4)

.

i4 >= (i5+...+in)

i4 >= i3/2

i4 >= 2,5mA R4 = 5v/2,5mA = 2*10^3 = 2k; (R3*2) => (R1*8)

.

i5 >= (i4+...+in)

i5 >= i4/2

i5 >= 1,25mA R5 = 5v/1,25mA = 4*10^3 = 4k; (R4*2) =>(R1*16)

0
None
psmurf56

2 years ago

One thing I think needs to be mentioned is that this article is using a Pull-Down resistor instead of a Pull-Up resistor. When nothing is pressed the pin is in a low state (0v), this can all be reversed by simply switching where the resistors are on the polarity.

0
None
mekodak

3 years ago on Introduction

Hi
Can anybody help me.
I want 8 buttons an i want to be able to make multiply button push.
but i dont know how to caltulate it.

I am going for the parelell solution like used in this tuturial.

0
None
inventorjack

9 years ago on Introduction

I don't think this would work so well in industry, due to the fact that resistor values can change over long periods of time, but this is an excellent and cheap technique for personal projects. Thanks for sharing how you simplified the process. I know math can be really tedious for some, and your process cuts all that out. Good instructable!

2 replies
0
None
AlyssonR2inventorjack

Reply 3 years ago on Introduction

This is certainly the method used in a lot of domestic and office equipment - printer controls, DVD, TV etc. where the cost is shaved by less-than-pennies where possible.

Thanks :) 

I guess you could deal with that in code. If you had button 1 tied to the supply voltage with no resistor, you know its value would be constant. So use button one to start a calibration process where you press each button in turn and the software records the new values for each button.

Of course then you need some form of memory to store the new values and it all starts getting more complicated again. Still, you could make it work if you were desperate enough :)

Of course, for a commercial venture, I would just use a micro-controller with more IO lines.

0
None
AlyssonR2

3 years ago on Introduction

By connecting the analog input to the centre of a series chain of equal value resistors, and by shorting varying numbers resistors upward and downward, it is theoretically possible to multiplex 1023 buttons on an Arduino.

In practice, a dozen or so could be managed even with 5% resistors.

Multiplexed Switches.png
0
None
Savassan

3 years ago on Step 7

What about taking averages when the button is pressed?

for(int i=0;i<150;i++)

{

sample+=analogRead(A1); //read the value

delay(2);

}

sample=sample/150;

0
None
ismadil

3 years ago

I have a project that I am working on where I am monitoring about 25 magnetic contact switches. Your wiring and code represents almost exactly what I am trying to do. I am trying to figure out though, what the upper limit is of switches that can be monitored on one input channel. Basically I have other functions that will require as many open inputs and outputs as possible. I'm thinking maybe I can double up and maybe even triple the resistors at a certain point so that I can get the differentiation in voltage values. Any help is appreciated, thanks!

0
None
Spirittribe

3 years ago on Introduction

Had great success wiring 6 buttons to an analog pin. Four buttons are great to serve as directional buttons and the other two for options. Resistors I'm using are 2.4k, 10k, 5k, 1k, 560, and 220. The 2.4k is not connected to any button but ends the circuit to ground. The first button closest to the 2.4k therefore has no resistor. I have attached a photo of my setup.

1pin6button.jpg
0
None
LordMekk

9 years ago on Step 7

 If you kept the resistor values increase by the power of two you could do binary addition and subtraction to get what buttons are pressed.  This is done in computer programing all the time

3 replies
0
None

I thought so too, and initially chose my resistor values that way, but the fact that the resistors are in parallel means that the binary doesn't hold when you connect multiples. For example, if I had 10K, 20K, 40K and 80K resistors on buttons 1, 2, 3 and 4 (To make the maths simpler), I get the following resistances when pressing multiple buttons:
1+2: 6.66K
1+3: 8K
1+4: 8.88K
1+2+3: 5.7K

As you can see, the multiple button presses result in resistances that are all very close together (and close to the button 1 resistance).

I'm wondering if there wouldn't be some way of rewiring the circuit to get the resistors in series when multiple buttons are pressed... Off the top of my head, I don't see an easy way, but it is after midnight here.

0
None
bugQriaancornelius

Reply 8 years ago on Introduction

Your buttons are double-throw switches, right? You should be able to put them in series just fine. All you have to do is short the "off" contact of one switch to the common of the next one, so that there's no resistance when it's not being pressed. Not sure how best to debounce it, though. Anyway, sorry for replying to such an old comment. I have a similar project where this could be verrry useful, though...

0
None
bugQbugQ

Reply 8 years ago on Introduction

It looks something like this...maybe the resistor values have to be tweaked to make it easier to distinguish the voltage readings, but you get the idea.

4finger.jpg