功耗控制¶
概要¶
本节内容为大家讲解ESP32的功耗控制方法。
ESP32工作频率¶
使用machine模块,你可以轻而易举的设置CPU的运行频率:
import machine machine.freq() # 查看当前的CPU运行频率 machine.freq(160000000) # 设置CPU运行频率至 160 MHz
ESP32默认工作在240MHz的主频下,它拥有三个可调的频率挡位:
-
80MHz
-
160MHz
-
240MHz
越低的运行主频意味着性能的下降,但同时也意味着更低的功耗,适用于计算力需求低,长续航的任务。
反之,越高的主频,提升了性能的同时意味着更高的功耗。实际应用中,大家按照需求,自行取舍。
休眠模式¶
有时候我们需要使用休眠模式来为设备节省功耗,保证续航。
进入休眠模式¶
ESP32进入休眠模式后,除了RTC的时钟电路不掉电继续工作外,其余各电路模块都将掉电.
注意¶
进入休眠模式也意味着你将失去网络连接,无法连接到WebREPL和EMP-IDE甚至是通过串口连接的REPL,直到休眠模式被唤醒或者重启复位
import machine machine.deepsleep() # 休眠,直到被人为唤醒 machine.deepsleep(5000) # 休眠5S
因此,当ESP32从休眠模式醒来时,相当于重启,不同之处在于:
-
普通的重启RTC会恢复至初始点
-
休眠时RTC不会被关闭,因此芯片醒来之后,RTC是正确的时间。
从休眠唤醒¶
当ESP32进入休眠模式后,很多时候我们希望能够人为的唤醒它。
我们有四种方式来唤醒ESP32:
-
RTC Timer 唤醒模式
-
EXT0 唤醒模式
-
EXT1 唤醒模式
-
TouchPad 唤醒模式
接下来,我们分别对前三种模式进行详细的阐述。
RTC Timer 唤醒模式¶
这是最简单的唤醒模式,这种方式其实我们上文的代码中就已经涉及:
import machine machine.deepsleep() # 休眠,直到被人为唤醒 machine.deepsleep(5000) # 休眠5S
这里的deepsleep()
函数本身可以接收一个休眠时间的参数,单位是毫秒,当该时间被计时器计时完成,便会触发唤醒。
RTC GPIO¶
在进行接下来的三种唤醒模式之前,你需要先了解什么是RTC GPIO
你可能并不清楚什么是RTC GPIO
, 简而言之,RTC GPIO
也属于GPIO
,只不过他们特殊的地方在于,RTC GPIO
和RTC
时钟模块相连,因此在低功耗睡眠模式下,这些RTC GPIO
才能够保证输入和输出信号能够被检测到,因此,只有RTC GPIO
才能够唤醒ESP32 。
NodeMCU-32S上,GPIO 总共有32个。
ESP32上,RTC GPIO有18个,拥有自己的一套独立的RTC GPIO编号,0-17
NodeMCU-32S上,引出的RTC GPIO共有16个:
EXT0唤醒模式¶
EXT0唤醒模式,允许用户配置 一个 RTC GPIO
, 来唤醒ESP32。
只有具备RTC GPIO
功能的GPIO
才能够被配置用以唤醒。
我们可以在GPIO上使用中断的方式来触发唤醒, 其中:
trigger
有两种触发方式:
-
Pin.WAKE_HIGH
高电平触发 -
Pin.WAKE_LOW
低电平触发
我们以高电平触发唤醒为例(大部分引脚默认都是低电平,所以WAKE_LOW
触发会立即执行),在GPIO27上接入一个按钮。
>>> from machine import Pin >>> import machine >>> wake_pin = Pin(27,Pin.IN) # GPIO27 支持 RTC GPIO >>> wake_pin.irq(trigger=Pin.WAKE_LOW, wake=machine.DEEPSLEEP) # 配置唤醒中断 >>> machine.deepsleep() # 开始睡眠
当我按下这个按钮的时候,ESP32就苏醒(重启)了。
EXT1 唤醒模式¶
在这种模式下,允许用户配置一个或者多个RTC GPIO 作为唤醒源, 在一个或者多个 RTC GPIO 存在任意一个高电平或者同时为低电平时唤醒。
我们可以使用GPIO26 , GPIO27同时按下时将其唤醒。
按照上面的GPIO中断进行配置的话,正如在ESP32-MicroPython的Github仓库ISSUE里开发者们所讨论的那样
pin1.irq(trigger=Pin.IRQ_LOW_LEVEL, wake=machine.DEEPSLEEP) # configures ext0 pin2.irq(trigger=Pin.IRQ_HIGH_LEVEL, wake=machine.DEEPSLEEP) # configures ext1 with "any high" pin3.irq(trigger=Pin.IRQ_HIGH_LEVEL, wake=machine.DEEPSLEEP) # reconfigures ext1 with "any high" with pin2 and pin3 pin4.irq(trigger=Pin.IRQ_LOW_LEVEL, wake=machine.DEEPSLEEP) # raises an exception, no resources left
我看完之后直接就懵圈了。
所以还好我们有另外一种方式进行配置——esp32
模块:
import esp32 esp32.wake_on_ext1(pins=(...), level=...) # 这样就简单很多了
pins
是一个元组,传入配置的多个RTC GPIO引脚
level
有以下两个选项:
-
WAKEUP_ANY_HIGH
任意一个RTC GPIO高电平即可唤醒 -
WAKEUP_ALL_LOW
所有RTC GPIO低电平时触发唤醒
笔者测试时使用 GPIO26(RTC GPIO7) GPIO27(RTC GPIO17)
使用WAKEUP_ANY_HIGN
的选项进行测试(WAKEUP_ALL_LOW
模式需要外部电路的支持,不然大部分引脚默认都是低电平,所以会立即触发唤醒),在这种模式下,我按下下图中的黑色或原谅色按钮,都可以唤醒
>>> import esp32 >>> import machine >>> esp32.wake_on_ext1(pins=(Pin(26),Pin(27)),level=esp32.WAKEUP_ALL_LOW) >>> machine.deepsleep()
判断重启和唤醒的原因¶
既然存在休眠被唤醒的情况,那么很多时候用户就需要知道当前重启是由于何种原因,以便决策启动之后的工作。
在machine模块中,包含了以下两个函数,可以让我们对重启和唤醒的原因进行侦查:
-
reset_cause
查看重启原因 -
wake_reason
查看唤醒原因
这些数值,与machine
模块中的宏定义有着一一对应的关系:
重启原因的宏定义 | 数值 | 含义 |
---|---|---|
PWRON_RESET | 1 | 上电重启 |
HARD_RESET | 2 | 硬重启 |
WDT_RESET | 3 | 看门狗计时器重启 |
DEEPSLEEP_RESET | 4 | 从休眠重启 |
SOFT_RESET | 5 | 软重启 |
唤醒原因的宏定义 | 数值 | 含义 |
---|---|---|
PIN_WAKE EXT0_WAKE | 1 | 单个RTC_GPIO唤醒 |
EXT1_WAKE | 2 | 多RTC_GPIO唤醒 |
TIMER_WAKE | 3 | 定时器唤醒 |
TOUCHPAD_WAKE | 4 | 触摸唤醒 |
ULP_WAKE | 5 | 协处理器唤醒 |
目前为止,笔者在测试的过程中,发现我们无论是使用machine.reset()
函数进行软重启,还是按开发板上的reset按键进行重启,machine.reset_cause()
的数值都是5
即对应machine.SOFT_RESET
当开发板从休眠模式唤醒后,重启原因是4
即machine.DEEPSLEEP_RESET
ESP32最常见的重启原因,无非也就以上两种了。
所以要想判断ESP32是从休眠中醒来还是正常的按键重启或是machine.reset()
函数的重启,我们只需在开机后通过machine.reset_cause()
函数来进行判断,如果是从睡眠中唤醒,那么进而可以继续判断唤醒的原因:
if machine.reset_cause() == machine.SOFT_RESET: print('normal reboot') # do something elif machine.reset_cause() == machine.DEEPSLEEP_RESET: print('reboot from deepsleep') # 进而可以继续判断 是由于什么原因导致的唤醒 if machine.wake_reason() == machine.PIN_WAKE: # do something pass elif machine.wake_reason() == machine.EXT1_WAKE: # do something else... pass # ......