Pular para o conteúdo

Sensores

Sensores na ESP32: DHT22, HC-SR04, PIR e o divisor de tensão

DHT22, HC-SR04 e PIR na ESP32 com MicroPython: o protocolo de cada sensor, os erros que a placa mostra e o divisor de tensão no ECHO de 5 V.

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

Com entradas digitais e o ADC, a ESP32 já consegue ler botões e tensões. Os sensores de verdade, porém, raramente são tão simples. Muitos têm um chip próprio e conversam com a placa por um protocolo: uma sequência combinada de pulsos, com tempos que precisam ser respeitados. Outros funcionam em 5 V, uma tensão que a ESP32 não suporta nos pinos. E quase todos têm limites de velocidade, alcance e precisão que o programa precisa conhecer.

Este artigo estuda três sensores clássicos de laboratório, cada um representando uma família: o DHT22, que manda temperatura e umidade prontas por um único fio; o HC-SR04, que mede distância cronometrando um eco; e o PIR HC-SR501, que detecta presença e entrega um sinal digital. No meio do caminho, o divisor de tensão aparece como a peça que separa uma montagem que funciona de uma ESP32 danificada.

DHT22: números prontos por um fio só

O DHT22 (também vendido como AM2302) mede a temperatura, de −40 a 80 °C com precisão de ±0,5 °C, e a umidade relativa do ar, de 0 a 100 %, com ±2 % típico (até ±5 % no pior caso), segundo a ficha da Aosong. Ele não é analógico: tem um pequeno chip que faz as medidas e envia os números para a ESP32 por um fio de dados.

O MicroPython da ESP32 já vem com o módulo dht no firmware, e o simulador usa o mesmo arquivo original da biblioteca oficial:

import dht
from machine import Pin
import time

sensor = dht.DHT22(Pin(4))

for i in range(5):
    sensor.measure()                 # conversa com o sensor
    t = sensor.temperature()         # °C
    u = sensor.humidity()            # % de umidade relativa
    print('%.1f °C  %.1f %%' % (t, u))
    time.sleep(2)                    # o DHT22 pede pelo menos 2 s entre leituras

Há uma divisão de tarefas que confunde muita gente: measure() é o único método que conversa com o sensor; temperature() e humidity() só devolvem o que chegou na última conversa. Esquecer o measure() dentro do laço faz o programa imprimir sempre o mesmo valor, mesmo com a sala esquentando.

A conversa no fio de dados

O protocolo do DHT22 é uma troca curta e cronometrada. A ESP32 segura a linha de dados em 0 por 18 ms — o "acorda!" — e depois solta. O sensor responde com 40 bits: 16 de umidade, 16 de temperatura e 8 de conferência (checksum), uma soma que permite detectar bits que chegaram errados. Cada bit é codificado pelo tempo em que a linha fica em nível alto: um pulso curto é 0, um pulso longo é 1. Somando a preparação, cada measure() leva cerca de 272 ms no simulador, e o programa fica parado durante esse tempo.

O resistor de pull-up e o ETIMEDOUT

Nessa linha de dados nenhum dos dois lados "empurra" o nível 1. A ESP32 e o sensor só sabem puxar para 0 ou soltar a linha — é uma saída de dreno aberto, o mesmo princípio que deixa vários aparelhos dividirem um fio sem curto. Quando os dois soltam, alguém precisa levar a linha para 1: é o resistor de pull-up, de 10 kΩ para o 3V3 no circuito do exemplo.

Sem pull-up, a ESP32 manda o "acorda!", solta a linha e não enxerga resposta nenhuma. O measure() desiste e a placa mostra:

OSError: [Errno 116] ETIMEDOUT

O 116 é o código de "tempo esgotado" da biblioteca C usada no firmware da ESP32 (em computadores com Linux e na antiga ESP8266, o mesmo erro aparece como 110 — por isso tutoriais antigos mostram outro número). O mesmo erro aparece com o sensor desligado, com o fio de dados solto ou no pino errado. Os módulos de DHT22 que vêm numa plaquinha já trazem o resistor; o sensor sozinho, de quatro pernas, não.

Um programa robusto trata esse erro em vez de travar:

import dht
from machine import Pin
import time

sensor = dht.DHT22(Pin(4))

for i in range(5):
    try:
        sensor.measure()
        print('temperatura: %.1f °C' % sensor.temperature())
    except OSError as e:
        print('o sensor não respondeu:', e)
    time.sleep(2)

