راه اندازی بخش خواب عمیق ESP32

به نام خدا

به آموزش راه اندازی بخش خواب عمیق ESP32 خوش اومدید.

در این آموزش با هم روش راه اندازی بخش خواب عمیق ESP32 و راههای خارج کردن از این حالت رو یاد می گیریم. این روش ها شامل تایمر بیداری ، بیداری با پپین های لمسی و بیداری با سیگنال خارجی است.

آموزشمون رو به چهار بخش تقسیم می کنیم :

  1. آشنایی با حالت خواب عمیق
  2. تایمر بیداری
  3. بیداری با پین های لمسی
  4. بیداری با سیگنال خارجی

بخش اول : آشنایی با حالت خواب عمیق

ESP32 چهار حالت مختلف داره :

  • حالت فعال
  • حالت خواب مودم
  • حالت خواب ضعیف
  • حالت خواب عمیق
  • حالت بیهوشی (Hibernation)

مقایسه این پنج حالت رو در جدول های زیر ببینیم.

چرا حالت خواب عمیق تعریف شده؟

استفاده مداوم از باتری برای این ماژول ایده آل نیست و خیلی زود شارژ باتری تخلیه میشه. پس اگر از حالت خواب عمیق استفاده کنیم علاوه بر کم کردن توان مصرفی میشه مدت زمان بیشتری شارژ باتری رو نگه داشت.

حالت خواب دقیقا چه معنی داره ؟ یعنی تمام فعالیت هایی که در زمان اجرا توان بیشتری مصرف می کنن رو غیر فعال کنیم و فقط زمانی که برای عملیات مهمی نیاز باشه دوباره فعال میشن.

در حالت خواب عمیق کارهای مربوط به پردازنده و WIFI غیر فعال هستن و فقط عملیاتی که با وضعیت کم توان برای کمک پردازنده اجرا میشن فعالیت میکنن. حافظهRTC  (بخشی از حافظه SRAM که مربوط به کمک پردازنده و فعالیت های بلادرنگ پردازنده است و در حالت Standby فعال میشه) در این حالت فعاله بنابراین میتونیم برنامه هایی رو برای سنسورها و پریفرال ها و تایمرهای داخلی در کمک پردازنده نوشت و در این حافظه ذخیره کرد .

همچنین اگر بخوایم CPU رو در وضعیت توان مصرفی کم با دستورات خارجی ، تایمر و یا هر دو بیدار کنیم حالت خواب عمیق بسیار مفیده .   

پین های GPIO مربوط به RTC

در حالت خواب عمیق بعضی از پین های ESP32 از طریق کمک پردازنده به کار گرفته میشن. اسم این پین ها ، پین های GPIO و پین های لمسیه. در دیتا شیت ESP32 میتونید مشخصات این پین ها رو از اینجا بخونید.

در شکل زیر پین هایی که با مستطیل نارنجی مشخص شدند پین های  RTC-GPIO هستند.

برای بیدار کردن ESP32 از حالت خواب عمیق چه راه هایی وجود داره؟

  • با استفاده از تایمر
  • با پین های لمسی
  • با سیگنال خارجی
  • با کمک پردازنده (توضیح این مبحث تو این مقاله ارائه نمیشه)

برای بردن ESP32 به حالت خواب عمیق به این نکات باید توجه کنید:

  • تو مرحله اول باید مشخص کنید با چه روشی از حالت خواب در میاد ؟ میتونید یک یا ترکیبی از روش های گفته شده در پاراگراف قبل رو مد نظر قرار بدید.
  • مشخص کنید چه پریفرال هایی باید فعال و غیر فعال باشن (البته ب صورت پیش فرض ESP32 موارد غیر ضروری رو غیر فعال می کنه)
  • در نهایت ESP32 رو با دستور ()esp_deep_sleep_start به حالت خواب عمیق می برید.

راجع به روش های بیدار کردن ESP32 بیشتر بخونیم .

بخش دوم : تایمر بیداری

