DeepSleep深度睡眠的實驗


為什麼要讓ESP32進入深度睡眠模式?

其實我也是最近剛學到這一塊,所以就順手紀錄下來。

記得以前做過一些要電池的成品,發現放一天半左右就

沒電了,後來網路上搜尋相關知識才知道Arduino和esp32

它們都有使其進入深度睡眠的方法。

在深度睡眠中,可以使機板降低功耗,CPU和WIFI都會

_停止運作,只有ULP還會以最低功耗運作,雖然 ESP32 _

處於深度睡眠模式,但 RTC 記憶體也仍然處於打開狀態,

因此我們可以為 ULP 共同處理器編寫一個程式,並將其

存儲在 RTC 記憶體中以訪問週邊設備、內部定時器和內

部感測器。

RTC引腳

下圖黃色區塊的都可以使用RTC


喚醒模式

主要有種喚醒模式

  1. 定時器喚醒
  2. 觸摸喚醒
  3. 外部喚醒/多種不同的外部喚醒
  4. ULP喚醒

1.定時器喚醒模式實驗

ESP32可進入深睡模式,並預設時間喚醒


#define us_to_s 1000000

#define time__to_sleep 5

  

RTC_DATA_ATTR int count = 0;

  

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

  ++count;

  Serial.println("boot num: " + String(count));

  print_wakeup_reason();

  esp_sleep_enable_timer_wakeup(us_to_s * time_to_sleep);

  delay(1000);

  esp_deep_sleep_start();

}


void loop(){

}

一開始設定微秒轉成秒,也可以以直接寫成TIME_TO_SLEEP  5000000

#define us_TO_s 1000000
#define TIME_TO_SLEEP  5   

這一段是說要在RTC上保存喚醒的次數,可以在最前面加上RTC_DATA_ATTR

**_但是在按下EN鍵重啓這個數據會流失掉_*

RTC_DATA_ATTR int count = 0;

這個函式主要是設定”被換醒的原因”

rst:0x5 (DEEPSLEEP_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)

configsip: 0, SPIWP:0xee

clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00

mode:DIO, clock div:2

load:0x3fff0018,len:4

load:0x3fff001c,len:1044

load:0x40078000,len:10124

load:0x40080400,len:5828

entry 0x400806a8

boot num: 2

Wakeup caused by timer

ets Jun  8 2016 00:22:57

  

rst:0x5 (DEEPSLEEP_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)

configsip: 0, SPIWP:0xee

clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00

mode:DIO, clock div:2

load:0x3fff0018,len:4

load:0x3fff001c,len:1044

load:0x40078000,len:10124

load:0x40080400,len:5828

entry 0x400806a8

boot num: 3

Wakeup caused by timer

ets Jun  8 2016 00:22:57

  

rst:0x5 (DEEPSLEEP\_RESET),boot:0x17 (SPI\_FAST\_FLASH\_BOOT)

configsip: 0, SPIWP:0xee

clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00

mode:DIO, clock div:2

load:0x3fff0018,len:4

load:0x3fff001c,len:1044

load:0x40078000,len:10124

load:0x40080400,len:5828

entry 0x400806a8

boot num: 4

Wakeup caused by timer

ets Jun  8 2016 00:22:57

進入到void setup(){}

設定序列埠的波特率

Serial.begin(115200);

每次被喚醒,count就會加1,並被印出來

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

調用剛最前方那個被喚醒的原因函式

print_wakeup_reason()

啓用幾秒後,調用睡眠模式的函式

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

esp_deep_sleep_start()

實驗結果

紅色字體是指進入深睡模式

土黃色字體是指被喚醒的次數

深藍色字體是被喚醒的原因

rst:0x5 (DEEPSLEEP\_RESET),boot:0x17 (SPI\_FAST\_FLASH\_BOOT)

configsip: 0, SPIWP:0xee

clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00

mode:DIO, clock div:2

load:0x3fff0018,len:4

load:0x3fff001c,len:1044

load:0x40078000,len:10124

load:0x40080400,len:5828

entry 0x400806a8

boot num: 2

Wakeup caused by timer

ets Jun  8 2016 00:22:57

  

rst:0x5 (DEEPSLEEP\_RESET),boot:0x17 (SPI\_FAST\_FLASH\_BOOT)

configsip: 0, SPIWP:0xee

clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00

mode:DIO, clock div:2

load:0x3fff0018,len:4