Rode, depois apague o resistor de pull-up no simulador (selecione e Delete) e rode de novo: o except passa a pegar o erro a cada volta.

Dois segundos entre leituras

O fabricante pede pelo menos 2 s entre uma medida e outra do DHT22 (no DHT11, o irmão mais simples, 1 s). Ler mais rápido não dá erro garantido, mas o fabricante não garante o resultado — e o simulador mostra o aviso dht-rapido. O DHT11, aliás, é mais barato e mais limitado: mede de 0 a 50 °C com ±2 °C e de 20 a 90 % de umidade com ±5 %, e manda os valores em números inteiros.

DHT11DHT22 (AM2302)
Temperatura0 a 50 °C, ±2 °C−40 a 80 °C, ±0,5 °C
Umidade20 a 90 %, ±5 %0 a 100 %, ±2 % típico
Intervalo mínimo1 s2 s
No MicroPythondht.DHT11(pin)dht.DHT22(pin)

A troca de um pelo outro no código é uma palavra só, porque os dois usam o mesmo protocolo de um fio e a mesma biblioteca. O que muda é a interpretação dos bytes: o DHT22 manda os valores em décimos e com bit de sinal, para representar temperaturas negativas; o DHT11, em inteiros. Usar DHT11 com um DHT22 na bancada (ou o contrário) não dá erro — dá números absurdos, o que é pior. Confira o nome impresso no sensor antes de escolher a classe.

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

HC-SR04: medindo distância com um eco

O HC-SR04 mede distância como um morcego: emite um som agudo demais para o ouvido humano, o ultrassom, e espera o eco voltar de um obstáculo. Quanto mais longe o obstáculo, mais o eco demora. O módulo tem quatro pinos: VCC (5 V), TRIG, ECHO e GND.

A conversa é assim:

  1. a ESP32 manda um pulso de pelo menos 10 µs no TRIG;
  2. o módulo emite o ultrassom e coloca o ECHO em 1;
  3. quando o eco volta, o ECHO cai para 0.

O tempo em que o ECHO fica em 1 é o tempo de ida e volta do som. O som percorre cerca de 1 cm a cada 29 µs; ida e volta, 58 µs por centímetro. Daí a conta mais famosa da eletrônica de hobby:

distância (cm) = tempo do ECHO (µs) ÷ 58

Diagrama de tempo do HC-SR04: um pulso de 10 microssegundos no TRIG, o envio do ultrassom e o ECHO em nível alto durante o tempo de ida e volta do som, igual à distância em centímetros vezes 58 microssegundos. Exemplo: 20 cm dá 1160 microssegundos.
O HC-SR04 em três tempos: pulso no TRIG, ECHO em 1 durante a ida e volta do som e a conta distância = tempo ÷ 58.

Cronometrando o pulso com time_pulse_us

Medir quanto tempo um pino fica em 1 é tão comum que o MicroPython tem uma função para isso: machine.time_pulse_us(pino, nivel, timeout_us). Ela espera o pino chegar ao nivel, mede quanto tempo ele fica lá e devolve o valor em microssegundos. Se algo der errado, devolve um número negativo:

  • −2: o pulso nem começou dentro do timeout_us (sensor desligado, TRIG solto, fio errado);
  • −1: o pulso começou, mas não terminou a tempo (obstáculo longe demais).
from machine import Pin, time_pulse_us
import time

trig = Pin(25, Pin.OUT, value=0)
echo = Pin(18, Pin.IN)

def medir_cm():
    trig.value(1)
    time.sleep_us(10)            # pulso de 10 µs no TRIG
    trig.value(0)
    t = time_pulse_us(echo, 1, 30000)
    if t < 0:
        return None              # o eco não voltou a tempo
    return t // 58

for i in range(10):
    print(medir_cm())
    time.sleep_ms(500)

O módulo mede de 2 a 400 cm. Sem obstáculo no alcance, o ECHO fica em 1 por uns 38 ms. Por isso o timeout_us de 30 000 µs devolve −1 nesse caso, e a função transforma isso em None — o programa não fica preso esperando.

Captura de tela do PyPlaca com a lição do HC-SR04: o código com a função medir_cm no editor, o circuito com o sensor ultrassônico, o divisor de tensão no ECHO e o obstáculo, e o Serial mostrando as distâncias.
A lição do HC-SR04 no simulador: o obstáculo arrastável muda a distância e o Serial mostra a medida em centímetros.

