If you are reading a raw value of 2048 from a 12-bit converter ADC with a 3.3V reference (like the ESP32 internal ADC or an ADS1115 module), the exact converted voltage is 1.650 V. If you are using a standard 10-bit Arduino Uno (5.0V reference), a raw value of 2048 is impossible (max is 1023), but a raw reading of 512 equates to exactly 2.502 V. These numbers assume a stable reference voltage and a source impedance below 10 kΩ. Below is the exact math, the neighboring value table, and the decision path to fix your circuit if your readings are drifting.
The Core Conversion Formula and Worked Examples
Every microcontroller analog-to-digital converter maps an input voltage to a discrete integer based on its bit resolution ($n$) and reference voltage ($V_{ref}$). The universal formula to convert a raw integer back to voltage is:
$V_{in} = \frac{Raw \times V_{ref}}{2^n - 1}$
$n = 12$ (Max value = $2^{12} - 1 = 4095$)
$V_{ref} = 3.3V$
$Raw = 2048$
$V_{in} = \frac{2048 \times 3.3}{4095} = 1.6504 V$
$n = 10$ (Max value = $2^{10} - 1 = 1023$)
$V_{ref} = 5.0V$
$Raw = 512$
$V_{in} = \frac{512 \times 5.0}{1023} = 2.5024 V$
Neighboring Values Reference Table (±20% Range)
When debugging sensor noise, it helps to know what voltage shift a small change in the raw integer represents. For a 12-bit converter ADC on a 3.3V system, one least significant bit (LSB) equals roughly 0.8 mV. Here is the ±20% neighborhood around our baseline raw value of 2048:
| Raw ADC Value | Calculated Voltage (3.3V Ref) | Delta from Baseline | Typical Sensor Equivalent |
|---|---|---|---|
| 1638 (-20%) | 1.320 V | -0.330 V | Low-range TMP36 temp (~82°C) |
| 1843 (-10%) | 1.485 V | -0.165 V | Mid-range potentiometer tap |
| 2048 (Baseline) | 1.650 V | 0.000 V | Exact VCC/2 voltage divider |
| 2253 (+10%) | 1.815 V | +0.165 V | High-range light dependent resistor |
| 2458 (+20%) | 1.980 V | +0.330 V | Upper threshold trigger point |
What Assumptions Fix Your Answer (And When It Shifts)
The math above is perfect on paper, but on the workbench, three assumptions dictate whether your converted number is real or garbage.
1. The Reference Voltage ($V_{ref}$) Assumption
Your calculation is only as accurate as your $V_{ref}$. If you assume 5.0V because the Arduino is powered by USB, but the USB port is actually sagging to 4.7V under load, your calculated voltage will be 6% too high.
- 3.3V Systems (ESP32, Raspberry Pi Pico): Usually tied to an onboard LDO. Relatively stable, but can sag if the board is powering high-current peripherals.
- 5.0V Systems (Arduino Uno via USB): Highly variable. USB voltage can range from 4.75V to 5.25V.
- Internal 1.1V Reference (ATmega328P): By calling
analogReference(INTERNAL), you bypass the noisy VCC rail. The assumption shifts to a fixed 1.1V (±10% factory tolerance), meaning a raw 1023 now equals 1.1V, not 5V.
2. The ESP32 Non-Linearity Caveat
If you are using the internal converter ADC on an ESP32-WROOM-32, manual math using the formula above will yield errors up to 100mV at the extremes of the scale. The ESP32 internal ADC is notoriously non-linear. According to the Espressif Technical Reference Manual, you should use the factory-calibrated eFuse data built into the Arduino Core v2.x:
// Do NOT use manual math on ESP32 internal ADCs
int raw = analogRead(34);
float actual_voltage = analogReadMilliVolts(34) / 1000.0;
3. When the Conversion is Meaningless
Your calculated voltage is physically meaningless under three conditions:
- Source Impedance > 10 kΩ: The ATmega328P datasheet explicitly states the analog source impedance must be 10 kΩ or less. The internal sample-and-hold capacitor needs time to charge. If your voltage divider uses 100 kΩ resistors, the capacitor won't charge fully before the conversion completes, resulting in a permanently low, drooping reading.
- Floating Pins: If the pin is not tied to a definitive voltage or ground, it acts as an antenna. You will read random noise, and the formula will output meaningless jitter.
- Exceeding $V_{ref}$: If you feed 4.2V into a 3.3V referenced ADC, the internal protection diodes clamp the signal. The raw value will max out at 4095, but the actual voltage is higher. The math will blindly output 3.3V, hiding the overvoltage condition.
Decision Tree: Internal Converter ADC vs. External Module
Stop guessing which ADC architecture to use. Follow this decision path to select the exact hardware for your next build.
| Your Project Condition | Required Action | Concrete Hardware Pick |
|---|---|---|
| Accuracy tolerance > 50mV; Signal is 0-3.3V; Pin count is low. | Use Microcontroller Internal ADC | ESP32-WROOM-32 (Use analogReadMilliVolts) |
| Accuracy tolerance < 10mV; Signal exceeds 3.3V (e.g., 12V battery monitoring); Need differential measurement. | Use External I2C Precision ADC | Texas Instruments ADS1115 (16-bit, Programmable Gain) |
| Need 8+ analog channels; High sampling rate required; SPI bus available. | Use External SPI ADC | Microchip MCP3008 (10-bit, 8-channel) |
Frequently Asked Questions
Why does my ADC reading fluctuate by ±5 digits when the input is grounded?
This is thermal noise and electromagnetic interference (EMI) picked up by the PCB traces. A 5-digit fluctuation on a 10-bit ADC (5V ref) is about 24mV of noise. Fix this by adding a 100nF ceramic capacitor physically close to the ADC pin, tied between the analog input and ground, and implement a software moving-average filter.
Can I use a 5V Arduino to read a 3.3V sensor directly?
Yes, but your resolution drops. A 3.3V signal on a 5V, 10-bit reference will only ever reach a raw value of roughly 675 ($\frac{3.3 \times 1023}{5.0}$). You are throwing away the top 33% of your bit depth. Use a logic level shifter or an external 3.3V-referenced ADC to reclaim that resolution.
What happens if I wire the ADC input to a negative voltage?
Microcontroller GPIO pins cannot read negative voltages. Current will flow backward through the internal ESD protection diodes into the VCC rail. If the current exceeds the diode's limit (typically 20mA), you will permanently destroy the pin or the entire silicon die. Always use a clamping diode or an op-amp offset circuit if your signal dips below 0V.






