Obtaining User Input to an Arduino
Using a Potentiometer
(code example at end)
There are many times where it's
convenient to enter in values using a simple potentiometer instead of
a GUI interface. An example would be whereby a user wants to set the
desired temperature on a thermostat.
A potentiometer has three (3) leads
coming from it. Typically, the center lead is the 'wiper'. The
wiper has the ability to vary the resistance from one end of the
potentiometer to the other end.
A potentiometer has a maximum
resistance between two leads, typically the first and last lead, and
an ability to vary the resistance seen on the other lead, the wiper.
Another way to think of this is to
realize the potentiometer's wiper has the ability to provide 0%
through 100% of the total resistance available through the other two
(2) leads.
Per Ohm's law, which states the
interaction between three (3) entities – resistance, voltage, and
current – if a resistance is connected to a voltage source, than
there will be a voltage drop across the two ends of the resistor.
A potentiometer is a resister that also
includes a third lead – the wiper, can can move between the two
ends of the resistor, and is capable of varying it's resistance while
doing so. Because of this, the wiper lead sees a different voltage.
The voltage at the wiper can not be
more than the maximum voltage connected on the voltage-in side of the
resistor, when measured to the other end of the resistor. Likewise,
the voltage at the wiper can not be less than the minimum voltage
connected on the voltage-out side of the resistor.
So the voltage seen at the wiper will
vary between 100% of the voltage at one end of the resistor, and 0%
of the voltage at the other end of the resistor.
In a linear potentiometer (as opposed
to a non-linear potentiometer, such as an 'audio' potentiometer,
which is logarithmic), turning the potentiometer 5% clockwise will
result in a change in the resistance seen at the wiper, by 5%. If
there is a voltage applied to the first lead of the potentiometer,
and ground and the last lead of the potentiometer, then this 5%
change in the resistance will result in a 5% change in the voltage.
The voltage will drop across the
potentiometer's wiper. Remember, it will either be at 0% of maximum,
or 100% of maximum, or anywhere in between, but can not exceed those
two values.
When working with an Arduino, I'm not
typically concerned about the actual voltage present at the wiper.
Instead, I'm concerned about the position of the wiper. For
instance, when using a potentiometer to turn a setpoint up or down
for a thermostat, I'm not interested, as a user of the thermostat, of
the voltage that is being changed; instead, I'm interested in the
temperature represented by the potentiometer, and how I'm changing
it.
For this reason, when using a
potentiometer in an Arduino circuit, I'm typically using it as a
ratio-device. I'm more interested in the ratio, or percentage, of
the position of the potentiometer's wiper, not the voltage being read
at the wiper.
Here's what I mean by that.
On my porch heater thermostat, I have
placed a potentiometer, which I use to set the temperature that I
desire the porch to stay at. By setting the potentiometer's value, I
am setting the temperature I desire for my porch.
If the potentiometer is connected at
one end to a 5 volt power supply, and the other end is connected to
ground, then the wiper, when turned, is capable of being at any
voltage between 5 volts and 0 volts, inclusive.
But I don't set my porch heater to a
voltage, I set it to a temperature.
On my porch heater, I decided I wanted
to be able to specify (the setpoint), a temperature between 70 dF and
75 dF. That's a 5 degree F range. Thinking in percentages, 0% would
be 70 dF, and 100% would be 75 dF. 50% would be half way the range
of 5 degrees, or 2.5 dF. Since my bottom temperature is 0% at 70 dF,
and 50% is half way between a range of 5 dF, thus the 2.5 dF, then
that 2.5 added to the 0% of 70 dF is 72.5 dF. So, if I set my
potentiometer to 50%, I'm actually setting my temperature to 72.5 dF.
Well, OK, you might be thinking, but
how do I get voltages and percentages into temperature?
That's where software comes into play –
the flexibility of software.
I'm constrained by the hardware here –
the only thing I've got to work with here is the voltage, and it is
going to range between 0% and 100% of the total 5 volts available.
The Arduino is capable of reading the voltage. So it's capable of
reading the 0 volts through 5 volts that are being supplied by the
potentiometer. But that's all it's directly capable of doing using
its Analog to Digital Converter (ADC).
So anything I want to do with the
Arduino, in reading an external voltage, is going to range between
this 0 volts and 5 volts. And the Arduino, in converting this analog
value to digital, has the capability of dividing that 0 – 5 volts
into 1024 equal divisions, because it has a 10 bit ADC converter.
(Take a calculator and see what 2^10 gives you). The calculator will
show you that 2^10 is 1024 individual values. But, since we are
starting at 0 instead of at one, then the range is 0 – 1023.
So the Arduino converts the analog 0 –
5 volts to a digital value of 0 – 1023.
Here's where the ratios make everything
simple, so it's important to understand this.
The ratio, or percentage, of the 0 –
5 volts is the same ratio, or percentage of 0 – 1023.
For example:
a voltage of 5 volts at the wiper,
is 100% of the 0 – 5 volts. Likewise, it is 100% of the 1023
value, or 1023.
a voltage of 2.5 volts at the
wiper, is 50% of the 0 – 5 volts, or 2.5 volts. Likewise, it is
50% of the 1023 value, or 512 (integer, not floating).
A voltage of 0 volts at the wiper,
is 0% of the 0 – 5 volts, or 0 volts. Likewise, it is 0% of the
1023 value, or 0.
What that means, is if you can convert
the input value to a ratio, or percentage, then you can apply that
percentage to anything.
For instance, on my porch heater, I
read the potentiometer, and get back a count of 256. To convert this
to a ratio, then I'm trying to find out what percentage is 256 of the
total 1024? So I'm going to divide 256 by 1024, and that will give
me 25%. From a voltage standpoint, 25% of 5 volts is 1.25 volts, but
I don't care about this at all. I'm only concerned with the
percentage, which we've determined is 25%. But I am concerned with
temperature, and my temperature range, 0% - 100% is 70 dF – 75 dF,
which is a range of 5 degrees F. So 25% of the range of 5 degrees F
is 1.25 degrees F, and since my base is 70 dF, and I'm 1.25 dF above
that 0% value, then I'm at 71.25 dF.
So you can apply this to anything, and
it's what makes a potentiometer so powerful in any circuit you are
building.
The hardware gives you the range of 0 –
5 vdc, 0% - 100%, the ADC gives you 0% - 100% of 0 – 1023, and then
using software, you choose what you want that to represent. In
my case, I wanted that 0% - 100% to represent 70 dF to 75 dF for a
porch heater. But for my Sous Vide cooker, I want that to represent
150 dF – 200 dF, which has a range of 50 dF, and using the previous
example of 25% of the potentiometer, and 25% of the max 1024 counts,
then I'm now talking about 25% of the range of 50 dF, or 12.5 degrees
F above the base of 150 dF, or 162.5 dF.
Using
software, you decide what the final values are that you are
representing with the potentiometer. Then taking the percentage of
the potentiometer, and the percentage of the maximum counts of 1024,
you can directly apply that to whatever you are doing – RPMs,
population, weights, valve opening, whatever.
Here's
a coding example.
Assume
we are wanting to set a desired temperature onto a thermostat.
Further assume the thermostate will be capable of setting the
temperature anywhere from 70 to 75 dF. Assume we will use analog pin
A0 for the wiper on the potentiometer.
void
setup() {
pinMode(A0,
INPUT);
Serial.begin(9600);
}
void
loop() {
float
setpoint = 0.0;
float
volts = 0.0;
int
counts = 0;
float
ratio = 0.0;
float
baseTemperature = 70.0;
float
tempratureRange = 5.0; //75 dF – 70dF = 5 degrees F range
//get
the potentiometer's wiper value in counts, 0 – 1024
counts
= analogRead(A0);
//get
the ratio of the counts as a percentage of mximum
ratio
= (float)counts / 1023.0;
//using
the ratio to calc the voltage (maximum of 5 vdc). It's not used,
but just for fun.
volts = 5.0 * ratio; //we have a max of 5 volts
//now
get the setpoint temperature
setpoint
= (ratio * temperatureRange) + baseTemperature;
//that's
all there is to it!
//
now print this out
Serial.print(“counts:
“); Serial.print(counts);
Serial.print(“,
ratio: “); Serial.print(ratio);
Serial.print(“,
volts: “); Serial.print(volts);
Serial.print(“,
setpoint: “); Serial.println(setpoint);
}