Guide · 17 min di lettura

ESP32 Deep Sleep: risveglio, consumi in µA e durata batteria

ESP32 deep sleep passo passo: consumi in µA di ogni modalità, risveglio con timer, pulsante, PIR e touch (ext0/ext1), memoria RTC e autonomia con una 18650.

Il deep sleep dell'ESP32 (sospensione profonda) è la modalità di risparmio energetico in cui l'ESP32 spegne i core, la radio Wi-Fi e Bluetooth e la memoria principale, lasciando acceso solo il piccolo dominio RTC. In questa modalità il consumo del chip scende dai 240 mA della trasmissione Wi-Fi a circa 10 µA, cioè ventiquattromila volte meno. La scheda si risveglia allo scadere del tempo che hai impostato, quando viene premuto un pulsante, quando un sensore PIR rileva un movimento o quando tocchi un pin; finisce il suo lavoro in pochi secondi e torna a dormire. È così che stazioni meteo, sensori da giardino, allarmi per porte e registratori remoti funzionano per mesi invece che per giorni con una sola batteria 18650.

In questa guida scoprirai le modalità di sospensione dell'ESP32 e i loro consumi reali, imparerai a risvegliare la scheda con un timer, un pulsante, un sensore PIR (ext0 ed ext1) o un tocco, a conservare contatori e misure nella memoria RTC che sopravvive al sonno, capirai perché le schede di sviluppo consumano milliampere anche mentre dormono e calcolerai passo passo quanti mesi dura una sola 18650. Gli sketch Arduino sono scritti per la versione 3.1 o successiva del core Arduino per ESP32; alla fine vedrai come fare la stessa cosa in MicroPython.

Scheda di sviluppo ESP32 (DevKit)
Scheda di sviluppo ESP32: il modulo schermato consuma circa 10 µA in deep sleep, ma il regolatore, il LED di alimentazione e il chip USB-seriale della scheda portano questo valore a diversi milliampere.

Che cos'è il deep sleep dell'ESP32 e come funziona?

Dentro l'ESP32 ci sono due mondi separati. Il primo è il dominio principale, con i core, 520 KB di RAM e la radio Wi-Fi e Bluetooth. Il secondo è il dominio RTC, con un proprio piccolo timer, 8 KB di memoria RTC FAST e 8 KB di RTC SLOW, i pin RTC GPIO e un coprocessore a bassissimo consumo chiamato ULP. In deep sleep il dominio principale viene spento del tutto e continua a funzionare solo quello RTC. Quando arriva il momento del risveglio, il chip in realtà si riavvia: parte il bootloader, il programma viene ricaricato dalla flash e setup() ricomincia dall'inizio. Per questo un programma con deep sleep fa tutto il lavoro dentro setup() e loop() non viene mai eseguito. Le variabili normali si azzerano a ogni risveglio; si conservano solo quelle che metti nella memoria RTC.

Modalità di sospensione dell'ESP32 e consumi (µA)

ModalitàCosa resta attivo?Corrente (chip ESP32)
Attiva: trasmissione Wi-Fi (802.11b, 19,5 dBm)CPU e radio240 mA
Attiva: ricezione e ascolto Wi-FiCPU e radio95–100 mA
Modem sleep, 240 MHzLa CPU funziona, radio spenta30–68 mA
Modem sleep, 80 MHzLa CPU funziona più lenta, radio spenta20–31 mA
Sospensione leggera (light sleep)CPU in pausa, RAM conservata0,8 mA
Deep sleep con ULP attivoDominio RTC e coprocessore ULP150 µA
Deep sleepTimer RTC e memoria RTC10 µA
IbernazioneSolo il timer RTC e alcuni pin RTC5 µA
Spento (pin EN a LOW)Niente1 µA

I valori provengono dal datasheet dell'ESP32 di Espressif e riguardano solo il chip. Nella tabella ci sono due punti importanti. Primo, in light sleep il programma riprende dalla riga in cui si era fermato e tutto ciò che è in RAM viene conservato, ma il consumo è ottanta volte più alto che in deep sleep; va bene per pause di pochi secondi. In deep sleep il programma riparte da capo, ma il consumo scende a pochi microampere, ed è la scelta giusta per attese di minuti o di ore. Secondo, nessuna delle due modalità mantiene la connessione Wi-Fi o Bluetooth; devi riconnetterti a ogni risveglio. I chip più recenti sono un po' diversi: l'ESP32-C3 consuma circa 5 µA in deep sleep e l'ESP32-S3 circa 7–8 µA.

