This article from our ESP32 Basics series demonstrates how to read analog values with the ESP32 using Arduino IDE.
This is useful for reading in a wide variety of sensors and variable components, including, but not limited to, trimpots, joysticks, sliders, and force-sensitive resistors.
ESP32 ADC Pins
The ESP32 includes two 12-bit SAR ADCs � ADC1 and ADC2 � and supports measurements on 18 channels (analog-enabled pins). ADC1 is available on eight GPIOs (32 to 39), while ADC2 is available on ten GPIOs (0, 2, 4, 12 to 15 and 25 to 27).
However, the DEVKIT V1 DOIT board (the version with 30 GPIOs) has only 15 ADC channels, as shown in the figure below.
The ADC in your ESP32 has a resolution of 12 bits, meaning that it can detect 4096 (2^12) discrete analog levels. In other words, it will convert input voltages ranging from 0 to 3.3V (operating voltage) into integer values ranging from 0 to 4095. This results in a resolution of 3.3 volts / 4096 units, or 0.0008 volts (0.8 mV) per unit.
Moreover, the ADC resolution and channel range can be set programmatically.
Limitations of the ESP32�s ADC
Truth be told, ADC is not the ESP32�s strongest point. There are several limitations that you should be aware of.
Unusable when WiFi is Enabled
The ADC2 pins cannot be used when Wi-Fi is enabled. Since there is a good chance of using WiFi on a microcontroller designed to use it, only the ADC1 can be used.
ADC Input Range
The ESP32�s ADC can only measure voltages ranging from 0 to 3.3V. You cannot measure analog voltages between 0 and 5V directly.
ADC Accuracy
Ideally, you would expect a linear behavior when using the ADC, but this is not the case. The ADC converters on the ESP32 are non-linear in nature. You can find more information about this in a discussion on GitHub.
In the graph below, the non-linearities at the lower and upper ends of the input voltage are clearly visible.
This basically means that the ESP32 cannot distinguish 3.2V from 3.3V; the measured value will be the same (4095). Similarly, it cannot distinguish between 0V and 0.13V signals; the measured value will be the same (0).
Electrical Noise
The electrical noise of the ADC implies a slight fluctuation of the measurements.
However, this can be corrected by adding a capacitor at the output and by oversampling.
The analogRead() Function
Reading the analog values from a GPIO pin is straightforward. In the Arduino IDE, you use the analogRead()
function, which accepts as an argument the GPIO pin number you want to read.
analogRead(GPIO);
Reading a potentiometer
To demonstrate how to use the ADC on the ESP32, we will use a simple example that reads an analog value from a potentiometer.
Hardware Hookup
Let�s setup a simple potentiometer circuit for this example.
Start by inserting the potentiometer into your breadboard. Wire the middle pin to pin GPIO 34 on your ESP32. Finally, wire one of the potentiometer�s outer pins � it doesn�t matter which � to ESP32�s 3V3 pin and the other to ground.
Example Code
Load the following sketch onto your ESP32. This sketch simply reads the potentiometer and prints the results to the Serial Monitor.
// Potentiometer is connected to GPIO 34 (Analog ADC1_CH6)
const int potPin = 34;
// variable for storing the potentiometer value
int potValue = 0;
void setup() {
Serial.begin(115200);
delay(1000);
}
void loop() {
// Reading potentiometer value
potValue = analogRead(potPin);
Serial.print("Analog value: ");
Serial.println(potValue);
delay(500);
}
Once you have uploaded the sketch, open the serial monitor at baud rate 115200 and press the EN button on the ESP32.
You should see a value between 0 and 4095, depending on the current rotation of the knob, being printed out to the serial monitor. Try turning the knob on the potentiometer to see how the values change.
Code Explanation:
The sketch begins by defining the GPIO pin to which the potentiometer is connected, which in this case is GPIO 34.
const int potPin = 34;
A variable is also defined to store the potentiometer values.
int potValue = 0;
In the setup(), we initialize the serial communication with the PC.
Serial.begin(115200);
In the loop, the analogRead()
function is used to read the voltage on the potPin
. The returned value is stored in the variable potValue
.
potValue = analogRead(potPin);
Finally, the values read from the potentiometer are printed to the serial monitor.
Serial.print("Analog value: ");
Serial.println(potValue);
potPin
does not need to be set as input. This is done for you automatically each time you call analogRead()
.
Other ADC Functions
There are other ADC functions that may be useful in other projects:
analogReadMilliVolts(pin)
: get ADC value for a given pin/ADC channel in millivolts.analogReadResolution(bits)
: sets the sample bits and read resolution. Default is 12-bit resolution. Range: 9 (0 � 511) to 12 bits (0 � 4095).analogSetWidth(bits)
: sets the hardware sample bits and read resolution. Default is 12-bit resolution. Range: 9 to 12 bits. 9-bit = 0-511, 10-bit = 0-1023, 11-bit = 0-2047 and 12-bit = 0-4095.analogSetCycles(cycles)
: sets the number of cycles per sample. Default is 8. Range: 1 to 255.analogSetSamples(samples)
: sets the number of samples in the range. Default is 1 sample. It has an effect of increasing sensitivity.analogSetClockDiv(clockDiv)
: sets the divider for the ADC clock. Default is 1. Range: 1 to 255.analogSetAttenuation(attenuation)
: sets the input attenuation for all ADC pins. Default isADC_11db
. Accepted values:
ADC_0db
: sets no attenuation (Measurable input voltage range = 100 mV ~ 950 mV).ADC_2_5db
: sets an attenuation of 1.34 (Measurable input voltage range = 100 mV ~ 1250 mV)ADC_6db
: sets an attenuation of 1.5 (Measurable input voltage range = 150 mV ~ 1750 mV)ADC_11db
: sets an attenuation of 3.6 (Measurable input voltage range = 150 mV ~ 2450 mV)
analogSetPinAttenuation(pin, attenuation)
: This function is the same as the previous one, except it sets the input attenuation for the specified pin.adcAttachPin(pin)
: Attaches a pin to ADC (also clears any other analog mode that could be on) and returns true if configuration is successful, else returns false.adcStart(pin)
: starts an ADC conversion on the attached pin�s bus.adcBusy(pin)
: checks if conversion on the pin�s ADC bus is currently running (returns TRUE or FALSE).resultadcEnd(pin)
: gets the result of the conversion (waits if ADC has not finished), returns 16-bit integer.
More information can be found at readthedocs.