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 leiturasHá 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.
| DHT11 | DHT22 (AM2302) | |
|---|---|---|
| Temperatura | 0 a 50 °C, ±2 °C | −40 a 80 °C, ±0,5 °C |
| Umidade | 20 a 90 %, ±5 % | 0 a 100 %, ±2 % típico |
| Intervalo mínimo | 1 s | 2 s |
| No MicroPython | dht.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.
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
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:
- a ESP32 manda um pulso de pelo menos 10 µs no TRIG;
- o módulo emite o ultrassom e coloca o ECHO em 1;
- 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
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.

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
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
- A razão
R2 / (R1 + R2)define a tensão. Com 1 kΩ e 2 kΩ, dois terços; - 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;
- 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.
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
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 oOSErrorquando a conversa falha; - o HC-SR04 mostra o padrão "medir tempo": o valor está na duração de um pulso, e
time_pulse_uscom umtimeout_usbem 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:
ETIMEDOUTno 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 omeasure(); - 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
- DHT22: temperatura e umidade
- HC-SR04: medindo distância com som
- O ECHO tem 5 V: divisor de tensão
- PIR: alguém passou?