با تایمر در بازه های زمانی متفاوتی که از قبل مشخص میشه ESP32 از حالت خواب عمیق بیرون میاد. این گزینه برای مواردی که پروژه هایی کم توان باید به صورت روزانه و یا تو مقاطع زمانی مختلفی تسک هایی رو اجرا کنن استفاده میشه.

یک کنترلر داخلی مربوط به RTC در ESP32 این کار رو انجام میده.

این تایمر چطوری فعال میشه؟

فقط کافیه در ARDUINO IDE زمان های به خواب رفتن رو در دستور زیر مشخص کنید (با واحد میکرو ثانیه)

esp_sleep_enable_timer_wakeup(time_in_us)

بررسی یک مثال از مرحله شروع تا نوشتن کد :

محیط ARDUINO IDE و به ترتیب Files =>  Examples => ESP32  =>Deep Sleep  و گزینه TimerWake Up رو باز کنید.

/*
Simple Deep Sleep with Timer Wake Up
=====================================
ESP32 offers a deep sleep mode for effective power
saving as power is an important factor for IoT
applications. In this mode CPUs, most of the RAM,
and all the digital peripherals which are clocked
from APB_CLK are powered off. The only parts of
the chip which can still be powered on are:
RTC controller, RTC peripherals ,and RTC memories

This code displays the most basic deep sleep with
a timer to wake it up and how to store data in
RTC memory to use it over reboots

This code is under Public Domain License.

Author:
Pranav Cherukupalli <cherukupallip@gmail.com>
*/

#define uS_TO_S_FACTOR 1000000  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  5        /* Time ESP32 will go to sleep (in seconds) */

RTC_DATA_ATTR int bootCount = 0;

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

void setup(){
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  /*
  First we configure the wake up source
  We set our ESP32 to wake up every 5 seconds
  */
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
  " Seconds");

  /*
  Next we decide what all peripherals to shut down/keep on
  By default, ESP32 will automatically power down the peripherals
  not needed by the wakeup source, but if you want to be a poweruser
  this is for you. Read in detail at the API docs
  http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html
  Left the line commented as an example of how to configure peripherals.
  The line below turns off all RTC peripherals in deep sleep.
  */
  //esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
  //Serial.println("Configured all RTC Peripherals to be powered down in sleep");

  /*
  Now that we have setup a wake cause and if needed setup the
  peripherals state in deep sleep, we can now start going to
  deep sleep.
  In the case that no wake up sources were provided but deep
  sleep was started, it will sleep forever unless hardware
  reset occurs.
  */
  Serial.println("Going to sleep now");
  delay(1000);
  Serial.flush(); 
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This is not going to be called
}

بررسی کنیم که این کد چطور داره کار می کنه

در خط اول مشخص شده که چه مواردی در این حالت با تایمر غیر فعال میشن. مواردی که غیر فعال میشن شامل  CPU ، اکثر رم ها ، همه پریفرال هایی که با APB-CLK کلاک میشن هستند. فقط کنترلر RTC ، پریفرال های  RTC و حافظه های RTC فعال باقی میمونن.

مشخص کردن زمان خواب

با دو خط کد زیر این زمان مشخص شده.

#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */ 
#define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in seconds) */

تو این مثال زمان خواب  از میکرو ثانیه به ثانیه تبدیل و برابر با ۵ ثانیه تعریف شده. پس با دستور TIME_TO_SLEEP میشه این متغیر رو با واحد ثانیه تعریف کنیم.

ذخیره کردن اطلاعات در حافظه RTC

ESP32 یک حافظه SRAM 8KBبه اندازه در قسمت RTC (به نام حافظه سریع RTC) داره . داده ای که در این حافظه ذخیره میشه در حالت خواب عمیق هم حفظ میشه و از بین نمیره و فقط با زدن کلید ریست روی برد (کلید EN) پاک میشه.

برای ذخیره کردن اطلاعات تو این حافظه قبل از متغیر مورد نظر دستور RTC_DATA_ATTR رو بنویسید . تو مثال زیر متغیر bootCount ذخیره شده.

