Pular para o conteúdo

Analógico

O ADC da ESP32: atenuação, curva e por que não chega a 3,3 V

Como a ESP32 mede tensões com MicroPython: read e read_uv, ADC1 e ADC2, as quatro atenuações, a curva de calibração, potenciômetro, LDR e média móvel.

Por Prof. Rodrigo Faustino · Atualizado em · 12 min de leitura

Até aqui, todo pino lia 0 ou 1. Muita coisa no mundo, porém, não é liga-desliga: a posição de um botão de volume, a claridade de uma sala, a temperatura de um líquido, a carga de uma bateria. Para trazer essas grandezas para o programa, a ESP32 tem um conversor analógico-digital, o ADC: ele mede a tensão num pino e devolve um número proporcional a ela.

O ADC da ESP32 é útil, rápido e cheio de pegadinhas. A leitura não é exatamente proporcional à tensão, o fundo de escala muda com uma configuração chamada atenuação, metade dos pinos analógicos para de funcionar quando o Wi-Fi liga e, com a configuração padrão, ele não chega aos 3,3 V que a placa fornece. Este artigo explica cada uma dessas pegadinhas e o porquê delas, com números que vêm da calibração do próprio chip.

De tensão para número

O MicroPython oferece o ADC como a classe ADC, do módulo machine. Ela recebe um Pin e tem três jeitos de ler:

from machine import Pin, ADC
import time

adc = ADC(Pin(34))   # GPIO34, um pino do ADC1

for i in range(20):
    print(adc.read(), adc.read_u16(), adc.read_uv())
    time.sleep_ms(250)
  • read() devolve um número de 0 a 4095. São 12 bits: a faixa de medida é dividida em 4096 degraus;
  • read_u16() devolve a mesma leitura esticada para 0 a 65535. Ele existe para que um programa funcione igual em placas com ADCs de resoluções diferentes;
  • read_uv() devolve a tensão em microvolts (1 V = 1 000 000 µV), já corrigida pela calibração do chip, com resolução de 1 mV.

Abra o exemplo no simulador, rode e arraste o eixo do potenciômetro enquanto o programa roda. A aba Pinos mostra o GPIO34 como ADC, com a leitura e a tensão.

Se você só quer saber "quantos volts tem no pino", read_uv() é o caminho mais direto: divida por um milhão e pronto. read() e read_u16() são úteis quando o que interessa é uma posição relativa ("o eixo está a 40 % do giro"), mas, como veremos, esse número não é uma régua perfeita.

Captura de tela do PyPlaca com a lição do ADC: o código que lê o GPIO34 no editor, o potenciômetro ligado à placa no circuito e o Serial mostrando leituras de read, read_u16 e read_uv.
A lição do ADC: girando o eixo do potenciômetro, o Serial mostra as três leituras e a aba Pinos, a tensão no GPIO34.
FastMindAssistente de IA local

A IA que lembra da sua vida e mora no seu computador

  • Memória de longo prazo com a fonte de cada resposta
  • Funciona offline: seus dados ficam no seu PC
  • Lê PDFs, slides, fotos e gravações de reunião
Baixar grátis para Windows

Plano Essencial grátis para sempre

ADC1, ADC2 e o Wi-Fi

A ESP32 tem dois conversores, e nem todo pino está ligado a um deles:

  • ADC1: GPIOs 32 a 39. Na DevKit V1, são o D32, o D33, o D34, o D35, o VP (GPIO36) e o VN (GPIO39);
  • ADC2: GPIOs 0, 2, 4, 12 a 15 e 25 a 27.

A diferença importa por um motivo prático: o ADC2 é usado pelo Wi-Fi. Depois que o Wi-Fi da ESP32 é ligado, o sistema que controla o rádio segura o ADC2 para si, e uma leitura num pino do ADC2 falha. No MicroPython v1.29.0, o erro é OSError: [Errno 116] ETIMEDOUT — a leitura esperou o conversor ficar livre e desistiu. O simulador reproduz o mesmo erro e acrescenta o aviso adc2-wifi, explicando a causa.

