Cách bật chế độ Deep Sleep ESP32 trên Arduino IDE

Trong bài viết này, IoTZone sẽ hướng dẫn chi tiết về chế độ Deep Sleep ESP32, bao gồm cách bật và tắt chế độ này. Để dễ theo dõi, mình sẽ chia bài viết thành 4 phần khác nhau như mục lục bên dưới:

Tìm hiểu về Deep Sleep ESP32

Deep Sleep là gì?

ESP32 có thể tự do chuyển đổi giữa 5 chế độ khác nhau, mỗi chế độ có mức tiêu thụ điện năng khác nhau:

  • Chế độ hoạt động bình thường
  • Chế độ Modem Sleep
  • Chế độ Light Sleep
  • Chế độ Deep Sleep
  • Chế độ Hibernation

Nhà phát triển ESP32 (Espressif) đã cung cấp bảng so sánh mức tiêu thụ của từng chế độ, cũng như trạng thái bật / tắt của từng chip trên mạch như sau:

Trạng thái bật tắt của từng chip ở chế dộ Deep Sleep ESP32
Trạng thái bật tắt của từng chip
Mức độ tiêu thụ điện năng của chế độ Deep Sleep ESP32
Mức độ tiêu thụ điện năng của chế độ Deep Sleep ESP32

Vai trò của chế độ Deep Sleep

Nếu để ESP32 ở chế độ hoạt động liên tục thì sẽ không ổn cho lắm, vì nó sẽ làm ESP32 bị hết pin rất nhanh. Ngược lại, khi cho ESP32 ở chế độ Deep Sleep, thì mức điện năng tiêu thụ sẽ thấp hơn nhiều và pin hoạt động lâu hơn.

Nói ngắn gọn, Deep Sleep là chế độ lược bỏ các hoạt động tiêu thụ nhiều năng lượng, chỉ giữ lại một số hoạt động vừa đủ để có thể đánh thức mạch ESP32 hoạt động trở lại khi có vấn đề gì xảy ra.

Ở chế độ Deep Sleep ESP32, cả WiFi và CPU đều không hoạt động, nhưng bộ ULP (bộ đồng xử lý nguồn điện thấp) vẫn hoạt động. Khi đó, chúng ta có thể viết chương trình cho ULP và lưu trữ trong bộ nhớ RTC, để truy cập vào các module ngoại vi, bộ hẹn giờ hoặc cảm biến bên trong.

Với chế độ này, bạn có thể đánh thức mạch ESP32 bằng một sự kiện nào đó, hoặc bằng bộ hẹn giờ Timer hoặc thậm chí là cả 2, nhưng vẫn đảm bảo lượng điện năng tiêu thụ ở mức thấp nhất.

Chân RTC_GPIO

Ở chế độ Deep Sleep ESP32, một số chân GPIO sẽ được ULP sử dụng, bao gồm chân Touch và chân RTC_GPIO. Bạn có thể xem sơ đồ chân của mạch ESP32 mình đang dùng để xác định vị trí của chân RTC này.

Chân RTC_GPIO dùng trong chế độ Deep Sleep ESP32

Cách đánh thức mạch khỏi chế độ Deep Sleep ESP32

Bạn có thể sử dụng một số cách bên dưới để đánh thức mạch ESP32:

  • Sử dụng bộ hẹn giờ, để gọi ESP32 thức dậy sau một khoảng thời gian xác định
  • Sử dụng chân cảm ứng
  • Đánh thức ESP32 bằng tác động bên ngoài
  • Sử dụng bộ đồng xử lý ULP (trong bài hướng dẫn này thì mình không đề cập phần này)

Tuy nhiên, khi viết code để bật chế độ Deep Sleep ESP32 rồi đánh thức nó dậy khỏi chế độ này, bạn cần lưu ý:

  • Cấu hình các nguồn đánh thức, bằng 1 trong 4 cách trên mình đã đề cập
  • Quyết định thiết bị ngoại vi nào được bật, thiết bị nào được tắt trong chế độ Deep Sleep ESP32. Tuy nhiên, ở trạng thái mặc định thì ESP32 sẽ tự tắt các ngoại vi không cần thiết dựa trên nguồn đánh thức mà bạn chọn.
  • Sử dụng cú pháp esp_deep_sleep_start() để đưa ESP32 vào chế độ Deep Sleep
Cách đánh thức mạch khỏi chế độ Deep Sleep ESP32

Để đánh thức ESP32, bạn có thể sử dụng câu lệnh sau:

esp_sleep_enable_timer_wakeup(time_in_us)

Cách bật Deep Sleep ESP32 bằng bộ hẹn giờ Timer

Bạn có thể mở ví dụ có sẵn trong thư viện của Arduino IDE, bằng cách click theo thứ tự sau File >> Examples >> ESP32 >> Deep Sleep và chọn vào sketch TimerWakeUp:

