一、低功耗模式简介
系统提供了多个低功耗模式,可在 CPU 不需要运行时(例如等待外部事件时)节省功耗。由用户根据应用选择具体的低功耗模式,以在低功耗、短启动时间和可用唤醒源之间寻求最佳平衡。
睡眠模式、停止模式及待机模式中,若备份域电源正常供电,备份域内的 RTC 都可以正常运行,备份域内的寄存器的数据会被保存,不受功耗模式影响。
从表中可以看到,这三种低功耗模式层层递进,运行的时钟或芯片功能越来越少,因而功耗越来越低。
模式名称 | 说明 | 进入方式 | 唤醒方式 | 对1.8V区域时钟的影响 | 对VDD区域时钟的影响 | 调压器 |
睡眠模式 | 内核停止,所有外设包括M3核心的外设,如NVIC、系统时钟(SysTick)等仍在运行 | 调用 | 任意中断 | 内核时钟关,对其他时钟和ADC时钟无影响 | 无 | 开 |
睡眠模式 | 内核停止,所有外设包括M3核心的外设,如NVIC、系统时钟(SysTick)等仍在运行 | 调用 | 唤醒事件 | 内核时钟关,对其他时钟和ADC时钟无影响 | 无 | 开 |
停止模式 | 所有的时钟都已停止 | 配置PWR_CR寄存器的 | 任意外部中断 | 关闭所有1.8V区域的时钟 | HSI和HSE的振荡器关闭 | 开启或处于低功耗模式(依据电源控制寄存器的设定) |
待机模式 | 1.8V电源关闭 | 配置PWR_CR寄存器的 | WKUP上升沿、引脚的RTC闹钟事件、NRST引脚上的外部复位、IWDG复位 | 关闭所有1.8V区域的时钟 | HSI和HSE的振荡器关闭 | 关 |
1.1 睡眠模式
在睡眠模式中,仅关闭了内核时钟,内核停止运行,但其片上外设,CM3 核心的外设全都还照常运行。有两种方式进入睡眠模式,它的进入方式决定了从睡眠唤醒的方式,分别是 WFI(wait for interrupt) 和 WFE(wait for event),即由等待“中断”唤醒和由“事件”唤醒。
特性和说明:
- 立即睡眠: 在执行
WFI
或WFE
指令时立即进入睡眠模式。- 退出时睡眠: 在退出优先级最低的中断服务程序后才进入睡眠模式。
- 进入方式: 内核寄存器的
SLEEPDEEP=0
,然后调用WFI
或WFE
指令即可进入睡眠模式;SLEEPONEXIT=1
时,进入“退出时睡眠”模式。- 唤醒方式: 如果是使用
WFI
指令睡眠的,则可使用任意中断唤醒;如果是使用WFE
指令睡眠的,则由事件唤醒。- 睡眠时: 关闭内核时钟,内核停止,而外设正常运行,在软件上表现为不再执行新的代码。这个状态会保留睡眠前的内核寄存器、内存的数据。
- 唤醒延迟: 无延迟。
- 唤醒后: 若由中断唤醒,先进入中断,退出中断服务程序后,接着执行
WFI
指令后的程序;若由事件唤醒,直接接着执行WFE
后的程序。
1.2 停止模式
在停止模式中,进一步关闭了其它所有的时钟,于是所有的外设都停止了工作,但由于其 1.8V 区域的部分电源没有关闭,还保留了内核的寄存器、内存的信息,所以从停止模式唤醒,并重新开启时钟后,还可以从上次停止处继续执行代码。停止模式可以由任意一个外部中断(EXTI)唤醒,在停止模式中可以选择电压调节器为开模式或低功耗模式。
特性和说明:
- 调压器低功耗模式: 在停止模式下调压器可工作在正常模式或低功耗模式,可进一步降低功耗。
- 进入方式: 内核寄存器的
SLEEPDEEP=1
,PWR_CR 寄存器中的PDDS=0
,然后调用WFI
或WFE
指令即可进入停止模式;PWR_CR 寄存器的LPDS=0
时,调压器工作在正常模式,LPDS=1
时工作在低功耗模式。- 唤醒方式: 如果是使用
WFI
指令睡眠的,可使用任意 EXTI 线的中断唤醒;如果是使用WFE
指令睡眠的,可使用任意配置为事件模式的 EXTI 线事件唤醒。- 停止时: 内核停止,片上外设也停止。这个状态会保留停止前的内核寄存器、内存的数据。
- 唤醒延迟: 基础延迟为 HSI 振荡器的启动时间,若调压器工作在低功耗模式,还需要加上调压器从低功耗切换至正常模式下的时间。
- 唤醒后: 若由中断唤醒,先进入中断,退出中断服务程序后,接着执行
WFI
指令后的程序;若由事件唤醒,直接接着执行WFE
后的程序。唤醒后,STM32 会使用 HSI 作为系统时钟。
1.3 待机模式
待机模式,它除了关闭所有的时钟,还把 1.8V 区域的电源也完全关闭了,也就是说,从待机模式唤醒后,由于没有之前代码的运行记录,只能对芯片复位,重新检测 boot 条件,从头开始执行程序。它有四种唤醒方式,分别是 WKUP(PA0)引脚的上升沿,RTC 闹钟事件,NRST 引脚的复位和 IWDG(独立看门狗)复位。
特性和说明:
- 进入方式: 内核寄存器的
SLEEPDEEP=1
,PWR_CR 寄存器中的PDDS=1
,PWR_CR 寄存器中的唤醒状态位WUF=0
,然后调用WFI
或WFE
指令即可进入待机模式。- 唤醒方式: 通过 WKUP 引脚的上升沿,RTC 闹钟、唤醒、入侵、时间戳事件或 NRST 引脚外部复位及 IWDG 复位唤醒。
- 待机时: 内核停止,片上外设也停止;内核寄存器、内存的数据会丢失;除复位引脚、RTC_AF1 引脚及 WKUP 引脚,其它 I/O 口均工作在高阻态。
- 唤醒延迟: 芯片复位的时间。
- 唤醒后: 相当于芯片复位,在程序表现为从头开始执行代码。
1.4 WFI与WFE命令
我们了解到进入各种低功耗模式时都需要调用 WFI
或 WFE
命令,它们实质上都是内核指令,在库文件 core_cm3.h
中把这些指令封装成了函数。
对于这两个指令,我们应用时一般只需要知道,调用它们都能进入低功耗模式,需要使用函数的格式“__WFI();”和“__WFE();”来调用(因为__wfi 及__wfe 是编译器内置的函数,函数内部调用了相应的汇编指令)。
其中
WFI
指令决定了它需要用中断唤醒,而WFE
则决定了它可用事件来唤醒。
二、新建工程
1. 打开 STM32CubeMX 软件,点击“新建工程”
2. 选择 MCU 和封装
3. 配置时钟
RCC 设置,选择 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)
开启 LSE(外部低速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)
选择 Clock Configuration,配置系统时钟 SYSCLK 为 72MHz
修改 HCLK 的值为 72 后,输入回车,软件会自动修改所有配置
4. 配置调试模式
非常重要的一步,否则会造成第一次烧录程序后续无法识别调试器
SYS 设置,选择 Debug 为 Serial Wire
三、待机模式
3.1 WKUP按键唤醒
3.1.1 流程图
3.1.2 HAL库与标准库代码比较
STM32CubeMX 使用 HAL 库的代码:
使用 STM32 标准库的代码:
3.1.3 添加WKUP按键
添加系统唤醒按键 PA0
,以便当系统进入待机模式的时候可以通过按键来唤醒。
或者勾选 System Wake-Up
3.1.4 添加LED灯
添加绿灯 PB0
表示本次复位是上电或引脚复位,蓝灯 PB1
表示本次是待机唤醒的复位。
查看 STM32CubeMX学习笔记(2)——GPIO接口使用
3.1.5 添加串口打印
添加 USART1
用于打印信息。
查看 STM32CubeMX学习笔记(6)——USART串口使用
3.1.6 生成代码
输入项目名和项目路径
选择应用的 IDE 开发环境 MDK-ARM V5
每个外设生成独立的 ’.c/.h’
文件
不勾:所有初始化代码都生成在 main.c
勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。
点击 GENERATE CODE 生成代码
3.1.7 修改main函数
程序中首先初始化了系统时钟、LED 灯及串口以便用于指示芯片的运行状态,由于待机模式唤醒使用 WKUP 引脚并不需要特别的引脚初始化。
使用库函数 __HAL_PWR_GET_FLAG 检测 PWR_FLAG_SB 标志位,当这个标志位为 SET 状态的时候,表示本次系统是从待机模式唤醒的复位,否则可能是上电复位。
我们利用这个区分两种复位形式,分别使用蓝色 LED 灯或绿色 LED 灯来指示。在使用库函数 HAL_PWR_EnableWakeUpPin 发送待机命令前,要先使用库函数 __HAL_PWR_CLEAR_FLAG 清除 PWR_FLAG_WU 标志位,并且使用库函数 HAL_PWR_EnableWakeUpPin 使能 WKUP 唤醒功能,这样进入待机模式后才能使用 WKUP 唤醒。
3.2 RTC时钟唤醒
3.2.1 添加RTC时钟
查看 STM32CubeMX学习笔记(14)——RTC实时时钟使用
3.1.2 添加LED灯
添加绿灯 PB0
表示本次复位是上电或引脚复位,蓝灯 PB1
表示本次是待机唤醒的复位。
查看 STM32CubeMX学习笔记(2)——GPIO接口使用
3.1.3 添加串口打印
添加 USART1
用于打印信息。
查看 STM32CubeMX学习笔记(6)——USART串口使用
3.2.4 使能RTC闹钟中断
3.2.5 生成代码
输入项目名和项目路径
选择应用的 IDE 开发环境 MDK-ARM V5
每个外设生成独立的 ’.c/.h’
文件
不勾:所有初始化代码都生成在 main.c
勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。
点击 GENERATE CODE 生成代码
3.2.6 添加RTC闹钟中断启动函数
3.2.7 修改main函数
程序中首先初始化了系统时钟、LED 灯及串口以便用于指示芯片的运行状态,由于待机模式唤醒使用 WKUP 引脚并不需要特别的引脚初始化。
使用库函数 __HAL_PWR_GET_FLAG 检测 PWR_FLAG_SB 标志位,当这个标志位为 SET 状态的时候,表示本次系统是从待机模式唤醒的复位,否则可能是上电复位。
我们利用这个区分两种复位形式,分别使用蓝色 LED 灯或绿色 LED 灯来指示。在使用库函数 HAL_PWR_EnableWakeUpPin 发送待机命令前,要先使用库函数 __HAL_PWR_CLEAR_FLAG 清除 PWR_FLAG_WU 标志位,并且使用库函数 HAL_PWR_EnableWakeUpPin 使能 WKUP 唤醒功能,这样进入待机模式后才能使用 WKUP 唤醒。
四、注意事项
用户代码要加在
USER CODE BEGIN N
和USER CODE END N
之间,否则下次使用 STM32CubeMX 重新生成代码后,会被删除。
进入低功耗之前可以将引脚全部配置为浮空输入或者Anglog模式,这样最省电,如果你是用STM32CUBEMX,在这里可以看到这么一项配置就是将没有用到的引脚配置为了Anglog模式:
当系统处于睡眠模式低功耗状态时(包括后面讲解的停止模式及待机模式),使用 DAP 下载器是无法给芯片下载程序的,所以下载程序时要先把系统唤醒。或者使用如下方法:按着板子的复位按键,使系统处于复位状态,然后点击电脑端的下载按钮下载程序,这时再释放复位按键,就能正常给板子下载程序了。