entradas-analogicas-adc-micropython

How to Read Analog Inputs (ADC) in MicroPython

  • 5 min

In this tutorial, we will see how we can use ADCs in MicroPython to perform an analog input with which to read sensors and other devices.

Unlike digital inputs, which can only detect two states (HIGH or LOW) analog inputs allow us to measure continuous values, within a range of voltages and with a specified resolution.

The measurement is performed using an ADC (Analog-to-Digital Converter), which transforms the analog voltage into a digital value that can be processed by the microcontroller.

We can use analog inputs to read sensors that operate through analog signals, such as potentiometers, temperature sensors, light sensors, pressure sensors (or any other quantity that varies gradually).

Configuration of Analog Inputs

In MicroPython, analog inputs are configured using the ADC class from the machine module (which by now we know well).

# Configure the analog pin (GPIO 34 on ESP32)
pot = ADC(Pin(34))

Once the ADC instance is defined, we can use some of its methods. Some of the common ones are,

CommandDescription
adc.read()Reads the analog value on a scale of 0 to 4095 (ESP32) or 0 to 1023 (ESP8266)
adc.read_u16()Reads the analog value with 16-bit resolution (0 to 65535)
adc.atten(attenuation)Sets the attenuation to adjust the input voltage range
adc.width(width)Sets the reading resolution (only on ESP32)

We can use the atten(attenuation) function to adapt the analog input range. On the ESP32, the available values are:

  • ADC.ATTN_0DB: 0 to 1.1V.
  • ADC.ATTN_2_5DB: 0 to 1.5V.
  • ADC.ATTN_6DB: 0 to 2.0V.
  • ADC.ATTN_11DB: 0 to 3.3V.

MicroPython allows you to set the ADC resolution using the width() method. On the ESP32, the available options are:

  • WIDTH_9BIT: Range of 0 to 511.
  • WIDTH_10BIT: Range of 0 to 1023.
  • WIDTH_11BIT: Range of 0 to 2047.
  • WIDTH_12BIT: Range of 0 to 4095.

Not all functions and values will be available on all board models. Check the information related to your specific board.

Practical Example

Let’s see it in a simple example. The following code shows how we could read an analog voltage value we have on a GPIO36 pin (corresponds to an ADC1 on the ESP32).

from machine import ADC, Pin

# ADC pin configuration
adc = ADC(Pin(36))  # GPIO36 or VP

adc.width(ADC.WIDTH_12BIT)  # Set resolution to 12 bits (default value)
adc.atten(ADC.ATTN_11DB)    # Set input range to 0-3.3V

# Read the analog value
value = adc.read()  # Read a value between 0 and 4095
print(f"Analog value read: {value}")

Analog signals often have noise. Use hardware filters (like capacitors) or software (averaging readings) to reduce noise. We will see this in the sensor reading tutorial.

Conversion of Analog Values to Physical Magnitudes

In general, the digital value obtained from the ADC is not useful by itself. We don’t care about its value, in ADC units 😜.

What we need is to convert it into a physical magnitude (such as voltage, temperature, light, etc). To do this, a conversion formula needs to be applied.

For example, let’s say we want to convert the digital value obtained from the ADC into a real voltage. The conversion formula is as follows:

In a 12-bit ADC with a reference voltage of 3.3V, the formula would be:

In code, this would look like this,

from machine import ADC, Pin
from time import sleep

# Configure the analog pin (GPIO 34 on ESP32)
pot = ADC(Pin(34))

# Configure the reading range (0-4095 for a 12-bit ADC)
pot.atten(ADC.ATTN_11DB)  # Full range of 0 to 3.3V

while True:
    value = pot.read()  # Read the analog value
    voltage = (value * 3.3) / 4095  # Convert to voltage
    print(f"Voltage: {voltage:.2f} V")
    sleep(0.5)  # Wait 0.5 seconds

Which would give this output (for example), which is what we need

Voltage: 1.65 V
Voltage: 0.82 V
Voltage: 2.47 V
...

To convert it to another magnitude, such as temperature or light, you will need the characteristic equation of the sensor, which converts voltage values into the measured magnitude.

Practical Examples