An ADC (analog to digital converter) is a hardware circuit that samples a continuous real-world voltage and translates it into a discrete binary number a microcontroller can process. This component fundamentally changes what a microcontroller can do by bridging the physical world—where temperature, light, and sound exist as continuously varying voltages—to the digital logic world of 0s and 1s. Without it, an Arduino or ESP32 is entirely blind to environmental sensors. While the concept seems straightforward, the gap between theoretical resolution and real-world accuracy is where most embedded projects hit a wall.
The Core Math: Resolution, VREF, and Step Size
To understand how an ADC analog to digital converter works, you need to look at three variables: the input voltage (Vin), the reference voltage (VREF), and the bit resolution (n). The ADC slices the VREF range into discrete steps. The number of steps is determined by 2^n.
Think of resolution like the millimeter marks on a ruler. A 10-bit ADC has 1,024 marks (0 to 1023), while a 12-bit ADC has 4,096 marks (0 to 4095). The distance between each mark is your step size (or LSB - Least Significant Bit voltage).
Step Size = VREF / (2^n - 1)
Digital Output = Vin / Step Size
A Worked Numeric Example
Let's compare reading a 1.65V signal on two common development boards.
- Arduino Uno (ATmega328P): Features a 10-bit ADC with a default 5V VREF. The step size is 5V / 1023 = 4.88mV. If you feed 1.65V into pin A0, the math is 1.65V / 0.00488V, yielding a raw digital reading of 338.
- ESP32 DevKit V1: Features a 12-bit ADC with a nominal 3.3V VREF. The step size is 3.3V / 4095 = 0.80mV. Feeding that same 1.65V into GPIO34 yields 1.65V / 0.0008V, resulting in a raw digital reading of 2062.
While the ESP32 gives you a finer ruler, that theoretical 0.8mV step size is rarely achievable in practice due to internal noise and VREF instability, which leads us to real-world application.
Where You Meet ADC Analog to Digital Conversion in Practice
You will use the ADC analog to digital conversion process anytime a sensor outputs a varying voltage rather than a digital protocol like I2C or SPI. Here are the most common bench and jobsite scenarios:
| Sensor Type | Typical Output Range | Circuit Requirement |
|---|---|---|
| NTC Thermistor | 0.1V to 3.0V | Voltage divider with a fixed resistor (e.g., 10kΩ) |
| ACS712 Current Sensor | VCC/2 ± 0.185V/A | Reads 2.5V at 0A; requires math to subtract the offset |
| Potentiometer | 0V to VREF | Direct connection to ADC pin and ground |
| LiPo Battery Monitor | 3.0V to 4.2V (or higher for packs) | Resistor divider to step down voltage below 3.3V max |
When wiring these, always keep analog traces short and route them away from high-frequency digital lines or switching power supplies. A 50kHz PWM signal running parallel to your thermistor wire will induce enough electromagnetic interference to make your ADC readings jitter by 20 to 30 LSBs.
The ESP32 ADC Non-Linearity Problem (And How to Fix It)
If you are using an ESP32, you will quickly discover that its internal ADC analog to digital converter is notoriously non-linear. The Espressif ADC calibration documentation explicitly notes that the ADC cannot accurately measure voltages near 0V or near the 3.3V rail. Readings below 0.1V often return 0, and readings above 2.6V curve sharply and saturate.
Furthermore, the ESP32 uses internal attenuation settings to scale higher voltages down to the internal comparator's range. If you don't set the attenuation correctly, a 2.5V input might max out the ADC and return 4095, completely destroying your data.
1. Use the Arduino core v2.0+ function
analogReadMilliVolts(pin) instead of analogRead(pin). This function reads the factory calibration data burned into the ESP32's eFuse during manufacturing and applies a correction curve to the raw reading.2. For voltages above 1.0V, ensure you set the attenuation in setup using
analogSetPinAttenuation(pin, ADC_11db) to allow the full 0-3.1V range.3. Never use ADC2 pins (GPIO 0, 2, 4, 12-15, 25-27) if you are using WiFi, as the WiFi radio hijacks the ADC2 hardware.
Common Confusions: Resolution vs. Accuracy vs. Sample Rate
What people commonly confuse with the ADC analog to digital process is the assumption that higher resolution equals higher accuracy. They are entirely different metrics.
- Resolution: How many slices the voltage pie is cut into (e.g., 12-bit = 4096 slices). This is a fixed hardware property.
- Accuracy: How close the reported slice is to the actual physical voltage. A 12-bit ADC with a noisy, unregulated 3.3V VREF might only yield 9 bits of effective accuracy because the bottom 3 bits are just measuring power supply noise.
- Sample Rate: How many times per second the ADC takes a reading. The Arduino Uno's default analogRead() takes about 100 microseconds (10,000 samples/second). If you try to sample a 5kHz audio signal at this rate, you will hit Nyquist limit aliasing and get garbage data.
If your project demands true 16-bit accuracy for precision load cells or medical-grade thermistors, you must abandon the microcontroller's internal ADC entirely and use an external chip over I2C or SPI.
Frequently Asked Questions
Why is my ESP32 ADC analog to digital reading non-linear at high voltages?
The ESP32's internal ADC saturates around 2.6V to 3.1V depending on the silicon batch, and the attenuation curve bends sharply near the top rail. If you are measuring a 4.2V LiPo battery directly, you are exceeding the absolute maximum rating of the pin, which can permanently damage the silicon. Always use a resistor voltage divider (e.g., 100kΩ and 47kΩ) to scale the battery voltage down to a maximum of 1.3V, then use analogReadMilliVolts() and multiply the result in software to reconstruct the true battery voltage.
How do I improve ADC analog to digital resolution without changing the microcontroller?
You can use a software technique called oversampling. By taking multiple rapid samples and averaging them, you can mathematically extract extra bits of resolution. The rule of thumb is that for every 1 extra bit of resolution you want, you must sample 4 times and average the result. If you need 12-bit resolution from an Arduino Uno's 10-bit ADC, take 16 samples (4^1 * 4^1), sum them, and divide by 4. This requires the signal to have a small amount of natural thermal noise (dither) to work perfectly, but it is highly effective for slow-moving signals like temperature.
What is the difference between an internal ADC analog to digital converter and an external ADC chip?
Internal ADCs are built into the microcontroller silicon. They are free, require no extra board space, but suffer from internal digital noise, lower effective resolution, and non-linearity (especially on the ESP32). External ADCs, like the Texas Instruments ADS1115, communicate over I2C. They feature internal programmable gain amplifiers (PGAs), highly stable internal voltage references, and true 16-bit resolution. You choose an external ADC when your sensor outputs microvolt-level signals (like a Wheatstone bridge strain gauge) or when you need simultaneous sampling without tying up the microcontroller's CPU in an interrupt loop.






