Arduino: read a potentiometer and print the value
Wire a 10k potentiometer to an Arduino analog pin and read its position with analogRead. The second project after blink.
After blink, this is the project that teaches you how the Arduino reads the real world. A potentiometer is a knob that varies its resistance as you turn it. Wire it to an analog pin and the Arduino reports the position as a number from 0 to 1023.
This is the foundation for “dim an LED with a knob,” “control a motor speed with a knob,” and “use a sensor that outputs an analog voltage.”
What you need
- Arduino (Uno, Nano, etc.)
- 10k ohm potentiometer (the panel-mount kind with three legs)
- Three jumper wires
Wiring
A potentiometer has three legs:
_______
/ \
| o | <-- the shaft (the part you turn)
| | |
1 2 3
- Pin 1 (left): goes to GND
- Pin 2 (middle): goes to A0 (analog input)
- Pin 3 (right): goes to 5V
If the readings go the wrong way when you turn the knob, swap the GND and 5V wires.
The pot I have on my desk right now has the GND and 5V on the outside pins and the wiper on the middle. That is the convention. If yours is different (e.g. a Bourns panel-mount pot), check the datasheet.
The code
Arduino (Uno, Nano, Mega)
void setup() {
Serial.begin(9600);
}
void loop() {
int value = analogRead(A0);
Serial.println(value);
delay(100);
}
Upload it. Open the Serial Monitor (Tools >> Serial Monitor or
Ctrl+Shift+M). Turn the knob. You should see the value change from 0
(all the way one direction) to 1023 (all the way the other direction).
ESP32 (Arduino)
The ESP32’s analog input has a different range (0-4095 instead of 0-1023) and accepts up to 3.3V. Most potentiometers wired to 3.3V work the same way:
void setup() {
Serial.begin(115200);
}
void loop() {
int value = analogRead(34); // GPIO 34 is an ADC-capable input
Serial.println(value);
delay(100);
}
The ESP32’s ADC has a known non-linearity, especially at the high and low ends of the range. For a “just turn the knob and read” project, this is fine. For a calibrated sensor readout, average a few samples or use a dedicated ADC chip.
MicroPython (ESP32 or Pico)
The ESP32 and Pico both have ADCs. Same wiring, different pin numbers.
from machine import ADC, Pin
import time
# ESP32: GPIO 34 (ADC1_CH6). Pico: GP26 (ADC0).
pot = ADC(Pin(34))
while True:
raw = pot.read_u16() # 0-65535
print(f'Raw: {raw}')
time.sleep(0.1)
read_u16() returns a 16-bit value (0-65535). For a “0-100%” mapping,
divide by 65535 and multiply by 100.
Raspberry Pi Python
The Raspberry Pi does not have a built-in ADC. To read a potentiometer on a Pi, use an external ADC chip like the MCP3002 (10-bit, SPI) or ADS1115 (16-bit, I2C). The wiring and chip selection are covered in the Pi ADC tutorial.
What you learned
analogRead(pin)reads the voltage on an analog pin and returns a value from 0 (0V) to 1023 (5V on a 5V Arduino, 3.3V on a 3.3V Arduino).- The Arduino’s ADC (analog-to-digital converter) is 10-bit, which is why the range is 0-1023 instead of 0-255.
- Reading takes about 100 microseconds. You can read at up to about 10 kHz if you need to.
Mapping the value to something useful
The 0-1023 range is rarely what you want. Use map() to rescale:
int raw = analogRead(A0);
int brightness = map(raw, 0, 1023, 0, 255);
analogWrite(9, brightness);
This maps the raw reading to the PWM range (0-255). Turn the knob and the LED on pin 9 fades up and down.
Smoothing noisy readings
A pot is mechanical. The wiper bounces a little, and the ADC has its own noise. If you are reading a sensor that needs to be steady (e.g. a temperature dial in a UI), average several readings:
int smoothRead(int pin) {
int total = 0;
for (int i = 0; i < 16; i++) {
total += analogRead(pin);
}
return total / 16;
}
16 samples is a good default. More samples = smoother but slower to react. For a pot driving a UI, 16 is fine. For a fast-changing sensor signal, fewer samples.
Reading other analog sensors
Anything that outputs 0-5V works on the analog pins. Common ones:
- Photoresistor (LDR): resistance changes with light. Wire it as a voltage divider with a 10k resistor.
- Thermistor: resistance changes with temperature. Same voltage divider.
- Soil moisture sensor: outputs 0-3V depending on wetness.
- Flex sensor: resistance changes when bent.
- Microphone breakout (e.g. MAX4466): outputs the audio waveform.
For all of these, the code is the same: analogRead(pin).
When the reading is stuck at 0 or 1023
- 0: the pot is turned all the way to GND, or the wiper (middle pin) is disconnected.
- 1023: the pot is turned all the way to 5V, or the wiper is shorted to 5V or GND.
- Settles at 512: the wiper is disconnected (middle pin not connected).
Double-check the wiring. Potentiometers are easy to wire backwards.
When you need more precision
The Arduino’s 10-bit ADC is fine for most projects. If you need 12-bit or 16-bit, use an external ADC chip:
- ADS1115: 16-bit, I2C, 4 channels, about $2.
- MCP3002: 10-bit, SPI, 2 channels.
These are also covered in the book Arduino Sensors.
What to build next
- A knob-controlled LED dimmer.
- A knob-controlled servo (rotate a small motor to match the knob).
- A “meter” display on an OLED that shows the value as a bar.
The knob-controlled servo is in the book Arduino Robotics. The OLED meter is one of the next tutorials on this site.