一、前言
在实际嵌入式开发过程中,我们会去考虑我们设计出来的产品的实际工作时间,例如桥梁探测系统,智能穿戴设备,我们希望在满足用户前提下尽可能地减少用户充电次数,所以引出今日沟通的主题:低功耗模式。比如桥梁探测设备,在冬季不下雨的时候,设备就可以进入休眠模式,实时探测数据的时间间隔可以适当拉长。接下来我们一起来了解下三种模式。
1 电源控制
电源控制(PWR:Power Control)。电源对电子设备来说非常重要,它是保证系统稳定运行的基础。在保证系统能稳定运行的同时,对嵌入式设备一般又有低功耗的需求。
1.1电源框图


1) V DDA 供电区域
主要负责模拟部分的供电。为了提高转换的精确度,ADC使用一个独立的电源供电,过滤和屏蔽来自印刷电路板上的毛刺干扰。主要给A/D转换器、温度传感器、复位模块、PLL等供电。
2)VDD供电区域
VDD是数字电的正极,VSS是数字电的负极,电压3.3V。给I/O电路、待机电路和电压调节器供电。
3)1.8V供电区域
CPU核心、内部存储器、内置的数字外设都是工作在1.8V的电压。1.8V的低电压是由从电压调节器得到的。
4)后备供电区域
VBAT引脚会接电池和其他电源,当VDD断电时,可以保存备份寄存器的内容和给RTC供电。
VBAT脚也为RTC、LSE振荡器和PC13至PC15供电,这保证当主要电源被切断时RTC能继续工作。
5)电压调节器
复位后,电压调节器总是工作使能的。有3种不同的工作模式:
- 运转模式:调节器以正常功耗模式提供1.8V电源(内核、内存和外设)2.
- 停止模式:调节器以低功耗模式提供1.8V电源,用于保存寄存器和 SRAM 的内容。
- 待机模式:调节器停止供电。除了备用电路和备份域外,寄存器和 SRAM 的内容全部丢失。
1.2上电复位和掉电复位

类似于按键(有延迟),当VDD/VDDA低于指定的限位电压VPOR/VPDR时,系统保持为复位状态,而无需外部复位电路。
复位和解除复位有一个40mv的迟滞电压。当电压大于VPOR时解除复位,当电压小于VPDR时进入复位。设置2个阈值的作用是当电压在附近抖动的时候防止频繁的复位和解除复位。
1.3 低功耗
在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时。
用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。
STM32F10xxx有三种低功耗模式:

1.3.1 睡眠模式

(1)睡眠模式
- SLEEP-NOW:如果SLEEPONEXIT位被清除,当WRI或WFE被执行时,微制器立即进入睡眠模式。
- SLEEP-ON-EXIT:如果SLEEPONEXIT位被置位,系统从最低优先级的中断处理程序中退出时,微控制器就立即进入睡眠模式。
注意:在睡眠模式下,所有的I/O引脚都保持它们在运行时的状态。验证:LED进入睡眠模式依然会亮
(2)退出睡眠模式
如果执行WFI指令进入睡眠模式,任意一个被嵌套向量中断控制器响应的外设中断都能将系统从睡眠模式唤醒。
如果执行WFE指令进入睡眠模式,则一旦发生唤醒事件时,微处理器都将从睡眠模式退出。
1.3.2停止模式
停止模式是在Cortex™-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电压调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止,PLL、HSI和HSE RC振荡器的功能被禁止,SRAM和寄存器内容被保留下来。
注意:在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。
(1)进入停止模式
在停止模式下,通过设置电源控制寄存器(PWR_CR)的LPDS位使内部调节器进入低功耗模式,能够降低更多的功耗。
- 如果正在进行闪存编程,直到对内存访问完成,系统才进入停止模式。
- 如果正在进行对APB的访问,直到对APB访问完成,系统才进入停止模式。
(2)退出停止模式

1.3.3待机模式
待机模式可实现系统的最低功耗。
该模式是在Cortex-M3深睡眠模式时关闭电压调节器。整个1.8V供电区域被断电。PLL、HSI和HSE振荡器也被断电。SRAM和寄存器内容丢失。只有备份寄存器和待机电路维持供电。这么说吧,能停的全停。

