When reading a microcontroller datasheet or wiring a sensor, ADC means Analog-to-Digital Converter. An Analog-to-Digital Converter (ADC) is a hardware peripheral that translates continuous real-world voltage signals into discrete digital numbers a microcontroller can process. In a real circuit, the ADC changes how you interface with the physical world: it bridges infinite analog curves (like temperature or sound) and the rigid digital logic of your code, but it inherently introduces quantization error and resolution limits based on its bit-depth.
Think of an ADC like a ruler with only millimeter marks; if an object is 10.5mm long, the ruler forces you to round it to either 10mm or 11mm. That rounding is the fundamental trade-off of digitizing analog signals. Let's break down the math, the hardware realities, and the specific traps that catch makers when using popular boards like the Arduino Uno R3 and the ESP32.
The Core Math: Resolution, Reference Voltage, and Step Size
To use an ADC effectively, you need to understand the relationship between the reference voltage (Vref) and the resolution (bit-depth). The ADC slices the voltage range from 0V to Vref into discrete steps. The formula for the voltage value of a single step (the Least Significant Bit, or LSB) is:
Step Size = Vref / (2^Resolution)
• Arduino Uno R3 (ATmega328P): 10-bit (1024 steps) | 5.0V Vref = 4.88mV per step
• ESP32-WROOM-32: 12-bit (4096 steps) | 3.3V Vref = 0.80mV per step (theoretical)
• TI ADS1115 (External I2C): 16-bit (65536 steps) | 4.096V Vref = 0.0625mV per step
Worked Numeric Example: Arduino Uno Reading a Potentiometer
Suppose you have a 10kΩ potentiometer wired across 5V and GND, with the wiper connected to A0 on an Arduino Uno R3. The Uno's default Vref is 5V, and it has a 10-bit ADC.
- Total Steps: 2^10 = 1024 steps (numbered 0 to 1023).
- Step Size: 5.0V / 1024 = 0.00488V (4.88mV) per step.
- The Scenario: You turn the knob until your multimeter reads exactly 2.50V at the wiper.
- The Math: 2.50V / 0.00488V = 512.29.
- The Result: The
analogRead(A0)function will return either 512 or 513. The microcontroller cannot distinguish between 2.500V and 2.504V; they both map to the same integer. If your project requires detecting a 2mV change, the Uno's internal ADC is mathematically incapable of doing it without external amplification.
Where You Meet ADCs in Practice
You will rely on ADCs whenever a sensor outputs a variable voltage rather than a digital protocol (like I2C or SPI). Common bench scenarios include:
- Resistive Sensors: Voltage dividers using NTC thermistors, photoresistors (LDRs), or flex sensors.
- Battery Monitoring: Reading a LiFePO4 or 18650 cell voltage through a high-impedance voltage divider to calculate State of Charge (SoC).
- User Inputs: Analog joysticks (reading X/Y potentiometers) or slide pots for lighting dimmers.
- Current Sensing: Reading the analog output of a Hall-effect sensor like the ACS712 or the shunt voltage from an INA219 (though the INA219 has an internal ADC and outputs via I2C).
The ESP32 ADC Non-Linearity Trap: A Real-World Scenario
The ESP32 is a powerhouse for IoT, but its internal ADC is notorious on the workbench for tripping up hobbyists who assume a 12-bit ADC behaves perfectly. Here is a real-world failure scenario.
The Setup
You are building a WiFi-enabled temperature logger using an ESP32-WROOM-32 DevKit v1. You wire a 10kΩ NTC thermistor in a voltage divider with a 10kΩ pull-up resistor to 3.3V. The midpoint goes to GPIO34 (an ADC1 channel). You write your code to read the 12-bit value (0-4095) and map it to temperature.
The Numbers
At room temperature (25°C), the thermistor resistance is roughly 10kΩ. The voltage divider outputs exactly half of 3.3V, which is 1.65V. The ESP32 reads this as ~2048. Perfect.
The Outcome
You test the circuit by holding the thermistor to heat it up. The resistance drops, the voltage rises toward 3.3V, and you expect the ADC reading to climb smoothly toward 4095. Instead, as the voltage passes 2.8V, the readings become erratic, and by 3.0V, the ADC completely saturates, returning a hard 4095 even if the actual voltage reaches 3.2V.
What Went Wrong
The ESP32's internal ADC is highly non-linear at the upper and lower extremes of its range. According to Espressif's official documentation, the usable linear range for the ESP32 ADC is roughly 0.1V to 2.8V. Furthermore, if you attempt to use ADC2 pins (like GPIO25 or GPIO26) while WiFi is active, the reads will fail entirely because the WiFi radio monopolizes the ADC2 hardware.
analogReadMilliVolts() function (available in newer Arduino cores), which applies factory eFuse calibration data to partially correct the non-linear curve.
Internal vs. External ADCs: When to Upgrade
When the internal ADC isn't enough, you move to an external chip. Here is how the common options stack up when you need precision.
| Feature | Arduino Uno (Internal) | ESP32 (Internal) | TI ADS1115 (External I2C) |
|---|---|---|---|
| Resolution | 10-bit (1024 steps) | 12-bit (4096 steps) | 16-bit (65536 steps) |
| Typical Cost | $0 (Included) | $0 (Included) | ~$4.00 (Breakout board) |
| Linearity | Excellent | Poor at extremes | Excellent (Precision PGA) |
| Best Use Case | Pots, basic joysticks | Basic battery monitoring | Load cells, precision thermistors, shunt current |
If you are reading a strain gauge or a precision PT100 RTD, the 0.8mV step size and non-linearity of the ESP32 will ruin your data. Spending $4 on an ADS1115 breakout board gives you 16-bit resolution, an internal programmable gain amplifier (PGA), and frees up your microcontroller's processing time since the ADC handles the conversion over I2C.
What People Commonly Confuse With ADCs
On the bench, I see two major points of confusion regarding analog conversion:
1. Resolution vs. Accuracy
A 12-bit ADC has a resolution of 4096 steps. But accuracy is dictated by Integral Non-Linearity (INL) and noise. An ESP32 has 12-bit resolution, but due to internal noise and non-linearity, its actual effective accuracy is closer to 9 or 10 bits. More bits do not automatically mean a more accurate measurement if the analog front-end is noisy.
2. ADC vs. DAC
An ADC (Analog-to-Digital) reads voltage into code. A DAC (Digital-to-Analog) outputs voltage from code. The Arduino Uno has an ADC but no true DAC (it fakes it with PWM). The ESP32 has both, but the ESP32's DAC pins (GPIO25, GPIO26) are limited to 8-bit resolution and are not suitable for high-fidelity audio without heavy external filtering.
3. Analog Pins vs. ADC Channels
Not all pins labeled "A0, A1" on a clone board are guaranteed to be mapped to the internal ADC multiplexer in custom PCB designs, and on the ESP32, pins like GPIO34, 35, 36, and 39 are input-only ADC pins. They lack internal pull-up/pull-down resistors. If you try to use them as digital inputs with INPUT_PULLUP, they will float and return garbage data.
FAQ: Common ADC Questions on the Bench
Why are my analogRead() values jumping around by 5-10 steps?
This is ADC noise, usually caused by a high-impedance voltage divider, unregulated USB power, or missing bypass capacitors. The Arduino analogRead reference recommends keeping the source impedance under 10kΩ. If your divider uses 100kΩ resistors to save battery, the internal sample-and-hold capacitor doesn't have enough time to charge, resulting in jitter. Add a 100nF ceramic capacitor between the analog pin and GND, or use an op-amp buffer.
Can I change the reference voltage on an Arduino?
Yes. By default, the Uno uses VCC (5V) as the reference. You can switch to the internal 1.1V reference using analogReference(INTERNAL). This is incredibly useful for reading low-voltage signals (like a 0-1V shunt resistor) because it shrinks the step size from 4.88mV down to roughly 1.07mV, giving you much finer resolution without needing an external op-amp.
Does sampling speed matter for my sensor?
For a thermistor or battery monitor, no. Temperature changes slowly. But if you are doing audio sampling or reading a fast-moving piezo knock sensor, you need to consider the Nyquist theorem. The standard analogRead() on an Arduino Uno takes about 104 microseconds (roughly 9,600 Hz sampling rate). If your signal frequency is higher than 4,800 Hz, you will get aliasing, and you must either speed up the ADC prescaler or use a dedicated external ADC chip.






