一. 關(guān)于UPL協(xié)處理器的概念
ESP32 有強(qiáng)大的超低功耗協(xié)處理器 (ULP co-processor)
ULP 協(xié)處理器是一個功耗極低的協(xié)處理器設(shè)備,無論主 CPU 是處于正常運(yùn)行模式還是 Deep-sleep 模式纵揍,ULP 協(xié)處理器都可以獨(dú)立運(yùn)行携狭。超低功耗協(xié)處理器的補(bǔ)充使得 ESP32 能夠勝任一些對低功耗要求較高的應(yīng)用場合辱士。
ULP 協(xié)處理器的主要特性有:
采用 8 MHz 頻率和 8 KB 內(nèi)存
內(nèi)建 ADC 和 I2C 接口
支持正常模式和 Deep-sleep 模式
可喚醒主 CPU 或向主 CPU 發(fā)送中斷
能夠訪問主 CPU 的外圍設(shè)備、內(nèi)部傳感器及 RTC 寄存器
鑒于以上的特性耀里,ULP 協(xié)處理器能夠在消耗較低電流的情況下筒捺,完成 ADC 采樣,進(jìn)行 I2C Sensor 的讀寫势就,驅(qū)動 RTC GPIO 口動作泉瞻,可以在某些超低功耗場景中完全替代主 CPU脉漏。
重要的: ULP是ESP32做出優(yōu)秀低功耗產(chǎn)品的關(guān)鍵
但是致命的: ULP只能用匯編????????
參考文檔: https://blog.csdn.net/espressif/article/details/79131076
二. 理解了ULP之后, 讓我們看一下ESP32的工作模式
可以看到ESP32在深睡眠模式下可以啟動或停止ULP協(xié)處理器
三. ESP32 deepsleep模式喚醒方式及關(guān)鍵API
喚醒方式:
- 定時器喚醒
- 兩種引腳喚醒方式
- 觸摸按鍵喚醒
- ULP喚醒
1. 開始進(jìn)入深睡眠: esp_deep_sleep_start();
esp_deep_sleep_start();
2. 獲取esp32被喚醒的原因 esp_deep_sleep_get_wakeup_cause();
這是一個ESP-IDF的原生方法, 如果我們想用, 需要引入頭文件
#include <esp_sleep.h>
注意:#include <esp_deep_sleep.h>
即將被棄用, 所以不要再用這個頭文件了
Serial.println(esp_deep_sleep_get_wakeup_cause());
返回: 被喚醒原因碼:
原因碼 | 對應(yīng)原因 | 說明 |
---|---|---|
0 | ESP_SLEEP_WAKEUP_UNDEFINED | 沒有定義被喚醒的原因(第一次啟動時會報(bào)) |
2 | ESP_SLEEP_WAKEUP_EXT0 | 被RTC_GPIO喚醒 |
3 | ESP_SLEEP_WAKEUP_EXT1 | 被RTC_CNTL引腳集合的變化喚醒 |
4 | ESP_SLEEP_WAKEUP_TIMER | 被ESP的定時器喚醒 |
5 | ESP_SLEEP_WAKEUP_TOUCHPAD | 被觸摸喚醒 |
6 | ESP_SLEEP_WAKEUP_ULP | 被ULP喚醒 |
7 | ESP_SLEEP_WAKEUP_GPIO | 被GPIO喚醒(僅限輕睡眠模式light sleep) |
8 | ESP_SLEEP_WAKEUP_UART | 被串口喚醒(僅限輕睡眠模式light sleep) |
3. 設(shè)置具體的喚醒源請看下面的相關(guān)章節(jié)
四. RTC memory
ESP32有8KB的RTC存儲器
在RTC memory里的變量不會因?yàn)閐eepsleep被清除, 創(chuàng)建方法:
RTC_DATA_ATTR int bootCount = 0;
注意, RTC memory會被硬件reset清除
五. 進(jìn)入休眠后定時器喚醒
esp_sleep_enable_timer_wakeup(20000000);
參數(shù):
- 定時時間,單位μ秒, 類型uint64_t, 所以定時時間要在584942年以內(nèi)??????
例子:
#include <Arduino.h>
#include <esp_sleep.h>
RTC_DATA_ATTR int bootCount = 0;
void setup()
{
Serial.begin(115200);
Serial.printf("ESP32 is restart now! It's the %d time\r\n", ++bootCount);
delay(5000);
esp_sleep_enable_timer_wakeup(20000000);
Serial.println(esp_sleep_get_wakeup_cause());
}
void loop()
{
Serial.println("ESP32 will sleep now!");
delay(100);
esp_deep_sleep_start();
}
六. 進(jìn)入休眠后被RTC_GPIO喚醒 (引腳喚醒方式一)
首先,并不是每個GPIO都是RTC_GPIO, 詳見下表
注意: 我們填寫的GPIO引腳號是真正的引腳號 不是其RTC_GPIO編號
esp_sleep_enable_ext0_wakeup(GPIO_NUM_35, 0);
#include <Arduino.h>
#include <esp_sleep.h>
RTC_DATA_ATTR int bootCount = 0;
void setup()
{
Serial.begin(115200);
Serial.printf("ESP32 is restart now! It's the %d time\r\n", ++bootCount);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_35, 0);
Serial.printf("the wakeup reason is :%d\r\n", esp_sleep_get_wakeup_cause());
}
void loop()
{
delay(3000);
Serial.println("ESP32 will sleep now!");
delay(100);
esp_deep_sleep_start();
}
七. 進(jìn)入休眠后被RTC_CNTL喚醒 (引腳喚醒方式二)
思考一個問題, 如果我們有8個GPIO引腳想喚醒ESP32, 難道要用上一節(jié)的方法操作8遍嗎?
當(dāng)然不是, 我們可以直接操作引腳集合, (我們用一個mask片選想操作的引腳,然后這些引腳都具有了喚醒ESP32的能力)
我們可以設(shè)置這些引腳是 每個都能觸發(fā)(每個葫蘆娃都能自己去救爺爺), 還是一起共同發(fā)力才能觸發(fā)(集齊七龍珠??)
esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode);
參數(shù):
- mask :
如: 我們想讓 32 33 35 39觸發(fā), 這樣計(jì)算mask
注意: 我們不要使用 37 38
- mode: 觸發(fā)方式 可選:
- ESP_EXT1_WAKEUP_ALL_LOW : 全都置低時觸發(fā)喚醒
- ESP_EXT1_WAKEUP_ANY_HIGH : 任意置高時觸發(fā)喚醒
八. 進(jìn)入休眠后被觸摸按鍵喚醒
值得注意的是,
- 觸摸按鍵喚醒所需deepsleep電流要大于 按鍵和定時器
- 必須寫觸摸回調(diào)函數(shù), 否則無用
#include <Arduino.h>
#include <esp_sleep.h>
RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR int BTN_Pin_BITMASK = 0;
void callbackPin2()
{
Serial.println("T2 weak ESP32 up");
}
void setup()
{
Serial.begin(115200);
Serial.printf("ESP32 is restart now! It's the %d time\r\n", ++bootCount);
esp_sleep_enable_touchpad_wakeup();
Serial.printf("the wakeup reason is :%d\r\n", esp_sleep_get_wakeup_cause());
touchAttachInterrupt(2,callbackPin2,40);
}
void loop()
{
delay(3000);
Serial.println("ESP32 will sleep now!");
delay(100);
esp_deep_sleep_start();
}
九. 被ULP喚醒
這個要做一個專門的ULP專題