【MicroPython ESP32】硬件低功耗:睡眠模式详解
- ✨本案例基于
Thonny
平台开发。✨
📖esp32硬件低功耗知识介绍
📗超低功耗协处理器 (ULP)
超低功耗协处理器 (ULP Coprocessor) 是一种功耗极低的协处理器设备,可在主系统级芯片 (SoC) 系统进入Deep-sleep 状态时保持上电,允许开发者通过存储在 RTC 中的专用程序,访问外围设备、内部传感器及 RTC寄存器。ULP 协处理器的主要应用场景包括一些需要在保证最低功耗的情况下,通过外部活动或计时器(或两者兼有)唤醒 CPU 的应用。
📘主要特性
- 🎉可访问最多 8 KB SRAM RTC 慢速内存,储存指令和数据
- 🎉采用 8 MHz RTC_FAST_CLK 时钟频率
- 🎉
支持正常模式
和Deep-sleep
模式 - 🎉可唤醒 CPU 或向 CPU 发送中断
- 🎉 可访问外围设备、内部传感器及 RTC 寄存器
- 🎉采用 4 个 16 位通用寄存器 (R0 - R3),进行数据操作和内存访问
- 🎉采用 1 个 8 位阶段计数器寄存器 Stage_cnt,可通过 ALU 指令进行操作并用于 JUMP 指令
- ⭐️架构图⭐️
🔥功能描述🔥
📢📢📢ULP 协处理器是一种可编程有限状态机 (FSM),可在 CPU 进入 Deep-sleep 状态时工作。协处理器支持部分通
用 CPU 指令,可协助进行一些复杂逻辑运算。此外,还支持一些特殊的 RTC 控制与外围设备控制指令。与CPU 一样,ULP 协处理器也可访问 8 KB SRAM RTC 慢速内存。也正因如此,这块内存经常被用于存储一些协处理器和 CPU 的通用指令。
ULP 协处理器可由软件程序或硬件定时器周期性启动,并通过执行 HALT 指令停止。协处理器的功能非常强大,
可以通过内置指令和 RTC 寄存器,访问 RTC 域中的几乎所有模块。ULP 协处理器可在很多应用场景中成为
CPU 的有力补充,甚至取代 CPU,特别是在一些对功耗很敏感的应用中。
- 🔖参考文档链接:👉
https://www.espressif.com.cn/sites/default/files/documentation/esp32_technical_reference_manual_cn.pdf
👈
🌻Micropython ESP32 的电源模式有5种:
📖查询 ESP32 的设计参考手册,可以发现 ESP32 的电源模式有5种:
Active
、Modem Sleep
、Light Sleep
、Deep Sleep
、Hibernation
, 相关的设定流程如下:(参考资料:ESP32 Datasheet)
✨通过
Thonny
平台,Shell
调试窗口:引入machine
模块。查阅📖到的相关函数:
⛳️lightsleep()
:正常低功耗模式是被唤醒后继续执行后面的语句。
⛳️deepsleep():
深度睡眠模式唤醒后是重启。
🌿重启原因函数:
machine.reset_cause() #复位原因:返回数字1-5 ,
复位原因 说明
1 machine.PWRON_RESET 电源复位
2 machine.HARD_RESET 硬重置(断电)
3 machine.WDT_RESET 看门狗复位
4 machine.DEEPSLEEP_RESET 深度睡眠
5 machine.SOFT_RESET 软复位
🌳lightsleep
和deepsleep
区别示例🌳
- 📍注意;测试本段代码需要将其保存到
micropython
设备当中才行,在线调试时如果启用了machine.deepsleep()代码,
无法看到Shell调试窗口相关的调试信息。📍
import time
import machine,esp32,time
from machine import Pin
ext_p32=Pin(32, Pin.IN,Pin.PULL_UP)
esp32.wake_on_ext0(pin = ext_p32, level = esp32.WAKEUP_ALL_LOW)
time.sleep(1)
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
print("This is a deepsleep wake-up condition")
if __name__=='__main__':
# machine.deepsleep()
print('deepsleep')
machine.lightsleep() # 浅睡眠唤醒后是继续执行下面的语句
print('lightsleep')
🌿lightsleep
和deepsleep
带参数🌿
import machine
machine.deepsleep(5000)
🎉
machine.deepsleep(5000)
参数的单位是 ms,也就是 5000ms 等于 5 秒,这段程序的意思就是让 ESP32 进入低功耗模式 5 秒,在之后就重新起动(Restart),这边需注意一下,进入 Deep-Sleep 后的 Restart,会让程序从第一行开始执行,如果需要有区别时,可以利用下面的程序来判断:
- 📍注意;测试本段代码需要将其保存到
micropython
设备当中才行,在线调试时如果启用了machine.deepsleep(5000)代码,
无法看到Shell调试窗口相关的调试信息。📍
import machine
import time
print(machine.reset_cause())
time.sleep(1)
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
print("This is a deepsleep wake-up condition")
if __name__=='__main__':
machine.deepsleep(5000)# 5秒后重启
print('deepsleep')
# machine.lightsleep(5000)# 5秒后继续执行后面的代码
print('lightsleep')
- Shell调试窗口信息
💥唤醒 ESP32 的多种方式
上面示例,是进入低功耗模式一定时间(5秒)后就回自行唤醒,这种方法就是 RTC(RealTimeClock) 唤醒, 因为在深度睡眠模式下,RTC Timer 仍保持运作,当 Timer 指定时间到达,即触发 CPU Restart。 ESP32 唤醒除支援 RTC wakeup 外,还可以透过外部的 IO 脚位进行唤醒,这边的脚位并不是任意 IO,而是标记为 RTC GPIO的脚位,怎么确定那几只脚位是 RTC 的 GPIO 呢?最直觉的方法就是查阅 ESP32 的参考手册:(下表撷取于 ESP32技术参考手册Page.56
表4.4⚡️外部IO唤醒方法,可以分为
ext0
跟ext1
,两种唤醒最大的差别就在于 ext0 可以设定1个IO
口作为唤醒源,ext1
可以同时设定多支 IO 作为唤醒机制.📙相关函数:
- 🌿
esp32.wake_on_ext0(pin, level)
🎉原文: Configure how
EXT0
wakes the device from sleep. pin can beNone
or a valid Pin object. level should beesp32.WAKEUP_ALL_LOW
oresp32.WAKEUP_ANY_HIGH
.
- 🌿
esp32.wake_on_ext1(pins, level)
🎉原文:Configure how
EXT1
wakes the device from sleep. pins can be None or atuple
/list
of valid Pin objects. level should beesp32.WAKEUP_ALL_LOW
oresp32.WAKEUP_ANY_HIGH
.
📝使用 ext0
外部触发唤醒的示例:
当按键(GPIO13)按下时,触发低功耗睡眠模式,当引脚(GPIO32)按下拉低时,被唤醒,根据选择的模式不同;深度睡眠模式唤醒后是重启,如果是正常模式就继续执行后面的语句。
import machine,esp32,time
from machine import Pin
led_p2=Pin(2,Pin.OUT)
btn_p13=Pin(13,Pin.IN,Pin.PULL_UP)
ext_p32=Pin(32, Pin.IN,Pin.PULL_UP)
esp32.wake_on_ext0(pin = ext_p32, level = esp32.WAKEUP_ALL_LOW)
led_p2.value(1)
print('This is in the active mode now.')
def blink():
for i in range(1,10):
led_p2.value(led_p2.value()^1) # 将引脚2设置为高电平
time.sleep(0.5) # 延时1秒
while True:
if btn_p13.value() == 0:
print('The cpu is going to enter the deep-sleep mode after 5s , look at LED !')
blink()# 闪烁5次
led_p2.value(0)
machine.deepsleep()# 进入睡眠模式,被唤醒后是重启,不会执行后面的语句
# machine.lightsleep() # 浅睡眠唤醒后是继续执行下面的语句
print('hello world!')# 唤醒后打印
else :
pass
📑使用ext1
外部触发唤醒的范例:(🚩测试通过🚩)
🎯在测试
ext1
外部触发时,容易收引脚干扰,容易被唤醒,触发引脚对象是元组或列表。
import machine,esp32,time
from machine import Pin
# list of pins
# GPIO_list =(1,2,15,13,12,14,27,32,33)
# for i in range(len(GPIO_list)):
# print(GPIO_list[i])
# Pin(GPIO_list[i], Pin.IN,Pin.PULL_UP)
print('star')
#touch1=Pin(0, Pin.IN,Pin.PULL_UP)
#touch2=Pin(1, Pin.IN,Pin.PULL_UP)
#touch3=Pin(2, Pin.IN,Pin.PULL_UP)
touch4=Pin(15, Pin.IN,Pin.PULL_UP)
touch5=Pin(13, Pin.IN,Pin.PULL_UP)
touch6=Pin(12, Pin.IN,Pin.PULL_UP)
touch7=Pin(14, Pin.IN,Pin.PULL_UP)
touch8=Pin(27, Pin.IN,Pin.PULL_UP)
touch9=Pin(33, Pin.IN,Pin.PULL_UP)
touch10=Pin(32, Pin.IN,Pin.PULL_UP)
pins_list = (touch4,touch5,touch6,touch7,touch8,touch9,touch10)
while True:
esp32.wake_on_ext1(pins =pins_list,level = esp32.WAKEUP_ALL_LOW)
print('Im Going to sleep in 3 seconds')
time.sleep(3)
print('The cpu is going to enter the deep-sleep mode after 3s , look at LED !')
time.sleep_ms(100)
machine.deepsleep()# 深度睡眠唤醒后是直接重启
#machine.lightsleep() # 浅睡眠唤醒后是继续执行下面的语句
print('hello world!')# lightsleep唤醒后打印
程序运行之后,通过拉低定义的引脚可以唤醒esp32