Se vuoi consumare ancora meno, puoi spegnere anche le periferiche RTC e la memoria RTC. Con esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF) e la stessa riga per ESP_PD_DOMAIN_RTC_SLOW_MEM ed ESP_PD_DOMAIN_RTC_FAST_MEM il chip si avvicina alla modalità di ibernazione e consuma circa 5 µA. In questo caso le variabili nella memoria RTC vanno perse e solo il timer o ext1 possono risvegliare la scheda. Nella maggior parte dei progetti la differenza tra 10 µA e 5 µA è trascurabile rispetto al resto della scheda, quindi risolvi prima i problemi della sezione successiva.

Perché le schede di sviluppo consumano milliampere in deep sleep?

Quando carichi lo sketch e colleghi un multimetro, spesso vedi 5–15 mA invece di 10 µA. Il problema non è il chip, ma i componenti aggiuntivi della scheda. La maggior parte delle schede DevKit e NodeMCU-32S economiche usa un regolatore AMS1117 per abbassare i 5 V a 3,3 V, e questo regolatore da solo consuma tipicamente 5 mA anche senza carico. A questo si aggiungono il LED di alimentazione sempre acceso e il chip USB-seriale (CP2102 o CH340) che comunica con il computer. Insieme arrivano di solito a circa 8 mA e consumano circa 190 mAh al giorno anche mentre l'ESP32 dorme: una 18650 da 3000 mAh dura a malapena due settimane con una scheda del genere. Per misurare la corrente, collega il multimetro in serie tra la batteria e il circuito e passa alla portata µA durante il sonno; trovi i dettagli nella guida come usare un multimetro.

Fonte di consumoCorrente in sospensioneSoluzione
Modulo ESP32 (deep sleep)≈10 µAGià basso, non serve altro
Regolatore AMS1117Tipicamente 5 mA (a riposo)Usa un MCP1700 (1,6 µA a riposo) o un HT7333 (circa 4 µA)
LED di alimentazione1–3 mADissalda il LED o la sua resistenza
Chip USB-seriale (CP2102, CH340)Dipende dalla scheda, può arrivare ai mAUsa una scheda senza chip USB o un modulo nudo
Partitore della batteria da 100 kΩ + 100 kΩ21 µA (a 4,2 V)Usa 1 MΩ + 1 MΩ o accendi il partitore con un MOSFET solo durante la misura
Sensori sempre alimentatiDa µA a mA secondo il sensoreAlimenta il sensore da un GPIO o da un MOSFET solo durante la misura
Non collegare mai una batteria agli ioni di litio come la 18650 direttamente al pin 3V3: una cella Li-ion carica è a 4,2 V, mentre l'ESP32 accetta al massimo 3,6 V. Anche collegarla al pin VIN non è una buona soluzione, perché sull'AMS1117 cade circa 1 V e la sua uscita scende sotto i 3 V quando la batteria è a metà carica. Il modo corretto è alimentare il pin 3V3 tramite un LDO da 3,3 V con bassa corrente di riposo e bassa caduta di tensione. I piccoli LDO come MCP1700 e HT7333 erogano solo 250 mA, quindi metti almeno 470 µF sulla loro uscita per coprire i picchi di corrente del Wi-Fi. Le celle LiFePO4, che non superano i 3,6 V nemmeno da cariche, si possono collegare direttamente al 3V3 senza regolatore.

Il tuo primo sketch deep sleep: risveglio con il timer

  1. Nel Gestore schede dell'Arduino IDE installa il pacchetto esp32 by Espressif Systems (versione 3.1 o successiva) e scegli ESP32 Dev Module come scheda.
  2. Carica lo sketch qui sotto e apri il Monitor seriale a 115200 baud.
  3. La scheda si risveglia ogni 10 secondi; osserva il contatore dei riavvii che sale e la causa del risveglio stampata come Timer.
  4. Premi il pulsante EN: il contatore torna a 1, perché si tratta di un normale reset e non di un risveglio dal deep sleep.
  5. Nel tuo progetto reale imposta TIME_TO_SLEEP a 600 (10 minuti) o a 3600 (1 ora).
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}