load:0x3fff001c,len:1044

load:0x40078000,len:10124

load:0x40080400,len:5828

entry 0x400806a8

boot num: 3

Wakeup caused by timer

ets Jun  8 2016 00:22:57

  

rst:0x5 (DEEPSLEEP\_RESET),boot:0x17 (SPI\_FAST\_FLASH\_BOOT)

configsip: 0, SPIWP:0xee

clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00

mode:DIO, clock div:2

load:0x3fff0018,len:4

load:0x3fff001c,len:1044

load:0x40078000,len:10124

load:0x40080400,len:5828

entry 0x400806a8

boot num: 4

Wakeup caused by timer

ets Jun  8 2016 00:22:57

2.觸摸喚醒實驗

後來我發現來在Arduino IDE裡切換到ESP32的模式下,範例裡就有DEEP SLEEP的範例可用

將範例載入後,上傳。


#define Threshold 40 

RTC_DATA_ATTR int bootCount = 0;

touch_pad_t touchPin;


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

}

void setup(){
  Serial.begin(115200)
  delay(1000); 

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

  print_wakeup_reason();
  print_wakeup_touchpad();

  touchAttachInterrupt(T4, callback, Threshold);

  esp_sleep_enable_touchpad_wakeup();

  Serial.println("Going to sleep now");

  esp_deep_sleep_start();

  Serial.println("This will never be printed");

}

void loop(){

}

程式碼裡面這個是給予觸摸觸發的值

#define Threshold   40

當在觸摸引腳上讀取的值低於 Threshold 變量上設置的值時,ESP32 喚醒並執行回調函數。
Callback() 函數只有在 ESP32 處於喚醒狀態時才會執行。

所以如果是在喚醒的狀態下壓著觸摸腳不放開,並不會執行callback()回調。

如果是在睡眠狀態下碰了一下引腳馬上放開,這樣也不會執行callback()回調。

touchAttachInterrupt(T3, callback, Threshold); 

callback() 函數是空的

void  callback(){   //placeholder callback function   }

接下來,使用 esp_sleep_enable_touchpad_wakeup() 函數將觸摸引腳設置為喚醒源。

esp_sleep_enable_touchpad_wakeup()


3.外部喚醒 (ext0)

要使用此喚醒,請使用以下函數:

Esp_sleep_enable_ext0_wakeup(GPIO_NUM_X,level)
此函數接受您要使用的引腳作為第一個參數,格式為 GPIO_NUM_X,其中 X 表示該引腳的 GPIO 編號。

第二個參數 level 可以是 1 或 0。這表示將觸發喚醒的 GPIO 狀態。

注意:使用此喚醒,只能使用 RTC 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 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
> 
> }

在這個例子中,我們使用了在代碼開頭定義的變量 BUTTON_PIN_BITMASK:

#define   BUTTON\_PIN\_BITMASK   0x200000000 // 2^33 in hex

按鈕連接到 GPIO 33。要獲取 GPIO 33 的十六進位碼:

計算 2的33次方,應該得到 8589934592,將該數字 (8589934592) 轉換為十六進制。您可以轉到此轉換器來執行此操作。

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

#可以使用任何其他 RTC GPIO 引腳來代替 GPIO 33


4.外部喚醒 (ext1)

在這裡不使用esp_sleep_enable_ext0_wakeup(),而是使用

esp_sleep_enable_ext1_wakeup()
```c#
/*

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

}

0x8004怎麼來的?

計算 2^2 + 2^15。你應該得到 32772

將該數字轉換為十六進制。你應該得到:8004

在這個例子中,我們使用了在代碼開頭定義的變量 BUTTON_PIN_BITMASK

#define BUTTON_PIN_BITMASK   0x8004

當您使用多個引腳來喚醒 ESP32 時,知道是哪個引腳引起了喚醒是很有用的。為此,您可以使用以下功能:

esp_sleep_get_ext1_wakeup_status()

該函數返回一個基數2,與GPIO號碼作為指數:2 ^(GPIO_NUMBER)。因此,在小數得到GPIO,你需要做以下計算:

GPIO = log(GPIO_NUMBER)/log(2)

其它程式碼如同前面試驗

將程式碼上傳後可以看到按壓哪個GPIO會顯示在監測窗口


文章作者: blairan
版權聲明: 本博客所有文章除特別聲明外,均採用 CC BY 4.0 許可協議。轉載請註明來源 blairan !
评论
  目錄