Learning Goals 5 min
By the end of this lesson you will be able to:
- Identify the three pins of a potentiometer — two ends and a centre wiper — and explain why the wiper voltage sweeps smoothly from 0 V to 5 V as the knob turns.
- Wire a potentiometer as a built-in voltage divider: end pins to 5V and GND, wiper to an analog input. No partner resistor needed — the pot is the divider.
- Read the wiper with
analogRead(0–1023) and use the value to drive an output continuously — LED brightness, tone frequency, animation speed — whatever needs a smoothly tweakable knob.
Warm-Up 10 min
L01-36 to L01-39 introduced four environmental sensors — the world dictates what they read. Today's sensor is different: it's a human input. A knob the user turns. The chip reads the position. The link between finger and software has never been more direct.
Quick-fire puzzle
Knobs are everywhere — a stereo's volume dial, a car's heating control, a guitar amp's tone, the old-style dimmer switch in a dining room. They all feel the same: turn left, less; turn right, more.
- Inside any of these, what physical thing do you think changes when you turn the knob?
- If the dimmer dial were just a regular variable resistor — say, between 0 Ω and 10 kΩ — wired directly to an LED, what would happen as you turned it?
- Could you wire that same dimmer dial to an Arduino's analog input the way you wired the LDR last week? What new piece would you need?
Reveal the answer
- A long strip of resistive material has a sliding metal contact (the "wiper") pressed against it. As the knob turns, the wiper slides along the strip. The fraction of the strip on each side of the wiper acts as a resistor.
- The LED would dim and brighten with the knob — more resistance = less current = dimmer LED. But this only works for the LED; for a microcontroller you don't have one.
- You'd need a partner resistor to make a voltage divider — exactly what you built in L01-36 with the LDR. Here's the punchline of today's lesson: a potentiometer is a built-in voltage divider. The wiper acts as the junction. You don't need to add a partner; the part already contains both halves of the divider, with the wiper position controlling the ratio.
New Concept — the wiper is the junction 15 min
The big idea — three pins, one knob
A potentiometer (or "pot" for short) is a three-pin component that looks like a small blue or grey cube with a knob or shaft on top. Inside:
- A resistive track shaped in an arc (rotary pots) or strip (slider pots) with a fixed total resistance — typical hobby values are 10 kΩ or 100 kΩ.
- A wiper — a small metal arm that touches the track and moves along it as the knob turns.
- Three external pins: two end pins connected to the two ends of the track, and one wiper pin in the middle.
The trick: connect the two end pins to 5V and GND. The track is now a 10 kΩ resistor with 5 V across it. The wiper taps a point somewhere along that track — depending on knob position. That point's voltage is exactly the junction of a voltage divider, with the two halves of the track playing the roles of R1 and R2 from L01-38.
What the wiper voltage works out to
Reusing L01-38's formula with Rb as the bottom resistor:
Vwiper = 5 V × Rb / (Ra + Rb)
And since Ra + Rb always equals the pot's full rated value, this simplifies into "the fraction of the track between the wiper and GND":
- Wiper at the GND end (Rb = 0):
Vwiper = 0 V→analogRead = 0 - Wiper in the middle (Ra = Rb):
Vwiper = 2.5 V→analogRead ≈ 512 - Wiper at the +5 V end (Ra = 0):
Vwiper = 5 V→analogRead = 1023
So a pot wired with ends to +5 V and GND gives you the full analogRead range, sweeping smoothly as you turn the knob. That's the whole point of the part.
The "value doesn't really matter" rule
You'll see 10 kΩ pots, 100 kΩ pots, even 1 kΩ pots in hobby kits. For analogRead, the value almost doesn't matter — the divider ratio is what determines the wiper voltage, and the ratio is what knob position controls regardless of the total. A 10 kΩ pot at half-turn gives the same 2.5 V as a 100 kΩ pot at half-turn.
The total value only matters for current: a 1 kΩ pot wastes 5 mA continuously (5 V ÷ 1 kΩ) through its track; a 100 kΩ pot wastes only 0.05 mA. Both are fine for a Uno; the 10 kΩ default is a nice middle ground.
Reading the wiper in code
Identical to L01-36 — there is no new function or pattern. Just read A0:
int knob = analogRead(A0); // 0..1023 across the knob's full sweepThat's the entire interface. Compare against a threshold for binary decisions (if (knob > 512) …), or scale to drive an output continuously (analogWrite(LED_PIN, knob / 4)), or use the number any way that makes sense.
Why it matters
Pots are the bridge between human and machine. Every physical knob on every device — guitar amplifier tone, oven temperature dial, lab-equipment fine-tune, old-school radio volume — is some form of pot. They also make development dramatically easier: instead of editing a constant in code and re-uploading every time you tune a parameter, wire a pot, point your sketch at it, and tune live with your fingers. Today's lesson is the foundation of every "control surface" you'll build, plus the developer's secret weapon for prototyping.
Worked Example — knob to LED brightness 20 min
The wiring
Three components: the pot, one LED with a 220 Ω resistor, and the breadboard's shared rails.
- Pot straddling three columns: one end-pin column jumpers to the + rail (5V), the other end-pin column to the − rail (GND), the middle (wiper) column runs a yellow signal wire to A0.
- LED on ~D9 with a 220 Ω resistor (L01-07 wiring), cathode to the − rail. ~D9 is PWM-capable, which you'll need for the brightness control.
- The + rail jumpers to the Arduino's 5V pin; the − rail jumpers to GND.
Step 1 — Print the wiper value live
// Pot reader — see the value as you turn the knob
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(analogRead(A0));
delay(100);
}Upload at 9600 baud, open the Monitor. Turn the knob fully one way — the reading should pin at 0 or 1023. Turn the other way — pins at the opposite extreme. Turn through the middle — readings sweep smoothly through every value in between. Roughly half a turn = roughly 512. If your minimum isn't 0 and your maximum isn't 1023, you've wired only two of the three pins; recheck the divider connections.
Step 2 — Drive the LED brightness from the knob
The killer app of pots: live continuous control of an output.
// Knob dimmer — turn pot, LED brightens or dims
const int POT_PIN = A0;
const int LED_PIN = 9;
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
}
void loop() {
int knob = analogRead(POT_PIN); // 0..1023
int bright = knob / 4; // 0..255 (1023/4 ≈ 255)
analogWrite(LED_PIN, bright);
Serial.print("knob="); Serial.print(knob);
Serial.print(" bright="); Serial.println(bright);
delay(30);
}Upload. Turn the knob; the LED brightens and dims smoothly. Watch the Monitor — knob value sweeps 0–1023, brightness value sweeps 0–255, both move in lockstep. Your finger now controls a continuous PWM output through twenty lines of code.
Trace the maths on paper
For each knob position, fill in what the sketch sends to the LED.
| Knob position | analogRead | knob / 4 | LED visible brightness |
|---|---|---|---|
| Fully left | 0 | 0 | off |
| Quarter turn | ~256 | ____ | ____ (about 25%) |
| Halfway | ~512 | ____ | ____ (about 50%) |
| Three-quarter turn | ~768 | ____ | ____ |
| Fully right | 1023 | ~255 | full brightness |
Notice that 1023 / 4 = 255 remainder 3 — integer division throws away the remainder. The biggest possible PWM value you can get from this formula is 255, not 256, which is conveniently the maximum analogWrite accepts. The maths is exact at both ends — no clamping needed.
Try It Yourself — three knob sketches 20 min
Goal: A pot-driven tone. Replace the LED with a piezo on D8 (L01-14 wiring). Turn the knob; the buzzer's pitch slides up and down. Range: 200 Hz at full left, 2000 Hz at full right.
Plan: scale the 0–1023 knob value to a 200–2000 Hz range. (knob × 1800) / 1023 + 200 works — though integer overflow is a risk if you write it the wrong way. Easier: knob × 2 + 200 gives roughly 200 to 2246 Hz; close enough, no overflow.
const int POT_PIN = A0;
const int BUZZER_PIN = 8;
void setup() {
pinMode(BUZZER_PIN, OUTPUT);
}
void loop() {
int knob = analogRead(POT_PIN);
int freq = knob * 2 + 200; // 200..2246 Hz
tone(BUZZER_PIN, freq); // no duration — continuous
delay(20);
}Questions:
- You've built a tiny theremin! Sweep your finger through the knob smoothly — does the pitch sound continuous or stepped? ____
- Why is there no
noTonecall anywhere? ____ (Hint: eachtonecall instantly replaces the previous frequency without stopping in between.) - Change the formula to
knob / 2 + 200. What's the new pitch range? Does the lower end sound very different from the buzzer's natural resonance? ____
Goal: A knob-controlled blink rate. Add an LED on D8 (any digital pin). The LED blinks; the knob sets the blink interval from 50 ms (very fast) at full left to 1000 ms (slow) at full right.
Plan: read the knob each loop pass, compute the interval, and run a non-blocking millis()-based blink (L01-22 pattern) so the LED keeps blinking smoothly while the knob value keeps updating.
const int POT_PIN = A0;
const int LED_PIN = 8;
unsigned long lastToggle = 0;
int ledState = LOW;
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void loop() {
int knob = analogRead(POT_PIN); // 0..1023
int interval = knob + 50; // 50..1073 ms
if (millis() - lastToggle >= (unsigned long)interval) {
lastToggle = millis();
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
}
}Questions:
- Why does this need
millis()rather thandelay(interval)? Try replacing it withdelayand see what happens to knob responsiveness. ____ - The fastest blink is at knob = 0 (50 ms), the slowest at knob = 1023 (about 1 s). How would you reverse it so left = slow, right = fast? ____
- What's the smallest blink interval that still looks like blinking to your eye, rather than just "dim"? ____ (Hint: around 30 ms is the human flicker fusion threshold.)
Goal: A pot-tuned threshold for the L01-36 nightlight. Now you don't pick the threshold in code — the user dials it in. Two analog sensors at once (LDR on A0, pot on A1), one LED on D8.
Plan: read both. The pot value is the threshold. If the LDR reads below the pot value, light the LED. Print both numbers + a marker showing which is bigger.
const int LDR_PIN = A0;
const int POT_PIN = A1;
const int LED_PIN = 8;
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
}
void loop() {
int light = analogRead(LDR_PIN);
int threshold = analogRead(POT_PIN);
bool dark = light < threshold;
digitalWrite(LED_PIN, dark);
Serial.print("light="); Serial.print(light);
Serial.print(" threshold="); Serial.print(threshold);
Serial.print(" dark="); Serial.println(dark);
delay(200);
}Questions:
- How does turning the pot to fully right (threshold = 1023) affect the LED? Why? ____ (Hint: every LDR reading is below 1023, so dark is always true.)
- How does it affect the LED with the pot fully left (threshold = 0)? ____
- Compare this with the L01-36 stretch task (auto-calibrating with millis). Which approach feels more "real product" — and why? ____ (Hint: both have a place; physical knobs vs auto-calibration is a UX design decision.)
Mini-Challenge — pot-controlled animation speed 10 min
"Take last week's chase animation, add a tempo knob"
Open your L01-34 sketch — the five-LED chase / bounce / wave animation that used 2D arrays. Today, replace the hardcoded stepMs value in your playPattern calls with a live reading from a pot wired to A1. Turning the knob speeds the animation up or slows it down without uploading.
Your task:
- Keep the L01-34 wiring (5 LEDs on D7–D11, sharing GND). Add a pot wired the L01-40 way (ends to 5V and GND, wiper to A1). You'll use 6 Arduino pins total: D7–D11 + A1.
- At the top of
loop(), readint speed = analogRead(A1);. - Convert that to a sensible step interval.
int stepMs = speed / 5 + 30;gives a range from 30 ms (super fast) to about 235 ms (relaxed) — fits well visually. - Pass
stepMsto yourplayPatterncalls so each frame's hold time tracks the knob. - Walk around your setup turning the knob while the chase runs. You should see the animation respond in real time.
It works if:
- Fully-left knob: the animation crawls one step every quarter-second or so.
- Fully-right knob: the animation blurs into a continuous moving glow.
- Mid-knob: the chase looks like the default L01-34 speed.
- You can change the speed during the animation — the next step picks up the new value.
Reveal one valid loop()
// Drop-in replacement for L01-34's loop()
const int POT_PIN = A1;
void loop() {
int speed = analogRead(POT_PIN);
int stepMs = speed / 5 + 30; // 30..235 ms per frame
playPattern(chase, CHASE_FRAMES, stepMs);
playPattern(bounce, BOUNCE_FRAMES, stepMs);
playPattern(wave, WAVE_FRAMES, stepMs);
}Only the loop() body and one pin constant changed. The data arrays, helpers, showFrame, and playPattern all stay exactly as in L01-34. This is the developer's superpower of pots in action — the parameter you used to hardcode and re-upload to tweak is now a live value your fingers can change while the sketch runs. Engineers wire a pot to half of their prototypes for exactly this reason.
Recap 5 min
A potentiometer is a three-pin component containing a built-in voltage divider — a resistive track between two end pins with a sliding wiper (middle pin) that taps a point along it. Wire the two ends to 5 V and GND; the wiper now sweeps from 0 V to 5 V as you turn the knob. Read it with analogRead(A0) — no partner resistor needed because the divider is inside the part. The value (10 kΩ, 100 kΩ) hardly matters for ADC reading; only ratio matters. Use the result to drive any continuous output — LED brightness, tone frequency, animation speed, threshold value — turning your finger into a live software dial.
- Potentiometer (pot)
- A three-pin variable resistor with a moving wiper. The two end pins are fixed at the ends of the resistive track; the wiper taps a point along it. The most common manually-adjusted analog input.
- Wiper
- The sliding contact inside a pot. Its position along the resistive track is what the knob controls. The middle pin connects to it.
- End pins
- The two pins at the ends of a pot's resistive track. Interchangeable — swap them and the knob simply turns the other way for the same reading.
- Built-in voltage divider
- The key insight about pots: with the two end pins at 5 V and GND, the part already is a divider. No partner resistor needed; the wiper voltage gives you the full ADC sweep from 0 to 1023.
- Live tuning
- The developer's practice of wiring a pot to a code parameter — speed, threshold, brightness — so it can be adjusted while the sketch is running, instead of editing constants and re-uploading. One of the most useful prototyping tricks.
- Linear vs audio (log) taper
- Linear pots change voltage evenly with knob angle. Audio-taper pots crowd the change into one end (matching how the ear hears volume). Hobby-kit pots are almost always linear; check the label if it matters.
Homework 5 min
The dual-pot mixer. Wire two pots — one on A0, one on A1 — and an RGB LED (D9 red, D10 green, D11 blue, the L01-30 wiring). Then build a sketch where:
- Pot A controls the LED's brightness overall (0 = off, 1023 = full).
- Pot B controls the colour position on a simple gradient — left = red, middle = green, right = blue.
This means each pot does something independent and the two together let you mix any of three colours at any brightness. Your hands are doing the work that the L01-31 rainbow-fade sketch did automatically.
Hint for the gradient: read pot B (0–1023), split it into three roughly equal bands (0–340 = red, 341–682 = green, 683–1023 = blue), and only light the matching channel. (A continuous interpolation would be nicer — but L01-41 introduces map(), which will make that genuinely elegant. For today, the three-band version is fine.)
Also: a design reflection on paper.
- What's the resolution of a pot on a Uno's ADC — i.e. how many distinguishable positions does the knob have? ____ (Hint: 0–1023 = 1024 positions.)
- If you wanted finer control near the middle of the knob and coarser near the ends — like an audio fader — what could you do in code, without changing the pot? ____ (Hint: don't read the value linearly; apply a curve.)
- Three pots controlling R, G, B directly would let you mix any of 16 million colours by hand. Why isn't that how digital colour pickers usually work? ____ (Hint: most people don't think in RGB — they think in "hue + saturation + brightness".)
- The L01-29 Serial Light Show used typed digits 1–9 to set animation speed. If you bolted on a pot for the same job, what's the user-experience trade-off compared to the typed digit? ____
Bring back next class:
- The saved
.inofile (call itdual-pot-mixer). - A 30-second phone video showing both pots changing the LED's colour and brightness independently.
- Your four written reflection answers, in your notebook.
Heads up for next class: L01-41 "The map() Function" introduces the one-liner that replaces every knob / 4, knob * 2 + 200, knob / 5 + 30 in today's lesson. Same idea — scale a value from one range to another — but the built-in map() makes it readable in a glance. After today, you'll be doing these conversions manually; tomorrow you'll have a clean tool for them.