ESP32 deep sleep: fontes de despertar, consumo de corrente e autonomia da bateria
ESP32 deep sleep explicado: corrente em µA em cada modo de sono, despertar por timer, botão, PIR e toque (ext0/ext1), contadores na memória RTC e cálculo de autonomia com bateria 18650.
ESP32 deep sleep (sono profundo) é o modo de energia em que o ESP32 desliga as CPUs, o rádio Wi-Fi e Bluetooth e a memória principal, mantendo ativo apenas o pequeno domínio RTC. Nesse modo, o consumo do chip cai de 240 mA, durante a transmissão por Wi-Fi, para cerca de 10 µA, uma redução de vinte e quatro mil vezes. A placa acorda quando o tempo definido por você termina, quando um botão é pressionado, quando um sensor PIR detecta movimento ou quando um pino é tocado; ela faz o seu trabalho em poucos segundos e volta a dormir. É assim que estações meteorológicas a bateria, sensores de jardim, alarmes de porta e registradores remotos funcionam por meses, e não por dias, com uma única célula 18650.
Neste guia você vai conhecer os modos de sono do ESP32 e os valores reais de corrente, aprender a acordar a placa com um timer, um botão, um sensor PIR (ext0 e ext1) ou um toque, guardar contadores e leituras na memória RTC, que sobrevive ao sono, entender por que as placas de desenvolvimento ainda consomem miliampères dormindo e calcular, passo a passo, quantos meses uma única 18650 vai durar. Os sketches Arduino foram escritos para a versão 3.1 ou posterior do core ESP32 para Arduino e, no final, você verá como fazer o mesmo em MicroPython.

O que é o deep sleep do ESP32 e como ele funciona?
Existem dois mundos separados dentro do ESP32. O primeiro é o domínio principal, com as CPUs, 520 KB de RAM e o rádio Wi-Fi e Bluetooth. O segundo é o domínio RTC, que tem seu próprio timer pequeno, 8 KB de memória RTC FAST e 8 KB de RTC SLOW, os pinos RTC GPIO e um coprocessador de consumo ultrabaixo chamado ULP. Em deep sleep, o domínio principal fica totalmente desligado e só o domínio RTC continua funcionando. Na hora de acordar, o chip na verdade reinicia: o bootloader roda, o programa é carregado da flash outra vez e o setup() começa do início. Por isso, um programa com deep sleep faz todo o trabalho dentro do setup(), e o loop() nunca é executado. As variáveis normais são zeradas a cada despertar; só as variáveis que você coloca na memória RTC são preservadas.
Modos de sono do ESP32 e consumo de corrente (µA)
| Modo | O que continua funcionando? | Corrente (chip ESP32) |
|---|---|---|
| Ativo: transmissão Wi-Fi (802.11b, 19,5 dBm) | CPU e rádio | 240 mA |
| Ativo: recepção e escuta Wi-Fi | CPU e rádio | 95–100 mA |
| Modem sleep, 240 MHz | CPU funcionando, rádio desligado | 30–68 mA |
| Modem sleep, 80 MHz | CPU mais lenta, rádio desligado | 20–31 mA |
| Light sleep (sono leve) | CPU pausada, RAM preservada | 0,8 mA |
| Deep sleep com ULP ligado | Domínio RTC e coprocessador ULP | 150 µA |
| Deep sleep (sono profundo) | Timer RTC e memória RTC | 10 µA |
| Hibernação | Só o timer RTC e alguns pinos RTC | 5 µA |
| Desligado (pino EN em LOW) | Nada | 1 µA |
Esses valores vêm do datasheet do ESP32 da Espressif e se referem apenas ao chip. Dois pontos da tabela merecem atenção. Primeiro, no light sleep o programa continua da linha em que parou e tudo na RAM é mantido, mas o consumo é oitenta vezes maior que no deep sleep, por isso ele serve para pausas de poucos segundos. No deep sleep o programa recomeça, mas o consumo cai para microampères, o que o torna a escolha certa para esperas de minutos ou horas. Segundo, nenhum dos dois modos mantém a conexão Wi-Fi ou Bluetooth; é preciso reconectar a cada despertar. Os chips mais novos são um pouco diferentes: o ESP32-C3 consome cerca de 5 µA em deep sleep e o ESP32-S3, cerca de 7–8 µA.
Se quiser um consumo ainda menor, você também pode desligar os periféricos RTC e a memória RTC. Escreva esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF) e a mesma linha para ESP_PD_DOMAIN_RTC_SLOW_MEM e ESP_PD_DOMAIN_RTC_FAST_MEM, e o chip se aproxima do modo de hibernação, com cerca de 5 µA. Nesse caso, as variáveis da memória RTC são perdidas e só o timer ou o ext1 podem acordar a placa. Na maioria dos projetos, a diferença entre 10 µA e 5 µA é desprezível perto do resto da placa, então resolva primeiro os problemas da próxima seção.
Por que as placas de desenvolvimento consomem miliampères em deep sleep?
Quando você carrega o sketch e liga um multímetro, muitas vezes vê 5–15 mA em vez de 10 µA. O problema não é o chip, e sim os componentes extras da placa. A maioria das placas DevKit e NodeMCU-32S baratas usa um regulador AMS1117 para baixar 5 V para 3,3 V, e esse regulador sozinho costuma desperdiçar 5 mA mesmo sem carga. Some a isso o LED de alimentação sempre aceso e o chip USB-serial que conversa com o computador (CP2102 ou CH340). Juntos, eles costumam chegar a cerca de 8 mA e drenam aproximadamente 190 mAh por dia da bateria, mesmo com o ESP32 dormindo; assim, uma 18650 de 3000 mAh mal dura duas semanas com uma placa dessas. Para medir a corrente, coloque o multímetro em série entre a bateria e o circuito e mude para a escala de µA durante o sono; os detalhes estão no guia como usar o multímetro.
| Fonte de consumo | Corrente no sono | Solução |
|---|---|---|
| Módulo ESP32 (deep sleep) | ≈10 µA | Já é baixo, nada a fazer |
| Regulador AMS1117 | Tipicamente 5 mA (corrente quiescente) | Use um MCP1700 (1,6 µA de corrente quiescente) ou um HT7333 (cerca de 4 µA) |
| LED de alimentação | 1–3 mA | Retire o LED ou o resistor dele |
| Chip USB-serial (CP2102, CH340) | Depende da placa, pode chegar à faixa de mA | Use uma placa sem chip USB ou um módulo puro |
| Divisor da bateria de 100 kΩ + 100 kΩ | 21 µA (a 4,2 V) | Use 1 MΩ + 1 MΩ ou ligue o divisor com um MOSFET só durante a medição |
| Sensores sempre alimentados | De µA a mA, conforme o sensor | Alimente o sensor por um GPIO ou por um MOSFET só durante a medição |
Seu primeiro sketch de deep sleep: despertar por timer
- No Gerenciador de Placas do Arduino IDE, instale o pacote esp32 by Espressif Systems (versão 3.1 ou posterior) e selecione ESP32 Dev Module como placa.
- Carregue o sketch abaixo e abra o Monitor Serial em 115200 baud.
- A placa acorda a cada 10 segundos; observe a contagem de inicializações subir e o motivo do despertar aparecer como Timer.
- Pressione o botão EN: o contador volta para 1, porque isso é um reset normal, e não um despertar do deep sleep.
- No seu projeto real, defina TIME_TO_SLEEP como 600 (10 minutos) ou 3600 (1 hora).
1// ESP32 deep sleep: zamanlayıcıyla uyanma ve RTC sayaç / timer wake-up and RTC counter
2#define uS_TO_S_FACTOR 1000000ULL // 1 saniye = 1.000.000 µs / 1 second = 1,000,000 µs
3#define TIME_TO_SLEEP 10 // uyku süresi, saniye / sleep time in seconds
4
5RTC_DATA_ATTR int bootCount = 0; // RTC belleğinde, derin uykuda silinmez / in RTC memory, kept in deep sleep
6
7void printWakeupReason() {
8 esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
9 switch (cause) {
10 case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Zamanlayici / Timer"); break;
11 case ESP_SLEEP_WAKEUP_EXT0: Serial.println("ext0 (tek pin / single pin)"); break;
12 case ESP_SLEEP_WAKEUP_EXT1: Serial.println("ext1 (coklu pin / multiple pins)"); break;
13 case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Dokunmatik / Touch"); break;
14 default: Serial.printf("Ilk acilis ya da reset / Power-on or reset (%d)\n", (int)cause); break;
15 }
16}
17
18void setup() {
19 Serial.begin(115200);
20 delay(500); // Seri Monitör'e zaman tanı / give the Serial Monitor time
21 bootCount++;
22 Serial.printf("Uyanis sayisi / Boot count: %d\n", bootCount);
23 printWakeupReason();
24
25 // Burada sensörü oku, veriyi gönder / read the sensor and send the data here
26
27 esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); // 10 s sonra uyan / wake after 10 s
28 Serial.println("Derin uyku basliyor / Entering deep sleep");
29 Serial.flush(); // yazı bitmeden uyuma / finish printing before sleeping
30 esp_deep_sleep_start(); // buradan sonrası çalışmaz / nothing below runs
31}
32
33void loop() {
34 // Derin uykuda loop() hiç çalışmaz / loop() never runs with deep sleep
35}O coração do sketch são duas linhas: esp_sleep_enable_timer_wakeup() define o tempo de despertar em microssegundos, e esp_deep_sleep_start() manda o chip dormir na hora; nada do que você escrever depois dessa linha será executado. Não esqueça o sufixo ULL (64 bits) ao calcular o tempo: 3600 * 1000000 estoura um int de 32 bits, o compilador só dá um aviso e a placa acorda na hora errada ou nunca acorda. Serial.flush() espera o buffer de transmissão esvaziar; sem ele, as últimas linhas ficam cortadas. esp_sleep_get_wakeup_cause() informa por que a placa acordou e não retorna nenhuma fonte de sono após a primeira energização ou um reset. O timer RTC que conta o tempo de sono funciona, por padrão, com um oscilador RC interno de aproximadamente 150 kHz. Ele não é tão estável quanto um cristal e pode variar alguns por cento com a temperatura; por isso, em projetos em que o horário importa, é uma boa ideia sincronizar o horário com NTP quando a placa acordar.
Guardando contadores e leituras na memória RTC
Se você precisa lembrar de algo entre um despertar e outro, coloque RTC_DATA_ATTR antes da variável: o compilador a coloca na memória RTC SLOW de 8 KB, que continua alimentada no deep sleep, em vez da RAM principal. Ela é ideal para dados pequenos, como contadores, leituras recentes, informações do canal Wi-Fi ou a última temperatura enviada. Mas essa memória não é permanente: segundo a documentação da Espressif, os dados da memória RTC são reinicializados em qualquer reinício que não seja um despertar do deep sleep. Trocar a bateria, pressionar o EN, carregar um novo código ou chamar ESP.restart() zera o contador. Guarde na flash, com a biblioteca Preferences, as configurações que precisam sobreviver a uma queda de energia, mas não faça isso a cada despertar, porque a flash tem um número limitado de ciclos de gravação.
| Evento | Variável normal | RTC_DATA_ATTR | Preferences (flash) |
|---|---|---|---|
| Despertar do deep sleep | Zerada | Mantida | Mantida |
| Botão EN ou ESP.restart() | Zerada | Volta ao valor inicial | Mantida |
| Bateria removida, queda de energia | Zerada | Perdida | Mantida |
| Novo código carregado | Zerada | Perdida | Mantida (se a flash não for apagada) |
Usada com inteligência, essa memória pode multiplicar a autonomia da bateria. Conectar ao Wi-Fi é a parte mais cara de cada despertar. Por isso, o sketch abaixo mede a tensão da bateria a cada 10 minutos, mas liga o Wi-Fi só uma vez por hora: seis leituras se acumulam num array na memória RTC e, no sexto despertar, são enviadas todas de uma vez. Ele também salva na memória RTC o canal e o endereço MAC (BSSID) do ponto de acesso, para que na próxima conexão o ESP32 vá direto a esse ponto de acesso sem varrer todos os canais, o que encurta bastante o tempo de conexão.
1// RTC belleğinde ölçüm biriktirip saatte bir gönderme / buffer readings in RTC memory, send hourly
2#include <WiFi.h>
3
4const char* SSID = "AgAdi"; // Wi-Fi adı / Wi-Fi name
5const char* PASS = "Sifre123"; // Wi-Fi şifresi / Wi-Fi password
6const int BAT_PIN = 35; // 1M + 1M bölücünün orta noktası / divider midpoint
7const uint64_t SLEEP_US = 600ULL * 1000000ULL; // 10 dakika / 10 minutes
8const int BATCH = 6; // 6 ölçümde bir gönder / send every 6 readings
9
10RTC_DATA_ATTR float readings[BATCH]; // uykuda korunan ölçümler / readings kept in sleep
11RTC_DATA_ATTR int count = 0; // biriken ölçüm sayısı / number of stored readings
12RTC_DATA_ATTR int32_t savedChannel = 0; // son Wi-Fi kanalı / last Wi-Fi channel
13RTC_DATA_ATTR uint8_t savedBssid[6]; // modemin MAC adresi / access point MAC address
14
15bool connectFast() {
16 WiFi.mode(WIFI_STA);
17 if (savedChannel > 0) {
18 WiFi.begin(SSID, PASS, savedChannel, savedBssid); // taramadan bağlan / connect without scanning
19 } else {
20 WiFi.begin(SSID, PASS); // ilk sefer: normal bağlantı / first time: normal connect
21 }
22 unsigned long start = millis();
23 while (WiFi.status() != WL_CONNECTED) {
24 if (millis() - start > 10000) { // 10 s içinde bağlanamazsa vazgeç / give up after 10 s
25 savedChannel = 0; // bir dahaki sefere tara / scan next time
26 return false;
27 }
28 delay(50);
29 }
30 savedChannel = WiFi.channel();
31 memcpy(savedBssid, WiFi.BSSID(), 6);
32 return true;
33}
34
35void setup() {
36 Serial.begin(115200);
37 // Pili Wi-Fi açılmadan önce ölç / measure the battery before Wi-Fi starts
38 float v = analogReadMilliVolts(BAT_PIN) * 2 / 1000.0; // bölücü gerilimi yarıya indirir / divider halves it
39 readings[count++] = v;
40 Serial.printf("Olcum / Reading %d: %.2f V\n", count, v);
41
42 if (count >= BATCH) {
43 if (connectFast()) {
44 for (int i = 0; i < BATCH; i++) {
45 Serial.printf("Gonder / Send: %.2f V\n", readings[i]); // burada HTTP ya da MQTT / HTTP or MQTT here
46 }
47 count = 0;
48 } else {
49 for (int i = 1; i < BATCH; i++) readings[i - 1] = readings[i]; // en eskiyi at / drop the oldest
50 count = BATCH - 1;
51 }
52 WiFi.disconnect(true);
53 WiFi.mode(WIFI_OFF); // radyoyu kapat / turn the radio off
54 }
55
56 Serial.flush();
57 esp_sleep_enable_timer_wakeup(SLEEP_US);
58 esp_deep_sleep_start();
59}
60
61void loop() {
62}A tensão da bateria é reduzida à metade por um divisor de tensão de 1 MΩ + 1 MΩ e lida no GPIO 35, um canal do ADC1. Um capacitor de 100 nF entre o ponto médio do divisor e o GND mantém a leitura estável mesmo com um divisor de impedância tão alta. Medir antes de ligar o Wi-Fi também é importante, porque a corrente consumida com o rádio funcionando faz a tensão da bateria cair por um instante. Se o Wi-Fi não conectar, a leitura mais antiga é descartada e as demais ficam guardadas para a próxima tentativa. Desligar o rádio corretamente com WiFi.disconnect(true) e WiFi.mode(WIFI_OFF) antes de dormir também é o que a Espressif recomenda. Para acelerar ainda mais a conexão, dê à placa um IP estático com WiFi.config() e pule a espera do DHCP. Você encontra o cálculo do divisor no guia divisor de tensão e o circuito de carga no guia módulo carregador TP4056.
Acordando com um botão ou um sensor PIR: ext0 e ext1
Além do timer, um sinal do mundo externo também pode acordar o ESP32. Há duas formas de fazer isso, e ambas só funcionam nos pinos RTC GPIO: 0, 2, 4, 12–15, 25–27 e 32–39. O ext0 monitora um único pino e acorda a placa quando esse pino atinge o nível escolhido (HIGH ou LOW); como ele mantém os periféricos RTC alimentados, os resistores internos de pull-up e pull-down continuam funcionando durante o sono. O ext1 monitora vários pinos ao mesmo tempo por meio de uma máscara de bits. No ESP32 clássico, o ext1 tem dois modos: ESP_EXT1_WAKEUP_ANY_HIGH acorda a placa quando qualquer um dos pinos selecionados vai para HIGH, e ESP_EXT1_WAKEUP_ALL_LOW acorda quando todos estão em LOW ao mesmo tempo. O modo ANY_LOW, que acorda quando qualquer pino vai para LOW, só existe no ESP32-S2, S3, C6 e H2. Então, se você quer que vários botões acordem um ESP32 clássico, ligue os botões ao 3V3 e coloque em cada pino um resistor de pull-down de 10 kΩ. Você também pode ativar várias fontes ao mesmo tempo; com o PIR e um timer de uma hora ativados, por exemplo, a placa acorda com o que vier primeiro.
| Fonte de despertar | Função | Pinos | Observação |
|---|---|---|---|
| Timer | esp_sleep_enable_timer_wakeup() (timer) | Não precisa de pino | Tempo em microssegundos, 64 bits |
| ext0 | esp_sleep_enable_ext0_wakeup() (um pino) | Um RTC GPIO | Acorda em HIGH ou LOW; não pode ser combinado com toque ou ULP |
| ext1 | esp_sleep_enable_ext1_wakeup_io() (vários pinos) | Vários RTC GPIOs | ANY_HIGH ou ALL_LOW; recomenda-se usar resistores externos |
| Toque | touchSleepWakeUpEnable() (toque) | T0–T9 (10 pinos) | Acorda quando o valor cai abaixo do limite; não pode ser combinado com ext0 |
| Coprocessador ULP | esp_sleep_enable_ulp_wakeup() (ULP) | Depende do programa | Pode ler sensores durante o sono; avançado |
Ligações do circuito de exemplo
| Componente | Pino do componente | Pino do ESP32 | Observação |
|---|---|---|---|
| Sensor PIR (HC-SR501 ou AM312) | OUT | GPIO 33 | Acorda a placa pelo ext0 |
| Sensor PIR | VCC / GND | 5V (HC-SR501) ou 3V3 (AM312) / GND | O HC-SR501 precisa de pelo menos 4,5 V |
| Botão A | Um terminal / outro terminal | 3V3 / GPIO 25 | Pull-down de 10 kΩ entre o GPIO 25 e o GND |
| Botão B | Um terminal / outro terminal | 3V3 / GPIO 26 | Pull-down de 10 kΩ entre o GPIO 26 e o GND |
| Superfície de toque ou fio | – | GPIO 27 (T7) | Funciona de forma mais confiável se for curto |
| LED + 220 Ω | Ânodo | GPIO 2 | Na maioria das DevKits, o LED azul integrado também fica neste pino |
| Divisor da bateria (1 MΩ + 1 MΩ) | Ponto médio | GPIO 35 | 100 nF entre o ponto médio e o GND |
| 18650 + TP4056 + LDO de 3,3 V | Saída do LDO / GND | 3V3 / GND | Capacitor de 470 µF na saída do LDO |
Sketch de despertar com sensor PIR (ext0)
1// PIR ile uyanma (ext0) / wake on PIR motion (ext0)
2#include "driver/rtc_io.h"
3
4const gpio_num_t PIR_PIN = GPIO_NUM_33; // RTC GPIO olmalı / must be an RTC GPIO
5const int LED_PIN = 2; // uyarı LED'i / alert LED
6
7RTC_DATA_ATTR int motionCount = 0; // toplam hareket sayısı / total motion count
8
9void setup() {
10 Serial.begin(115200);
11 rtc_gpio_deinit(PIR_PIN); // pini yeniden normal GPIO yap / turn the pad back into a normal GPIO
12 pinMode(PIR_PIN, INPUT);
13 pinMode(LED_PIN, OUTPUT);
14
15 if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT0) {
16 motionCount++;
17 Serial.printf("Hareket! / Motion! Toplam / Total: %d\n", motionCount);
18 digitalWrite(LED_PIN, HIGH); // burada bildirim gönderebilirsin / send a notification here
19 delay(1000);
20 digitalWrite(LED_PIN, LOW);
21 }
22
23 // PIR çıkışı LOW olana kadar bekle, yoksa hemen yeniden uyanır / wait for LOW or it wakes again at once
24 while (digitalRead(PIR_PIN) == HIGH) {
25 delay(100);
26 }
27
28 esp_sleep_enable_ext0_wakeup(PIR_PIN, 1); // pin HIGH olunca uyan / wake when the pin goes HIGH
29 rtc_gpio_pullup_dis(PIR_PIN);
30 rtc_gpio_pulldown_en(PIR_PIN); // boştayken LOW tut / keep it LOW while idle
31 Serial.println("Uyku / Sleep");
32 Serial.flush();
33 esp_deep_sleep_start();
34}
35
36void loop() {
37}Ao acordar, o sketch primeiro devolve o pino ao modo GPIO normal com rtc_gpio_deinit(). Depois de um despertar pelo ext0, o pino continua em modo RTC e, sem essa linha, o digitalRead() pode não funcionar direito. Ele conta o movimento, pisca o LED e depois espera a saída do PIR voltar para LOW. Essa espera é essencial: se você for dormir com a saída ainda em HIGH, a placa acorda na hora e entra num loop que liga e desliga várias vezes por segundo. O HC-SR501 mantém a saída em HIGH pelo tempo ajustado no potenciômetro dele, então gire o potenciômetro de tempo para o mínimo para encurtar a espera. Como o HC-SR501 precisa de pelo menos 4,5 V, prefira o pequeno módulo PIR AM312, que também funciona com 3,3 V, em projetos alimentados por uma única 18650. Para os ajustes do sensor, veja o guia sensor de movimento PIR.
Sketch de despertar com dois botões (ext1)
1// İki butonla uyanma (ext1) / wake with two buttons (ext1)
2#include "driver/rtc_io.h"
3
4const gpio_num_t BTN_A = GPIO_NUM_25; // buton A: 3V3'e, 10k pull-down / button A: to 3V3, 10k pull-down
5const gpio_num_t BTN_B = GPIO_NUM_26; // buton B: 3V3'e, 10k pull-down / button B: to 3V3, 10k pull-down
6const uint64_t WAKE_MASK = (1ULL << BTN_A) | (1ULL << BTN_B);
7
8void setup() {
9 Serial.begin(115200);
10 rtc_gpio_deinit(BTN_A); // pinleri normal GPIO'ya döndür / back to normal GPIO
11 rtc_gpio_deinit(BTN_B);
12 pinMode(BTN_A, INPUT);
13 pinMode(BTN_B, INPUT);
14
15 if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT1) {
16 uint64_t pins = esp_sleep_get_ext1_wakeup_status(); // hangi pin uyandırdı? / which pin woke us?
17 if (pins & (1ULL << BTN_A)) Serial.println("Buton A: isigi ac / Button A: lights on");
18 if (pins & (1ULL << BTN_B)) Serial.println("Buton B: isigi kapat / Button B: lights off");
19 } else {
20 Serial.println("Ilk acilis / First boot");
21 }
22
23 while (digitalRead(BTN_A) == HIGH || digitalRead(BTN_B) == HIGH) {
24 delay(10); // butonlar bırakılana kadar bekle / wait until released
25 }
26
27 esp_sleep_enable_ext1_wakeup_io(WAKE_MASK, ESP_EXT1_WAKEUP_ANY_HIGH); // biri HIGH olunca / any goes HIGH
28 Serial.flush();
29 esp_deep_sleep_start();
30}
31
32void loop() {
33}Depois de um despertar pelo ext1, esp_sleep_get_ext1_wakeup_status() retorna uma máscara de bits que mostra qual pino acordou a placa. Assim, você pode dar funções diferentes aos dois botões: um liga a luz e o outro desliga, ou um envia uma leitura e o outro abre um menu. Como os botões estão ligados ao 3V3 e os pinos são puxados para o GND com 10 kΩ, eles leem LOW quando soltos e HIGH quando pressionados, exatamente o que o modo ANY_HIGH espera. O sketch espera os botões serem soltos antes de dormir; caso contrário, um botão ainda pressionado acordaria a placa de novo imediatamente. Se você usa o core ESP32 para Arduino 2.x ou 3.0.x, que não tem a função _io, escreva esp_sleep_enable_ext1_wakeup com os mesmos parâmetros no lugar de esp_sleep_enable_ext1_wakeup_io. Você descobre por que o resistor de pull-down é necessário no guia como ligar um botão no Arduino.
Acordando com um toque (touch wake-up)
Dez pinos do ESP32 (T0–T9) funcionam como sensores capacitivos de toque e conseguem detectar o seu dedo mesmo em deep sleep. Um fio, uma tira de fita de cobre ou uma ilha de PCB ligada ao pino se comporta como um botão e pode até ficar atrás de uma tampa fina de plástico ou madeira. No ESP32 clássico, o valor de touchRead() cai quando há toque: com um fio curto, ele costuma ler 60–80 sem toque e 10–20 com toque. Coloque o limite de despertar entre esses dois valores; o 40 do exemplo é um bom ponto de partida. No ESP32 clássico, você pode usar vários pinos de toque como fontes de despertar ao mesmo tempo. Já no ESP32-S2 e no S3, só um pino pode acordar o chip, o valor sobe quando há toque e o limite usa uma escala totalmente diferente (5000 no exemplo da Espressif). O despertar por toque não pode ser combinado com o ext0; se você também precisa de um botão, use o ext1. Para a lista de pinos e a calibração, leia o guia pinos de toque do ESP32.
1// Dokunarak uyandırma: T7 = GPIO 27 / touch wake-up: T7 = GPIO 27
2#define THRESHOLD 40 // değer bunun altına inince uyanır / wakes when the value drops below this
3
4RTC_DATA_ATTR int touchWakes = 0;
5
6void setup() {
7 Serial.begin(115200);
8 delay(500);
9 if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_TOUCHPAD) {
10 touchWakes++;
11 Serial.printf("Dokunusla uyanma / Touch wake #%d\n", touchWakes);
12 }
13 // Eşiği ayarlamak için dokunmadan ve dokunarak değeri izle / watch the value untouched and touched
14 Serial.printf("T7 degeri / value: %d\n", (int)touchRead(T7));
15
16 touchSleepWakeUpEnable(T7, THRESHOLD); // dokunmatikle uyanmayı aç / enable touch wake-up
17 Serial.flush();
18 esp_deep_sleep_start();
19}
20
21void loop() {
22}Deep sleep do ESP32 com MicroPython
Se você programa o ESP32 em MicroPython, dá para fazer o mesmo com um código mais curto. machine.deepsleep(ms) coloca a placa para dormir pelo número de milissegundos indicado, esp32.wake_on_ext0() transforma um pino em fonte de despertar e machine.RTC().memory() oferece um buffer de bytes que sobrevive ao sono; no ESP32 ele tem 2048 bytes por padrão. Ao acordar, o main.py roda do início; machine.reset_cause() informa se a placa saiu do deep sleep e machine.wake_reason() informa o que a acordou. Pinos RTC configurados com pull-up ou pull-down mantêm essa configuração durante o sono. Se você é novo no MicroPython, comece pelo guia fundamentos do MicroPython.
1import machine, esp32, time
2from machine import Pin
3
4rtc = machine.RTC()
5led = Pin(2, Pin.OUT)
6
7mem = rtc.memory() # RTC belleğini oku / read RTC memory
8count = int.from_bytes(mem, "little") if mem else 0
9
10if machine.reset_cause() == machine.DEEPSLEEP_RESET:
11 count += 1
12 if machine.wake_reason() == machine.EXT0_WAKE:
13 print("Butonla uyandi / Woken by button")
14 else:
15 print("Zamanlayiciyla uyandi / Woken by timer")
16else:
17 count = 0
18 print("Ilk acilis / First boot")
19
20rtc.memory(count.to_bytes(4, "little")) # sayacı sakla / store the counter
21print("Uyanis / Wake:", count)
22
23led.on() # kısa iş: ölç ve gönder / short task: measure and send
24time.sleep_ms(200)
25led.off()
26
27button = Pin(33, Pin.IN, Pin.PULL_DOWN) # buton GPIO 33 ile 3V3 arasında / button between GPIO 33 and 3V3
28esp32.wake_on_ext0(button, esp32.WAKEUP_ANY_HIGH) # basınca uyan / wake on press
29machine.deepsleep(60000) # 60 s uyu / sleep for 60 sO Raspberry Pi Pico, por outro lado, não tem um deep sleep na faixa dos microampères como o ESP32. No MicroPython, machine.lightsleep(ms) para a maioria dos clocks, pausa a CPU e mantém a RAM, enquanto machine.deepsleep(ms) reinicia a placa depois do mesmo tipo de sono. Mesmo nesses modos, o consumo da placa continua na faixa dos miliampères. Por isso, se você quer montar com o Pico um dispositivo que funcione meses com bateria, cortar totalmente a alimentação da placa entre as medições com um temporizador de energia como o TPL5110 dá resultados melhores. Para o básico do Pico, veja o guia o que é o Raspberry Pi Pico.
Um sensor que funciona meses com uma 18650: cálculo da autonomia da bateria
Para descobrir a autonomia de um dispositivo que dorme e acorda, primeiro você calcula a corrente média: Corrente média = (Corrente acordado × Tempo acordado + Corrente no sono × Tempo de sono) / Tempo total. Depois, divide a capacidade útil da bateria por essa média. Não dá para usar toda a capacidade de uma 18650 com 3000 mAh no rótulo; considerar cerca de 85%, ou 2550 mAh, por causa do corte por baixa tensão, das perdas do regulador e do envelhecimento é realista. A tabela abaixo foi calculada para um sensor que acorda a cada 10 minutos, envia dados por Wi-Fi e consome em média 120 mA enquanto está conectado.
| Cenário | Corrente no sono | Tempo acordado | Corrente média | Autonomia estimada |
|---|---|---|---|---|
| Placa DevKit | 8 mA | 3 s, 120 mA | 8,56 mA | ≈12 dias |
| Placa DevKit, conexão rápida | 8 mA | 1 s, 120 mA | 8,19 mA | ≈13 dias |
| Módulo puro + MCP1700 + divisor de 1 MΩ | 15 µA | 3 s, 120 mA | 0,61 mA | ≈173 dias (5,7 meses) |
| Módulo puro, conexão rápida | 15 µA | 1 s, 120 mA | 0,215 mA | ≈494 dias (16 meses) |
| Módulo puro, envio em lote a cada hora | 15 µA | 1 s de Wi-Fi por hora (120 mA) + 5 × 0,3 s de leituras (40 mA) | 0,065 mA | ≈4,5 anos em teoria |
A conclusão é clara: numa placa de desenvolvimento, encurtar o tempo acordado quase não muda nada, porque o que realmente esgota a bateria são os 8 mA no sono. Quando a corrente de sono cai para microampères, a balança se inverte e cada segundo acordado conta: reduzir a conexão Wi-Fi de 3 segundos para 1 quase triplica a autonomia. Quando a corrente média fica abaixo de 0,1 mA, a autodescarga da bateria passa a pesar. Uma célula de Li-ion perde cerca de 2–3% da capacidade por mês, então os 4,5 anos teóricos encolhem para cerca de 2 anos na prática. Para fazer as contas com os seus valores, use a calculadora Autonomia da bateria e leia sobre mAh e Wh no guia o que significa mAh.
- Escolha a placa certa: placas sem chip USB e sem LED de alimentação, ou um módulo ESP32 puro, consomem microampères no sono.
- Troque o regulador: use um LDO com corrente quiescente de poucos microampères no lugar do AMS1117.
- Alimente o sensor só durante a medição: alimente sensores que consomem poucos mA direto de um GPIO e cargas maiores por um MOSFET de canal P; coloque um resistor de pull-up no gate do MOSFET para que ele fique desligado durante o sono. Os detalhes estão no guia MOSFET com Arduino.
- Ligue o Wi-Fi raramente: acumule as leituras na memória RTC e envie em lotes; se você vai mandar dados para outro ESP32 por perto, o ESP-NOW transmite em bem menos tempo, porque não precisa se conectar a um ponto de acesso.
- Acelere a conexão: com IP estático e canal e BSSID salvos, a conexão Wi-Fi muitas vezes leva menos de um segundo.
- Elimine esperas desnecessárias: apague a saída para o Monitor Serial e as linhas longas de delay() do projeto pronto; cada milissegundo acordado sai da bateria.
- Não esqueça o divisor e os LEDs: um divisor de 100 kΩ + 100 kΩ ligado o tempo todo consome o dobro da corrente do ESP32 dormindo.
Ideias de projetos com deep sleep do ESP32
- Estação meteorológica a bateria: meça temperatura, umidade e pressão com um BME280 a cada 10 minutos e envie uma vez por hora para o Home Assistant via MQTT.
- Sensor de umidade para o jardim: acorde uma vez por hora, meça a umidade do solo e mande uma mensagem para o seu celular quando o solo ficar seco.
- Alarme de porta e janela: quando a porta abre, uma chave reed acorda o ESP32 pelo ext0 e um bot do Telegram manda uma mensagem para você.
- Sensor de segurança a bateria: monte um dispositivo que acorda e envia um alerta quando o PIR detecta movimento e dorme por meses no resto do tempo.
- Campainha por toque: cole fita de cobre atrás de um painel de madeira; um toque acorda o ESP32, que avisa a campainha dentro de casa via ESP-NOW.
- Registrador de temperatura a bateria: meça a temperatura de uma geladeira ou de um aquário com um DS18B20 à prova d'água, acumule os valores na memória RTC e envie algumas vezes por dia.
Erros comuns e como resolvê-los
| Sintoma | Causa | Solução |
|---|---|---|
| A placa acorda logo depois de ir dormir | O pino de despertar ainda está ativo (PIR em HIGH, botão pressionado) ou flutuando | Espere o pino voltar ao nível de repouso antes de dormir e adicione um resistor de pull-down ou pull-up |
| A placa não acorda no tempo esperado | Estouro de 32 bits no cálculo do tempo (3600 * 1000000) | Adicione ULL às constantes: 3600ULL * 1000000ULL |
| O contador sempre começa do 1 | A variável não é RTC_DATA_ATTR ou a placa foi resetada | Adicione RTC_DATA_ATTR; use Preferences para dados permanentes |
| 5–15 mA medidos no sono | Regulador, LED de alimentação, chip USB, divisor ou sensores | Placa de baixo consumo ou módulo puro, LDO com baixa corrente quiescente |
| As últimas linhas no Monitor Serial ficam cortadas | A placa foi dormir antes de o buffer esvaziar | Chame Serial.flush() antes de esp_deep_sleep_start() |
| digitalRead() dá valores errados depois de acordar | O pino de despertar ainda está em modo RTC | Chame rtc_gpio_deinit() antes de usar o pino |
| Um botão no GPIO 34–39 não acorda a placa | Esses pinos não têm resistores internos de pull, então o pino fica flutuando | Adicione um resistor externo de 10 kΩ |
| O código não carrega enquanto a placa dorme | A placa não tem circuito de auto-reset; no S3 e no C3, a porta USB nativa some durante o sono | Segure o BOOT, pressione e solte o EN (RESET) e depois inicie o carregamento |
| Um relé ou LED muda de estado quando a placa vai dormir | Os pinos digitais ficam flutuando (alta impedância) em deep sleep | Use um resistor de pull ou mantenha o nível do pino com rtc_gpio_hold_en() |
O deep sleep do ESP32 é a chave para fazer o mesmo código funcionar meses, e não dias, com bateria: mantenha o trabalho curto, escolha a fonte de despertar certa, guarde na memória RTC os pequenos dados necessários entre um despertar e outro e nunca esqueça o consumo da própria placa. Se quiser voltar ao básico do ESP32, o guia o que é o ESP32 é um bom começo. No app BlueGrays, o projeto ESP32 Deep Sleep — Economia de bateria (OLED + contador na RTC RAM) permite testar a lógica do timer e do contador RTC deste artigo num circuito com display OLED, com esquema do circuito passo a passo e código pronto.
Perguntas frequentes
Quanta corrente o ESP32 consome em deep sleep?
Segundo o datasheet da Espressif, o chip ESP32 consome cerca de 10 µA em deep sleep com o timer RTC e a memória RTC ligados, e 5 µA no modo de hibernação. Em placas de desenvolvimento como a DevKit, porém, o regulador, o LED de alimentação e o chip USB-serial costumam elevar a corrente de sono para 5–15 mA.
Como acordar um ESP32 do deep sleep?
Há cinco formas: o timer RTC, um único pino RTC (ext0), vários pinos RTC (ext1), os pinos de toque e o coprocessador ULP. Você configura a fonte de despertar antes de chamar esp_deep_sleep_start() e pode ativar várias ao mesmo tempo; só o ext0 e o despertar por toque não podem ser usados juntos.
As variáveis são perdidas no deep sleep do ESP32?
Sim, as variáveis normais são perdidas, porque acordar do deep sleep é um reinício e o setup() roda desde o começo. As variáveis marcadas com RTC_DATA_ATTR ficam na memória RTC e são mantidas entre os despertares, mas voltam aos valores iniciais depois de uma queda de energia, de um toque no botão EN ou de um novo carregamento.
Quanto tempo um ESP32 funciona com uma bateria 18650?
De um dia a mais de um ano, dependendo da placa e de como você a usa. Uma DevKit sempre conectada ao Wi-Fi dura só 1–2 dias com uma 18650 de 3000 mAh, e uma DevKit que acorda a cada 10 minutos dura cerca de 12 dias. Um circuito de baixo consumo fazendo o mesmo trabalho com corrente de sono de 15 µA funciona de 5 a 16 meses, dependendo de quanto tempo leva cada conexão.
Qual é a diferença entre light sleep e deep sleep no ESP32?
No light sleep a CPU fica pausada, mas a RAM é mantida; quando a placa acorda, o programa continua da linha em que parou, e o chip consome cerca de 0,8 mA. No deep sleep a RAM também é desligada e o consumo cai para 10 µA, mas o programa recomeça a cada despertar. O light sleep serve para pausas de poucos segundos; o deep sleep, para esperas de minutos ou horas.
Como carregar código num ESP32 em deep sleep?
Em placas com circuito de auto-reset, o carregamento costuma começar sem problemas, porque o carregador reinicia o chip pelo pino EN. Se não começar, segure o botão BOOT, pressione e solte o EN (RESET) e depois inicie o carregamento. Em placas com USB nativo, como o ESP32-S3 e o C3, a porta some durante o sono, então esse método muitas vezes é obrigatório.
Projetos para montar depois desta leitura
Ver todos os projetos
LED piscando com ESP32
Ensina o uso básico de uma saída GPIO no ESP32. Fazemos um LED piscar ligando e desligando um pino digital. É a versão para ESP32 do clássico projeto blink do Arduino UNO: os comandos básicos de blink no ambiente Arduino são os mesmos, mas a disposição dos pinos e os níveis de 3,3 V dos GPIOs do ESP32 diferem dos do Arduino UNO.

