An ADC (Analog-to-Digital Converter) translates continuous real-world voltage signals into discrete binary numbers that a microcontroller can process. By bridging the physical and digital domains, an ADC changes a physical variable—like a thermistor's resistance or a battery's voltage drop—into a usable integer in your code, fundamentally dictating your measurement resolution and sampling limits. Beginners commonly confuse ADC resolution (the number of bits) with ADC accuracy (how close the reading is to reality, governed by noise, source impedance, and reference voltage stability), or they mix it up with a DAC (which outputs analog signals instead of reading them).

Understanding the practical uses of ADC is the difference between a battery monitor that triggers a false low-voltage alarm and one that reliably tracks state-of-charge to the millivolt. Let's break down the math, the real-world applications, and the hardware traps that ruin your readings.

The Math Behind the Measurement

Every ADC has a reference voltage ($V_{ref}$) and a bit-depth ($n$). The smallest voltage change the ADC can detect is the step size, calculated as:

Step Size = $V_{ref} / 2^n$

Let's look at a worked numeric example. Suppose you are building a battery monitor for a 12V LiFePO4 pack (nominal 13.2V, max 14.4V) using an ESP32. You use a voltage divider to scale the 0-14.4V range down to 0-3.3V to fit the ESP32's input limits.

  • Internal 12-bit ADC (ESP32/Arduino Due): $2^{12} = 4096$ steps. Step size on the 3.3V rail is $3.3V / 4096 = 0.8mV$. Scaled back to the battery, each step represents $14.4V / 4096 = 3.5mV$ of battery voltage.
  • Internal 10-bit ADC (Arduino Uno/Nano): $2^{10} = 1024$ steps. Scaled to the battery, each step is $14.4V / 1024 = 14mV$.
  • External 16-bit ADC (ADS1115): $2^{15}$ (1 bit is sign) = 32768 steps over a 4.096V internal reference. Step size is $0.125mV$. Scaled to the battery, you get sub-millivolt resolution.

If your BMS requires 5mV accuracy to balance cells, the Arduino Uno's 14mV step size is physically incapable of doing the job, regardless of how much you oversample in software. You must match the ADC step size to your system's required precision.

Where You Meet ADC in Practice

You will use ADCs in almost every embedded project that interacts with the physical environment. Here are the three most common bench and jobsite applications:

1. Battery Voltage and Current Monitoring

Voltage is read via a high-impedance resistor divider. Current is read by measuring the voltage drop across a shunt resistor (e.g., a 50A/75mV shunt). Because the shunt voltage is tiny and sits on top of common-mode noise, you usually route it through an op-amp or a dedicated current-sense amplifier (like the INA219, which has a built-in ADC and I2C interface) before it hits the microcontroller's ADC pin.

2. NTC Thermistor Temperature Sensing