Il cuore dello sketch sono due righe: esp_sleep_enable_timer_wakeup() imposta il tempo di risveglio in microsecondi ed esp_deep_sleep_start() manda subito il chip a dormire; nulla di ciò che scrivi dopo quella riga viene eseguito. Non dimenticare il suffisso ULL (64 bit) nel calcolo del tempo: 3600 * 1000000 supera il limite di un int a 32 bit, il compilatore dà solo un avviso e la scheda si risveglia al momento sbagliato oppure non si risveglia più. Serial.flush() aspetta che il buffer di trasmissione si svuoti; senza, le ultime righe vengono troncate. esp_sleep_get_wakeup_cause() ti dice perché la scheda si è risvegliata e non restituisce alcuna sorgente di sospensione dopo la prima accensione o un reset. Il timer RTC che conta la durata del sonno usa per impostazione predefinita un oscillatore RC interno da circa 150 kHz. Non è stabile come un quarzo e può derivare di qualche punto percentuale con la temperatura; se l'orario è importante nel tuo progetto, conviene sincronizzarlo con NTP al risveglio.

Conservare contatori e misure nella memoria RTC

Se devi ricordare qualcosa tra un risveglio e l'altro, scrivi RTC_DATA_ATTR davanti alla variabile: il compilatore la mette negli 8 KB di memoria RTC SLOW, che restano alimentati in deep sleep, invece che nella RAM principale. È perfetta per piccoli dati come contatori, ultime misure, informazioni sul canale Wi-Fi o l'ultima temperatura inviata. Questa memoria però non è permanente: secondo la documentazione di Espressif, i dati nella memoria RTC vengono reinizializzati a ogni riavvio, tranne al risveglio dal deep sleep. Cambiare la batteria, premere EN, caricare nuovo codice o chiamare ESP.restart() azzera il contatore. Le impostazioni che devono sopravvivere a un'interruzione di corrente scrivile nella flash con la libreria Preferences, ma non a ogni risveglio, perché la flash sopporta un numero limitato di scritture.

EventoVariabile normaleRTC_DATA_ATTRPreferences (flash)
Risveglio dal deep sleepAzzerataConservataConservata
Pulsante EN o ESP.restart()AzzerataTorna al valore inizialeConservata
Batteria rimossa, mancanza di correnteAzzerataCancellataConservata
Caricamento di nuovo codiceAzzerataCancellataConservata (se la flash non viene cancellata)

Usata bene, questa memoria moltiplica la durata della batteria. Connettersi al Wi-Fi è la parte più costosa di ogni risveglio. Per questo lo sketch seguente misura la tensione della batteria ogni 10 minuti ma accende il Wi-Fi solo una volta all'ora: sei misure si accumulano in un array nella memoria RTC e al sesto risveglio vengono inviate tutte insieme. Inoltre salva nella memoria RTC il canale e l'indirizzo MAC (BSSID) del router, così alla connessione successiva l'ESP32 si collega direttamente a quel router senza scansionare tutti i canali e la connessione si accorcia in modo evidente.

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}

La tensione della batteria viene dimezzata da un partitore di tensione da 1 MΩ + 1 MΩ e letta sul GPIO 35, un canale dell'ADC1. Un condensatore da 100 nF tra il punto centrale del partitore e GND rende stabile la misura anche con un partitore ad alta impedenza come questo. È importante anche misurare prima di accendere il Wi-Fi, perché la corrente assorbita dalla radio fa calare per un attimo la tensione della batteria. Se il Wi-Fi non si connette, la misura più vecchia viene scartata e le altre vengono tenute per il tentativo successivo. Spegnere correttamente la radio prima di dormire con WiFi.disconnect(true) e WiFi.mode(WIFI_OFF) è anche ciò che consiglia Espressif. Per accelerare ancora la connessione, assegna un IP statico con WiFi.config() e salta l'attesa del DHCP. Trovi il calcolo del partitore nella guida partitore di tensione e il circuito di ricarica in modulo di ricarica TP4056.

Risveglio con pulsante o sensore PIR: ext0 ed ext1

Oltre al timer, anche un segnale dall'esterno può risvegliare l'ESP32. Ci sono due modi per farlo ed entrambi funzionano solo sui pin RTC GPIO: 0, 2, 4, 12–15, 25–27 e 32–39. ext0 controlla un solo pin e risveglia la scheda quando quel pin raggiunge il livello scelto (HIGH o LOW); poiché mantiene alimentate le periferiche RTC, le resistenze interne di pull-up e pull-down continuano a funzionare durante il sonno. ext1 controlla più pin contemporaneamente tramite una maschera di bit. Sull'ESP32 classico ext1 ha due modalità: ESP_EXT1_WAKEUP_ANY_HIGH risveglia la scheda quando uno qualsiasi dei pin scelti va a HIGH, ESP_EXT1_WAKEUP_ALL_LOW quando sono tutti a LOW nello stesso momento. La modalità ANY_LOW, che risveglia quando un pin qualsiasi va a LOW, esiste solo su ESP32-S2, S3, C6 e H2. Quindi, se vuoi risvegliare un ESP32 classico con più pulsanti, collega i pulsanti al 3V3 e metti su ogni pin una resistenza di pull-down da 10 kΩ. Puoi anche attivare più sorgenti insieme; con il PIR e un timer orario attivi, per esempio, la scheda si risveglia con quello che arriva per primo.

