😴 دیپ اسلیپ ESP32: خواب عمیق، بیدار شدن با تایمر و دکمه و ماه‌ها کار با یک باتری

✍️ تیم ووکوی فارسی ·

فرض کن می‌خواهی یک دماسنج کوچک را با باتری در گلخانه یا بالکن بگذاری و هر چند دقیقه یک‌بار دما را بفرستد. ESP32 وقتی بیدار است و وای‌فایش روشن است، بین ۱۰۰ تا ۲۴۰ میلی‌آمپر جریان می‌کشد و یک باتری معمولی را در یکی دو روز خالی می‌کند. راه‌حل، دیپ اسلیپ ESP32 (Deep Sleep) است: برد کارش را در چند ثانیه انجام می‌دهد، بعد به خواب عمیق می‌رود و در این حالت خود تراشه فقط حدود ۱۰ میکروآمپر مصرف دارد. در این آموزش یاد می‌گیریم برد را بخوابانیم، با تایمر یا دکمه بیدارش کنیم و یک شمارنده را با RTC_DATA_ATTR از خواب به خواب نگه داریم.

💡 این آموزش برای برد واقعی است. خواب عمیق در شبیه‌ساز مدل نمی‌شود؛ پایین‌تر گفته‌ایم کدام بخش کار را می‌شود در شبیه‌ساز تمرین کرد.

حالت‌های مصرف ESP32

ESP32 چند حالت کاری دارد. عددها تقریبی‌اند و به برد، ولتاژ و کارهای روشن بستگی دارند، ولی ترتیبشان مهم است:

حالتچه چیزی روشن استمصرف تقریبی
فعال با وای‌فایهمه‌چیز۱۰۰ تا ۲۴۰ میلی‌آمپر
Modem sleepپردازنده روشن، رادیو خاموشچند ده میلی‌آمپر
Light sleepپردازنده متوقف، حافظه حفظ می‌شودحدود ۰٫۸ میلی‌آمپر
Deep sleepفقط بخش RTC: تایمر، حافظه‌ی RTC و پین‌های RTCحدود ۱۰ میکروآمپر
Hibernationفقط تایمر RTCحدود ۵ میکروآمپر

فرق دیپ اسلیپ با بقیه این است که پردازنده و حافظه‌ی اصلی واقعاً خاموش می‌شوند. وقتی برد بیدار می‌شود، برنامه از اول setup شروع می‌شود؛ انگار دکمه‌ی ری‌استارت را زده باشی. همه‌ی متغیرهای معمولی پاک می‌شوند، مگر آن‌هایی که در حافظه‌ی کوچک RTC (حدود ۸ کیلوبایت) نگه داشته شده‌اند.

چه می‌سازیم؟

برنامه‌ای که هر بار بیدار می‌شود شماره‌ی بیداری را می‌شمارد، دلیل بیدار شدن (تایمر یا دکمه) را در سریال مانیتور می‌نویسد، یک چشمک کوتاه با LED روی برد می‌زند و دوباره می‌خوابد. برد هر ۳۰ ثانیه خودش بیدار می‌شود، یا هر وقت دکمه را فشار بدهی.

قطعه‌ها و سیم‌کشی

ازبهتوضیح
یک پایه‌ی دکمهGPIO33باید یکی از پین‌های RTC باشد
پایه‌ی دیگر دکمهGNDفشار دادن، پین را LOW می‌کند
مقاومت ۱۰ کیلواهمبین GPIO33 و 3V3در حالت عادی پین را HIGH نگه می‌دارد
LED آبی روی بردGPIO2 (از قبل وصل است)نشانه‌ی بیدار بودن

بیدار شدن با یک پین (روش ext0) فقط روی پین‌های RTC کار می‌کند: GPIO0، 2، 4، 12 تا 15، 25 تا 27 و 32 تا 39. فهرست کامل پین‌ها و کاربردشان را در پین اوت ESP32 ببین.

کد کامل

// ESP32 deep sleep: wake up every 30 s, or when the button is pressed.
// Real board only: the simulator does not model deep sleep.
#include "driver/rtc_io.h"

const int LED = 2;                        // built-in LED
const gpio_num_t WAKE_PIN = GPIO_NUM_33;  // must be an RTC GPIO
const uint64_t SLEEP_SECONDS = 30;

RTC_DATA_ATTR int bootCount = 0;          // lives in RTC memory: survives deep sleep

void printWakeReason() {
  esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
  switch (cause) {
    case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Woke up: timer"); break;
    case ESP_SLEEP_WAKEUP_EXT0:  Serial.println("Woke up: button"); break;
    default:                     Serial.println("Woke up: power on or reset"); break;
  }
}

void setup() {
  Serial.begin(115200);
  delay(300);                             // give the monitor a moment
  bootCount++;
  Serial.print("Boot number: ");
  Serial.println(bootCount);
  printWakeReason();

  // The "work" of this wake-up. In a real project: read a sensor, send it.
  pinMode(LED, OUTPUT);
  digitalWrite(LED, HIGH);
  delay(200);
  digitalWrite(LED, LOW);

  // Wake-up source 1: a timer, in microseconds.
  esp_sleep_enable_timer_wakeup(SLEEP_SECONDS * 1000000ULL);

  // Wake-up source 2: GPIO33 going LOW (button to GND).
  esp_sleep_enable_ext0_wakeup(WAKE_PIN, 0);
  rtc_gpio_pullup_en(WAKE_PIN);           // keep the pin HIGH while asleep
  rtc_gpio_pulldown_dis(WAKE_PIN);

  Serial.println("Going to sleep now");
  Serial.flush();                         // let the text leave before sleeping
  esp_deep_sleep_start();
}

