Measure an analog voltage with the ESP32 ADC in MicroPython
(Updated at 11/28/2022)
On the ESP32, some pins are connected to the integrated ADC of the microcontroller. An ADC is an analog to digital converter that returns a digital value proportional to the measured voltage.
Features
On the ESP32, pins 36, 39, 34 and 35 can be analog inputs with MicroPython. The resolution of the measurements is 12 bits, so the measurements are between 0 and 4095.
Warning
Unlike the Arduino, the analog inputs on the ESP32 must not exceed a voltage of 3.3V. This could damage or even destroy the inputs of the ADC. It is, therefore, necessary to check that you do not use a supply voltage of 5V to measure the value of a sensor. There are solutions to limit the input voltage of the ADC.
Read an analog input from the ESP32 with MicroPython
The voltage of analog input is measured using the sub-module ADC
of the machine
. As for PWM, a physical pin is associated with the ADC
object.
from machine import Pin, ADC
# Pin definitions
adc_pin = Pin(36, mode=Pin.IN)
adc = ADC(adc_pin)
adc.atten(ADC.ATTN_11DB)
Do not forget to import the ADC sub-module. You will note that for the ESP32, you must also specify attenuation of 11 dB (with ADC.ATTN_11DB
) to read a voltage over the range of 0 to 3.3V.
You can also create an ADC
by specifying the number of the analog channel you want to use.
from machine import ADC
adc = ADC(0) # Select the ADC_0 ()
Warning
On the ESP32, the analog channels are assigned to the pins disorderly. It is, therefore, better to use the definition by pin number.
Once you have configured an analog input in MicroPython, you only need to use the function read()
to read the analog value.
from machine import Pin, ADC
adc = ADC(Pin(36, mode=Pin.IN))
print(adc.read())
It will be necessary to use a cross product to have the value measured in volt:
Mini-Project: Control the intensity of an LED via a potentiometer on the ESP32
We will use PWM and ADC with MicroPython to control the brightness of an external LED.
Electrical schematic :
Note
Remember putting a resistor in series with the LED to prevent it from burning (330 Ω, for example)
To read the position of the potentiometer alone:
from machine import Pin, ADC
import time
# Create an ADC object linked to pin 36
adc = ADC(Pin(36, mode=Pin.IN))
while True:
# Read ADC and convert to voltage
val = adc.read()
val = val * (3.3 / 4095)
print(round(val, 2), "V") # Keep only 2 digits
# Wait a bit before taking another reading
time.sleep_ms(100)
For reading the position of the potentiometer and changing the brightness:
from machine import Pin, ADC, PWM
import time
def map(x, in_min, in_max, out_min, out_max):
""" return linear interpolation like map() fonction in Arduino"""
return (x - in_min) * (out_max - out_min) // (in_max - in_min) + out_min
if __name__ == "__main__":
# Create a PWM object linked to pin 23
pwm_led = PWM(Pin(23,mode=Pin.OUT))
pwm_led.freq(1_000)
# Create an ADC object linked to pin 36
adc = ADC(Pin(36, mode=Pin.IN))
adc.atten(ADC.ATTN_11DB)
while True:
val = adc.read()
pwm_value = map(x=val, in_min=0, in_max=4095, out_min=0,out_max=1023)
pwm_led.duty(pwm_value)
time.sleep_ms(10)