RTC_DATA_ATTR int bootCount = 0;

دلیل بیداری

در مرحله بعد با دستور ()print_wakeup_reason دلیل اینکه ESP32 از حالت خواب عمیق بیدار خارج شده اعلام میشه.

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason){
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

()The setup

کد رو باید در این دستور قرار بدید. در حالت خواب عمیق کد هیچ وقت به ()loop نمی رسه پس باید همه دستورات رو در ()setup نوشت. پس بخش ()loop خالیه چون کد در setup نوشته میشه.

تو این مثال با مقداردهی به ارتباط سریال با بادریت ۱۱۵۲۰۰ شروع میشه.

Serial.begin(115200);

در مرحله بعد کد، متغیر bootCount با هر بار بوت شدن برنامه یک واحد بیشتر میشه و در مانیتور سریال نمایش داده میشه.

++bootCount;
Serial.println("Boot number: " + String(bootCount));

سپس دستور print_wakeup_reason() فراخوانی میشه . اما هر تسک دیگه ای تو این مرحله می تونه فراخوانی بشه. مثلا تنظیم کنید که ESP32 هر روز مقدار یک سنسوری رو بخونه.

خب در مرحله بعد منبع بیداری با دستور زیر مشخص میشه:

esp_sleep_enable_timer_wakeup(time_in_us)

ورودی این دستور زمان در واحد میکروثانیه است.

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

بعد از اینکه همه تسک ها اجرا شد ESP با دستور زیر به حالت خواب میره :

esp_deep_sleep_start()

تست عملی مثال

کد رو در ESP32 آپلود کنید و مانیتور سریال رو در بادریت ۱۱۵۲۰۰ تنظیم کنید.

هر ۵ ثانیه یک بار ESP بیدار شده و پیامی رو در مانیتور نمایش داده و دوباره به حالت خواب میره.

هر باری که ESP بیدار میشه متغیر bootCount یک واحد اضافه میشه و یک پیامی شامل دلیل بیداری رو مثل شکل زیر نمایش میده :

اما اگر کلید EN رو بزنید متغیر bootCount مقدارش ۱ میشه! همچنین میتونید تنظیم کنید که با هر بار بیداری به جای نمایش دادن پیام یک تسکی رو اجرا کنه . تایمر بیداری برای تسک های روزانه و کم مصرف خیلی مفیده.

بخش سوم : بیداری با پین های لمسی

ESP32 رو با پین های لمسی هم میشه بیدار کرد.اما با چه روشی ؟ در ARDUINO IDE دستور زیر رو بنویسید :

esp_sleep_enable_touchpad_wakeup()

کد مربوط به پین های لمسی

محیط ARDUINO IDE و به ترتیب Files =>  Examples => ESP32  =>Deep Sleep  و گزینه TimerWake Up رو باز کنید .

/*
Deep Sleep with Touch Wake Up
=====================================
This code displays how to use deep sleep with
a touch as a wake up source and how to store data in
RTC memory to use it over reboots

This code is under Public Domain License.

Author:
Pranav Cherukupalli <cherukupallip@gmail.com>
*/

#define Threshold 40 /* Greater the value, more the sensitivity */

RTC_DATA_ATTR int bootCount = 0;
touch_pad_t touchPin;
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

/*
Method to print the touchpad by which ESP32
has been awaken from sleep
*/
void print_wakeup_touchpad(){
  touchPin = esp_sleep_get_touchpad_wakeup_status();

  switch(touchPin)
  {
    case 0  : Serial.println("Touch detected on GPIO 4"); break;
    case 1  : Serial.println("Touch detected on GPIO 0"); break;
    case 2  : Serial.println("Touch detected on GPIO 2"); break;
    case 3  : Serial.println("Touch detected on GPIO 15"); break;
    case 4  : Serial.println("Touch detected on GPIO 13"); break;
    case 5  : Serial.println("Touch detected on GPIO 12"); break;
    case 6  : Serial.println("Touch detected on GPIO 14"); break;
    case 7  : Serial.println("Touch detected on GPIO 27"); break;
    case 8  : Serial.println("Touch detected on GPIO 33"); break;
    case 9  : Serial.println("Touch detected on GPIO 32"); break;
    default : Serial.println("Wakeup not by touchpad"); break;
  }
}

void callback(){
  //placeholder callback function
}

void setup(){
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32 and touchpad too
  print_wakeup_reason();
  print_wakeup_touchpad();

  //Setup interrupt on Touch Pad 3 (GPIO15)
  touchAttachInterrupt(T3, callback, Threshold);

  //Configure Touchpad as wakeup source
  esp_sleep_enable_touchpad_wakeup();

  //Go to sleep now
  Serial.println("Going to sleep now");
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This will never be reached
}

تنظیم کردن حد آستانه

اولین قدم تعیین حد آستانه برای هر پین لمسیه . ما تو این مثال حد آستانه رو برابر با ۴۰ قرار دادیم اما به هر عدد دیگه ای قابل تغییر دادنه.

#define Threshold 40

وقتی که هر کدوم از این پین های لمسی ، لمس بشه مقدارش افزایش پیدا میکنه پس تو این مثال حد آستانه ۴۰ یعنی مقداری که توسط سنسور GPIO خونده میشه کتر از ۴۰ باشه، ESP32 باید بیدار بشه.

ضمیمه کردن وقفه

برای پین های لمسی باید وقفه تعریف بشه و زمانی که لمس کردنی روی یک  GPIOحس بشه یک دستور بازفراخوانی(callback) میشه. مثال:

//Setup interrupt on Touch Pad 3 (GPIO15)
touchAttachInterrupt(T3, callback, Threshold);

اگر مقداری که در T3 (GPIO15) خونده میشه از مقداری که در آستانه تعریف شده کمتر باشه ESP32 بیدار میشه و یک دستور بازفراخوانی و اجرا میشه. این دستور فقط زمانی اجرا میشه که ESP32 بیدار شده باشه.

  • اگر ESP32 در حالت خواب باشه و T3 رو لمس کنید، ESPبیدار میشه – اگر پین لمسی رو فشار داده و رها کنید دستور callback اجرا نمیشه.
  • اگر ESP32 در حالت بیدار باشه و T3 رو لمس کنید، دستور callback اجرا میشه– پس برای اجرا شدن این دستور باید پین رو با دست لمس کنید و تا زمان اجرا شدن دستور نگه دارید. تو این حالت دستور  callback خالیه :
void callback(){
   //placeholder callback function
}

اگر بخوایم ESP32 رو با پین های لمسی مختلفی بیدار کنیم کافیه به اون پین ها وقفه بدیم و بعد با دستور ()esp_sleep_enable_touchpad_wakeup رو اون پین ها رو تعیین کنیم.

//Configure Touchpad as wakeup source
esp_sleep_enable_touchpad_wakeup()

تست مدار

برای تست مدار شکل مطابق شکل زیر یک سیم به  GPIO15 وصل کنید و کد رو تو ESP32 آپلود کنید و مانیتور سریال رو در بادریت ۱۱۵۲۰۰ قرار بدید.

حالا ESP32 به حالت خواب عمیق میره و شما مثل شکل زیر با لمس پین لمسی شماره ۳، از حالت خواب عمیق خارجش کنید.

وقتی که پین لمس میشه پیام زیر در مانیتور نمایش داده میشه و شامل : شماره بوت ، دلیل بیداری و GPIO ای که در اون لمس تشخیص داده شده.

بخش چهارم : بیداری با سیگنال خارجی

خب در کنار روش های قبل که توضیح داده شد یک روش دیگه ای برای بیدار کردن  ESP32 وجود داره که با استفاده از سیگنالی خارجی انجام میشه . مثلا با زدن یک کلید. برای ایجاد سیگنال با این روش دو تا منبع میشه در نظر گرفت : ext0 و ext1 .

بیداری با سیگنال خارجی ext0

این منبع امکان بیداری با استفاده از یک پین رو میده . در واقع با پین های  RTC این کار رو امجام میده.پس اگر از این روش استفاده کنیم پریفرال های RTC در مدت خواب عمیق ESP32 باید فعال بمونن. این روش بیداری با دستور زیر قابل اجراست :

esp_sleep_enable_ext0_wakeup(GPIO_NUM_X, level)

ورودی اول این دستور پینی هست که معرفی میشه و  در واقع X شماره پینه. و ورودی دوم وضعیت GPIO ایه که محرک عمل بیدار کردنه . مقدارش هم ۰ و ۱ .

بیداری با سیگنال خارجی ext1

این منبع امکان بیداری با استفاده از چند پین رو میده و میشه حالت های منطقی متفاوتی در نظر گرفت :

  • بیدار کردن ESP32 در حالتی که همه پین های انتخابی در وضعیت  HIGHباشن.
  • بیدار کردن ESP32 در حالتی که همه پین های انتخابی در وضعیت  LOW باشن.

این روش با کنترلر RTC پیاده سازی میشه پس پریفرال ها و حافظه های RTC با این روش میتونن غیرفعال بمونن. این روش بیداری با دستور زیر قابل اجراست :

esp_sleep_enable_ext1_wakeup(bitmask, mode)

ورودی اول این دستور یک الگوی بیتی از شماره GPIO های مورد نظره و ورودی دوم حالته . این ورودی عدد منطقیه که برای بیدار کردن به کار گرفته میشه و شامل این دو حالته :

  • ESP_EXT1_WAKEUP_ALL_LOW : وقتی همه بین ها LOW باشن ESP32 بیدار میشه.
  • ESP_EXT1_WAKEUP_ANY_HIGH : وقتی هر کدوم از پین ها در وضعیت HIGH باشن ESP32 بیدار میشه.

نکته مهم  : با این دو روش فقط میشه از پین GPIO های  RTC استفاده کرد.

کد برنامه

یک مثال رو برای این روش با کتابخونه ESP32 بررسی کنیم.

Files =>  Examples => ESP32  =>Deep Sleep  => TimerWake Up .

/*
Deep Sleep with External Wake Up
=====================================
This code displays how to use deep sleep with
an external trigger as a wake up source and how
to store data in RTC memory to use it over reboots

This code is under Public Domain License.

Hardware Connections
======================
Push Button to GPIO 33 pulled down with a 10K Ohm
resistor

NOTE:
======
Only RTC IO can be used as a source for external wake
source. They are pins: 0,2,4,12-15,25-27,32-39.

Author:
Pranav Cherukupalli <cherukupallip@gmail.com>
*/

#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex

RTC_DATA_ATTR int bootCount = 0;

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

void setup(){
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  /*
  First we configure the wake up source
  We set our ESP32 to wake up for an external trigger.
  There are two types for ESP32, ext0 and ext1 .
  ext0 uses RTC_IO to wakeup thus requires RTC peripherals
  to be on while ext1 uses RTC Controller so doesnt need
  peripherals to be powered on.
  Note that using internal pullups/pulldowns also requires
  RTC peripherals to be turned on.
  */
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1); //1 = High, 0 = Low

  //If you were to use ext1, you would use it like
  //esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

  //Go to sleep now
  Serial.println("Going to sleep now");
  delay(1000);
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This is not going to be called
}

