Use 1 Analog Input for 6 Buttons for Arduino
by JABA 3D in Circuits > Arduino
10969 Views, 24 Favorites, 0 Comments
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.
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.
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.
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);
}
}
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"!!!
"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.
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")