Repare em Pin(25, Pin.OUT, value=0): o value=0 é aplicado antes de o pino virar saída, então o TRIG nunca passa por um instante em nível alto ao ser configurado. E por que o GPIO25, e não o GPIO5 de muitos tutoriais? O GPIO5 é um pino de strapping com pull-up de fábrica: ele nasce em 1 quando a placa liga. Ligado ao TRIG, no momento em que o programa o coloca em 0 o módulo enxerga uma descida e faz uma medida "fantasma". O simulador reproduz esse comportamento, igual ao da placa.

O ECHO tem 5 V: o divisor de tensão

O HC-SR04 é alimentado com 5 V, e o ECHO sai com 5 V quando está em 1. Os pinos da ESP32 trabalham com 3,3 V e aguentam no máximo 3,6 V. Ligar o ECHO direto num GPIO pode danificar a ESP32. O simulador mostra o aviso crítico cinco-volts-gpio quando isso acontece.

A solução clássica é baixar a tensão com um divisor de tensão: dois resistores em série entre o ECHO e o GND, com o GPIO ligado no meio.

V_meio = V_entrada × R2 / (R1 + R2)

Com R1 = 1 kΩ (entre o ECHO e o meio) e R2 = 2 kΩ (entre o meio e o GND):

V_meio = 5 × 2000 / (1000 + 2000) ≈ 3,33 V

Esquema do divisor de tensão no ECHO do HC-SR04: o ECHO de 5 volts passa por um resistor de 1 quilo-ohm até o ponto do meio, ligado ao GPIO18, e do ponto do meio um resistor de 2 quilo-ohms vai ao GND. O ponto do meio fica com cerca de 3,33 volts, abaixo do máximo de 3,6 volts e acima de 2,48 volts.
O divisor 1 kΩ / 2 kΩ leva o ECHO de 5 V para cerca de 3,33 V: seguro para o pino (máximo de 3,6 V) e acima do limiar de leitura do 1 (≈ 2,48 V).

Esse valor atende às duas exigências ao mesmo tempo: está abaixo dos 3,6 V que o pino suporta e acima dos cerca de 2,48 V que a ESP32 precisa para ler um 1 (três quartos de 3,3 V, como vimos no artigo sobre GPIO). Quando o ECHO está em 0, o meio fica em 0 V. O sinal chega inteiro, só que na tensão certa.

Três regras para escolher os resistores

  1. A razão R2 / (R1 + R2) define a tensão. Com 1 kΩ e 2 kΩ, dois terços;
  2. Trocar os dois de lugar muda tudo. Com 2 kΩ em cima e 1 kΩ embaixo sobra só um terço, cerca de 1,67 V, que não chega aos 2,48 V: o pino leria sempre 0 e o sensor pareceria quebrado;
  3. Valores muito altos deixam as bordas do sinal lentas; valores muito baixos gastam corrente à toa. A dupla 1 kΩ e 2 kΩ é a mais comum com o HC-SR04.

Conferindo a conta com o ADC

Dá para conferir a conta de um divisor com o ADC do artigo anterior. O circuito do exemplo abaixo monta justamente o divisor "trocado" (2 kΩ em cima, 1 kΩ embaixo), ligado aos 5 V do VIN, e mede o ponto do meio no GPIO34:

from machine import Pin, ADC

adc = ADC(Pin(34))
v = adc.read_uv() / 1_000_000
print('no meio do divisor: %.2f V' % v)
print('pela conta: %.2f V' % (5 * 1000 / (2000 + 1000)))

As duas linhas mostram praticamente o mesmo valor, perto de 1,67 V. E por que não medir o divisor certo, de 3,33 V? Porque, em 11 dB, o ADC da ESP32 satura perto de 3,13 V. O pino aguenta os 3,33 V; o conversor é que não consegue medi-los. É um bom exemplo de como "o pino suporta" e "o ADC mede" são coisas diferentes.

Existe também a variante HC-SR04P, que funciona em 3,3 V e dispensa o divisor. Na dúvida sobre qual módulo está na bancada, monte o divisor: ele funciona com as duas.

PIR HC-SR501: alguém passou?

O PIR HC-SR501 é o sensor das luzes automáticas de corredor. Ele percebe a radiação infravermelha do calor do corpo se movendo na frente da cúpula branca. Uma pessoa parada, ou uma parede quente, não dispara: o que ele detecta é a mudança.

