本篇知识点基于F0讲解
一、STM32三种低功耗模式参考表格
模式 | 功耗 | 唤醒时间 | 保持状态 | 典型应用场景 |
---|---|---|---|---|
睡眠模式 | 中等 (mA级) | 最短 (μs级) | CPU停止,外设保持 | 短暂待机,快速响应 |
停止模式 | 低 (μA级) | 中等 (ms级) | RAM保持,时钟停止 | 长时间待机,电池供电 |
待机模式 | 极低 (nA级) | 最长 (复位级) | 仅备份域保持 | 超低功耗需求,看门狗唤醒 |
二、睡眠模式深入解析
1. 进入睡眠模式
void PWR_EnterSleepMode(uint8_t PWR_SLEEPEntry)
{/* 1. 参数合法性检查 */assert_param(IS_PWR_SLEEP_ENTRY(PWR_SLEEPEntry));/* 2. 清除SLEEPDEEP位(关键步骤)*/SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;/* 3. 选择进入方式 */if(PWR_SLEEPEntry == PWR_SLEEPEntry_WFI) {__WFI(); // 等待中断指令} else {__WFE(); // 等待事件指令}
}
关键操作解析:
-
参数检查
assert_param()
- 确保传入参数只能是:
PWR_SLEEPEntry_WFI
(0x01)PWR_SLEEPEntry_WFE
(0x02)
- 防止非法参数导致未定义行为
- 确保传入参数只能是:
-
清除SLEEPDEEP位
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
- 目的:明确指定进入睡眠模式(非停止/待机模式)
- 寄存器说明:
Cortex-M0系统控制寄存器(SCR)的SLEEPDEEP位:0
= 睡眠模式1
= 深度睡眠模式(停止/待机)
- 硬件关联:该位与电源控制寄存器(PWR_CR)的PDDS和LPDS位协同工作
-
休眠指令选择
指令 汇编指令 唤醒条件 特点 WFI WFI
任意中断 传统唤醒方式 WFE WFE
事件信号 支持SEVONPEND和事件线
2. 退出睡眠模式
(1) WFI唤醒机制
- 唤醒条件:任何在NVIC中使能的外设中断
- 唤醒流程:
- 特点:
- 自动清除中断挂起位
- 唤醒后从WFI下一条指令开始执行
(2) WFE唤醒机制
提供两种事件驱动唤醒方式:
方式一:SEVONPEND机制
配置步骤:
- 使能SCB_SCR的SEVONPEND位
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
- 配置外设中断(但禁用NVIC中断)
- 执行
__WFE()
进入睡眠
唤醒条件:外设中断挂起位置位(即使NVIC中断禁用)
唤醒后操作:
// 必须双重清除挂起位!
EXTI_ClearITPendingBit(EXTI_LineX); // 清除外设级挂起位
NVIC_ClearPendingIRQ(IRQn); // 清除NVIC级挂起位
注意事项:
- 不清除挂起位会导致之后如果执行WFE时会立即唤醒(无法正常进入睡眠)
- 适用于复用现有中断逻辑的场景
实践代码
void Enter_Sleep_WFE(void)
{// 配置唤醒源(SEVONPEND模式)SCB->SCR |= SCB_SCR_SEVONPEND_Msk;EXTI->IMR |= EXTI_IMR_MR5; // 使能PA5中断NVIC_DisableIRQ(EXTI4_15_IRQn); // 禁用NVIC中断__WFE(); // 进入睡眠// ===== 唤醒后处理 =====// 1. 清除外设挂起位(写1清除)EXTI->PR = EXTI_PR_PR5;//NVIC_ClearPendingIRQ(IRQn); // 清除NVIC级挂起位// 2. 清除NVIC挂起位NVIC->ICPR[0] = (1 << (EXTI4_15_IRQn & 0x1F));//NVIC_ClearPendingIRQ(IRQn); // 清除NVIC级挂起位// 3. 添加延迟防止信号抖动for(volatile int i=0; i<100; i++);// 4. 执行业务逻辑Handle_Wakeup_Event();
}
方式二:纯事件模式
配置步骤:
- 设置EXTI为事件模式
EXTI_InitTypeDef exti = {0}; exti.EXTI_Line = EXTI_Line5; exti.EXTI_Mode = EXTI_Mode_Event; // 关键配置 exti.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_Init(&exti);
- 执行
__WFE()
进入睡眠
唤醒条件:EXTI线检测到指定事件边沿
优势:
- 无需中断处理函数
- 无需清除挂起位
- 唤醒延迟最短(约6个时钟周期)
3. 唤醒机制对比表
特性 | WFI唤醒 | WFE+SEVONPEND | WFE+事件模式 |
---|---|---|---|
配置复杂度 | ★☆☆ (简单) | ★★☆ (中等) | ★★☆ (中等) |
中断处理程序 | 需要 | 不需要 | 不需要 |
挂起位管理 | 自动清除 | 需手动双重清除 | 无挂起位产生 |
唤醒延迟 | 12-15周期 | 12-15周期 | 5-8周期 |
功耗优化 | ★★☆ | ★★★ | ★★★★ |
适用场景 | 常规中断响应 | 复用现有中断资源 | 专用低功耗事件 |
4. 最佳实践建议
(1) 配置推荐
// 最优配置:纯事件模式唤醒
void Enter_LowPower_Mode(void)
{// 1. 配置事件唤醒源EXTI_InitTypeDef exti = {0};exti.EXTI_Line = EXTI_Line5;exti.EXTI_Mode = EXTI_Mode_Event;exti.EXTI_Trigger = EXTI_Trigger_Falling;exti.EXTI_LineCmd = ENABLE;EXTI_Init(&exti);// 2. 关闭非必要外设时钟RCC_APB1PeriphClockCmd(UNUSED_PERIPH, DISABLE);// 3. 进入睡眠PWR_EnterSleepMode(PWR_SLEEPEntry_WFE);
}
- 关键提醒:事件模式需确保 GPIO 时钟开启(RCC_AHBPeriph_GPIOx)。若为省电关闭时钟,事件将无法触发唤醒。
(2) 唤醒处理
// 事件唤醒后直接处理业务
if(GPIO_ReadInputDataBit(WAKEUP_PORT, WAKEUP_PIN) == ACTIVE_STATE)
{Process_Wakeup_Event(); // 无需清除挂起位
}
(3) 常见问题解决
问题:唤醒后立即重新睡眠
- 原因:未正确清除挂起位
- 解决方案:
// 对于SEVONPEND模式 EXTI_ClearITPendingBit(EXTI_LineX); NVIC_ClearPendingIRQ(IRQn);// 额外添加延迟 delay_us(10);
5. 功耗优化技巧
- 时钟管理:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, DISABLE);
- IO状态配置:
- 未用引脚设为模拟输入
- 输出引脚固定电平
- 外设状态管理:
- ADC禁用并关闭参考电压
- 串口接收器禁用
- 唤醒源选择:
- 优先选择低功耗唤醒源(EXTI > 定时器)