Analog vs Digital Signals
Digital signals are binary: they are either HIGH or LOW. Analog signals vary continuously across a range of voltages — a temperature sensor might output 0.5V at 0°C and 2.5V at 100°C. ESP32 includes an Analog-to-Digital Converter (ADC) that samples this continuous voltage and converts it to a number your code can work with.
ESP32 ADC Pins
| ADC | GPIO Pins | Wi-Fi Compatible? | Recommended? |
|---|---|---|---|
| ADC1 | GPIO32, GPIO33, GPIO34, GPIO35, GPIO36, GPIO39 | Yes ✓ | Always use ADC1 |
| ADC2 | GPIO0, GPIO2, GPIO4, GPIO12–GPIO15, GPIO25–GPIO27 | No ✗ | Avoid when Wi-Fi active |
Best practice: Use GPIO34, GPIO35, GPIO36 (VP), GPIO39 (VN) for analog readings — these are input-only pins with no boot-strapping concerns and dedicated ADC channels.
Basic analogRead() Setup
#define ADC_PIN 34 // ADC1_CH6 — input-only, no boot concern
void setup() {
Serial.begin(115200);
analogReadResolution(12); // 12-bit: 0–4095
analogSetAttenuation(ADC_11db); // Full range: 0–3.3V
// OR per-pin: analogSetPinAttenuation(ADC_PIN, ADC_11db);
}
void loop() {
int raw = analogRead(ADC_PIN);
float volts = raw * (3.3f / 4095.0f);
Serial.printf("Raw: %4d Voltage: %.3f Vn", raw, volts);
delay(200);
}
Attenuation Settings
| Attenuation | Constant | Input Range | Use When |
|---|---|---|---|
| 0 dB | ADC_0db | 0 – 1.1 V | Low-voltage precision sensors |
| 2.5 dB | ADC_2_5db | 0 – 1.5 V | Audio input signals |
| 6 dB | ADC_6db | 0 – 2.2 V | Half-scale 3.3V sensors |
| 11 dB | ADC_11db | 0 – 3.3 V | Potentiometers, most sensors |
Reading a Potentiometer
| Potentiometer Pin | Connect To |
|---|---|
| Left terminal | ESP32 GND |
| Right terminal | ESP32 3.3V |
| Wiper (middle) | ESP32 GPIO34 |
#define POT_PIN 34
#define LED_PIN 16
void setup() {
Serial.begin(115200);
analogReadResolution(12);
analogSetAttenuation(ADC_11db);
ledcSetup(0, 5000, 8);
ledcAttachPin(LED_PIN, 0);
}
void loop() {
int raw = analogRead(POT_PIN); // 0–4095
int brightness = map(raw, 0, 4095, 0, 255); // Scale to 8-bit PWM
ledcWrite(0, brightness);
Serial.printf("Pot: %4d Brightness: %3dn", raw, brightness);
delay(50);
}
Averaging to Reduce Noise
int readADCAverage(int pin, int samples = 16) {
long sum = 0;
for (int i = 0; i < samples; i++) {
sum += analogRead(pin);
delayMicroseconds(100); // Small gap between samples
}
return sum / samples;
}
void loop() {
int smooth = readADCAverage(34, 16);
float v = smooth * (3.3f / 4095.0f);
Serial.printf("Averaged: %4d (%.3f V)n", smooth, v);
delay(100);
}
Reading an LDR (Light Sensor)
An LDR (Light Dependent Resistor) changes resistance with light level. Wire it as a voltage divider:
| Component | Connection |
|---|---|
| LDR leg 1 | ESP32 3.3V |
| LDR leg 2 | GPIO35 AND 10kΩ resistor to GND |
#define LDR_PIN 35
void setup() {
Serial.begin(115200);
analogReadResolution(12);
analogSetPinAttenuation(LDR_PIN, ADC_11db);
}
void loop() {
int raw = analogRead(LDR_PIN);
int light = map(raw, 0, 4095, 0, 100); // 0 = dark, 100 = bright
Serial.printf("LDR raw: %4d Light: %3d%%n", raw, light);
if (light < 20) Serial.println(" ← Dark — turn on lights");
else Serial.println(" ← Bright enough");
delay(500);
}
Reading an NTC Thermistor
#define NTC_PIN 34
#define NOMINAL_R 10000.0f // 10kΩ at 25°C
#define NOMINAL_T 25.0f // Reference temperature
#define BETA 3950.0f // Beta coefficient (from datasheet)
#define SERIES_R 10000.0f // Fixed 10kΩ resistor in divider
void setup() {
Serial.begin(115200);
analogReadResolution(12);
analogSetPinAttenuation(NTC_PIN, ADC_11db);
}
void loop() {
int raw = analogRead(NTC_PIN);
// Calculate NTC resistance from voltage divider
float voltage = raw * (3.3f / 4095.0f);
float ntcR = SERIES_R * voltage / (3.3f - voltage);
// Steinhart-Hart simplified (Beta equation)
float steinhart = ntcR / NOMINAL_R;
steinhart = log(steinhart);
steinhart /= BETA;
steinhart += 1.0f / (NOMINAL_T + 273.15f);
float tempC = (1.0f / steinhart) - 273.15f;
Serial.printf("Temperature: %.1f °Cn", tempC);
delay(1000);
}
ADC Non-Linearity Warning
ESP32 ADC has a known non-linearity issue: readings near 0 and near 4095 are less accurate. The ADC is most linear between approximately 100–3900 (out of 4095). For precision measurements, use Espressif's calibration API or an external 16-bit ADC (ADS1115 over I2C) which provides far better accuracy.
Summary
Use ADC1 pins (GPIO32–GPIO39) for reliable analog readings, especially in Wi-Fi projects. Set 11 dB attenuation for full 0–3.3V range. Average multiple readings to reduce noise. Be aware of the non-linearity in the 0–100 and 3980–4095 ranges. For sensors requiring higher accuracy (medical, precision control), use an external I2C ADC.