void loop() {
  // Never reached: every wake-up starts again from setup().
}

توضیح خط به خط

مصرف باتری را حساب کن

فرض کن برد هر ۱۰ دقیقه بیدار می‌شود، ۳ ثانیه با وای‌فای روشن کار می‌کند (به‌طور میانگین ۱۲۰ میلی‌آمپر) و بقیه‌ی ۵۹۷ ثانیه می‌خوابد. میانگین مصرف می‌شود: (۳ × ۱۲۰ + ۵۹۷ × مصرف خواب) تقسیم بر ۶۰۰.

یعنی بخش بزرگ مصرف در خواب مال خود برد است، نه ESP32. برای این حساب‌ها می‌توانی از ماشین‌حساب عمر باتری استفاده کنی. سه راه برای کم کردن مصرف: بردهای مخصوص کم‌مصرف که رگولاتور خوب و چراغ قابل قطع دارند، ماژول خام ESP32 با رگولاتوری مثل MCP1700، و کوتاه کردن زمان بیداری؛ مثلاً داده‌ها را چند بار در حافظه‌ی RTC جمع کن و هر ده بار یک‌بار وای‌فای را روشن کن.

منبع‌های دیگر بیدار شدن

این کد برای ESP32 معمولی نوشته شده است. مدل‌های جدیدتر مثل ESP32-C3 روش ext0 ندارند و برای بیدار شدن با پین از تابع‌های مخصوص خودشان استفاده می‌کنند.

در شبیه‌ساز چه چیزی را تمرین کنیم؟

خواب عمیق و مصرف میکروآمپری را فقط روی برد واقعی و با مولتی‌متر می‌شود دید. اما بخش «بیدار» برنامه، که معمولاً بیشتر اشکال‌ها همان‌جاست، کاملاً در شبیه‌ساز قابل ساختن است: خواندن سنسور، وصل شدن به شبکه‌ی Wokwi-GUEST با تایم‌اوت، و فرستادن داده. هنگام تست، به‌جای esp_deep_sleep_start() یک delay بگذار و وقتی همه‌چیز درست بود، روی برد واقعی خواب را برگردان. نمونه‌ی آماده‌ی وصل شدن به شبکه در تینکرکد فارسی پروژه‌ی «وصل شدن ESP32 به وای‌فای» است. خواندن مثال‌ها رایگان است و برای اجرای برد ESP32 در شبیه‌ساز اشتراک Plus لازم است. اگر تازه با ESP32 آشنا شده‌ای، درس «سلام ESP32» شروع خوبی است.

اشکال‌های رایج

قدم بعدی این است که در همان چند ثانیه‌ی بیداری داده را بفرستی: اتصال ESP32 به وای‌فای و بعد پروژه‌ی MQTT و اینترنت اشیا. برای ایده‌های باتری‌خور، سری به ایده‌های پروژه‌ی اینترنت اشیا با ESP32 بزن و همه‌ی آموزش‌های این برد را در صفحه‌ی ESP32 ببین.

بخش بیداری پروژه را در تینکرکد فارسی بساز 🔋

سؤال‌های رایج

آیا دیپ اسلیپ ESP32 در شبیه‌ساز کار می‌کند؟

نه. خواب عمیق و بیدار شدن با تایمر یا دکمه فقط روی برد واقعی امتحان می‌شود. در شبیه‌ساز بخش «بیدار» برنامه را می‌سازی و تست می‌کنی، یعنی خواندن سنسور و وصل شدن به وای‌فای، و به‌جای خواب موقتاً از delay استفاده می‌کنی.

چرا بعد از بیدار شدن، برنامه دوباره از setup شروع می‌شود؟

چون در دیپ اسلیپ پردازنده و حافظه‌ی اصلی خاموش می‌شوند و بیدار شدن در عمل یک ری‌استارت است. برای همین همه‌ی کار را در setup می‌نویسی و loop هیچ‌وقت اجرا نمی‌شود. متغیری که باید بماند را با RTC_DATA_ATTR تعریف کن.

برد ESP32 من در خواب هم چند میلی‌آمپر مصرف دارد؛ چرا؟

عدد ۱۰ میکروآمپر مال خود تراشه است. روی بردهای توسعه، رگولاتور ولتاژ، چراغ پاور و تراشه‌ی USB به سریال همیشه روشن‌اند و چند میلی‌آمپر می‌کشند. برای باتری از بردهای کم‌مصرف یا ماژول خام با رگولاتور کم‌مصرف استفاده کن.

مقاله‌های مرتبط

🕰️

ساعت اینترنتی با ESP32: گرفتن ساعت دقیق از NTP به وقت تهران

🌍

گرفتن داده از اینترنت با ESP32: HTTPClient، خواندن JSON از API و HTTPS

🧠

FreeRTOS و دو هسته‌ی ESP32: اجرای چند کار هم‌زمان با xTaskCreatePinnedToCore

🌈

نمایشگر OLED و نئوپیکسل با میکروپایتون روی رزبری پای پیکو

همه‌ی آموزش‌های ESP32 و اینترنت اشیا ← · همه‌ی مقاله‌ها