تو این مثال وقتی GPIO33 به وضعیت HIGH بره ESP32 بیدار میشه. این مثال از دو منبع ext0 و  ext1 استفاده شده. (ext1 به صورته کامنت شده است)

این روش هم مثل روش های قبلی با مقداردهی اولیه رابط سریال در ()setup شروع میشه:

Serial.begin(115200); 
delay(1000); //Take some time to open up the Serial Monitor

تو مرحله یک واحد به bootCount اضافه و در مانیتور نمایش داده میشه :

++bootCount;
Serial.println("Boot number: " + String(bootCount));

در خط بعد دلیل بیداری با دستور ()print_wakeup_reason نمایش داده میشه:

//Print the wakeup reason for ESP32
print_wakeup_reason();

حالا تو این مرحله باید منبع ext0 و یا ext1 بودن رو معین کنیم. هر دو رو به صورت جدا توضیح میدیم.

EXT0

تو این مثال زمانی که GPIO33 به وضعیت HIGH تغییر کنهESP32  بیدار میشه:

esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1); //1 = High, 0 = Low

شماتیک مدار

طبق شکل زیر یک کلید در مدار قرار بدید . این کلید به  GPIO33 (هر پین GPIO RTC دیگه ای میتونه جایگزین باشه) از طریق مقاومت پول دان ۱۰K اهم متصل شده.

