هنگامی که پروژه اینترنت اشیا شما با یک آداپتور دیواری تغذیه می شود، به مصرف انرژی خیلی اهمیت نمی دهید. اما اگر قصد دارید پروژه خود را از باتری تغذیه کنید، هر mA مهم است.
بسته به حالتی که در آن قرار دارد ESP32 میتواند یک دستگاه نسبتاً پر انرژی باشد. معمولاً برای عملکردهای عادی حدود 75 میلی آمپر و هنگام انتقال داده از طریق WiFi حدود 240 میلی آمپر مصرف میکند.
راه حل در اینجا کاهش مصرف برق ESP32 با استفاده از حالت خواب عمیق است.
برای کسب اطلاعات بیشتر در مورد سایر حالت های خواب ESP32 و مصرف انرژی آنها، لطفاً از آموزش زیر دیدن کنید.
ESP32 خواب عمیق
در حالت خواب عمیق، پردازندهها، بیشتر رم و تمام تجهیزات جانبی دیجیتال خاموش میشوند. تنها بخش هایی از تراشه که عملیاتی می شوند عبارتند از:
- پردازنده کمکی ULP
- کنترلر RTC
- لوازم جانبی RTC
- حافظه RTC سریع و کند
تراشه حدود 0.15 میلی آمپر (در صورت روشن بودن پردازنده کمکی ULP) تا 10 میکروآمپر مصرف می کند.
در حالت خواب عمیق، CPU اصلی خاموش میشود، در حالی که پردازنده کمکی UltraLowPower (ULP) میتواند قرائتهای سنسور را بگیرد و هر زمان که لازم باشد CPU را بیدار کند. این الگوی خواب به الگوی نظارت شده با حسگر ULP معروف است . این برای طراحی برنامه هایی مفید است که در آن CPU باید توسط یک رویداد خارجی یا تایمر یا ترکیبی از هر دو بیدار شود و در عین حال حداقل مصرف انرژی را حفظ کند.
همراه با CPU، حافظه اصلی تراشه نیز غیرفعال است. در نتیجه هر چیزی که در آن حافظه ذخیره شده است پاک می شود و قابل دسترسی نیست.
از آنجایی که حافظه RTC روشن است، محتویات آن حتی در هنگام خواب عمیق نیز حفظ می شود و پس از بیدار شدن تراشه قابل بازیابی است. به همین دلیل است که تراشه اطلاعات اتصال Wi-Fi و بلوتوث را قبل از وارد شدن به خواب عمیق در حافظه RTC ذخیره می کند.
اگر میخواهید پس از راهاندازی مجدد از دادهها استفاده کنید، با تعریف یک متغیر سراسری با RTC_DATA_ATTR
ویژگی، آن را در حافظه RTC ذخیره کنید. مثلا،RTC_DATA_ATTR int myVar = 0;
پس از خارج شدن از خواب عمیق تراشه با ریست مجدد راه اندازی می شود و اجرای برنامه را از ابتدا آغاز می کند.
ESP32 هنگام بیرون آمدن از خواب عمیق از اجرای یک بیدار خواب عمیق پشتیبانی می کند. این تابع بلافاصله به محض بیدار شدن تراشه اجرا می شود – قبل از اینکه هر گونه اولیه سازی معمولی، بوت لودر یا کد ESP-IDF اجرا شود. پس از اجرا شدن تراشه خرد، تراشه میتواند به حالت خواب برگردد یا به طور معمول به راهاندازی ESP-IDF ادامه دهد.
برخلاف سایر حالت های خواب، سیستم نمی تواند به طور خودکار به حالت خواب عمیق برود. این esp_deep_sleep_start()
تابع برای ورود به خواب عمیق بلافاصله پس از پیکربندی منابع بیدار شدن استفاده می شود.
ESP32 منابع بیداری خواب عمیق
ESP32 را می توان با استفاده از چندین منبع از حالت خواب عمیق بیدار کرد. این منابع عبارتند از:
- تایمر
- پد لمسی
- بیداری خارجی (ext0 و ext1)
چندین منبع بیدار کننده را می توان ترکیب کرد، در این صورت تراشه با فعال شدن یکی از منابع بیدار می شود.
هشدار:
امکان قرار دادن ESP32 در خواب عمیق بدون پیکربندی منابع بیدار شدن وجود دارد، در این صورت تراشه تا زمانی که یک تنظیم مجدد خارجی اعمال شود، به طور نامحدود در حالت خواب عمیق باقی می ماند.
ESP32 Wake-up منبع: تایمر
کنترلر ESP32 RTC دارای یک تایمر داخلی است که می توانید از آن برای بیدار کردن ESP32 پس از مدت زمان از پیش تعریف شده استفاده کنید.
این ویژگی مخصوصاً در پروژهای که نیاز به زمانبندی یا کارهای روزانه دارد و در عین حال مصرف انرژی پایینی دارد بسیار مفید است.
این esp_sleep_enable_timer_wakeup(time_in_us)
تابع برای پیکربندی تایمر به عنوان منبع بیدار شدن استفاده می شود. این تابع مقدار زمان را بر حسب میکروثانیه (μs) می پذیرد.
کد مثال
بیایید با استفاده از مثالی از کتابخانه ببینیم چگونه کار می کند. Arduino IDE خود را باز کنید و به File > Examples > ESP32 > Deep Sleep بروید و طرح TimerWakeUp را باز کنید .
این طرح ابتدایی ترین مثال خواب عمیق را با یک تایمر به عنوان منبع بیداری و نحوه ذخیره داده ها در حافظه RTC برای استفاده از آن پس از راه اندازی مجدد نشان می دهد.
#define uS_TO_S_FACTOR 1000000ULL /* 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");
Serial.flush();
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop(){
//This is not going to be called
}
هنگامی که طرح آپلود شد، مانیتور سریال خود را باز کنید، نرخ باود را روی 115200 bps تنظیم کنید.
ESP32 هر 5 ثانیه بیدار می شود، دلیل بیدار شدن و bootCount را روی مانیتور سریال چاپ می کند و دوباره به خواب عمیق می رود.
اکنون ESP32 را با فشار دادن دکمه EN مجدداً تنظیم کنید، باید bootCount را دوباره به 1 تنظیم کنید که نشان می دهد حافظه RTC کاملاً پاک شده است.
توضیح کد:
این دو خط اول کد، زمان خواب ESP32 را مشخص می کند.
این مثال از ضریب تبدیل از میکروثانیه به ثانیه استفاده می کند، بنابراین می توانید زمان خواب را بر حسب ثانیه در TIME_TO_SLEEP
متغیر تنظیم کنید. در اینجا ESP32 به مدت 5 ثانیه در حالت خواب عمیق قرار می گیرد.
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in seconds) */
همانطور که قبلاً مشخص شد، می توانید داده ها را در حافظه RTC ESP32 (8 کیلوبایت SRAM) ذخیره کنید که در طول خواب عمیق پاک نمی شود. با این حال، با تنظیم مجدد ESP32 پاک می شود.
برای ذخیره داده ها در حافظه RTC، فقط باید RTC_DATA_ATTR
قبل از تعریف یک متغیر، ویژگی را اضافه کنید. در این مثال bootCount
متغیر در حافظه RTC ذخیره می شود. شمارش خواهد شد که چند بار ESP32 از خواب عمیق بیدار شده است.
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;
}
}
در تنظیمات، ابتدا ارتباط سریال با رایانه شخصی را راه اندازی می کنیم.
Serial.begin(115200);
سپس این bootCount
متغیر یک عدد افزایش می یابد و در مانیتور سریال چاپ می شود تا تعداد دفعاتی که ESP32 از خواب عمیق بیدار شده است را نشان دهد.
++bootCount;
Serial.println("Boot number: " + String(bootCount));
سپس print_wakeup_reason()
تابع فراخوانی می شود، اما شما می توانید هر تابعی را که می خواهید برای انجام وظیفه مورد نظر فراخوانی کنید، مثلاً مقدار یک سنسور را بخوانید.
print_wakeup_reason();
سپس منبع بیدار شدن تایمر را با استفاده از esp_sleep_enable_timer_wakeup(time_in_us)
تابع پیکربندی می کنیم. در اینجا ESP32 تنظیم شده است که هر 5 ثانیه یکبار بیدار شود.
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
در نهایت ESP32 با فراخوانی esp_deep_sleep_start()
تابع به حالت Sleep قرار می گیرد.
esp_deep_sleep_start();
در این طرح ESP32 در خود تابع setup() وارد خواب عمیق می شود، بنابراین هرگز به تابع ()loop نمی رسد. بنابراین loop()
تابع خالی می ماند.
void loop(){
//This is not going to be called
}
منبع بیدار شدن ESP32: تاچ پد
با استفاده از پین های لمسی زیر می توانید ESP32 را از خواب عمیق بیدار کنید.
فعال کردن ESP32 برای بیدار شدن با استفاده از پین لمسی ساده است. در Arduino IDE فقط باید از esp_sleep_enable_touchpad_wakeup()
تابع استفاده کنید.
سیم کشی
بیایید یک کابل را به GPIO#15 (لمس شماره 3) سیم کشی کنیم که به عنوان منبع بیدارکننده لمسی عمل می کند. می توانید هر شی رسانایی مانند سیم، فویل آلومینیوم، پارچه رسانا، رنگ رسانا و غیره را به پین حساس به لمس وصل کنید و آن را به یک صفحه لمسی تبدیل کنید.
کد مثال
بیایید با استفاده از مثالی از کتابخانه ببینیم چگونه کار می کند. Arduino IDE خود را باز کنید و به File > Examples > ESP32 > Deep Sleep بروید و طرح TouchWakeUp را باز کنید .
این طرح ابتدایی ترین مثال خواب عمیق را با لمس به عنوان منبع بیداری و نحوه ذخیره داده ها در حافظه RTC برای استفاده از آن پس از راه اندازی مجدد نشان می دهد.
#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
}
هنگامی که طرح آپلود شد، مانیتور سریال خود را باز کنید، نرخ باود را روی 115200 bps تنظیم کنید.
اکنون هنگامی که پین لمس می شود، ESP32 تعداد بوت، دلیل بیدار شدن و اینکه کدام GPIO در مانیتور سریال لمس شده را نشان می دهد.
توضیح کد:
خط اول کد، مقدار آستانه را برای پین لمسی روی 40 تنظیم می کند. هر چه مقدار آستانه بالاتر باشد، حساسیت بالاتر است. شما می توانید این مقدار را با توجه به پروژه خود تغییر دهید.
#define Threshold 40 /* Greater the value, more the sensitivity */
همانطور که قبلاً مشخص شد، می توانید داده ها را در حافظه RTC ESP32 (8 کیلوبایت SRAM) ذخیره کنید که در طول خواب عمیق پاک نمی شود. با این حال، با تنظیم مجدد ESP32 پاک می شود.
برای ذخیره داده ها در حافظه RTC، فقط باید RTC_DATA_ATTR
قبل از تعریف یک متغیر، ویژگی را اضافه کنید. در این مثال bootCount
متغیر در حافظه RTC ذخیره می شود. شمارش خواهد شد که چند بار ESP32 از خواب عمیق بیدار شده است.
RTC_DATA_ATTR int bootCount = 0;
پس از این یک متغیر به نام touchPin
نوع touch_pad_t
(type enum) تعریف می شود که بعداً به ما کمک می کند تا GPIO را چاپ کنیم که توسط آن ESP32 از خواب بیدار می شود.
touch_pad_t touchPin;
در مرحله بعد، 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;
}
}
این print_wakeup_touchpad()
تابع همچنین تعریف شده است که شماره GPIO را که توسط آن ESP32 از خواب عمیق بیدار شده است را چاپ می کند.
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;
}
}
بعد یک callback()
تابع تعریف می شود. این چیزی نیست جز یک روال سرویس وقفه (ISR)، که هر بار که یک وقفه لمسی فعال می شود، فراخوانی می شود. اما متاسفانه اگر ESP32 در خواب عمیق باشد این تابع اجرا نمی شود. بنابراین این تابع خالی می ماند.
void callback(){
//placeholder callback function
}
در تنظیمات، ابتدا ارتباط سریال با رایانه شخصی را راه اندازی می کنیم.
Serial.begin(115200);
سپس این bootCount
متغیر یک عدد افزایش می یابد و در مانیتور سریال چاپ می شود تا تعداد دفعاتی که ESP32 از خواب عمیق بیدار شده است را نشان دهد.
++bootCount;
Serial.println("Boot number: " + String(bootCount));
سپس توابع print_wakeup_reason()
و print_wakeup_touchpad()
فراخوانی می شوند، اما شما می توانید هر تابعی را که می خواهید برای انجام وظیفه مورد نظر فراخوانی کنید، مثلاً مقدار یک سنسور را بخوانید.
print_wakeup_reason();
print_wakeup_touchpad();
اکنون وقفه باید به یکی از پایه های لمسی با آستانه حساسیت مورد نظر متصل شود. در اینجا وقفه به صفحه لمسی 3 (GPIO15) متصل است.
touchAttachInterrupt(T3, callback, Threshold);
سپس منبع بیدار شدن لمسی را با استفاده از esp_sleep_enable_touchpad_wakeup()
تابع پیکربندی می کنیم.
esp_sleep_enable_touchpad_wakeup();
در نهایت ESP32 با فراخوانی esp_deep_sleep_start()
تابع به حالت Sleep قرار می گیرد.
esp_deep_sleep_start();
در این طرح ESP32 وارد خواب عمیق در setup()
خود تابع می شود، بنابراین هرگز به loop()
عملکرد نمی رسد. بنابراین loop()
تابع خالی می ماند.
void loop(){
//This is not going to be called
}
ESP32 Wake-up منبع: External Wake-up
دو نوع محرک خارجی برای بیدار کردن ESP32 از خواب عمیق وجود دارد.
- ext0 – زمانی که می خواهید تراشه را فقط با یک پین خاص GPIO بیدار کنید از این استفاده کنید.
- ext1 – زمانی که می خواهید تراشه را با استفاده از چندین پین GPIO بیدار کنید از این استفاده کنید.
اگر می خواهید از یک پین وقفه برای بیدار کردن ESP32 از خواب عمیق استفاده کنید، باید از پین های RTC_GPIO استفاده کنید. این GPIO ها به زیرسیستم کم مصرف RTC هدایت می شوند تا زمانی که ESP32 در خواب عمیق است از آنها استفاده شود.
پین های RTC_GPIO عبارتند از:
ext0 منبع بیداری خارجی
ESP32 را می توان طوری پیکربندی کرد که وقتی یکی از پین های RTC_GPIO سطح منطقی خود را تغییر می دهد، از خواب عمیق بیدار شود.
این esp_sleep_enable_ext0_wakeup(GPIO_PIN, LOGIC_LEVEL)
تابع برای فعال کردن این منبع بیدار کردن استفاده می شود. این تابع دو پارامتر می گیرد. اولی شماره پین GPIO و دومی سطح منطقی (LOW یا HIGH) است که میخواهیم بیدار شدن را با آن فعال کنیم.
از آنجایی که ext0 از RTC IO برای بیدار کردن ESP32 استفاده می کند، تجهیزات جانبی RTC در طول خواب عمیق کار می کنند.
و از آنجایی که ماژول RTC IO فعال است، میتوانید از مقاومتهای کششی داخلی یا پایینکشی استفاده کنید. آنها باید با استفاده از توابع rtc_gpio_pullup_en()
و rtc_gpio_pulldown_en()
قبل از esp_deep_sleep_start()
فراخوانی پیکربندی شوند.
سیم کشی
بیایید یک دکمه فشاری را با استفاده از یک مقاومت کششی 10K به GPIO#33 سیم کشی کنیم.
کد مثال
بیایید با استفاده از مثالی از کتابخانه ببینیم چگونه کار می کند. Arduino IDE خود را باز کنید و به File > Examples > ESP32 > Deep Sleep بروید و طرح ExternalWakeUp را باز کنید .
این طرح ابتدایی ترین مثال خواب عمیق را با یک ext0 به عنوان منبع بیداری نشان می دهد.
#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");
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop(){
//This is not going to be called
}
هنگامی که طرح آپلود شد، مانیتور سریال خود را باز کنید، نرخ باود را روی 115200 bps تنظیم کنید.
اکنون هنگامی که دکمه فشاری را فشار می دهید، ESP32 تعداد بوت و دلیل بیدار شدن را در مانیتور سریال نمایش می دهد. چندین بار آن را امتحان کنید و با فشار دادن هر دکمه شاهد افزایش تعداد بوت باشید. همچنین توجه داشته باشید که ext0 از RTC IO برای بیدار کردن ESP32 استفاده می کند.
توضیح کد:
خط اول کد بیت ماسک را تنظیم می کند. برای بیدارسازی خارجی ext0 لازم نیست، بنابراین میتوانید فعلاً آن را نادیده بگیرید. ما در این مورد در طی توضیح کد بیداری خارجی ext1 یاد خواهیم گرفت.
#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex
همانطور که قبلاً مشخص شد، می توانید داده ها را در حافظه RTC ESP32 (8 کیلوبایت SRAM) ذخیره کنید که در طول خواب عمیق پاک نمی شود. با این حال، با تنظیم مجدد ESP32 پاک می شود.
برای ذخیره داده ها در حافظه RTC، فقط باید RTC_DATA_ATTR
قبل از تعریف یک متغیر، ویژگی را اضافه کنید. در این مثال bootCount
متغیر در حافظه RTC ذخیره می شود. شمارش خواهد شد که چند بار ESP32 از خواب عمیق بیدار شده است.
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;
}
}
در تنظیمات، ابتدا ارتباط سریال با رایانه شخصی را راه اندازی می کنیم.
Serial.begin(115200);
سپس این bootCount
متغیر یک عدد افزایش می یابد و در مانیتور سریال چاپ می شود تا تعداد دفعاتی که ESP32 از خواب عمیق بیدار شده است را نشان دهد.
++bootCount;
Serial.println("Boot number: " + String(bootCount));
سپس print_wakeup_reason()
تابع فراخوانی می شود، اما شما می توانید هر تابعی را که می خواهید برای انجام وظیفه مورد نظر فراخوانی کنید، مثلاً مقدار یک سنسور را بخوانید.
print_wakeup_reason();
اکنون منبع بیدارکننده خارجی ext0 با استفاده از esp_sleep_enable_ext0_wakeup(GPIO_PIN, LOGIC_LEVEL)
تابع پیکربندی شده است. این تابع دو پارامتر می گیرد. اولی شماره پین GPIO و دومی سطح منطقی (LOW یا HIGH) است که میخواهیم بیدار شدن را با آن فعال کنیم. در این مثال ESP32 طوری پیکربندی شده است که وقتی سطح منطقی GPIO#33 بالا میشود، بیدار شود.
esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1);
در نهایت ESP32 با فراخوانی esp_deep_sleep_start()
تابع به حالت Sleep قرار می گیرد.
esp_deep_sleep_start();
در این طرح ESP32 وارد خواب عمیق در setup()
خود تابع می شود، بنابراین هرگز به loop()
عملکرد نمی رسد. بنابراین loop()
تابع خالی می ماند.
void loop(){
//This is not going to be called
}
ext1 منبع بیداری خارجی
ESP32 را می توان برای بیدار شدن از خواب عمیق با استفاده از چندین پین پیکربندی کرد. به یاد داشته باشید که این پین ها باید در بین پین های RTC GPIO باشند.
از آنجایی که منبع بیدارکننده ext1 از یک کنترلر RTC استفاده می کند، نیازی به روشن شدن تجهیزات جانبی RTC و حافظه RTC ندارد. در این حالت مقاومت های کششی و کششی داخلی در دسترس نخواهند بود.
به منظور استفاده از مقاومتهای کششی یا کشویی داخلی، باید درخواست کنیم که لوازم جانبی RTC در حین خواب روشن بماند و مقاومتهای کشش/کشش را با استفاده از توابع rtc_gpio_pullup_en()
و rtc_gpio_pulldown_en()
قبل از ورود به حالت خواب پیکربندی کنیم.
این esp_sleep_enable_ext1_wakeup(BUTTON_PIN_MASK, LOGIC_LEVEL)
تابع برای فعال کردن این منبع بیدار کردن استفاده می شود. این تابع دو پارامتر می گیرد. اولی ماسک بیتی است که به ESP32 میگوید کدام پینها را میخواهیم استفاده کنیم و پارامتر دوم میتواند یکی از دو سطح منطقی ذکر شده در زیر برای فعال کردن بیدار شدن باشد:
ESP_EXT1_WAKEUP_ANY_HIGH
اگر یکی از پین های انتخابی HIGH ( ) باشد بیدار شویدESP_EXT1_WAKEUP_ALL_LOW
اگر همه پینهای انتخابشده کم باشند ( ) بیدار شوید
بیت ماسک
ساده ترین راه برای درک بیت ماسک نوشتن آن در قالب باینری است. می بینید که شماره گذاری بیت بر اساس شماره گذاری معمولی GPIO است. کمترین بیت (LSB) نشان دهنده GPIO#0 و مهم ترین بیت (MSB) نشان دهنده GPIO#39 است.
- 0 نشان دهنده پین های ماسک شده است
- 1 نشان دهنده پین هایی است که به عنوان منبع بیداری فعال می شوند
بنابراین اگر میخواهید یک GPIO را فعال کنید، باید یک عدد 1 در محل مربوطه و یک عدد 0 برای هر یک از پینهای باقیمانده بنویسید. و در نهایت باید آن را به HEX تبدیل کنید.
به عنوان مثال، اگر می خواهید از GPIO#32 و GPIO#33 به عنوان منابع بیدارکننده خارجی استفاده کنید، بیت ماسک به این صورت خواهد بود:
سیم کشی
بیایید دو دکمه فشاری را به GPIO#33 و GPIO#32 با استفاده از مقاومت های کششی 10K متصل کنیم.
کد مثال
بیایید ببینیم که چگونه با استفاده از همان مثال ExternalWakeUp از کتابخانه کار می کند. یک بار دیگر Arduino IDE خود را باز کنید و به File > Examples > ESP32 > Deep Sleep بروید و طرح ExternalWakeup را باز کنید .
بیایید سه تغییر در طرح ایجاد کنیم تا برای ما کار کند:
- ثابت BUTTON_PIN_BITMASK را تغییر دهید
- کد ext0 را کامنت کنید
- کد ext1 را از کامنت خارج کنید
تغییرات در طرح در برجسته شده استسبز.
#define BUTTON_PIN_BITMASK 0x300000000
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");
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop(){
//This is not going to be called
}
هنگامی که طرح آپلود شد، مانیتور سریال خود را باز کنید، نرخ باود را روی 115200 bps تنظیم کنید.
حالا وقتی دکمه فشاری را فشار دهید، چیزی مشابه در مانیتور سریال دریافت خواهید کرد. همچنین توجه داشته باشید که ext1 از کنترلر RTC برای بیدار کردن ESP32 استفاده می کند.
توضیح کد:
این کد به جز دو تغییر مشابه کد ext0 است.
در ابتدای کد، بیت ماسک تعریف شده است. از آنجایی که ما در مثال از پینهای GPIO#32 و GPIO#33 استفاده میکنیم، ماسک دارای 1 در موقعیتهای مربوطه است، با 32 0 در سمت راست و 6 0 در سمت چپ.
00000011 00000000 00000000 00000000 00000000 BIN = 0x300000000 HEX
#define BUTTON_PIN_BITMASK 0x300000000
و در نهایت ext1 به عنوان منبع بیدار شدن فعال می شود.
esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);
ترجمه از https://lastminuteengineers.com/esp32-deep-sleep-wakeup-sources/
آخرین دیدگاهها