A regra prática é simples: para projetos com Wi-Fi, use o ADC1. Os GPIOs 34 a 39 são escolhas ótimas, porque são só de entrada e não têm outra função para atrapalhar. Os exemplos deste artigo usam o 34 e o 35.

A referência interna e a atenuação

Por dentro, o ADC da ESP32 compara a tensão do pino com uma referência interna de cerca de 1,1 V. Sozinho, ele só mede até perto disso: qualquer coisa acima vira o número máximo, 4095. Para medir tensões maiores, a entrada passa antes por um atenuador, que divide a tensão antes da comparação. Quanto dividir é você quem escolhe, com o método atten():

AtenuaçãoFundo de escala (calibração)Faixa boa (documentação)
ADC.ATTN_0DB≈ 1,04 V0,10 a 0,95 V
ADC.ATTN_2_5DB≈ 1,36 V0,10 a 1,25 V
ADC.ATTN_6DB≈ 1,88 V0,15 a 1,75 V
ADC.ATTN_11DB≈ 3,13 V0,15 a 2,45 V

A coluna do meio é a tensão em que a leitura bate no 4095 para um ESP32 típico, segundo a calibração do ESP-IDF; a última coluna é a faixa em que a documentação do MicroPython considera a medida confiável. 11 dB é o padrão do MicroPython: criar o ADC ou chamar init() sem dizer a atenuação volta para 11 dB e 12 bits.

Gráfico de barras horizontais com o fundo de escala de cada atenuação do ADC da ESP32: 0 dB perto de 1,04 V, 2,5 dB perto de 1,36 V, 6 dB perto de 1,88 V e 11 dB perto de 3,13 V, comparados com a linha de 3,3 V. Em cada barra, a faixa boa da documentação aparece destacada.
Fundo de escala de cada atenuação (calibração da ESP32) e a faixa boa da documentação do MicroPython. Nem a de 11 dB chega aos 3,3 V.

Por que não chega a 3,3 V

Olhe a última linha da tabela: mesmo na atenuação máxima, o fundo de escala fica em torno de 3,13 V. Um pino ligado direto no 3V3 lê 4095, mas um pino a 3,15 V também lê 4095, e um a 3,2 V também. A faixa entre ~3,13 V e 3,3 V simplesmente não existe para o ADC. É por isso que, ao girar um potenciômetro ligado entre o GND e o 3V3, a leitura chega ao máximo um pouco antes do fim do giro.

E há mais: a documentação considera a medida em 11 dB confiável só até 2,45 V. Entre 2,45 V e 3,13 V a curva do ADC entorta — a mesma variação de tensão produz cada vez menos degraus de leitura. A calibração do chip compensa parte disso no read_uv(), mas a precisão cai. Se o seu sensor vai até 3,3 V e você precisa medir bem a parte de cima, a solução é um divisor de tensão que traga o sinal para dentro da faixa boa.

O pé da curva: tensões muito baixas

No outro extremo também há um limite. Abaixo de algo entre 75 mV e 142 mV, conforme a atenuação, a leitura fica em 0. Com o potenciômetro todo para o lado do GND, read() dá 0, enquanto read_uv() mostra cerca de 0,14 V — o menor valor que a calibração consegue representar nessa atenuação. A documentação recomenda não confiar em medidas abaixo de 0,10 V a 0,15 V, e esse é o motivo.

Por que não usar sempre 11 dB

Se 11 dB mede a faixa mais larga, por que existem as outras? Porque os 4096 degraus se espalham pela faixa inteira. Um sinal que vai só até 0,9 V, lido em 11 dB, usa menos de um quarto dos degraus. Em 0 dB, o mesmo sinal usa quase todos: a medida fica bem mais fina. A regra é escolher a menor atenuação em que o seu sinal ainda caiba.