تست مدار

دقیقا مثل مثال های قبل کد رو در ESP32 آپلود و تنظیمات مربوط به مانیتور رو انجام بدید. و کلید رو برای بیدار کردن ESP فشار بدید.

با تکرار چندین باره این کار میبینید که bootCount در حال افزایشه.

این روش برای اجرای یک تسک مناسبه اما اگر نیاز به اجرای چندین تسک باشه باید از منبع ext1 استفاده کنیم.

EXT1

اگر در نظر داشته باشیم که با کلیدهای مختلف و تسک های مختلف ESP32 رو بیدار کنیم باید از منبع ext1 کمک بگیریم.

به جای استفاده از دستور ()esp_sleep_enable_ext0_wakeup ، دستور ()esp_sleep_enable_ext1_wakeup رو جایگزین می کنیم.(این بخش رو در کد از حالت کامنت خارج کنید ). بنابراین به این شکل میشه :

esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

ورودی اول الگوی بیتی (توضیحات بیشتر در ادامه گفته میشه) از GPIOهاییه که استفاده می کنیم و اول کد مشخصشون کردیم.

#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex

تو این کد فقط GPIO33 تعیین شده . برای استفاده از GPIOهای بیشتر باید این کد رو دست کاری کنیم.

الگوی بیتی GPIO ها

