Why the ends are not exact
On an Uno or a Pico the two stops should read 0 and full scale, or within a few counts of them. On an ESP32 the first few percent of travel read 0 and the last few read 4095 before the wheel reaches its stop, because the ADC stops measuring at about 0.1 V and 3.1 V. The cure is the same everywhere: take your own two stops and map from them.
Where the numbers stop moving
Pick the ESP32 and slide the wheel towards either end. For most of the travel the reading follows the wheel. In the last few percent at each end it stops moving: 0 at the bottom, 4095 at the top, while the wheel still has a little way to go.
The ESP32's two flat stretches
With the Arduino core's default settings, the ESP32's ADC and the ESP32-S3's read from roughly 0.1 V to roughly 3.1 V. The block gives them 0 V to 3.3 V. So below about 0.1 V there is nothing to read and the answer is 0, and above about 3.1 V there is nothing left to count and the answer is 4095.
On a 3.3 V track that is about 3 % of the travel at the bottom and about 6 % at the top. The exact knees vary from chip to chip, which is why the figure says illustrative and the prose says about. Reading the ADC has the ESP32's side of it. Near the ends the ESP32's ADC is also less linear than in the middle, so the last reading before each flat stretch is the least trustworthy.
The Uno and the Pico
Their ADCs measure all the way from 0 V to their reference, and with VCC on the same supply the stops are the top and bottom of that range. They should read 0 and full scale, or within a few counts.
A few counts short is not a fault. Many pots do not quite put the wiper on the very end of the track at the stops, and nobody has measured this one. The supply at the Uno's ADC reference and at its 5V pin can also differ slightly.
Take your own stops
Every one of these has the same answer: stop assuming the ends are 0 and
ADC_MAX, and use the numbers your block actually gives. The sketch keeps
the lowest and highest reading it has seen, and maps between them. Turn the
wheel to both stops once and from then on 0 % and 100 % are exactly where the
number stops moving.
The code
The first read, plus two variables that remember the lowest and highest reading seen. Turn the wheel to both stops once after a reset, and from then on the percentage runs from 0 to 100 exactly between them.
/*
Disc Potentiometer - taking your own stops TK07 / /p/tk07
Wiring. Count from the square pad on the TinkerBlock board, wheel
up, header at the bottom:
GND -> GND
VCC -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
(at one stop, SIGNAL gives your pin whatever VCC is)
NC -> nothing (unconnected on the board)
SIGNAL -> A0 on an Uno, GPIO 34 on an ESP32, GPIO 4 on an
ESP32-S3, GP26 on a Raspberry Pi Pico
Arduino IDE
Tools > Board your board, e.g. ESP32S3 Dev Module
Tools > Port the one that appears when you plug in
Tools > USB CDC On Boot Enabled (ESP32-S3 only)
No library needed.
*/
// The pin SIGNAL is wired to.
// Uno: A0. ESP32: 34. ESP32-S3: 4. Pico: 26.
const int POT_PIN = 4;
// What analogRead returns at full scale on your board.
// Uno: 1023. ESP32, ESP32-S3: 4095. Pico: 1023.
const int ADC_MAX = 4095;
int lowest = ADC_MAX; // the lowest reading seen so far
int highest = 0; // and the highest
void setup() {
Serial.begin(115200);
}
void loop() {
int reading = analogRead(POT_PIN);
if (reading < lowest) lowest = reading;
if (reading > highest) highest = reading;
int percent = 0;
if (highest > lowest) {
percent = map(reading, lowest, highest, 0, 100);
}
Serial.print(reading);
Serial.print(" stops ");
Serial.print(lowest);
Serial.print(" to ");
Serial.print(highest);
Serial.print(" ");
Serial.print(percent);
Serial.println(" %");
delay(100);
}lowest starts at ADC_MAX and highest at 0, so the first read moves both. The if guards against dividing by zero before the wheel has moved. Once you know your stops, replace lowest and highest with the numbers it printed.
The same in MicroPython: remember the lowest and highest read_u16() seen, and scale between them. Turn the wheel to both stops once after starting it.
"""
Disc Potentiometer - taking your own stops TK07 / /p/tk07
Wiring. Count from the square pad on the TinkerBlock board, wheel
up, header at the bottom:
GND -> GND
VCC -> 3V3 (never 5V: at one stop, SIGNAL gives your pin VCC)
NC -> nothing (unconnected on the board)
SIGNAL -> GPIO 34 on an ESP32, GPIO 4 on an ESP32-S3,
GP26 on a Raspberry Pi Pico
Thonny
Run > Configure interpreter MicroPython (ESP32) or
MicroPython (Raspberry Pi Pico)
Save it to the board as main.py to run it on every power-up.
Nothing to install: machine, sys and time are built in.
"""
from machine import ADC, Pin
import sys
import time
# The GPIO number SIGNAL is wired to. ESP32: 34. ESP32-S3: 4. Pico: 26.
POT_PIN = 4
pot = ADC(Pin(POT_PIN))
if sys.platform == "esp32": # both ESP32s report "esp32"
pot.atten(ADC.ATTN_11DB) # measure up to about 3.1 V
lowest = 65535 # the lowest reading seen so far
highest = 0 # and the highest
while True:
reading = pot.read_u16()
lowest = min(lowest, reading)
highest = max(highest, reading)
percent = 0
if highest > lowest:
percent = (reading - lowest) * 100 // (highest - lowest)
print(reading, " stops", lowest, "to", highest, " ", percent, "%")
time.sleep_ms(100)There is no Uno here: an Uno cannot run MicroPython. read_u16() runs 0 to 65535, so lowest starts at 65535. Once you know your stops, replace the two variables with the numbers it printed.
When it does not work
No, that is the usual case. With VCC on 3V3, the stop is 3.3 V, above the roughly 3.1 V the ADC reads as full scale, so it reads 4095 there and for a little way before it. What you lose is not the top number but the last few percent of travel, which all read the same.
A few counts short at a stop is common and not a fault. The likely reasons are the wiper, which on many pots does not sit exactly on the end of the track, and the Uno's own 5 V being a little different at the ADC's reference pin. Nobody has measured this part's ends. The sketch below takes whatever yours are.
Not with VCC on 3V3 and the default settings: the ADC simply stops at about 3.1 V. You could give it less than 3.3 V at the top, but for a thumbwheel the few percent lost at each end rarely matter. Mapping from your measured stops makes 0 and 100 land where the wheel stops moving the number.
They are ordinary variables, so they start again at every reset, and the percentage is rough until you have turned the wheel to both stops once. Once you know your block's stops, write them into the sketch as constants and delete the tracking lines.
Stuck at 0, stuck at the top, wandering or backwards, and where to look for each.
When the reading is wrong →Edit this page — content/books/disc-potentiometer/why-the-ends-are-not-exact.mdx
Questions about this product
See what other owners have asked, and read their solutions.
Disc Potentiometer
Loading discussions…
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.