voltmeter/Reading a voltage/09. From a number to volts
Reading a voltage · 09 of 12

From a number to volts

analogRead gives a count, not volts. The count's share of full scale, times the voltage the board measures against, is SIG; five times SIG is the input. On an ESP32 the core does the first step for you, and does it better.

A count is a fraction

An analog pin does not report volts. It reports how far up its range the voltage is, as a whole number: 0 at the bottom, the largest count at the top. On an Uno that range is 0 to 1023 against its 5 V supply. On a Pico running arduino-pico it is 0 to 1023 against 3.3 V, unless the sketch asks for 12 bits.

So a count is a fraction of the board's reference voltage:

SIG   = count × VREF / ADC_MAX
input = SIG × 5
From a number to volts
Your board
The reading368
SIG
1.799 V
On the terminal
8.99 V
One step
24 mV
The Uno's ADC counts 0 to 1023 against its 5 V supply. 368 of 1023 is 1.799 V on SIG, and five times that is on the terminal. One count is about 24 mV of input, so a 9 V battery reads to about a fortieth of a volt.

An Uno reading 368 has SIG at 368 × 5.0 / 1023, which is 1.80 V, and the input at five times that, 8.99 V.

One step of the input

The count moves in whole steps, so the input does too. On an Uno one count is 5 V / 1023, about 4.9 mV on SIG, and five times that on the terminal: about 24 mV. A 9 V battery reads to the nearest fortieth of a volt, which is finer than its own voltage stays still.

On a Pico at the default 10 bits, one count is about 16 mV of input. Call analogReadResolution(12) and change ADC_MAX to 4095, and it is about 4 mV.

The ESP32 does its own conversion

The ESP32 and ESP32-S3 have a 12-bit ADC, 0 to 4095, but a count there is not a clean fraction of 3.3 V. With the Arduino core's default setting the ADC reads only to about 3.1 V, and its response bends near both ends. Dividing a raw count by 4095 and multiplying by 3.3 gives a number that is off by different amounts at different voltages.

Each chip carries calibration data for its own ADC. analogReadMilliVolts applies it and returns SIG in millivolts, so the sketch divides by 1000 and multiplies by five. MicroPython's read_uv does the same in microvolts. That is why the sketches treat the ESP32s separately: not a different formula, but a better first step.

When it does not work

Should I divide by 1023 or 1024?

The ATmega328P datasheet's formula uses 1024, and 1023 is the largest count the Uno returns. The difference is a tenth of a percent, smaller than the resistors' tolerance, and calibration absorbs it either way. The sketches use 1023 so that the top count reads as the top voltage.

My Pico's readings go up to 4095, not 1023.

Something in your sketch called analogReadResolution(12). That is fine and gives four times finer steps; change ADC_MAX to 4095 to match, or every voltage reads four times too high.

Why not divide an ESP32's raw count by 4095?

Because the ESP32's ADC is not a straight line, and its top is about 3.1 V rather than 3.3 V. A raw count times 3.3 / 4095 is wrong by different amounts at different voltages. analogReadMilliVolts, and read_uv in MicroPython, apply the calibration the chip carries for exactly this.

My Uno's readings drift when its USB cable changes.

The Uno measures against its own 5 V supply, and that supply comes from whatever powers the board. A different cable or port can move it by a tenth of a volt or more, and every reading moves with it. Calibrate on the supply you will actually use.

Where this goes next

One number from a multimeter, and sixteen readings instead of one.

Calibrating and averaging

Edit this page — content/books/voltmeter/from-a-number-to-volts.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

Voltmeter

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.

Browse Modules and blocks on the forum