Introduction: Use 1 Analog Input for 6 Buttons for Arduino
I have often wondered how I could get more Digital Inputs for my Arduino. It recently occurred to me that I should be able to use one of the Analog Inputs for bringing in multiple digital inputs. I did a quick search and found where people were able to do this, but that these only allowed for a single button to be pressed at a time. I want to be able to have any combination of buttons to be pressed SIMULTANEOUSLY. So, with the help of TINKERCAD CIRCUITS, I set out to make this happen.
Why would I want simultaneous button presses? As illustrated in the TinkerCad Circuits design, it could be used for DIP switch inputs for selection of different modes within the program.
The circuit that I came up with uses the 5V source available from the Arduino and uses 7 resistors and 6 buttons or switches.
Step 1: The Circuit
Arduino's have analog inputs that accept a 0V to 5V input. This input has a 10-bit resolution, which means that the signal is broken into 2^10 segments, or 1024 counts. Based on this, the most that we could ever possibly input into an analog input while allowing for simultaneous presses would be 10 buttons to 1 analog input. But, this is not a perfect world. There is resistance in conductors, noise from outside sources, and imperfect power. So, to give myself plenty of flexibility, I planned on designing this for 6 buttons. This was, in part, influenced by the fact that TinkerCAD Circuits had a 6-Switch DIP Switch object, which would make testing easy.
The first step in my design was to make sure that each button, when pressed individually, would provide a unique voltage. This ruled out all of the resistors being the same value. The next step was that the resistance values, when added in parallel, could not have the same resistance as any single resistor value. When resistors are connected in parallel, the resulting resistance can be calculated by Rx=1/[(1/R1)+(1/R2)]. So, if R1=2000 and R2=1000, Rx=667. I speculated that by doubling the size of each resistor, I would not see the same resistance for any of the combinations.
So, my circuit to this point was to have 6 switches, each with its own resistor. But, there is one more resistor required to complete this circuit.
The last resistor has 3 purposes. First, it acts as a Pull-Down resistor. Without the resistor, when no buttons are pressed the circuit is incomplete. This would allow the voltage at the Arduino's Analog Input to float to any voltage potential. A Pull-Down resistor essentially Pulls Down the voltage to 0 V. The Second purpose is to limit the current of this circuit. Ohm's law states that V=IR, or Voltage = Current multiplied by Resistance. With a given voltage source, the larger the resistor means that the current would be smaller. So, if a 5V signal was applied to a 500ohm resistor, the largest current we could see would be 0.01A, or 10mA. The Third purpose is to provide the signal voltage. The total current flowing through the last resistor would be: i=5V / Rtotal, where Rtotal = Rlast + {1/[(1/R1)+(1/R2)+(1/R3)+(1/R4)+(1/R5)+(1/R6)]}. However, only include 1/Rx for each Resistor that has its corresponding button pressed. From the total current, the Voltage supplied to the Analog Input would be i*Rlast, or i*500.
Step 2: Proof - Excel
The quickest and easiest way to prove that I would get unique resistances and thus unique voltages with this circuit was to use the capabilities of Excel.
I set up all of the possible combinations of switch inputs and organized these sequentially following binary patterns. A value of "1" indicates that the switch is on, blank indicates it is off. At the top of the spreadsheet, I put in the resistance values for each switch and for the pull-down resistor. I then calculated the equivalent resistance for each of the combinations, except for when all resistors are off since these resistors won't have an affect without have a power source supplying it. To make my calculations easy so that I could copy and paste to each combination, I included all combinations in the calculation by multiplying each switch value (0 or 1) by its inverted resistance value. Doing so eliminated its resistance from the calculation if the switch was off. The resulting equation can be seen in the image of the spreadsheet, but Req = Rx+1/(Sw1/R1 + Sw2/R2 + Sw3/R3 + Sw4/R4 + Sw5/R5 + Sw6/R6). Using Itotal = 5V / Req, we determine the total current through the circuit. This is the same current that goes through the Pull-down resistor, and provides us the Voltage to our Analog Input. This is calculated as Vin = Itotal x Rx. Examining both the Req data and the Vin data, we can see that we indeed have unique values.
At this point, it appears that our circuit will work. Now to figure out how to program the Arduino.
Step 3: Arduino Programming
When I started thinking about how to program the Arduino, I initially planned on setting up individual voltage ranges for determining whether a switch was on or off. But, while lying in bed one night, it occurred to me that I should be able to find an equation to do this. How? EXCEL. Excel has the ability to calculate equations to best fit data in a chart. To do this, I will want an equation of the Integer Value of the switches (binary) versus the voltage input corresponding to that value. In my Excel Workbook, I put the Integer Value down the left side of the spreadsheet. Now to determine my equation.
Here's a quick tutorial on how to determine the equation of a line within Excel.
1) Select a cell that does not contain any data. If you have a cell selected that has data, Excel will try to guess what it is you want to trend. This makes it much more difficult to set up a trend, because Excel rarely predicts correctly.
2) Select the "Insert" tab and Select a "Scatter" chart.
3) Right Click in the chart box and click on "Select Data...". This will pop up the "Select Data Source" window. Select the Add button to continue to select the data.
4) Give it a Series Name (Optional). Select the Range for the X-Axis by clicking the up arrow and then selecting the Voltage data. Select the Range for the Y-Axis by clicking the up arrow and then selecting the Integer Data (0-63).
5) Right Click on the data points and Select "Add Trendline..." In the "Format Trendline" window, select the Polynomial button. Looking at the trend, we see that the Order of 2 does not quite match. I selected an Order of 3 and felt this was much more accurate. Select the checkbox for "Display Equation on chart". The final equation now is displayed on the chart.
6) Done.
OK. Back to the Arduino program. Now that we have the equation, programming the Arduino is easy. The Integer that represents the switch positions is calculated in 1 line of code. By using the "bitread" function, we can grab the value of each individual bit and thus know the state of each button. (SEE PHOTOS)
Here's the Actual Arduino logic that I used in this instructable:
int sensorValue = 0;
float volt = 0;
long bitvalue = 0;
bool DIP1 = 0;
bool DIP2 = 0;
bool DIP3 = 0;
bool DIP4 = 0;
bool DIP5 = 0;
bool DIP6 = 0;
void setup()
{
pinMode(A0, INPUT);
pinMode(13, OUTPUT);
pinMode(11, OUTPUT);
pinMode(9, OUTPUT);
pinMode(7, OUTPUT);
pinMode(5, OUTPUT);
pinMode(3, OUTPUT);
}
void loop()
{
// read the value from the sensor
sensorValue = analogRead(A0);
volt = sensorValue * 0.0049;
bitvalue = round((1.9123*pow(volt, 3))-(0.4559*pow(volt,2))+(14.774 * volt) - 0.2613);
// Detect DIP1
DIP1 = bitRead(bitvalue, 0);
if (DIP1==1)
{
digitalWrite(13, HIGH);
}
else
{
digitalWrite(13, LOW);
}
// Detect DIP2
DIP2 = bitRead(bitvalue, 1);
if (DIP2==1)
{
digitalWrite(11, HIGH);
}
else
{
digitalWrite(11, LOW);
}
// Detect DIP3
DIP3 = bitRead(bitvalue, 2);
if (DIP3==1)
{
digitalWrite(9, HIGH);
}
else
{
digitalWrite(9, LOW);
}
// Detect DIP4
DIP4 = bitRead(bitvalue, 3);
if (DIP4==1)
{
digitalWrite(7, HIGH);
}
else
{
digitalWrite(7, LOW);
}
// Detect DIP5
DIP5 = bitRead(bitvalue, 4);
if (DIP5==1)
{
digitalWrite(5, HIGH);
}
else
{
digitalWrite(5, LOW);
}
// Detect DIP6
DIP6 = bitRead(bitvalue, 5);
if (DIP6==1)
{
digitalWrite(3, HIGH);
}
else
{
digitalWrite(3, LOW);
}
}
Step 4: TinkerCAD Circuits
If you haven't checked out TinkerCAD Circuits, do it now. WAIT!!!! Finish reading my Instructable, and then check it out. TinkerCAD Circuits makes testing Arduino circuits very easy. It includes several electrical objects and Arduinos, even allowing you to program the Arduino for testing.
To test my circuit, I set up 6 switches by using a DIP switch pack and tied them to the resistors. To prove that the voltage value in my Excel Spreadsheet was correct, I displayed a voltmeter at the Input to the Arduino. This all worked as expected.
To prove that the Arduino Programming worked, I output the states of the switches to LED's, using the Arduino's digital outputs.
I then switched every switch for every possible combination and am proud to say "IT WORKS"!!!
Step 5: "So Long, and Thanks for All the Fish." (ref.1)
I have yet to try this out using real equipment, as I am currently traveling for work. But, after proving it out with TinkerCAD Circuits, I believe that it will work. The challenge is that the values of resistors that I have specified are not all standard values for resistors. To get around this, I plan to use potentiometers and combinations of resistors to get the values that I need.
Thank you for reading my instructable. I hope that it helps you with your projects.
Please leave comments if you have attempted to tackle this same obstacle and how you had solved it. I would love to learn more ways to do this.
Step 6: References
You didn't think I would provide a quote without providing a reference to its source did you?
ref. 1: Adams, Douglas. So Long, and Thanks for All the Fish. (The 4th book of the Hitchhiker's Guide to the Galaxy "trilogy")

Participated in the
Electronics Tips & Tricks Challenge
8 Comments
2 months ago
I had to adjust resistor values to match up with standard resistors values I had available. Changed the pull-down to 680 ohms. I had 8 dip positions to monitor though and used two analog inputs. Worked like a charm, I did make some changes however to optimize the code. First, I made the polynomial function a little faster, I created a function called polyFunc(float v) that takes the voltage in and returns the bit value. the pow(volt,x) are removed and pre-calculated. so it looks like this:
So now I just call
bitValue=polyFunc(volt);
You could also simplify this further by either defining all of the constants instead of computing the coefficients and simplifying the polynomial expression by factoring out common terms or you could eliminate this all together with a look up table since we have the spreadsheet that will give us known values...
example;
bitvalue = round((0.1231*pow(volt,3) - 0.2056*pow(volt,2))*(volt*3.99+6.9338));
I haven't played with this yet though.
Also, I made the dip read a function which returns a bool array and does an iterative to store the switch positions in the array. Since I had 8 positions to read on two seperate inputs my function looks like this:
bool* readDIP(int analogPin1, int analogPin2) {
// Allocate an array to store the switch states
bool* DIPStates = new bool[8];
// read the analog inputs and convert to voltages and then to bit values
long bitvalue1 = polyFunc(analogRead(analogPin1) * 0.0049);
long bitvalue2 = polyFunc(analogRead(analogPin2) * 0.0049);
// Read DIP positions and store them in the array
for (int i = 0; i < 8; i++) {
if (i < 4) {
DIPStates[i] = bitRead(bitvalue1, i);
} else {
DIPStates[i] = bitRead(bitvalue2, i - 4);
}
}
// Return the array of switch states
return DIPStates;
}
and can use it in a variable with
bool* DIPStates = readDIP(A0,A1);
When I need to free up memory I use
delete[] DIPStates;
Thank you for the Instructable! Very helpful!
Reply 2 months ago
Thanks for your detailed comment.
6 months ago
I've been trying for days, but I can't understand the logic for getting the values of the switches from the single bitRead function. I'm utterly perplexed. I've created scatter charts and binary charts with the integers in both binary and converted to base 10. NONE OF IT MAKES SENSE TO ME! Please help.
8 months ago
Hy! I have created this acc just for to say FREAKING THANKS FOR THIS! Can i have a question?
4 years ago
Thank you so much for this tutorial!
I used your method to read the input from the big arcade joystick. This joystick didn't have any internal wiring and consisted of just 4 separate switches. I also connected one push button and can add one more later if needed. So now your tutorial has been tested on the real hardware.
One thing I should mention is that the resistor values should be exactly as shown in the schematics although it is not most common values. If you use 470 instead of 500 Ohm it won't calculate all the values correctly. It is possible to connect several resistors in series to get the right value (for example 470 + 33 Ohm instead of 500 Ohm). Before soldering the circuit I tested it out on the breadboard and tested different combination of resistors until I got it all working as expected (I needed to do it on 2 DIPs and the pull-down resistor).
As for the instructable itself, it would be nice if you could add Arduino code as a text instead of a low resolution image - it would make it easier. It would be also interesting to be able to llok at the Excel sheet, but it is not available for download (or maybe I just missed the link).
Once again, thank you for good work!
Reply 4 years ago
Thank you for the feedback. I'm glad that this worked out for your application. I still have an application in mind for this, but it'll be quite awhile before I can try it.
Again, thanks for building this and letting me know that it worked!
4 years ago
Very nice use of a weighted resistor circuit. As another method that can simplify the resistor values, you should look at a R-2R ladder, you'd only need two values with one double the other.
Reply 4 years ago
Great Information! I had not come across the R-2R ladder before and looks to be a simple solution. Although it uses more individual resistors, it would be easier to implement since R/2R Ladder Networks are available in DIP and SIP chip formats.