=====================================
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
}

Cùng xem qua chương trình trên, dòng đầu tiên sẽ mô tả những thiết bị ngoại vi bị tắt khi bật chế độ Deep Sleep ESP32, và sử dụng chế độ hẹn giờ để đánh thức mạch:

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

Khi chúng ta sử dụng chức năng hẹn giờ, các ngoại vi được bật là bộ điều khiển RTC, ngoại vi RTC và bộ nhớ RTC.

Giải thích chương trình

Dưới đây, mình sẽ giải thích chi tiết chương trình trên:

1. Khai báo thời gian Sleep

Xác định khoảng thời gian mà ESP32 ở trong chế độ ngủ:

#define uS_TO_S_FACTOR 1000000 /* Đổi micro giây sang giây */ 
#define TIME_TO_SLEEP 5 /* Thời gian mà ESP32 ở trong chế độ Deep Sleep */

Trong ví dụ trên, mình đã chuyển đổi đơn vị từ micro giây sang giây để bạn dễ hình dung. Cụ thể, ESP32 sẽ ở trong chế độ Deep Sleep trong vòng 5 giây.

2. Lưu dữ liệu trong bộ nhớ RTV

Ở chế độ Deep Sleep ESP32, chúng ta có thể lưu dữ liệu vào bộ nhớ RTC. Trong ESP32 có bộ nhớ SRAM 8kB ở mục RTC, còn được gọi là bộ nhớ nhanh RTC. Trong chế độ Deep Sleep ESP32 thì vùng dữ liệu này không bị xóa, tuy nhiên nếu bạn nhấn nút reset (RST) thì chúng sẽ bị xóa.

Để lưu trữ dữ liệu trong bộ nhớ RTC, bạn cần thêm RTC_DATA_ATTR trước định nghĩa biến. Ví dụ, mình cần lưu biến bootCount vào bộ nhớ RTC, biến này giúp đếm ESP32 đã thức dậy bao nhiêu lần từ chế độ Deep Sleep:

RTC_DATA_ATTR int bootCount = 0;

3. Lý do mạch ESP32 bị đánh thức

Đoạn code giúp in ra lý do tại sao ESP32 lại bị đánh thức khỏi chế độ Deep 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;
  }
}

4. Setup ()

Trong chế độ Deep Sleep ESP32, chúng ta chỉ viết code trong phần setup() chứ không cần viết code trong mục loop().

Đầu tiên, bạn cần bật Serial ở tốc độ 115200:

Serial.begin(115200);

Sau đó, biến bootCount sẽ tăng thêm 1 sau mỗi lần ESP32 thức dậy:

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

Sau đó, trong code chúng ta gọi hàm print_wakeup_reason(). Tuy nhiên, bạn có thể gọi bất kỳ hàm nào mình cần để làm một tác vụ nào đó mình muốn. Ví dụ, đánh thức ESP32 mỗi ngày một lần để đọc thông tin mà cảm biến đọc được.

Gọi hàm đánh thức ESP32:

esp_sleep_enable_timer_wakeup(time_in_us)

Time_in_us là thời gian ngủ của ESP32 (tính bằng micro giây).

Trong ví dụ của mình, thì mình có các hoạt động như sau:

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

Khi tất cả các tác vụ được thực hiện, phần code sẽ chuyển sang chế độ Deep Sleep ESP32 bằng cách gọi hàm:

esp_deep_sleep_start()

Nạp code và kiểm tra

Bây giờ, bạn hãy nạp code trên vào mạch ESP32 và xem kết quả nhé!

Sau khi nạp code, bạn hãy mở Serial Monitor ở tốc độ 115200.

Cứ mỗi 5 giây, mạch ESP32 sẽ thức dậy một lần và in thông báo lên Serial Monitor, sau đó lại chìm vào chế độ Deep Sleep.

Mỗi khi ESP32 thức dậy, chúng sẽ in ra lý do đánh thức như hình dưới:

Chương trình bật chế độ Deep Sleep ESP32

Tuy nhiên, nếu bạn nhấn vào nút RST trên ESP32 thì số Boot number sẽ quay lại thành số 1.

Bạn có thể tự do điều chỉnh con số này, ví dụ thay vì in số đếm ra Serial Monitor thì bạn thực hiện một nhiệm vụ nào khác.

Cách bật Deep Sleep ESP32 bằng bộ Touch

Bạn có thể đánh thức ESP32 bằng các chân Touch (chân cảm ứng). Mình sẽ hướng dẫn chi tiết:

Kích hoạt Touch

Việc kích hoạt chân Touch để đánh thức ESP32 bằng câu lệnh sau:

esp_sleep_enable_touchpad_wakeup()

Code

Tương tự như phần trên, bạn click vào File Examples ESP32 Deep Sleep và mở chương trình TouchWakeUp như sau:

/*
  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
  ESP32 can have multiple touch pads enabled as wakeup source
  ESP32-S2 and ESP32-S3 supports only 1 touch pad as wakeup source enabled
  This code is under Public Domain License. Author: Pranav Cherukupalli <cherukupallip@gmail.com>
*/

#if CONFIG_IDF_TARGET_ESP32
  #define THRESHOLD   40      /* Greater the value, more the sensitivity */
#else //ESP32-S2 and ESP32-S3 + default for other chips (to be adjusted) */
  #define THRESHOLD   5000   /* Lower the value, more the sensitivity */
#endif

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();

  #if CONFIG_IDF_TARGET_ESP32
    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;
    }
  #else
    if(touchPin < TOUCH_PAD_MAX)
    {
      Serial.printf("Touch detected on GPIO %d\n", touchPin); 
    }
    else
    {
      Serial.println("Wakeup not by touchpad");
    }
  #endif
}

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();

  #if CONFIG_IDF_TARGET_ESP32 
  //Setup sleep wakeup on Touch Pad 3 + 7 (GPIO15 + GPIO 27) 
  touchSleepWakeUpEnable(T3,THRESHOLD);
  touchSleepWakeUpEnable(T7,THRESHOLD);
  
  #else //ESP32-S2 + ESP32-S3
  //Setup sleep wakeup on Touch Pad 3 (GPIO3) 
  touchSleepWakeUpEnable(T3,THRESHOLD);

  #endif

  //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
}

Giải thích chương trình

1. Đặt ngưỡng

Đặt giá trị ngưỡng cho các chân Touch, mình đang thiết lập ở mức 40. Bạn có thể thay đổi tùy thích:

#define Threshold 40

Khi chạm vào chân GPIO Touch, giá trị mà chân Touch đọc được sẽ giảm. Khi đó, bạn có thể đặt giá trị ngưỡng để ESP32 phát hiện chân Touch được chạm.

Nói cách khác, giá trị ngưỡng ở đây tương ứng với độ nhạy bạn muốn.

2. Gắn các ngắt vào chân Touch

Khi phát hiện chân Touch GPIO được chạm, chương trình sẽ thực thi hàm callback:

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

Vụ thể, khi giá trị đọc được trên chân Touch Pad 3 (GPIO 15) thấp hơn giá trị ngưỡng vừa đặt, mạch ESP32 sẽ thức dậy và thực thi hàm callback.

Lưu ý:

  • Khi ESP32 trong chế độ Deep Sleep và bạn chạm vào Touch Pad 3, ESP32 sẽ thức dậy. Nhưng nếu bạn chỉ nhấn và thả chân Touch ngay lập tức thì hàm callback không được thực thi.
  • Khi ESP32 đang thức và bạn chạm vào chân Touch Pad 3, hàm callback sẽ được thực thi. Nếu bạn muốn thực hiện callback khi đánh thức ESP32, bạn cần nhấn giữ chân Touch một lúc cho đến khi chức năng được thực thi.

Chức năng callback đang trống:

void callback(){
   //placeholder callback function
}

Nếu muốn đánh thức ESP32 bằng các chân Touch, bạn cần gắn các ngắt vào những chân đó.

Sử dụng Esp_sleep_enable_touchpad_wakeup() để đặt các chân Touch làm nguồn đánh thức.

//Configure Touchpad as wakeup source
esp_sleep_enable_touchpad_wakeup()

Sơ đồ kết nối

Nối dây cáp GPIO 15 như sơ đồ dây:

Sơ đồ kết nối bật chế độ Deep Sleep ESP32
Sơ đồ kết nối bật chế độ Deep Sleep ESP32

Nạp code và kiểm tra

Nạp code vào ESP32, bật Serial Monitor ở chế đọ 115200.

ESP32 ở chế độ Deep Sleep, bạn chạm tay vào chân Touch 3 để đánh thức:

Nạp code và kiểm tra Deep Sleep ESP32
Nạp code và kiểm tra Deep Sleep ESP32

Khi đó, ESP32 sẽ hiển thị trên Serial Monitor:

Nạp code và kiểm tra Deep Sleep ESP32
Nạp code và kiểm tra Deep Sleep ESP32

Lời kết

Trên đây, IoTZone đã giới thiệu đến bạn cách bật chế độ Deep Sleep ESP32 và đánh thức mạch khỏi trạng thái này. Có nhiều cách khác nhau để thực hiện, bạn có thể chọn bất kỳ cách thức nào mình thích. Chúc các bạn thành công.

Bạn có thể xem hướng dẫn cách bật chế độ Deep Sleep bằng yếu tố bên ngoài ở phần 2: Bật ESP32 Deep Sleep và cách đánh thức bằng yếu tố bên ngoài [Phần 2]

IoTZone – Chuyên cung cấp thiết bị điện tử & tài liệu cho Makers

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *