Guias · 17 min de leitura

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.

Placa de desenvolvimento ESP32 (DevKit)
Placa de desenvolvimento ESP32: o módulo com blindagem metálica consome cerca de 10 µA em deep sleep, enquanto o regulador, o LED de alimentação e o chip USB-serial da placa elevam esse valor para a faixa dos miliampères.

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)

ModoO que continua funcionando?Corrente (chip ESP32)
Ativo: transmissão Wi-Fi (802.11b, 19,5 dBm)CPU e rádio240 mA
Ativo: recepção e escuta Wi-FiCPU e rádio95–100 mA
Modem sleep, 240 MHzCPU funcionando, rádio desligado30–68 mA
Modem sleep, 80 MHzCPU mais lenta, rádio desligado20–31 mA
Light sleep (sono leve)CPU pausada, RAM preservada0,8 mA
Deep sleep com ULP ligadoDomínio RTC e coprocessador ULP150 µA
Deep sleep (sono profundo)Timer RTC e memória RTC10 µA
HibernaçãoSó o timer RTC e alguns pinos RTC5 µA
Desligado (pino EN em LOW)Nada1 µ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 consumoCorrente no sonoSolução
Módulo ESP32 (deep sleep)≈10 µAJá é baixo, nada a fazer
Regulador AMS1117Tipicamente 5 mA (corrente quiescente)Use um MCP1700 (1,6 µA de corrente quiescente) ou um HT7333 (cerca de 4 µA)
LED de alimentação1–3 mARetire o LED ou o resistor dele
Chip USB-serial (CP2102, CH340)Depende da placa, pode chegar à faixa de mAUse 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 alimentadosDe µA a mA, conforme o sensorAlimente o sensor por um GPIO ou por um MOSFET só durante a medição
Nunca ligue uma célula de Li-ion, como uma 18650, direto no pino 3V3: uma célula de Li-ion cheia fica em 4,2 V, enquanto o ESP32 aceita no máximo 3,6 V. Ligar a bateria no pino VIN também não é uma boa solução, porque o AMS1117 derruba cerca de 1 V e sua saída cai abaixo de 3 V quando a célula está pela metade. O certo é alimentar o pino 3V3 por um LDO de 3,3 V com baixa corrente quiescente e baixo dropout. LDOs pequenos como o MCP1700 e o HT7333 fornecem só 250 mA, então coloque pelo menos 470 µF na saída para cobrir os picos de corrente do Wi-Fi. As células LiFePO4, que não passam de 3,6 V nem quando cheias, podem ser ligadas direto no 3V3, sem regulador.

Seu primeiro sketch de deep sleep: despertar por timer

  1. 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.
  2. Carregue o sketch abaixo e abra o Monitor Serial em 115200 baud.
  3. A placa acorda a cada 10 segundos; observe a contagem de inicializações subir e o motivo do despertar aparecer como Timer.
  4. Pressione o botão EN: o contador volta para 1, porque isso é um reset normal, e não um despertar do deep sleep.
  5. No seu projeto real, defina TIME_TO_SLEEP como 600 (10 minutos) ou 3600 (1 hora).
C++ (Arduino IDE)
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.

EventoVariável normalRTC_DATA_ATTRPreferences (flash)
Despertar do deep sleepZeradaMantidaMantida
Botão EN ou ESP.restart()ZeradaVolta ao valor inicialMantida
Bateria removida, queda de energiaZeradaPerdidaMantida
Novo código carregadoZeradaPerdidaMantida (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.

C++ (Arduino IDE)
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 despertarFunçãoPinosObservação
Timeresp_sleep_enable_timer_wakeup() (timer)Não precisa de pinoTempo em microssegundos, 64 bits
ext0esp_sleep_enable_ext0_wakeup() (um pino)Um RTC GPIOAcorda em HIGH ou LOW; não pode ser combinado com toque ou ULP
ext1esp_sleep_enable_ext1_wakeup_io() (vários pinos)Vários RTC GPIOsANY_HIGH ou ALL_LOW; recomenda-se usar resistores externos
ToquetouchSleepWakeUpEnable() (toque)T0–T9 (10 pinos)Acorda quando o valor cai abaixo do limite; não pode ser combinado com ext0
Coprocessador ULPesp_sleep_enable_ulp_wakeup() (ULP)Depende do programaPode ler sensores durante o sono; avançado

Ligações do circuito de exemplo

ComponentePino do componentePino do ESP32Observação
Sensor PIR (HC-SR501 ou AM312)OUTGPIO 33Acorda a placa pelo ext0
Sensor PIRVCC / GND5V (HC-SR501) ou 3V3 (AM312) / GNDO HC-SR501 precisa de pelo menos 4,5 V
Botão AUm terminal / outro terminal3V3 / GPIO 25Pull-down de 10 kΩ entre o GPIO 25 e o GND
Botão BUm terminal / outro terminal3V3 / GPIO 26Pull-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 ΩÂnodoGPIO 2Na maioria das DevKits, o LED azul integrado também fica neste pino
Divisor da bateria (1 MΩ + 1 MΩ)Ponto médioGPIO 35100 nF entre o ponto médio e o GND
18650 + TP4056 + LDO de 3,3 VSaída do LDO / GND3V3 / GNDCapacitor de 470 µF na saída do LDO
Evite os pinos GPIO 0, 2, 12 e 15 como entradas de despertar. Eles são pinos de strapping; se um botão ou sensor os mantiver no nível errado durante o reset, a placa entra no modo de download ou nem inicia. Por exemplo, se o GPIO 12 estiver em HIGH na inicialização, a tensão da flash é configurada para 1,8 V e a placa não consegue iniciar. Os GPIO 34–39 são somente entrada e não têm resistores internos de pull-up ou pull-down, então adicione o resistor externamente se for acordar a placa com esses pinos. Você pode conferir o mapa completo de pinos da sua placa na ferramenta Pinagem.

Sketch de despertar com sensor PIR (ext0)

C++ (Arduino IDE)
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)