Sorgente di risveglioFunzionePinNota
Timeresp_sleep_enable_timer_wakeup()Nessun pinTempo in microsecondi, 64 bit
ext0esp_sleep_enable_ext0_wakeup()Un RTC GPIORisveglia su HIGH o LOW; non si combina con touch e ULP
ext1esp_sleep_enable_ext1_wakeup_io()Più RTC GPIOANY_HIGH o ALL_LOW; consigliate resistenze esterne
TouchtouchSleepWakeUpEnable()T0–T9 (10 pin)Risveglia quando il valore scende sotto la soglia; non si combina con ext0
Coprocessore ULPesp_sleep_enable_ulp_wakeup()Dipende dal programmaPuò leggere sensori durante il sonno; livello avanzato

Collegamenti del circuito di esempio

ComponentePin del componentePin dell'ESP32Nota
Sensore PIR (HC-SR501 o AM312)OUTGPIO 33Risveglia la scheda tramite ext0
Sensore PIRVCC / GND5V (HC-SR501) o 3V3 (AM312) / GNDL'HC-SR501 richiede almeno 4,5 V
Pulsante AUn piedino / l'altro piedino3V3 / GPIO 25Pull-down da 10 kΩ tra GPIO 25 e GND
Pulsante BUn piedino / l'altro piedino3V3 / GPIO 26Pull-down da 10 kΩ tra GPIO 26 e GND
Piazzola touch o filo–GPIO 27 (T7)Più affidabile se resta corto
LED + 220 ΩAnodoGPIO 2Sulla maggior parte delle DevKit anche il LED blu integrato è su questo pin
Partitore della batteria (1 MΩ + 1 MΩ)Punto centraleGPIO 35100 nF tra il punto centrale e GND
18650 + TP4056 + LDO da 3,3 VUscita LDO / GND3V3 / GNDCondensatore da 470 µF sull'uscita dell'LDO
Evita i pin GPIO 0, 2, 12 e 15 come ingressi di risveglio. Sono pin di avvio (strapping): se un pulsante o un sensore li tiene al livello sbagliato durante il reset, la scheda entra in modalità di programmazione o non si avvia affatto. Per esempio, se il GPIO 12 è a HIGH all'avvio, la tensione della flash viene impostata a 1,8 V e la scheda non riesce a partire. I GPIO 34–39 sono solo ingressi e non hanno resistenze interne di pull-up o pull-down; se li usi per il risveglio, aggiungi la resistenza esternamente. Puoi vedere la piedinatura completa della tua scheda con lo strumento Pinout.

Sketch di risveglio con sensore 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}

Al risveglio lo sketch riporta prima il pin a GPIO normale con rtc_gpio_deinit(). Dopo un risveglio con ext0 il pin resta in modalità RTC e, senza questa riga, digitalRead() potrebbe non funzionare correttamente. Conta il movimento, accende il LED e poi aspetta che l'uscita del PIR torni a LOW. Questa attesa è fondamentale: se vai a dormire mentre l'uscita è ancora HIGH, la scheda si risveglia subito ed entra in un ciclo che si accende e si spegne più volte al secondo. L'HC-SR501 tiene l'uscita a HIGH per il tempo impostato; gira al minimo il trimmer del tempo per accorciare l'attesa. Poiché l'HC-SR501 richiede almeno 4,5 V, nei progetti alimentati da una sola 18650 scegli il piccolo modulo PIR AM312, che funziona anche a 3,3 V. Per le regolazioni del sensore consulta la guida sensore di movimento PIR.

Sketch di risveglio con due pulsanti (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}

Dopo un risveglio con ext1, esp_sleep_get_ext1_wakeup_status() restituisce una maschera di bit che indica quale pin ha risvegliato la scheda. Così puoi dare compiti diversi ai due pulsanti: uno accende la luce e l'altro la spegne, oppure uno invia una misura e l'altro apre un menu. Dato che i pulsanti sono collegati al 3V3 e i pin sono portati a GND con 10 kΩ, leggono LOW da rilasciati e HIGH da premuti, esattamente ciò che si aspetta la modalità ANY_HIGH. Prima di dormire lo sketch aspetta che i pulsanti vengano rilasciati, altrimenti un pulsante ancora premuto risveglierebbe subito la scheda. Se usi la versione 2.x o 3.0.x del core Arduino per ESP32, che non ha la funzione _io, scrivi esp_sleep_enable_ext1_wakeup con gli stessi parametri al posto di esp_sleep_enable_ext1_wakeup_io. Nella guida come collegare un pulsante ad Arduino trovi spiegato in dettaglio perché serve la resistenza di pull-down.