خب برای اینکه این مبحث رو بهتر متوجه بشیم با یک مثال بررسی می کنیم. در کد مثال از GPIO33 استفاده شده . برای اینکه الگوی بیتی این پین رو محاسبه کنیم طبق مراحل زیر پیش میریم:

  • ۲^۳۳ رو محاسبه می کنیم . باید به مقدار ۸۵۸۹۹۳۴۵۹۲ برسیم.
  • این عدد (۸۵۸۹۹۳۴۵۹۲) رو به هگزادسیمال تبدیل می کنیم. از اینجا میتونید کمک بگیرید.
  • عدد هگز رو در متغیر BUTTON_PIN_BITMASK کپی کنید(طبق کد زیر):
#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex

الگوی بیتی برای چندین GPIO

مثلا اگر GPIO2 و GPIO15 منبع بیداری باشن طبق این مراحل محاسبه می کنیم :

  1. ۲^۲+۲^۱۵ رو محاسبه کنید (۳۲۷۷۲ به دست میاد)
  2. ۳۲۷۷۲ رو به هگز تبدیل کنید. حاصل میشه ۸۰۰۴.
  3. عدد هگز رو در متغیر BUTTON_PIN_BITMASK کپی کنید(طبق کد زیر):
#define BUTTON_PIN_BITMASK 0x8004

شناسایی GPIO هایی که مورد استفاده در بیداری

وقتی از چند پین استفاده می کنیم باید بدونیم کدوم پین باعث ایجاد بیداری ESP32 میشه. از دستور زیر برای این کار استفاده  می کنیم :

esp_sleep_get_ext1_wakeup_status()

با این دستور به عددی در مبنای ۲ با توان شماره پین GPIO میرسیم.(شماره پین GPIO)^2 .برای تبدیل این عدد به دسیمال هم از دستور زیر کمک می گیریم :

