【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种:ActiveModem SleepLight SleepDeep SleepHibernation, 相关的设定流程如下:(参考资料:ESP32 Datasheet)

QuecPython 低功耗处理 micropython 低功耗_MicroPython

✨通过Thonny平台,Shell调试窗口:引入machine模块。查阅📖到的相关函数:

QuecPython 低功耗处理 micropython 低功耗_MicroPython_02

⛳️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	软复位

🌳lightsleepdeepsleep区别示例🌳

  • 📍注意;测试本段代码需要将其保存到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')

🌿lightsleepdeepsleep带参数🌿

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

QuecPython 低功耗处理 micropython 低功耗_低功耗_03


QuecPython 低功耗处理 micropython 低功耗_QuecPython 低功耗处理_04

⚡️外部IO唤醒方法,可以分为 ext0ext1,两种唤醒最大的差别就在于 ext0 可以设定1个IO口作为唤醒源,ext1 可以同时设定多支 IO 作为唤醒机制.

📙相关函数:
  • 🌿esp32.wake_on_ext0(pin, level)

🎉原文: Configure how EXT0 wakes the device from sleep. pin can be None or a valid Pin object. level should be esp32.WAKEUP_ALL_LOW or esp32.WAKEUP_ANY_HIGH.

  • 🌿esp32.wake_on_ext1(pins, level)

🎉原文:Configure how EXT1 wakes the device from sleep. pins can be None or a tuple/list of valid Pin objects. level should be esp32.WAKEUP_ALL_LOW or esp32.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

QuecPython 低功耗处理 micropython 低功耗_QuecPython 低功耗处理_05