注意:在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:
- 复位引脚(始终有效)
- 当被设置为防侵入或校准输出时的TAMPER引脚。
- 被使能的唤醒引脚。
二、代码介绍
1 睡眠模式
cpp
/**
* 需求 : 测试STM32芯片进入低功耗 - 睡眠模式
*/
/**
* 睡眠模式
*/
void enter_sleep_mode() {
SCB->SCR &= ~SCB_SCR_SLEEPONEXIT; // 立即进入睡眠
//SCB->SCR |= SCB_SCR_SLEEPONEXIT; // 所有中断程序处理完后再进入睡眠
__wfi();
}
int main(void)
{
USART_Init();
LED_Init();
LED_On(LED_BLUE);
printf("测试STM32芯片进入低功耗 - 睡眠模式 \n");
printf("5s后STM32芯片进入睡眠模式 \n");
SysTick_DelayS(2);
printf("3s后STM32芯片进入睡眠模式 \n");
SysTick_DelayS(1);
printf("2s后STM32芯片进入睡眠模式 \n");
SysTick_DelayS(1);
printf("1s后STM32芯片进入睡眠模式 \n");
SysTick_DelayS(1);
// !进入睡眠模式
enter_sleep_mode();
// 蓝灯依然点亮
printf("STM32正常工作 \n");
while(1)
{
LED_Blink(LED_BLUE);
}
}
2 停止模式
cpp
/**
* 需求 : 测试STM32芯片进入低功耗 - 停止模式
*/
/**
* 停止模式
*/
void enter_stop_mode() {
// 开启时钟
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
// 深睡眠
SCB->SCR |= SCB_SCR_SLEEPDEEP;
// 掉电
PWR->CR &= ~PWR_CR_PDDS;
// 低功耗
PWR->CR |= PWR_CR_LPDS;
__wfi();
}
/**
* 睡眠模式
*/
void enter_sleep_mode() {
// 浅睡眠
SCB->SCR &= ~SCB_SCR_SLEEPDEEP;
SCB->SCR &= ~SCB_SCR_SLEEPONEXIT; // 立即进入睡眠
//SCB->SCR |= SCB_SCR_SLEEPONEXIT; // 所有中断程序处理完后再进入睡眠
__wfi();
}
void system_clock_reset(void) {
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}
}
int main(void)
{
USART_Init();
KEY_Init();
LED_Init();
LED_On(LED_BLUE);
printf("测试STM32芯片进入低功耗 - 停止模式 \n");
printf("5s后STM32芯片进入停止模式 \n");
SysTick_DelayS(2);
printf("3s后STM32芯片进入停止模式 \n");
SysTick_DelayS(1);
printf("2s后STM32芯片进入停止模式 \n");
SysTick_DelayS(1);
printf("1s后STM32芯片进入停止模式 \n");
SysTick_DelayS(1);
// !进入停止模式
enter_stop_mode();
// !外部中断唤醒芯片后,默认会采用HSI的震荡电路的频率,所以不是72M。
// !所以如果想要STM32芯片正常工作,那么就需要重新选择PLL时钟源
system_clock_reset();
SysTick_DelayMs(10);
// 蓝灯依然点亮
printf("STM32正常工作 \n");
while(1)
{
LED_Blink(LED_BLUE);
}
}
3 待机模式
cpp
/**
* 需求 : 测试STM32芯片进入低功耗 - 待机模式
*/
/**
* 待机模式
*/
void enter_standby_mode() {
// 开启时钟
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
// 深睡眠
SCB->SCR |= SCB_SCR_SLEEPDEEP;
// 掉电
PWR->CR |= PWR_CR_PDDS;
// 清除唤醒标志位
PWR->CR |= PWR_CR_CWUF;
// 使能唤醒引脚
PWR->CSR |= PWR_CSR_EWUP;
__wfi();
}
/**
* 停止模式
*/
void enter_stop_mode() {
// 开启时钟
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
// 深睡眠
SCB->SCR |= SCB_SCR_SLEEPDEEP;
// 掉电
PWR->CR &= ~PWR_CR_PDDS;
// 低功耗
PWR->CR |= PWR_CR_LPDS;
__wfi();
}
/**
* 睡眠模式
*/
void enter_sleep_mode() {
// 浅睡眠
SCB->SCR &= ~SCB_SCR_SLEEPDEEP;
SCB->SCR &= ~SCB_SCR_SLEEPONEXIT; // 立即进入睡眠
//SCB->SCR |= SCB_SCR_SLEEPONEXIT; // 所有中断程序处理完后再进入睡眠
__wfi();
}
void system_clock_reset(void) {
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}
}
int main(void)
{
USART_Init();
KEY_Init();
LED_Init();
LED_On(LED_BLUE);
printf("测试STM32芯片进入低功耗 - 待机模式 \n");
printf("5s后STM32芯片进入待机模式 \n");
SysTick_DelayS(2);
printf("3s后STM32芯片进入待机模式 \n");
SysTick_DelayS(1);
printf("2s后STM32芯片进入待机模式 \n");
SysTick_DelayS(1);
printf("1s后STM32芯片进入待机模式 \n");
SysTick_DelayS(1);
// !进入待机模式
enter_standby_mode();
while(1)
{
}
}
三、寄存器介绍



四、归纳和总结
相同点
- 三种模式均通过
PWR外设控制,核心操作是配置PWR_CR寄存器 + 执行WFI/WFE指令。 - 唤醒后都需要重新配置部分硬件(待机模式需完全重启,停止模式需配置外设时钟,睡眠模式无需额外配置)。
- 低功耗的核心逻辑都是减少时钟和电压调节器的功耗消耗。
不同点
- 断电程度:睡眠模式 < 停止模式 < 待机模式,断电越彻底,功耗越低,但数据保持能力越弱。
- 唤醒难度:睡眠模式最容易(任意中断 / 事件),待机模式最难(仅特定唤醒源)。
- 恢复速度:睡眠模式最快(无缝恢复),待机模式最慢(相当于复位重启)。
核心参数对比

