嵌入式系统应用-拓展-STM32 低功耗设计
STM32 低功耗设计
- 1 低功耗介绍
- 1.1 睡眠模式(Sleep Mode)
- 1.2 停止模式(Stop Mode)
- 1.3 待机模式(Standby Mode)
- 2 代码编写
- 2.1 进入睡眠模式
- 2.1.1代码说明
- 2.1.2 参考代码
- 2.1.3 功耗优化建议
- 2.2 停止模式
- 2.2.1 代码说明
- 2.2.2 代码编写
- 2.2.3 代码优化建议
- 2.3 待机模式
- 2.3.1 代码说明
- 2.3.2 代码编写
- 2.3.3 优化建议
- 3 总结
1 低功耗介绍
在手持设备使用过程中,功耗一直是一个比较敏感的问题。 如何优化低功耗设计,以下有几个方案:
1. 关闭未使用的外设时钟
通过 RCC_AHB1ENR、RCC_APB1ENR 等寄存器禁用不需要的外设时钟。
2. 降低主频
降低系统时钟频率(如使用 HSI 或 MSI 时钟源代替 HSE)。
3. 配置 GPIO 为低功耗状态
未使用的 GPIO 设置为模拟输入(高阻态)或输出低电平。
4. 使用 RTC 和低功耗定时器
利用 RTC 或 LPTIM(低功耗定时器)唤醒系统,替代普通定时器。
5. 电源管理
使用低功耗稳压器(如 STM32F407 支持电压调节范围)。
1.1 睡眠模式(Sleep Mode)
进入方式:通过执行 WFI(Wait for Interrupt)或 WFE(Wait for Event)指令。
功耗:内核停止运行,但外设(如 GPIO、定时器、UART 等)仍可工作。
唤醒方式:任何中断或事件均可唤醒。
1.2 停止模式(Stop Mode)
进入方式:通过配置电源控制寄存器(PWR_CR)进入。
功耗:关闭内核和大部分外设的时钟,仅保留 SRAM 和寄存器内容。
唤醒方式:
-
外部中断(EXTI)
-
RTC 闹钟
-
USB 唤醒信号等
注意:退出后需要重新配置时钟(HSI 作为默认时钟源)。
1.3 待机模式(Standby Mode)
进入方式:通过配置 PWR_CR 寄存器的 PDDS 位和 SLEEPDEEP 位。
功耗:最低功耗模式,关闭所有时钟(包括 SRAM),仅备份域(RTC、备份寄存器)可工作。
唤醒方式:
1.1 外部复位(NRST 引脚)
1.2 RTC 闹钟
1.2 独立看门狗(IWDG)
1.3 WKUP 引脚上升沿
注意:退出后相当于系统复位,程序从头开始执行
2 代码编写
2.1 进入睡眠模式
2.1.1代码说明
-
进入睡眠模式(内核停止,外设可选运行)。
-
通过 PA0(WKUP 引脚)的上升沿 触发外部中断(EXTI)唤醒。
-
唤醒后继续执行主程序。
2.1.2 参考代码
- 发送指令进入睡眠模式
// 进入睡眠模式
Enter_Sleep_Mode();
void Enter_Sleep_Mode(void) {
// 执行 WFI(Wait For Interrupt),进入睡眠模式
__WFI();
}
- 配置wakeup指令进入中断
// 配置 EXTI 中断(PA0 上升沿触发)
void EXTI_Configuration(void) {
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
// 连接 PA0 到 EXTI0
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
// 配置 EXTI0 为上升沿触发
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
// 配置 NVIC(设置中断优先级)
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
// EXTI0 中断服务函数(唤醒后自动执行)
void EXTI0_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
// 清除中断标志
EXTI_ClearITPendingBit(EXTI_Line0);
// 唤醒后无需额外操作,系统会继续执行主循环
}
}
2.1.3 功耗优化建议
在进入睡眠模式前关闭不必要的外设时钟(如 ADC、UART 等)。
将未使用的 GPIO 设置为模拟输入(高阻态)。
如果无需快速唤醒,可以降低系统时钟频率(如切换至 HSI)。
一般情况下,电流从几百mA降低到10或者20mA左右。
2.2 停止模式
2.2.1 代码说明
-
更低功耗(典型值约 1~2 μA,具体取决于外设状态)。
-
内核停止,SRAM 和寄存器内容保留。
-
唤醒后需重新配置时钟(默认切换为 HSI 时钟源)
2.2.2 代码编写
- 发送指令,进入停止模式
// 进入停止模式(最低功耗,保留 SRAM)
void Enter_Stop_Mode(void) {
// 使能 PWR 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
// 设置电压调节器为低功耗模式(进一步降低功耗)
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
}
- 配置唤醒中断
void EXTI_Config(void) {
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
// 连接 PA0 到 EXTI0
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
// 设置 EXTI0 为上升沿触发
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
// 配置 NVIC 中断
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
// EXTI0 中断服务函数(唤醒时不需额外操作)
void EXTI0_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志
}
}
- 重新配置时钟
// 唤醒后重新配置时钟(Stop 模式会复位为 HSI)
void Clock_Reconfig(void) {
// 重新启用 HSE 和 PLL
RCC_HSEConfig(RCC_HSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);
RCC_PLLConfig(RCC_PLLSource_HSE, 8, 336, 2, 7); // 168MHz 配置
RCC_PLLCmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource() != 0x08);
}
2.2.3 代码优化建议
- 更低功耗配置
进入停止模式前调用 PWR_Regulator_LowPower,进一步降低稳压器功耗。
关闭所有不必要的外设时钟(如 RCC_AHB1PeriphClockCmd 仅启用 GPIOA 和 GPIOD)。
- 唤醒后时钟恢复
停止模式会复位系统时钟为 HSI(16MHz),需手动重新配置为 HSE+PLL(168MHz)。
- GPIO 状态优化
PA0 设置为 内部上拉,避免悬空误触发。
未使用的 GPIO 应设为 模拟输入(代码中未体现,实际需补充)。
4 功耗
停止模式 1~2 μA
2.3 待机模式
2.3.1 代码说明
-
最低功耗(约 2μA)。
-
完全关闭内核和大部分外设,仅备份域(RTC、备份寄存器)可选保持。
-
唤醒后系统复位(程序从头执行)。
-
唤醒源:WKUP 引脚(PA0)上升沿,RTC 闹钟事件,NRST 引脚外部复位,独立看门狗(IWDG)复位。
-
调用 PWR_EnterSTANDBYMode() 后,系统立即进入待机模式。需提前使能 PWR_WakeUpPin_1(对应 PA0)。
-
唤醒后程序 从头开始执行(相当于复位),可通过 PWR_GetFlagStatus(PWR_FLAG_SB) 检测是否从待机模式唤醒。需手动清除唤醒标志 PWR_ClearFlag(PWR_FLAG_SB)。
-
PA0(WKUP 引脚)必须配置为 无内部上下拉(GPIO_PuPd_NOPULL),由外部电路确保明确电平。未使用的 GPIO 应设为 模拟输入 以降低漏电流
2.3.2 代码编写
- 进入待机模式
// 进入待机模式(通过 WKUP 引脚或 RTC 唤醒)
void Enter_Standby_Mode(void) {
// 使能 PWR 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
// 使能 WKUP 引脚唤醒功能(PA0 上升沿)
PWR_WakeUpPinCmd(PWR_WakeUpPin_1, ENABLE);
// 清除唤醒标志(避免误触发)
PWR_ClearFlag(PWR_FLAG_WU);
// 进入待机模式
PWR_EnterSTANDBYMode();
}
- PA0 配置输入口,不需要中断;但是需要注意事情是,需要外部电路确定IO的电平。一个上升沿就可以触发复位。
2.3.3 优化建议
- 关闭所有外设时钟,在进入待机模式前关闭不必要的时钟(如 ADC、USART 等);
- 配置 GPIO 为模拟输入,将所有未使用的 GPIO 设置为模拟输入(高阻态);
- 由于待机模式唤醒后程序会复位,若需保存状态,可使用:
- 备份寄存器(Backup Registers)(需启用 RCC_APB1Periph_BKP 时钟)。RTC 数据寄存器(需配置 RTC 和备份域)
3 总结
- 功耗对比图
2 . STM32F4系列 不是专为低功耗设计,如需极低功耗,建议选择 STM32L 系列(如 STM32L4)。退出待机模式后,程序会从头执行(相当于复位)。在停止模式下,部分外设需要重新初始化。通过合理配置低功耗模式,STM32F407 可以用于电池供电或间歇性工作的场景。