September 1, 2009
Update: A version of this article was published in the April 22, 2010 Issue of Electronics Design News (EDN) Magazine. It appears on page 71 of the magazine in the Design Ideas column entitled "Read multiple switches and a potentiometer setting with one microcontroller input pin."
A Varswistor is a portmanteau that I came up with to describe a simple analog electronic device consisting of a variable resistor and a number of switches which provide a analog and digital input to a microcontroller using a single pin. It's kind-of a combination of variable resistor and switch. The interesting part of this application has to do with the careful selection of the resistor values to provide not only an independent analog input but also a number of discrete switch inputs providing digital information.
I came up with this idea while working with a small 8-bit microcontroller and finding I had only one-pin left for any type of input I might want to add. I know I needed at a minimum a control knob (a variable resistor) but also wanted a number of switch inputs as well. Unfortunately only one pin was available, but it did have an A/D converter on it. So I wondered; could the A/D converter input be used for both analog control as well as switch inputs at the same time? Sure. Why not!
The Varswistor – A Single Microcontroller’s Pin Allows Mixed Analog and Digital Inputs
By Kevin Fodor
The challenge in working with small 8-bit microcontrollers is to effectively manage what limited resources are available. Recently one of my projects required the ability to tweak several operating parameters while the software was running. Having additional analog inputs from a potentiometer as well as several pushbuttons would be ideal. The problem however was that the microcontroller I was using had only one unused pin remaining. So after dreadfully considering the possibility that I might need to choose a different microcontroller with more pins I decided to try to figure out a way to cleverly add the inputs I needed with only one available input pin. Fortunately the available pin had an Analog-to-Digital Converter (ADC) function attached to it which could easily be used to read the variable resistor, but what about the pushbuttons? Then it came to me…what I really need is a Varswistor!
The Varswistor is a portmanteau that I came up with to describe a simple analog electronic device consisting of a single variable resistor and a number of SPST switches. The device provides a way to convey mixed analog and digital inputs into a microcontroller using a single input pin. The pushbuttons allow the user to select different modes, states or options while the analog input provides a method to convey a parameter which can be tweaked during run time.
The implementation of a Varswistor is quite simple as it requires only the analysis of a parallel resistor circuit and voltage divider. The interesting part of this application however has to do with the careful selection of the resistor values to provide not only discernable analog input, but also a number of discrete pushbutton input states as well.
A basic schematic diagram is shown in Figure 1 above which contains two pushbuttons and a single variable resistor (Radj) for analog input. The output of the Varswistor is connected to an available microcontroller’s ADC input pin. Using this configuration, the pushbuttons can be used to select different parameters while a single variable resistor can be used to make adjustments to the parameter.
The selection of the resistor values is a multi-step process, thus creating a spreadsheet aids in performing the calculations (see attached). In this example a 5k potentiometer (Radj) was chosen. For my application this needs to produce a 0-100% value into the microcontroller. Typically using an 8-bit ADC one would simply map the sampled valued of 0-255 into a 0-100 value to represent a percentage. However by carefully selecting the bias resistors Rbias one can arrive at a direct analog input centered about the 0-255 range of the ADC (e.g. 78-178). To compute the appropriate high and low side bias resistor values we solve this circuit as a simple voltage divider.
Substituting and solving for Rbias and given that Vmax = 255; Vlow = 78; Vhigh=178 and Radj=5k
The computed value of Rbias is 3875 ohms, however a nominal value of 3.3k the potentiometer’s input range (Vlow to Vhigh) is between 73 and 182. This gives a larger dynamic range than desired, but allows for a guard range between this potentiometer values and the pushbuttons as we will compute next.
Since the position of Radj affects the overall resistance seen by the circuit when either switch is pressed, a range of values must be interpreted for each switch. To determine Rsw for either PB1 or PB2 we solve this as a parallel resistor network at both extremes of the potentiometer’s position.
For PB1 when Radj is at the maximum position the effective resistance (Reff) seen by the voltage divider to the ADC is Rsw in parallel with Radj and Rbias in series. Likewise at the minimum position the effective resistance (Reff) is simply Rsw in parallel with Rbias.
The value produced when PB1 is pressed (VPB1max) is determined by evaluating the voltage divider formed by Rbias and Reffmax.
Observe that when Radj is at its maximum value and PB1 is pressed, it must produce a value less than the smallest value Radj produces by itself in order to uniquely determine the switch has been pressed. So Reffmax must produce a value less than Vlow as computed earlier. Simultaneously evaluating these equations we get;
Substituting and solving this equation for Rsw we get;
Using the spreadsheet to compute Rsw we get 1558 ohms and subsequently choose a nominal 1.5k resistor which results in PB1 producing a range of 28 to 71 when pressed depending on the potentiometer’s position. Likewise choosing the same value for PB2 produces a range of 184 to 227. These ranges are “bands” of values which can be used to determine which switch is pressed regardless of the potentiometer’s position. Although selecting symmetrical resistor values is not required, it minimizes the number of calculations needed and simplifies the design. Furthermore selecting smaller series switch resistors will open the “guard range” between them and the potentiometer which may be desirable if the resulting values are too close together.
The code used to interpret both the switch positions as well as the analog input is shown below.
#define PB1 ((unsigned char)0x01 << 0)
#define PB2 ((unsigned char)0x02 << 0)
// Process both Analog and Digital I/O
void ProcessInputs(unsigned char *perct, unsigned char *switches)
unsigned char raw = 0;
// Sample ADC
Measure(); // Trigger a measurement & wait
GetValue8(&raw); // Get measurement value
// The following is good for;
// RbiasLow = 3.3k ohms
// RbiasHigh = 3.3k ohms
// Rswh = 1.5k ohms
// Rswl = 1.5k ohms
// Extract PB1, PB2 and Analog Percentage
if(raw >= 184) // Calculated = 184 -> 227
*switches |= PB2;
else if(raw > 178) // Calculated = 182 (–4 guard)
*perct = 100; // 100%
else if(raw > 78) // Calculated = 73 (+5 guard)
*perct = raw - 78; // n% (normalized to %)
else if(raw >= 73)
*perct = 0; // 0%
else // Calculated = 71 -> 28
*switches |= PB1;
The limitation of this technique is of course that no more than one pushbutton can be pressed at any one time. Furthermore the potentiometer’s position can be read only when no other pushbuttons are pressed. But if these limitations meet your requirements, this might just be the way to go.
This example showed how two pushbuttons could be used within the Varswistor concept, but the number of pushbuttons which is not limited to only two. The graph in Figure 2 below shows various input ranges for up to 10 separate pushbuttons and one potentiometer all sharing the same input pin. Although the computed ranges do not overlap and are unique, it is doubtful than your ADC hardware is able to reliably distinguish these bands under all circumstances. As noted above choosing smaller resistor values will separate these bands farther apart creating a larger “guard range”. From the values computed however, using this technique for at least four pushbuttons and one potentiometer is well within reason. Experimenting with the spreadsheet provided helps make quick work of determining just the right series resistor values for each switch and its output range.
Figure 2 – Dynamic Range vs. Inputs for a Varswistor with 10 Pushbuttons and 1 Potentiometer using a Single Pin