GPIO = log(GPIO_NUMBER)/log(2)

بیداری با سیگنال خارجی- چندین GPIO

خب با مطالبی که گفته شد دیگه میتونیم مثالی رو برای بیداری  ESP32 با چندین کلید و با استفاده از چند GPIO انجام بدیم. همچنین میتونیم منبع بیداری رو مشخص کنیم که کدئم GPIO بوده. تو این مثال ما GPIO2 و GPIO15رو استفاده کردیم.

شماتیک مدار رو طبق شکل زیر ببندید. دو کلید رو به دو پین گفته شده متصل کنید.

کد برنامه

کافیه کد مثال قبل رو تغییراتی بدیم :

یک الگوی بیتی برای GPIO2 و GPIO15بنویسید. Ext1 رو به عنوان منبع ورودی فعال کنید.با دستور esp_sleep_get_ext1_wakeup_status() پین GPIO رو فعال کنید. کد در نهایت به صورت زیر میشه :

/*
Deep Sleep with External Wake Up
=====================================
This code displays how to use deep sleep with
an external trigger as a wake up source and how
to store data in RTC memory to use it over reboots

This code is under Public Domain License.

Hardware Connections
======================
Push Button to GPIO 33 pulled down with a 10K Ohm
resistor

NOTE:
======
Only RTC IO can be used as a source for external wake
source. They are pins: 0,2,4,12-15,25-27,32-39.

Author:
Pranav Cherukupalli <cherukupallip@gmail.com>
*/

#define BUTTON_PIN_BITMASK 0x8004 // GPIOs 2 and 15

RTC_DATA_ATTR int bootCount = 0;

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

/*
Method to print the GPIO that triggered the wakeup
*/
void print_GPIO_wake_up(){
  uint64_t GPIO_reason = esp_sleep_get_ext1_wakeup_status();
  Serial.print("GPIO that triggered the wake up: GPIO ");
  Serial.println((log(GPIO_reason))/log(2), 0);
}
  
void setup(){
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  //Print the GPIO used to wake up
  print_GPIO_wake_up();

  /*
  First we configure the wake up source
  We set our ESP32 to wake up for an external trigger.
  There are two types for ESP32, ext0 and ext1 .
  ext0 uses RTC_IO to wakeup thus requires RTC peripherals
  to be on while ext1 uses RTC Controller so doesnt need
  peripherals to be powered on.
  Note that using internal pullups/pulldowns also requires
  RTC peripherals to be turned on.
  */
  //esp_deep_sleep_enable_ext0_wakeup(GPIO_NUM_15,1); //1 = High, 0 = Low

  //If you were to use ext1, you would use it like
  esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

  //Go to sleep now
  Serial.println("Going to sleep now");
  delay(1000);
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This is not going to be called
}

در ابتدای کد الگوی بیتی مشخص میشه :

#define BUTTON_PIN_BITMASK 0x8004 // GPIOs 2 and 15

در خط های بعدی GPIO هایی که باعث بیداری شدند اعلام میشه :

void print_GPIO_wake_up(){
  int GPIO_reason = esp_sleep_get_ext1_wakeup_status();
  Serial.print("GPIO that triggered the wake up: GPIO ");
  Serial.println((log(GPIO_reason))/log(2), 0);
}

و در نهایت ext1 برای بیدار کردن ESP32 استفاده میشه.

esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

تست مدار

کد رو در ESP32 آپلود کنید . همینطور که در شکل زیر میبینید ESP32 الان در حالت خواب عمیقه و با زدن هر کدوم از کلیدها بیدار میشه.

مانیتور سریال رو مثل مراحل قبل تنظیم کنید. با زدن هر کدوم از کلیدها ESP32 از خواب عمیق خارج میشه و پیامی شبیه شکل زور در مانیتور نمایش داده میشه.

پایان آموزش راه اندازی بخش خواب عمیق ESP32.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

قبلا حساب کاربری ایجاد کرده اید؟
گذرواژه خود را فراموش کرده اید؟
Loading...