from machine import Pin, ADC

adc = ADC(Pin(34))

for nome, at in (('0 dB', ADC.ATTN_0DB), ('2,5 dB', ADC.ATTN_2_5DB),
                 ('6 dB', ADC.ATTN_6DB), ('11 dB', ADC.ATTN_11DB)):
    adc.atten(at)
    print(nome, adc.read(), adc.read_uv())

O circuito deste exemplo tem um resistor de 27 kΩ em série entre o 3V3 e o potenciômetro, que "rouba" a maior parte da tensão: o cursor só vai de 0 V até perto de 0,9 V (o divisor agora é 3,3 × 10 kΩ / 37 kΩ). Com o eixo no fim do giro, a leitura em 0 dB chega perto de 3500, enquanto em 11 dB fica perto de 900. A tensão é a mesma; a resolução é que muda quase quatro vezes. O read_uv(), em compensação, dá praticamente o mesmo valor em todas — ele já devolve a tensão, não os degraus.

A leitura não é uma régua: read() × read_uv()

Com o potenciômetro exatamente no meio do giro, a tensão no cursor é 1,65 V — metade de 3,3 V. Se o ADC fosse uma régua perfeita de 0 a 3,3 V, read() daria 2047, a metade de 4095. Na ESP32 em 11 dB, dá 1872.

Duas coisas explicam a diferença. Primeiro, o fundo de escala não é 3,3 V, e sim ~3,13 V. Segundo, a relação entre a tensão e os degraus não é uma reta: tem um deslocamento no começo e entorta no fim. A ESP32 grava na fábrica dados de calibração, e o ESP-IDF tem um modelo dessa curva; o MicroPython usa esse modelo para converter os degraus em tensão no read_uv(). O simulador faz o caminho contrário — da tensão do circuito para os degraus — com o mesmo modelo de calibração do ESP-IDF, invertido. Por isso os números que você vê na tela são os que um ESP32 típico mostraria.

A consequência para o seu código: para converter em volts, use read_uv(). Fazer read() * 3.3 / 4095 é um erro comum e dá valores alguns por cento errados, mais ainda nas pontas da faixa.

FastTeacherPara professores

Da ementa ao semestre planejado

  • Plano de ensino e calendário montados sozinhos
  • Diário de aulas pronto para colar no SIGA
  • Slides e listas de exercícios com gabarito
Conhecer o FastTeacher

Versão Community grátis · Windows

Potenciômetro: o divisor de tensão que gira

O ADC mede tensão e quase não puxa corrente do pino. Então, para medir "quanto o eixo girou" ou "quanta luz há na sala", o truque é transformar essa grandeza numa tensão. O circuito que faz isso é o divisor de tensão: dois resistores em série entre a alimentação e o GND, com o pino ligado no ponto do meio. A tensão no meio é:

V_meio = V_alimentação × R_baixo / (R_cima + R_baixo)

O potenciômetro é um divisor ajustável: um resistor de 10 kΩ com um cursor que desliza sobre ele. As pontas vão no GND e no 3V3; o cursor pega uma fração da tensão. Como o potenciômetro do laboratório é linear, a tensão cresce em linha reta com o giro: no meio, 1,65 V; a um quarto, 0,825 V.

Uma regra que protege a placa: ligue as pontas do potenciômetro sempre no 3V3, nunca no VIN. O VIN tem 5 V, e um pino da ESP32 aguenta no máximo 3,6 V.

Dois divisores de tensão lado a lado. À esquerda, um potenciômetro de 10 quilo-ohms entre 3V3 e GND com o cursor no GPIO34. À direita, um LDR entre 3V3 e o GPIO35 e um resistor fixo de 10 quilo-ohms entre o GPIO35 e o GND, com as fórmulas da tensão no ponto do meio.
O ADC mede tensão, não resistência: o potenciômetro e o LDR entram em divisores de tensão, e o pino lê o ponto do meio.