C++ (Arduino IDE)
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.

C++ (Arduino IDE)
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.

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 s

O 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árioCorrente no sonoTempo acordadoCorrente médiaAutonomia estimada
Placa DevKit8 mA3 s, 120 mA8,56 mA≈12 dias
Placa DevKit, conexão rápida8 mA1 s, 120 mA8,19 mA≈13 dias
Módulo puro + MCP1700 + divisor de 1 MΩ15 µA3 s, 120 mA0,61 mA≈173 dias (5,7 meses)
Módulo puro, conexão rápida15 µA1 s, 120 mA0,215 mA≈494 dias (16 meses)
Módulo puro, envio em lote a cada hora15 µA1 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

SintomaCausaSolução
A placa acorda logo depois de ir dormirO pino de despertar ainda está ativo (PIR em HIGH, botão pressionado) ou flutuandoEspere 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 esperadoEstouro de 32 bits no cálculo do tempo (3600 * 1000000)Adicione ULL às constantes: 3600ULL * 1000000ULL
O contador sempre começa do 1A variável não é RTC_DATA_ATTR ou a placa foi resetadaAdicione RTC_DATA_ATTR; use Preferences para dados permanentes
5–15 mA medidos no sonoRegulador, LED de alimentação, chip USB, divisor ou sensoresPlaca de baixo consumo ou módulo puro, LDO com baixa corrente quiescente
As últimas linhas no Monitor Serial ficam cortadasA placa foi dormir antes de o buffer esvaziarChame Serial.flush() antes de esp_deep_sleep_start()
digitalRead() dá valores errados depois de acordarO pino de despertar ainda está em modo RTCChame rtc_gpio_deinit() antes de usar o pino
Um botão no GPIO 34–39 não acorda a placaEsses pinos não têm resistores internos de pull, então o pino fica flutuandoAdicione um resistor externo de 10 kΩ
O código não carrega enquanto a placa dormeA placa não tem circuito de auto-reset; no S3 e no C3, a porta USB nativa some durante o sonoSegure o BOOT, pressione e solte o EN (RESET) e depois inicie o carregamento
Um relé ou LED muda de estado quando a placa vai dormirOs pinos digitais ficam flutuando (alta impedância) em deep sleepUse um resistor de pull ou mantenha o nível do pino com rtc_gpio_hold_en()
Durante o desenvolvimento, adicione temporariamente uma espera de 5 segundos no início do setup(), ou uma condição que pula o sono enquanto um botão estiver pressionado. Assim você tem tempo de abrir o Monitor Serial e carregar um novo código mesmo com a placa dormindo o tempo todo; só lembre de remover isso quando o projeto estiver pronto. Se a placa reinicia sozinha de vez em quando na bateria, os picos de corrente do Wi-Fi são a causa mais provável; as soluções estão no guia erro de brownout no ESP32.

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.

Ver todos os projetos
LED piscando com ESP32
#103Iniciante

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.

4.7(37)
99
Controle de LED com botão no ESP32 (momentâneo)
#104Iniciante

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.

4.6(36)
55
ESP32 em sono profundo — Economia de bateria (OLED + contador na RAM RTC)
#135Avançado
Premium

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.

4.3(10)
16
Alarme de movimento com ESP32 (PIR + buzzer + LED + Telegram)
#145Avançado
Premium

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.

0.0(0)
9
Iluminação automática com ESP32 e sensor de movimento PIR
#121Intermediário
Premium

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.

4.4(24)
38
Temperatura e umidade com ESP32 e DHT22 (com display LCD)
#117Intermediário

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.

4.8(38)
56
Registrador de temperatura com ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
#144Avançado
Premium

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…

4.7(7)
12