Controle de LED com botão no ESP32 (momentâneo)
O LED acende enquanto o botão está pressionado e apaga ao soltá-lo. Mostra como usar o pino de entrada digital e o resistor pull-up interno do ESP32. O modo INPUT_PULLUP dispensa um resistor externo.

ESP32 em sono profundo — Economia de bateria (OLED + contador na RAM RTC)
O modo de sono profundo do ESP32 reduz o consumo de corrente para ~10 µA ao desligar a CPU e a maioria dos periféricos, sendo essencial para dispositivos IoT alimentados por bateria. Neste projeto, usamos três fontes de despertar: um temporizador (15 segundos), um pino externo (EXT0 — botão no GPIO 33) e toque (T0/GPIO 4). As variáveis marcadas com RTC_DATA_ATTR são preservadas durante o sono profundo, mantendo os contadores de inicializações e de despertares por temporizador e botão.

Alarme de movimento com ESP32 (PIR + buzzer + LED + Telegram)
Um sistema de alarme de segurança inteligente que aciona o buzzer e o LED quando o sensor PIR detecta movimento e, ao mesmo tempo, envia uma notificação instantânea ao proprietário pelo Telegram. Inclui um intervalo de espera de 30 segundos para limitar a frequência dos alarmes repetidos; esse mecanismo não valida as detecções do PIR nem elimina disparos falsos. Pode ser usado na segurança de casas, no monitoramento de garagens, depósitos ou salas de trabalho.