Mapeando a leitura para o que importa

Quase nunca o programa quer o número de 0 a 4095 em si: quer um brilho de LED (0 a 65535), um ângulo de servo (0 a 180), uma porcentagem. Passar de uma faixa para outra é mapear:

from machine import Pin, ADC, PWM
import time

pot = ADC(Pin(34))
led = PWM(Pin(18), freq=1000, duty_u16=0)

def mapear(x, de_min, de_max, para_min, para_max):
    return (x - de_min) * (para_max - para_min) // (de_max - de_min) + para_min

for i in range(40):
    leitura = pot.read()
    led.duty_u16(mapear(leitura, 0, 4095, 0, 65535))
    print(leitura, '->', mapear(leitura, 0, 4095, 0, 100), '%')
    time.sleep_ms(250)

Com isso o potenciômetro vira um dimmer: girar o eixo muda o brilho do LED no GPIO18. Repare na ordem da conta: multiplicar antes de dividir evita perder tudo no meio do caminho (1872 // 4095 daria 0). A mesma função serve para faixas invertidas: mapear(x, 0, 4095, 100, 0) faz o 0 virar 100.

O Arduino tem uma função map() igual a esta. No MicroPython ela não existe — e o map do Python é outra coisa (aplica uma função a cada item de uma sequência). Por isso vale ter a sua.

LDR: medindo a luz

O LDR (light dependent resistor, o GL5528 do catálogo) é um resistor que muda com a luz. Pela ficha do fabricante, com 10 lux — a luz de um cômodo meio escuro — ele fica entre 10 e 20 kΩ; no escuro, sobe para 1 MΩ ou mais. Entre 10 e 100 lux, a resistência segue aproximadamente R ≈ R10 × (lux/10)^(−0,7): dobrar a luz não divide a resistência por dois.

Como o ADC não mede resistência, o LDR entra num divisor com um resistor fixo de 10 kΩ. Com o LDR em cima (no 3V3) e o resistor embaixo (no GND), a tensão no pino é 3,3 × 10 kΩ / (R_LDR + 10 kΩ):

  • claro: R_LDR pequena, tensão perto de 3,3 V, leitura alta;
  • escuro: R_LDR enorme, tensão perto de 0 V, leitura baixa.

Trocar o LDR e o resistor de lugar inverte tudo. As duas montagens funcionam; o importante é saber qual você montou.

Por que 10 kΩ? Um divisor fica mais sensível quando o resistor fixo tem a mesma ordem de grandeza do LDR na faixa de luz que mais interessa. Com 10 kΩ, a transição entre "luz de cômodo" e "quase escuro" cai no meio da escala do ADC.

from machine import Pin, ADC
import time

luz = ADC(Pin(35))
LIMIAR = 1500   # abaixo disso, consideramos escuro

for i in range(30):
    leitura = luz.read()
    print(leitura, 'escuro' if leitura < LIMIAR else 'claro')
    time.sleep_ms(300)

Rode e mude a luz do ambiente do LDR no simulador (no Circuito, na 2D ou na 3D). Anote a leitura com 1, 10, 100 e 1000 lux e repare como ela não cresce em linha reta. Para acender uma luz quando escurece, isso não atrapalha: basta escolher um limiar, como no exemplo.

Ruído e média móvel

Na placa de verdade, ler o mesmo potenciômetro parado várias vezes não dá sempre o mesmo número: a leitura "pula" alguns degraus. Isso é ruído, que vem da alimentação, dos fios e do próprio conversor. Um programa que acende um LED quando a leitura passa de um limiar pode ficar piscando bem em cima dele.

O simulador ainda não acrescenta esse ruído: o tamanho do ruído real vai ser medido numa placa do laboratório antes de entrar na simulação. Mesmo assim, vale aprender o remédio desde já, e os desafios da trilha sacodem o eixo de propósito para conferir se o programa se defende.

O remédio mais simples é a média móvel: em vez de usar a última leitura, usar a média das N últimas. Uma leitura estranha sozinha muda pouco a média.

from machine import Pin, ADC
import time

pot = ADC(Pin(34))
ultimas = []

for i in range(30):
    ultimas.append(pot.read())
    if len(ultimas) > 5:
        ultimas.pop(0)               # sai a mais antiga
    media = sum(ultimas) // len(ultimas)
    print(ultimas[-1], media)
    time.sleep_ms(100)

O tamanho da janela é uma troca. Janela grande dá uma média mais calma, mas demora para acompanhar uma mudança de verdade; janela pequena responde rápido, mas filtra menos. Gire o eixo de uma vez de uma ponta à outra e veja a média chegar ao novo valor em degraus, ao longo de cinco leituras.

Outra defesa contra a leitura que oscila em cima do limiar é a histerese: usar dois limiares, um para ligar e outro, um pouco abaixo, para desligar. A luz acende abaixo de 1400 e só apaga acima de 1600, por exemplo. Entre os dois, o estado não muda.

Outros detalhes do ADC no MicroPython

Alguns comportamentos que o simulador reproduz da v1.29.0 e que evitam surpresas:

  • ADC(Pin(34)) devolve sempre o mesmo objeto para o mesmo pino;
  • configurar o canal deixa o pino em modo analógico: ele deixa de funcionar como entrada digital, saída ou pull;
  • width() escolhe a resolução de read(), de 9 a 12 bits (12 é o padrão);
  • deinit() desliga o bloco do conversor; ler depois dá OSError: [Errno 1] EPERM;
  • um pino de ADC sem nada ligado lê 0 e gera o aviso adc-solto: assim como no digital, um pino analógico solto não tem tensão definida.

Resumo para levar para a bancada

  1. Use o ADC1 (GPIOs 32 a 39) sempre que o projeto tiver Wi-Fi;
  2. Para volts, use read_uv(); read() não é proporcional à tensão;
  3. Em 11 dB (o padrão), a leitura satura perto de 3,13 V e é mais confiável até 2,45 V;
  4. Escolha a menor atenuação em que o sinal caiba, para ganhar resolução;
  5. Grandezas que não são tensão (posição, luz) entram por um divisor de tensão;
  6. Nada acima de 3,6 V num pino: alimente divisores e potenciômetros pelo 3V3;
  7. Contra ruído, média móvel; contra oscilação em cima do limiar, histerese.

O próximo artigo, sobre sensores DHT22, HC-SR04 e PIR, usa o ADC para conferir a conta de um divisor de tensão — e mostra por que o ADC não consegue medir um sinal de 3,33 V que o pino, ainda assim, aguenta. A trilha analógica refaz este artigo em lições com circuito pronto, do primeiro read() ao desafio de montar o LDR.

Para praticar no PyPlaca

Trilhas

Lições

Fichas de componentes

FastTeacherPara professores

Da ementa ao semestre planejado

  • Plano de ensino e calendário montados sozinhos
  • Diário de aulas pronto para colar no SIGA
  • Slides e listas de exercícios com gabarito
Conhecer o FastTeacher

Versão Community grátis · Windows

FastMindAssistente de IA local

A IA que lembra da sua vida e mora no seu computador

  • Memória de longo prazo com a fonte de cada resposta
  • Funciona offline: seus dados ficam no seu PC
  • Lê PDFs, slides, fotos e gravações de reunião
Baixar grátis para Windows

Plano Essencial grátis para sempre

FastTeacherPara professores

Da ementa ao semestre planejado

  • Plano de ensino e calendário montados sozinhos
  • Diário de aulas pronto para colar no SIGA
  • Slides e listas de exercícios com gabarito
Conhecer o FastTeacher

Versão Community grátis · Windows