An NTC thermistor changes resistance with temperature. You place it in a voltage divider with a fixed resistor (usually matched to the thermistor's resistance at room temperature, e.g., 10kΩ). The ADC reads the divider's midpoint voltage, and your code uses the Steinhart-Hart equation to convert that voltage into a precise temperature in Celsius.

3. Audio and AC Waveform Sampling

Reading a microphone or an AC current transformer requires sampling the waveform fast enough to reconstruct it. According to the Nyquist theorem, your ADC sample rate must be at least twice the highest frequency you want to measure. For 60Hz mains power, a 1kHz sample rate is sufficient to calculate RMS current. For audio, you need at least 16kHz (often 44.1kHz).

Internal vs. External ADCs: A Decision Tree

Microcontrollers have built-in ADCs, but they are often noisy, non-linear, or multiplexed in ways that limit speed. Use this decision path to choose your hardware:

Your Requirement Architecture Concrete Part Pick
High-speed audio or AC waveform (>10kHz sampling) Internal SAR ADC or dedicated Audio ADC ESP32 internal ADC (via I2S DMA) or PCM1808
High precision DC (battery, load cells, slow sensors) External I2C Sigma-Delta ADC ADS1115 (16-bit, 4-channel, built-in PGA)
Many channels (8+) for joysticks, pots, or DIP switches External SPI SAR ADC MCP3008 (10-bit, 8-channel)
Simple UI buttons, rough light levels (LDR) Internal Microcontroller ADC Arduino Uno A0-A5 / ESP32 GPIO32-39
The Default Pick for Precision: If you need accurate DC measurements and your internal ADC is too noisy, default to the Texas Instruments ADS1115. It costs about $4 on a breakout board, communicates over I2C, and includes a Programmable Gain Amplifier (PGA) that lets you measure signals as small as ±256mV with 16-bit resolution. It is the undisputed workhorse for DIY precision sensing.

Common Hardware Mistakes That Destroy ADC Accuracy

Even a 24-bit ADC will give you garbage data if the analog front-end is designed poorly. Watch out for these specific failure modes:

The ESP32 ADC2 vs. WiFi Conflict

This is the most common trap for ESP32 builders. The ESP32 has two ADC peripherals: ADC1 and ADC2. ADC2 is shared with the WiFi radio. If you initialize WiFi (or BLE) in your sketch, ADC2 pins (GPIO 0, 2, 4, 12-15, 25-27) will return erratic, locked, or zero values. Fix: Always route precision analog sensors to ADC1 pins (GPIO 32, 33, 34, 35, 36, 39) if your project uses wireless communication (Espressif ADC Documentation).

Source Impedance is Too High

Most microcontroller ADCs use a Successive Approximation Register (SAR) architecture. Inside the chip, a tiny capacitor must charge up to the input voltage during the sampling window. If your external circuit (like a 1MΩ voltage divider) has too much resistance, the capacitor won't charge in time, resulting in readings that are always lower than reality or that lag behind actual changes. Fix: Keep the Thevenin equivalent source impedance below 10kΩ. If you must use high-value resistors to save battery, add a 100nF ceramic capacitor directly across the ADC input pin to act as a local charge reservoir.

ESP32 Internal ADC Non-Linearity

The ESP32's internal 12-bit ADC is notoriously non-linear at the extremes of its range. Readings near 0V and above 3.1V are highly inaccurate, and the attenuation settings (0dB, 2.5dB, 6dB, 11dB) have overlapping and messy curves. If you are measuring a 0-3.3V signal directly on an ESP32 without external calibration, expect up to a 10% error at the rails. For anything requiring true precision, bypass the internal ADC entirely and use an external module like the ADS1115 (Adafruit ADS1115 Guide).

FAQ: Quick Answers on ADC Implementation

Can I just average 100 ADC readings in software to get 16-bit resolution from a 10-bit ADC?

No. Oversampling and averaging can reduce random white noise and effectively gain you 1 or 2 extra bits of resolution (e.g., turning 10-bit into 12-bit). However, it cannot fix missing codes, integral non-linearity (INL), or offset errors inherent to the silicon. You cannot software-average a 10-bit ADC into a true 16-bit ADC.

Why does my ADC reading bounce around by 3 or 4 digits even when the input is tied to a battery?

You are likely seeing noise from the microcontroller's digital switching or the USB power supply coupling into the analog reference. To fix this, ensure your $V_{ref}$ is clean (use an external precision voltage reference like the LM4040 if your MCU supports it), place a 100nF decoupling capacitor on the ADC input, and use twisted pair wire for remote sensors to reject common-mode magnetic interference.

What is the absolute best setup for a high-precision DIY load cell scale?

Do not use a standard microcontroller ADC or even the ADS1115 for load cells. Load cells output tiny differential signals in the millivolt range that require specialized low-noise amplification. Use a dedicated 24-bit ADC designed specifically for bridge sensors, such as the HX711 or the NAU7802. They handle the excitation voltage, amplification, and 24-bit conversion in a single $2 chip.

Final Bench Advice: Stop fighting your microcontroller's internal ADC for precision DC tasks. The moment your project requires measuring a LiFePO4 cell to within 10mV, or reading a precision shunt, wire up an I2C ADS1115. It costs less than a cup of coffee, requires only four jumper wires, and instantly eliminates 90% of your analog debugging headaches.