Learning Goals 5 min
- Read a voltage on any of the six analog inputs (A0–A5) with
analogRead(pin), knowing that the returned value is an integer 0–1023. - Convert a raw ADC reading into a voltage in millivolts:
mV = raw × 5000 / 1024. - Wire a potentiometer to A0 and watch the live reading in the Serial Monitor as you turn the knob — your first real input from the analog world.
Warm-Up 10 min
The previous six lessons have been about output — making the Arduino produce a voltage. Today flips it. We now want the Arduino to measure a voltage and tell us what it sees. The chip inside the UNO that does this job is called the ADC — Analog-to-Digital Converter.
Predict-the-output
You connect a wire from 5V directly to A0. The sketch reads analogRead(A0) and prints it. What do you expect to see?
Reveal
1023 (or very close — 1022 or 1023 due to noise). 5 V is the maximum the ADC can measure with its default reference, so it returns the top of its scale. Connect GND instead → returns 0. Anything in between → a number between 0 and 1023 proportional to the voltage.
New Concept · How the ADC measures voltage 20 min
The big idea — slicing 0 to 5 V into 1024 steps
The ATmega328 chip inside the UNO has a 10-bit ADC. "10-bit" means it can report one of 210 = 1024 distinct values, numbered 0 to 1023. It maps the entire 0 V to 5 V range across those 1024 steps:
| Pin voltage | analogRead returns | What this means |
|---|---|---|
| 0.00 V | 0 | Pin tied to GND. |
| 1.25 V | ~256 | Quarter way up the scale. |
| 2.50 V | ~512 | Halfway up the scale. |
| 3.75 V | ~768 | Three-quarters way up. |
| 5.00 V | 1023 | Pin tied to +5 V. |
Resolution: how fine can it slice?
5 V divided into 1024 steps = 4.88 mV per step. That's the smallest voltage change the ADC can detect. If your pin sits at 1.234 V vs 1.235 V, the ADC will return the same number — the difference is below its resolution.
This is roughly the precision of a basic multimeter. For most projects (reading a potentiometer, a light sensor, a thermistor) it's comfortable. For something needing micro-volts (medical-grade sensors, audio) you'd need a higher-resolution external ADC chip.
The conversion formulas
// raw → millivolts
mV = raw * 5000 / 1024
// raw → volts (floating-point)
V = raw * (5.0 / 1023.0)
// raw → percentage of full scale
pct = raw * 100 / 1023Note the two divisors — 1024 for millivolts (because 5000 mV ÷ 1024 = 4.88 mV per step) and 1023 for the float / percent version (because the top reading is 1023, not 1024). Both are technically correct; the difference is one step (a fraction of a percent). Pick one and stay consistent.
Where the six analog inputs are
On the UNO, look at the right-hand edge of the board: pins labelled A0, A1, A2, A3, A4, A5. Each of these is connected to the chip's ADC. You can call analogRead(A0), analogRead(A1), etc. — the chip switches its single ADC between pins, sampling each in turn.
Each conversion takes about 100 microseconds, so you can comfortably sample 6 channels at 1 kHz each. For most sensors that's overkill — humans react at ~100 ms, so 10 reads per second is plenty for a knob.
No pinMode required (and how it differs from digital)
You do not call pinMode(A0, INPUT) — analogRead sets the pin to analog-input mode automatically. (You can use A0–A5 as digital pins too if you call pinMode first, but for analog reading it's unnecessary and the ADC will configure things for you.)
Worked Example · Read a potentiometer 20 min
Step 1 — wiring
A potentiometer has three legs. The outer two go to +5V and GND — order doesn't matter functionally, but swapping them inverts which end is the high reading. The middle leg (the "wiper") is the variable voltage — connect it to A0.
| Pot leg | Goes to |
|---|---|
| Outer left | +5V rail |
| Middle (wiper) | A0 |
| Outer right | GND rail |
Step 2 — the sketch
Save as pot-read.ino:
// L02-07: read the pot on A0 and print the value
const int POT = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
int raw = analogRead(POT);
Serial.print("raw: ");
Serial.println(raw);
delay(100);
}Step 3 — upload & turn the knob
Open the Serial Monitor (Tools → Serial Monitor, set baud rate to 9600). You should see a stream of values:
Sample output as you turn the knob
raw: 0 raw: 0 raw: 47 raw: 215 raw: 511 raw: 798 raw: 1022 raw: 1023 raw: 1023
Turn the knob slowly all the way one way — you should see 0. All the way the other way — you should see 1023 (or 1022). Anywhere in between gives a proportional value.
Step 4 — print as voltage
Useful, but "raw: 511" isn't very meaningful to a human. Let's also print the voltage:
void loop() {
int raw = analogRead(POT);
long mV = (long)raw * 5000 / 1024; // integer mV
Serial.print("raw: ");
Serial.print(raw);
Serial.print(" → ");
Serial.print(mV);
Serial.println(" mV");
delay(100);
}Output
raw: 0 → 0 mV raw: 256 → 1250 mV raw: 512 → 2500 mV raw: 768 → 3750 mV raw: 1023 → 4995 mV
The (long) cast in front of raw is important — raw * 5000 would overflow a 16-bit int at any value over ~6, giving garbage. Casting to long (32-bit) handles all 1024 possible values cleanly.
Step 5 — confirm with a multimeter
Put the multimeter on DC volts and probe between A0 and GND. Turn the pot. The multimeter reading should match the Arduino's mV reading divided by 1000. If they disagree by more than 5%, double-check your wiring — the most common mistake is swapping +5V and GND on the pot.
Try It Yourself 20 min
Goal: Print the percentage instead of raw or mV. Should read 0% at one end, 100% at the other.
Hint
int pct = raw * 100 / 1023;
Serial.print(pct);
Serial.println(" %");Integer division means you'll see 99% at the very top and 0% at the bottom — fine for most uses. Use pct = raw * 100.0 / 1023 if you want decimals.
Goal: Wire the LDR from L01-36 to A1 (with a 10 kΩ pull-down to GND) and read both the pot (A0) and the LDR (A1) at the same time. Print both values side-by-side.
Hint
const int POT = A0;
const int LDR = A1;
void loop() {
int p = analogRead(POT);
int l = analogRead(LDR);
Serial.print("pot: "); Serial.print(p);
Serial.print(" LDR: "); Serial.println(l);
delay(100);
}Cover the LDR with your hand → the value drops (less light = higher resistance = lower voltage at the divider tap). Shine your phone torch at it → value spikes. Same chip, two simultaneous inputs.
Goal: Drive an LED's brightness from the pot. Turn the knob and the LED on pin ~9 fades smoothly. You'll need to scale the 0–1023 pot reading down to 0–255 for analogWrite.
Hint
const int POT = A0;
const int LED = 9;
void setup() {
pinMode(LED, OUTPUT);
}
void loop() {
int raw = analogRead(POT);
int bright = raw / 4; // 1023 / 4 ≈ 255
analogWrite(LED, bright);
}raw / 4 is the simplest scale-down — 1024 ≈ 4 × 256. We'll learn the proper way (map(raw, 0, 1023, 0, 255)) in L02-10. For now / 4 is fine and uses no extra functions.
Mini-Challenge · The voltmeter 15 min
Build a 3-decimal-place voltmeter. Connect a wire to A0 (loose end in the air, no sensor) — you'll touch it to different test points (the 5 V rail, GND, an LED's anode, the middle of a voltage divider) and read the voltage to 3 decimal places.
It works if:
- The reading on the 5 V rail says
4.995 Vor thereabouts (always slightly below 5.000 because of the 1023 / 1024 quirk). - The reading on GND says
0.000 V. - The reading on the middle leg of a powered-up pot tracks smoothly as you turn the pot.
- The print uses
Serial.print(volts, 3)with the second argument controlling decimal places.
Reveal one valid sketch
// Mini-voltmeter — read A0, print volts to 3 decimal places.
const int PROBE = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
int raw = analogRead(PROBE);
float volts = raw * 5.0 / 1023.0;
Serial.print("raw: ");
Serial.print(raw);
Serial.print(" ");
Serial.print(volts, 3);
Serial.println(" V");
delay(250);
}Touch the probe wire to +5V → see ~4.995 V. Touch it to GND → see 0.000 V. Touch it to the wiper of a pot → see whatever the pot is currently dialled to. You've built a (very simple) multimeter.
Recap 5 min
The ADC slices the voltage range into 1024 steps. analogRead(pin) returns the step number — 0 to 1023 — for any of A0–A5. Each step is about 4.88 mV wide. Convert to millivolts with raw × 5000 / 1024, or to volts with raw × 5.0 / 1023.0. Tomorrow we use this to read noisy sensors — and discover why raw readings often jump around even on a perfectly still pot.
- ADC (Analog-to-Digital Converter)
- The chip subsystem that measures a voltage and returns an integer. The UNO's is 10-bit, returning 0–1023.
- Resolution
- The smallest voltage change the ADC can detect. For UNO at 5 V default: 5 V / 1024 ≈ 4.88 mV.
analogRead(pin)- Built-in. Returns an integer 0–1023. Takes ~100 µs per call. No
pinModeneeded. - A0–A5
- The six analog input pins on the UNO. Located on the right edge of the board.
- Floating pin
- A pin connected to nothing. Reads random noise. Always connect to something — a sensor, a divider, GND.
- Integer overflow
- What happens when a calculation exceeds the variable's range.
(int)1023 * 5000overflows;(long)1023 * 5000doesn't. Cast tolongwhen multiplying ADC values. - Wiper
- The middle leg of a potentiometer — the sliding tap. It outputs a variable voltage between the two outer pins.
Homework 5 min
Map the pot. With the pot wired to A0, slowly turn it from one end to the other. Stop at five distinct positions and record:
- The raw ADC value at each position.
- The corresponding voltage you compute (using
raw × 5.0 / 1023.0). - The voltage your multimeter shows when you probe between the wiper and GND.
Compare columns 2 and 3 — they should be within 1% of each other. If they're wildly different, your wiring needs another look.
Then think: if you replace the pot with the LDR (with a 10 kΩ pull-down), what range of raw values would you expect from "hand over the sensor" vs "phone torch on the sensor"? Predict on paper, then test in your homework sketch.
Bring back next class:
- Your three-column table with five rows.
- Your LDR prediction + the actual numbers you saw.
- One question about anything that didn't make sense.