Risveglio con un tocco (touch wake-up)

Dieci pin dell'ESP32 (T0–T9) funzionano come sensori touch capacitivi e rilevano il tuo dito anche in deep sleep. Un filo, una striscia di nastro di rame o una piazzola sul PCB collegata al pin si comporta come un pulsante e può stare perfino dietro un sottile coperchio di plastica o di legno. Sull'ESP32 classico il valore di touchRead() scende quando tocchi: con un filo corto di solito legge 60–80 senza contatto e 10–20 al tocco. La soglia di risveglio va messa tra questi due valori; il 40 dell'esempio è un buon punto di partenza. Sull'ESP32 classico puoi usare più pin touch insieme come sorgenti di risveglio. Su ESP32-S2 e S3, invece, un solo pin può risvegliare il chip, il valore sale al tocco e la soglia usa una scala completamente diversa (5000 nell'esempio di Espressif). Il risveglio touch non si può combinare con ext0; se ti serve anche un pulsante, usa ext1. Per l'elenco dei pin e la calibrazione leggi la guida pin touch dell'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 dell'ESP32 con MicroPython

Se programmi l'ESP32 in MicroPython, ottieni lo stesso risultato con meno codice. machine.deepsleep(ms) fa dormire la scheda per i millisecondi indicati, esp32.wake_on_ext0() trasforma un pin in sorgente di risveglio e machine.RTC().memory() offre un buffer di byte che sopravvive al sonno; sull'ESP32 contiene 2048 byte per impostazione predefinita. Al risveglio main.py riparte dall'inizio; con machine.reset_cause() capisci se la scheda esce dal deep sleep e con machine.wake_reason() che cosa l'ha risvegliata. I pin RTC configurati con pull-up o pull-down mantengono questa impostazione durante il sonno. Se sei alle prime armi con MicroPython, parti dalla guida basi di 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

Il Raspberry Pi Pico, invece, non ha una sospensione profonda da pochi microampere come quella dell'ESP32. In MicroPython machine.lightsleep(ms) ferma gran parte dei clock, mette in pausa la CPU e conserva la RAM, mentre machine.deepsleep(ms) resetta la scheda dopo lo stesso tipo di sonno. Anche in queste modalità il consumo della scheda resta nell'ordine dei milliampere. Quindi, se vuoi costruire con il Pico un dispositivo che funzioni a batteria per mesi, otterrai risultati migliori togliendo del tutto l'alimentazione tra una misura e l'altra con un timer di alimentazione come il TPL5110. Per le basi del Pico consulta la guida che cos'è il Raspberry Pi Pico.

Un sensore che dura mesi con una 18650: calcolo della durata della batteria

Per trovare la durata della batteria di un dispositivo che dorme e si risveglia, calcoli prima la corrente media: Corrente media = (Corrente da sveglio × Tempo da sveglio + Corrente in sospensione × Tempo di sospensione) / Tempo totale. Poi dividi la capacità utile della batteria per questa media. Non si può sfruttare tutta una 18650 che riporta 3000 mAh sull'etichetta; considerare circa l'85 %, cioè 2550 mAh, per lo stacco a bassa tensione, le perdite del regolatore e l'invecchiamento è realistico. La tabella seguente è calcolata per un sensore che si risveglia ogni 10 minuti, invia dati via Wi-Fi e durante la connessione assorbe in media 120 mA.

ScenarioCorrente in sospensioneTempo da sveglioCorrente mediaDurata stimata
Scheda DevKit8 mA3 s, 120 mA8,56 mA≈12 giorni
Scheda DevKit, connessione rapida8 mA1 s, 120 mA8,19 mA≈13 giorni
Modulo nudo + MCP1700 + partitore da 1 MΩ15 µA3 s, 120 mA0,61 mA≈173 giorni (5,7 mesi)
Modulo nudo, connessione rapida15 µA1 s, 120 mA0,215 mA≈494 giorni (16 mesi)
Modulo nudo, invio cumulativo ogni ora15 µA1 s di Wi-Fi all'ora (120 mA) + 5 × 0,3 s di misura (40 mA)0,065 mA≈4,5 anni in teoria

Il risultato è chiaro: su una scheda di sviluppo accorciare il tempo da sveglio non cambia quasi nulla, perché a scaricare davvero la batteria sono gli 8 mA in sospensione. Quando la corrente di sospensione scende ai microampere, l'equilibrio si ribalta e ogni secondo da sveglio conta: ridurre la connessione Wi-Fi da 3 secondi a 1 quasi triplica la durata della batteria. Quando la corrente media scende sotto 0,1 mA entra in gioco l'autoscarica della batteria. Una cella Li-ion perde circa il 2–3 % della capacità al mese, quindi i 4,5 anni teorici diventano in pratica circa 2 anni. Per fare il calcolo con i tuoi valori usa il calcolatore della durata della batteria e approfondisci mAh e Wh nella guida che cosa significa mAh.

  • Scegli la scheda giusta: le schede senza chip USB e LED di alimentazione, o un modulo ESP32 nudo, consumano pochi microampere in sospensione.
  • Cambia regolatore: al posto dell'AMS1117 usa un LDO con una corrente di riposo di pochi microampere.
  • Alimenta il sensore solo durante la misura: i sensori che assorbono pochi mA possono essere alimentati direttamente da un GPIO, i carichi più grandi tramite un MOSFET a canale P; metti una resistenza di pull-up sul gate del MOSFET perché resti spento durante il sonno. Trovi i dettagli nella guida MOSFET con Arduino.
  • Accendi raramente il Wi-Fi: accumula le misure nella memoria RTC e inviale in blocco; se invii dati a un altro ESP32 vicino, ESP-NOW trasmette in molto meno tempo perché non deve associarsi a un router.
  • Velocizza la connessione: con IP statico, canale e BSSID salvati, la connessione Wi-Fi spesso richiede meno di un secondo.
  • Elimina le attese inutili: nel progetto finito togli le stampe sul Monitor seriale e le righe delay() lunghe; ogni millisecondo da sveglio lo paga la batteria.
  • Non dimenticare il partitore e i LED: un partitore da 100 kΩ + 100 kΩ sempre collegato assorbe il doppio della corrente dell'ESP32 addormentato.

Idee di progetto con il deep sleep dell'ESP32

  • Stazione meteo a batteria: misura temperatura, umidità e pressione con un BME280 ogni 10 minuti e inviale ogni ora a Home Assistant via MQTT.
  • Sensore di umidità per il giardino: risvegliati ogni ora, misura l'umidità del terreno e avvisa il tuo telefono quando la terra si secca.
  • Allarme per porte e finestre: quando la porta si apre, un reed switch risveglia l'ESP32 tramite ext0 e un bot Telegram ti manda un messaggio.
  • Sensore di sicurezza a batteria: costruisci un dispositivo che si risveglia e invia un avviso quando il PIR rileva un movimento e che per il resto del tempo dorme per mesi.
  • Campanello touch: incolla del nastro di rame dietro un pannello di legno; al tocco l'ESP32 si risveglia e manda un segnale al campanello in casa tramite ESP-NOW.
  • Datalogger di temperatura a batteria: misura la temperatura di un frigorifero o di un acquario con un DS18B20 impermeabile, accumula i valori nella memoria RTC e inviali qualche volta al giorno.

Errori comuni e soluzioni

SintomoCausaSoluzione
La scheda si risveglia appena si addormentaIl pin di risveglio è ancora attivo (PIR a HIGH, pulsante premuto) o flottantePrima di dormire aspetta che il pin torni al livello di riposo e aggiungi una resistenza di pull-down o pull-up
La scheda non si risveglia al momento previstoOverflow a 32 bit nel calcolo del tempo (3600 * 1000000)Aggiungi ULL alle costanti: 3600ULL * 1000000ULL
Il contatore riparte sempre da 1La variabile non è RTC_DATA_ATTR oppure la scheda è stata resettataAggiungi RTC_DATA_ATTR; per dati permanenti usa Preferences
In sospensione si misurano 5–15 mARegolatore, LED di alimentazione, chip USB, partitore o sensoriScheda a basso consumo o modulo nudo, LDO con bassa corrente di riposo
Le ultime righe del Monitor seriale sono troncateLa scheda si è addormentata prima che il buffer si svuotasseChiama Serial.flush() prima di esp_deep_sleep_start()
digitalRead() dà valori errati dopo il risveglioIl pin di risveglio è rimasto in modalità RTCChiama rtc_gpio_deinit() prima di usare il pin
Un pulsante su GPIO 34–39 non risveglia la schedaQuesti pin non hanno resistenze interne di pull, quindi il pin è flottanteAggiungi una resistenza esterna da 10 kΩ
Non si riesce a caricare il codice mentre la scheda dormeLa scheda non ha il circuito di reset automatico; su S3 e C3 la porta USB nativa sparisce durante il sonnoTieni premuto BOOT, premi e rilascia EN (RESET), poi avvia il caricamento
Un relè o un LED cambia stato quando la scheda si addormentaIn deep sleep i pin digitali restano in alta impedenzaUsa una resistenza di pull o mantieni il livello del pin con rtc_gpio_hold_en()
Durante lo sviluppo aggiungi temporaneamente un'attesa di 5 secondi all'inizio di setup(), oppure una condizione che non manda a dormire la scheda finché un pulsante è premuto. Così hai il tempo di aprire il Monitor seriale e caricare nuovo codice anche se la scheda dorme quasi sempre; ricordati di togliere questa riga a progetto finito. Se, alimentata a batteria, la scheda si resetta da sola ogni tanto, la causa più probabile sono i picchi di corrente del Wi-Fi; le soluzioni sono nella guida errore brownout dell'ESP32.

Il deep sleep dell'ESP32 è la chiave per far funzionare lo stesso codice a batteria per mesi invece che per giorni: tieni breve il lavoro, scegli la sorgente di risveglio giusta, conserva nella memoria RTC i piccoli dati che ti servono tra un risveglio e l'altro e non dimenticare mai il consumo proprio della scheda. Se vuoi ripassare le basi dell'ESP32, la guida che cos'è l'ESP32 è un buon punto di partenza. Nell'app BlueGrays, il progetto ESP32 Deep Sleep — Risparmio della batteria (OLED + contatore in RAM RTC) ti permette di provare la logica del timer e del contatore RTC di questo articolo su un circuito con display OLED, con schema passo passo e codice pronto.

Domande frequenti

Quanta corrente consuma l'ESP32 in deep sleep?

Secondo il datasheet di Espressif, il chip ESP32 consuma circa 10 µA in deep sleep con timer e memoria RTC attivi, e 5 µA in modalità ibernazione. Sulle schede di sviluppo come la DevKit, però, il regolatore, il LED di alimentazione e il chip USB-seriale portano di solito la corrente in sospensione a 5–15 mA.

Come si risveglia un ESP32 dal deep sleep?

Ci sono cinque modi: il timer RTC, un singolo pin RTC (ext0), più pin RTC (ext1), i pin touch e il coprocessore ULP. La sorgente di risveglio si configura prima di chiamare esp_deep_sleep_start() e se ne possono attivare più di una insieme; solo ext0 e il risveglio touch non si possono usare contemporaneamente.

Le variabili si cancellano nel deep sleep dell'ESP32?

Sì, le variabili normali si cancellano, perché il risveglio dal deep sleep è un riavvio e setup() riparte dall'inizio. Le variabili con RTC_DATA_ATTR vengono salvate nella memoria RTC e si conservano tra un risveglio e l'altro, ma tornano al valore iniziale dopo un'interruzione di corrente, la pressione di EN o il caricamento di nuovo codice.

Quanto dura un ESP32 con una batteria 18650?

Da un giorno a più di un anno, a seconda della scheda e dell'uso. Una DevKit sempre connessa al Wi-Fi dura solo 1–2 giorni con una 18650 da 3000 mAh, mentre una DevKit che si risveglia ogni 10 minuti dura circa 12 giorni. Un circuito a basso consumo che fa lo stesso lavoro con 15 µA in sospensione funziona da 5 a 16 mesi, secondo la durata di ogni connessione.

Che differenza c'è tra light sleep e deep sleep nell'ESP32?

In light sleep la CPU viene messa in pausa ma la RAM si conserva; al risveglio il programma riprende dalla riga in cui si era fermato e il chip consuma circa 0,8 mA. In deep sleep si spegne anche la RAM e il consumo scende a 10 µA, ma il programma riparte da capo a ogni risveglio. La sospensione leggera è adatta a pause di qualche secondo, quella profonda ad attese di minuti o ore.

Come si carica il codice su un ESP32 in deep sleep?

Sulle schede con circuito di reset automatico il caricamento di solito parte senza problemi, perché lo strumento di upload resetta il chip tramite il pin EN. Se non parte, tieni premuto il pulsante BOOT, premi e rilascia EN (RESET) e poi avvia il caricamento. Sulle schede con USB nativa come l'ESP32-S3 e il C3 la porta sparisce durante il sonno, quindi questo metodo è spesso indispensabile.

Vedi tutti i progetti
LED Lampeggiante con ESP32
#103Principiante

LED Lampeggiante con ESP32

Insegna l'uso di base delle uscite GPIO con l'ESP32. Otteniamo un effetto lampeggiante accendendo e spegnendo un LED dal pin digitale. Versione ESP32 del classico progetto blink su Arduino UNO; i comandi di base di blink nell'ambiente Arduino sono gli stessi, ma la disposizione dei pin e i livelli GPIO a 3,3 V dell'ESP32 sono diversi da quelli di Arduino UNO.

4.7(37)
99
Controllo LED ESP32 con pulsante (Push)
#104Principiante

Controllo LED ESP32 con pulsante (Push)

Il LED si accende quando il pulsante viene premuto e si spegne quando viene rilasciato. Mostra come vengono utilizzati il pin di ingresso digitale dell'ESP32 e la resistenza di pull-up interna. Grazie alla modalità INPUT_PULLUP, non è necessaria alcuna resistenza esterna.

4.6(36)
55
ESP32 Deep Sleep — Risparmio della batteria (OLED + contatore in RTC RAM)
#135Avanzato
Premium

ESP32 Deep Sleep — Risparmio della batteria (OLED + contatore in RTC RAM)

La modalità Deep Sleep dell'ESP32 riduce il consumo di corrente a circa 10 µA spegnendo la CPU e la maggior parte dei dispositivi periferici ed è di fondamentale importanza per i dispositivi IoT alimentati a batteria. In questo progetto utilizziamo tre diverse fonti di risveglio: il timer (15 secondi), un pin esterno (EXT0 — pulsante GPIO 33) e il sensore tattile (T0/GPIO 4). Le variabili contrassegnate con RTC_DATA_ATTR vengono preservate durante la modalità Deep Sleep: il contatore di avvio,

4.3(10)
16
Sistema di Allarme Movimento ESP32 (PIR + Buzzer + LED + Telegram)
#145Avanzato
Premium

Sistema di Allarme Movimento ESP32 (PIR + Buzzer + LED + Telegram)

Un sistema di allarme di sicurezza intelligente che attiva buzzer e LED quando il sensore PIR rileva movimento, inviando contemporaneamente una notifica istantanea al proprietario tramite Telegram. Dispone di un tempo di attesa di 30 secondi per limitare la frequenza degli allarmi ripetuti; questo meccanismo non verifica la validità dei rilevamenti del sensore PIR né elimina le false attivazioni. Adatto a sicurezza domestica, monitoraggio di garage, magazzini o studi. Con l'ESP32-CAM è possibile

0.0(0)
9
Illuminazione automatica con sensore di movimento PIR ESP32
#121Intermedio
Premium

Illuminazione automatica con sensore di movimento PIR ESP32

In questo progetto, utilizzeremo il sensore di movimento PIR HC-SR501 per rilevare la presenza di una persona che entra nella stanza e accendere automaticamente il LED. Monitoreremo il tempo di accensione del LED con millis(); ogni lettura HIGH del sensore aggiornerà l'istante dell'ultimo movimento e il LED si spegnerà quando saranno trascorsi almeno 10 secondi dall'ultima lettura HIGH. Il codice attuale attende anche 50 ms a ogni iterazione con delay(50), quindi il ciclo dell'applicazione n

4.4(24)
38
ESP32 DHT22 Temperatura e umidità (con display LCD)
#117Intermedio

ESP32 DHT22 Temperatura e umidità (con display LCD)

Si tratta di un progetto che misura la temperatura e l'umidità dell'ambiente tramite il sensore DHT22 e le visualizza in tempo reale su un display LCD I2C 16x2. I dati vengono letti dal sensore utilizzando il protocollo one-wire tramite la libreria Adafruit DHT. Questo progetto costituisce la base per stazioni meteorologiche IoT, sistemi di automazione domestica intelligente o sistemi di monitoraggio ambientale nelle serre. La comunicazione con il DHT22 avviene tramite il pin GPIO 4 dell'ESP32.

4.8(38)
56
Data Logger di Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)
#144Avanzato
Premium

Data Logger di Temperatura ESP32 (DHT22 + DS1307 RTC + microSD + OLED)

Costruisci un data logger di temperatura con timestamp usando ESP32! Leggi temperatura/umidità dal DHT22 ogni minuto, ottieni l'ora reale dal DS1307 RTC e registra su scheda microSD in formato CSV. L'OLED mostra dal vivo temperatura (font grande), percentuale di umidità, timestamp e contatore di log. Il file /temp_log.csv sulla scheda SD si apre in Excel, Google Sheets o Python pandas per l'analisi — perfetto per il monitoraggio di serre, tracciamento della temperatura domestica, raccolta

4.7(7)
12