Iluminação automática com ESP32 e sensor de movimento PIR
Neste projeto, usaremos o sensor de movimento PIR HC-SR501 para detectar quando alguém entra no cômodo e acender o LED automaticamente. Acompanharemos o tempo em que o LED fica aceso com millis(). Cada leitura HIGH do sensor atualizará o instante do último movimento, e o LED apagará pelo menos 10 segundos após a última leitura HIGH. O código atual também espera 50 ms em cada ciclo com delay(50), portanto o laço da aplicação não é totalmente livre de bloqueios.

Temperatura e umidade com ESP32 e DHT22 (com display LCD)
Este projeto mede a temperatura e a umidade do ambiente com um sensor DHT22 e exibe os dados em tempo real em um LCD I2C 16x2. Os dados são lidos do sensor pelo protocolo de um fio (one-wire) com a biblioteca Adafruit DHT. Este projeto serve de base para estações meteorológicas IoT, automação residencial ou sistemas de monitoramento ambiental em estufas. A comunicação com o DHT22 é feita pelo pino GPIO 4 do ESP32.

Registrador de temperatura com ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
Monte um registrador de temperatura com data e hora usando ESP32! Leia a temperatura e a umidade do DHT22 a cada minuto, obtenha a hora real do DS1307 RTC e grave os dados em CSV no cartão microSD. O OLED exibe a temperatura atual em letras grandes, a porcentagem de umidade, a data e a hora e o contador de registros. O arquivo /temp_log.csv no cartão SD pode ser aberto no Excel, Google Sheets ou pandas do Python para análise — ideal para monitorar estufas, acompanhar a temperatura de casa ou…
Mais artigos
App BlueGrays
Monte este circuito passo a passo pelo celular
Esquema do circuito, código e lista de componentes em uma só tela. Mais de 200 projetos com Arduino, ESP32 e Pico prontos para montar.
Escaneie com seu celular
Aponte a câmera para o código para abrir a loja de aplicativos do seu celular.
ou abrir a loja