São três pinos: VCC (5 V, no VIN), OUT e GND. Uma boa notícia: embora alimentado com 5 V, o OUT sai em 3,3 V — pode ir direto num GPIO, sem divisor. O comportamento do OUT é:

  • movimento detectado: OUT vai para 1 na hora;
  • o movimento parou: OUT continua em 1 pelo tempo de retenção e só então cai para 0;
  • novo movimento durante a retenção: o tempo recomeça.

O tempo de retenção é ajustado num pequeno potenciômetro do módulo (o trimpot). No circuito do exemplo ele está em 3 s, e no simulador você muda o valor no painel da peça.

Para o programa, então, "chegou alguém" é a borda de subida do OUT, e "tudo parado" é a borda de descida, uns segundos depois de a pessoa sair. Detectar bordas é o trabalho do Pin.irq:

from machine import Pin
import time

pir = Pin(27, Pin.IN)
led = Pin(2, Pin.OUT)

def mudou(pino):
    if pino.value():
        print('movimento!')
    else:
        print('tudo parado')
    led.value(pino.value())

pir.irq(mudou, Pin.IRQ_RISING | Pin.IRQ_FALLING)

while True:
    time.sleep(1)

Com IRQ_RISING | IRQ_FALLING, a função roda nas duas bordas e pino.value() diz qual foi. O LED azul da placa acompanha o sensor. No simulador, use o botão de passar a mão na frente do PIR; passe de novo antes de o OUT cair e veja o "tudo parado" demorar mais.

Um cuidado da placa real que o simulador não reproduz: depois de ligado, o PIR precisa de um tempo para "aquecer", e nesse começo pode disparar sozinho. Num projeto de verdade, espere um pouco antes de confiar nas primeiras leituras.

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

Três sensores, três lições

Cada sensor deste artigo ensina algo que vale para dezenas de outros:

  • o DHT22 mostra o padrão "sensor com chip e protocolo": uma biblioteca cuida dos tempos, o programa chama measure(), respeita o intervalo mínimo e trata o OSError quando a conversa falha;
  • o HC-SR04 mostra o padrão "medir tempo": o valor está na duração de um pulso, e time_pulse_us com um timeout_us bem escolhido evita que o programa trave;
  • o PIR mostra o padrão "evento": o que interessa é a mudança, e interrupções nas bordas são a ferramenta certa.

E os três juntos mostram a regra elétrica mais importante da ESP32: nenhum pino recebe mais de 3,6 V. Antes de ligar um sensor, confira a tensão da saída dele — e, se for 5 V, o divisor entra no circuito.

Erros comuns na bancada

Quase todos os problemas com esses três sensores caem numa destas situações:

  • ETIMEDOUT no DHT22: falta o pull-up na linha de dados, o sensor está sem alimentação ou o fio de dados está em outro pino. Confira os três antes de desconfiar do código;
  • o DHT22 devolve sempre o mesmo valor: o laço chama temperature() mas esqueceu o measure();
  • o HC-SR04 só devolve None: o obstáculo está fora do alcance, o TRIG está solto, o VCC está no 3V3 em vez do VIN, ou o divisor foi montado ao contrário e o pino nunca vê o 1;
  • o HC-SR04 mede uma vez a mais ao ligar: o TRIG está num pino de strapping que nasce em 1, como o GPIO5;
  • o PIR "dispara sozinho" logo ao ligar: é o aquecimento do sensor, que a placa real tem e o simulador pula;
  • o PIR demora para dizer "tudo parado": é o tempo de retenção do trimpot, não um atraso do programa.

O simulador ajuda em boa parte deles: a aba Avisos aponta o pull-up que falta, os 5 V num GPIO e o sensor sem alimentação, e a aba Pinos mostra o pulso do ECHO com a duração em microssegundos.

Juntando sensores sem travar

Um último aviso, que leva ao penúltimo artigo da série. Cada measure() do DHT22 leva uns 272 ms, e cada medida do HC-SR04 pode levar até o timeout_us. Se o programa também precisa piscar um LED, atualizar um display e atender um botão, essas esperas somadas começam a atrapalhar. Como organizar várias tarefas com tempos diferentes sem que uma trave as outras é o assunto de Programar sem travar.

Antes disso, o próximo artigo mostra como exibir as leituras numa tela: I2C com OLED e LCD. Na trilha de sensores, cada parte deste artigo vira uma lição com circuito pronto e desafios como o termômetro, a trena e o alarme de presença.

Para praticar no PyPlaca

Trilhas

Lições

Fichas de componentes

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

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