【STM32 + CubeMX】低功耗 -- Standby 待机模式

STM32 低功耗共有三种模式:

Sleep 睡眠模式 、Stop 停止模式、Standby 待机模式。

三种模式的 操作图解 地址:

本文将重点拆解Standby 待机模式 的代码实现、关键事项 。

参考资源:

目录

[一、 STM32 三种低功耗模式 区别](#一、 STM32 三种低功耗模式 区别)

[1、睡眠模式 Sleep Mode](#1、睡眠模式 Sleep Mode)

[2、停止模式 Stop Mode](#2、停止模式 Stop Mode)

二、工程准备

1、基础工程

2、烧录问题

[三、Standby 待机模式 代码实现](#三、Standby 待机模式 代码实现)

[1. 进入 Standby 待机 模式](#1. 进入 Standby 待机 模式)

[2. 唤醒后的处理](#2. 唤醒后的处理)

[四、 验证 & 测试](#四、 验证 & 测试)

[五、常见问题 & 避坑指南](#五、常见问题 & 避坑指南)


一、 STM32 三种低功耗模式 区别

1、睡眠模式 Sleep Mode

  • 功耗:芯片工作电流约 10~20mA (参考值)
  • 特点:CPU暂停在SLEEP这一行;外设正常工作;唤醒时间极快;
  • 注意1:能被所有中断事件唤醒;若无法进入 SLEEP,优先检查是否未关闭 SysTick 等频繁中断。
  • 注意2:被中断唤醒后,先进入对应中断函数执行,完成后再运行 SLEEP 下一行代码。
  • 注意3:SLEEP 模式无硬件唤醒标志,唤醒后无需额外处理;通常自定义软件标志配合业务逻辑。

|------|------------------------------------------------|
| 停止资源 | CPU内核停止运行、内核时钟关闭、程序暂停运行 |
| 保持资源 | 系统时钟、所有外设时钟保持运行 GPIO 口状态保持运行时的电平 内存、寄存器 数据保持不变 |
| 唤醒方式 | 任意中断事件均可唤醒 (如 GPIO中断、Systick、UART、RTC 等) |
| 唤醒后 | 程序正常运行,无需重新初始化时钟 / 外设。 |
| 适合场景 | 短时间无需 CPU 运算, 但需要外设(如串口、ADC、定时器)持续工作的场景 |

2、停止模式 Stop Mode

  • 功耗:芯片工作电流约 1mA (参考值)
  • 特点:系统时钟关闭;CPU和外设停止;内存数据保持;唤醒后仅需恢复系统时钟

|------|--------------------------------------------------------------------|
| 停止资源 | CPU 与所有外设停止工作 内核时钟、外设时钟,主时钟(HSE/HSI)被关闭 外设停止工作 |
| 保持资源 | 低速时钟(LSI/LSE,用于 RTC)继续运行 内核1.8V供电保持 内存、寄存器 数据保持不变; GPIO 口状态保持运行时电平 |
| 唤醒方式 | 外部中断 EXTI RTC 闹钟 |
| 唤醒后 | 不需要重新初始化 UART、SPI、ADC等外设 必须重新配置系统时钟(如启用 HSE/PLL) |
| 适合场景 | 需要低功耗、同时要求快速唤醒、数据不丢失的场合。 |

3、待机模式 Standby Mode

  • 功耗:芯片工作电流约 4uA (参考值)
  • 特点:几乎断电,内存数据丢失,唤醒后相当于复位

|------|---------------------------------------------------------------------------------------|
| 停止资源 | 内核1.8V电源关闭,内存、寄存器数据全部丢失 内核与外设时钟关闭,但 LSI/LSE 可在备份域继续给 RTC 供电 IO 口变为高阻态(模拟输入/浮空输入) |
| 保持资源 | 备份域(Backup Domain):备份寄存器、RTC 备份区域; WAKEUP唤醒引脚 PA0 RTC 相关引脚 复位引脚 |
| 唤醒方式 | WAKEUP 引脚(PA0)上升沿 RTC 闹钟 |
| 唤醒之后 | 程序从 从头运行 (相当于复位 )(不会回到 Standby下一行) 可通过 PWR_CSR 的 SBF / WUF 标志判断是 [待机唤醒] 还是 [上电复位] |
| 适合场景 | 长时间休眠、对功耗要求极致的电池供电设备、遥测终端等 |

注意 1 : WAKEUP 引脚(PA0)仅在 Standby 模式下具备硬件自动唤醒功能 ,Sleep / Stop 模式下 PA0 不具备此功能,必须配置为 EXTI 外部中断 才能唤醒。

**注意 2 :**IWDG 独立看门狗,只能复位芯片!不能唤醒!因为 IWDG 不会产生中断。


二、工程准备

1、基础工程

三种低功耗模式均支持 RTC 闹钟唤醒,因此统一使用 RTC 闹钟作为工程模板,添加低功耗测试。

不熟悉 RTC 闹钟的朋友,参考教程:

本文所用工程模板:【 Keil 工程文件 -- RTC 闹钟 】

当然,你可以使用自己的工程模板、需要的唤醒方式:

  • Sleep 睡眠模式:任意中断事件唤醒。
  • Stop停止模式:外部中断 EXTI 、RTC闹钟
  • Standby待机模式:WAKEUP 引脚 PA0 的上升沿 、 RTC 闹钟

2、烧录问题

STM32 进入 Stop、Standby 低功耗模式后,芯片内核停止工作,无法正常响应烧录信号,可能出现无法下载、烧录失败的情况。

以下是不同仿真器的解决方法:

STLink 仿真器的解决方法:

  • 方法1:按着板子复位按键,不放手,keil 点击 Load 后,马上放开复位按键。利用复位后的空档期识别烧录信号。
  • 方法2:BOOT0接线3.3V,按一次复位按键,烧录。拔掉BOOT0接线,按一次复位按键,即可。

CMSIS-DAP 仿真器的解决方法:

  • Connect这一项:选择 under Reset,即可随时烧录。

JLink 仿真器:

  • Stop 模式,不影响,随时可烧录。
  • Standby 模式,方法1:按着板子复位按键,不放手,keil 点击 Load 后,马上放开复位按键。利用复位后的空档期识别烧录信号。
  • Standby 模式,方法2:BOOT0接线3.3V,按一次复位按键,烧录。拔掉BOOT0接线,按一次复位按键,即可。

三、Standby 待机模式 代码实现

与 Sleep、Stop 模式相比,Standby 模式有以下关键特点:

  • 唤醒后程序复位,内存、寄存器数据都会丢失(除备份域)
  • 无需恢复系统时钟,因为复位后系统会自动重新初始化时钟(从 HSI 启动,再由SystemClock_Config() 配置为 HSE)。
  • 如果后备域可用,可以通过 备份寄存器 保存少量数据(最多 20 个 32 位寄存器,芯片型号不同数量有别),用于判断唤醒源或恢复关键状态。

本节以 RTC 闹钟 B 周期性唤醒 为例,演示进入 Standby 待机模式、唤醒后判断原因并执行对应任务。

方案仅作思路参考,实际项目可灵活扩展。

1. 进入 Standby 待机 模式

进入 Standby 待机模式本身很简单,只需调用HAL库函数:HAL_PWR_EnterSTANDBYMode ();

真正的重点在于:进入前的准备、以及进入的时机。

我们编写一个用户函数:把进入 Standby前的准备工作,整合在一起 。

具体操作:

  • main.c文件 ,在 /* USER CODE BEGIN 0 */ 区域
  • 在闹钟B中断回调函数的下方,添加函数。(按你所用中断回调函数位置而定)
cpp 复制代码
/******************************************************************************
 * 函  数: EnterStandbyMode
 * 功  能: 进入 STANDBY 待机模式
 * 说  明: 1. 内核电源关闭,内存、寄存器数据丢失(备份域除外)
 *          2. 唤醒后系统复位,程序从 main 函数重新执行
 *          3. 进入前需清除 PWR 唤醒标志,否则可能无法进入
 *          4. 唤醒源:仅两种合法唤醒方式, RTC闹钟、 WAKEUP引脚(PA0上升沿)
 * 参  数: 无
 * 返回值: 无
 * 备  注: 最后修改_2026年03月25日
 ******************************************************************************/
void EnterStandbyMode(void)
{
    /* 打印提示 */
    printf("\r\n");                                            // 打印 换行
    printf("① 即将进入 Standby 待机模式! \r\n");              // 打印 提示
    
    /* 开启 PWR 时钟 */
    __HAL_RCC_PWR_CLK_ENABLE();                                //开启PWR时钟; (新版本HAL库不再需要手动开启)

    /* 清除相关标志 */
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);                         // 清除唤醒标志 (关键)
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);                         // 清除待机标志 (建议)
    
    /* 配置唤醒源 */
    RTC_SetAlarmB(5);                                          // 设置RTC的闹钟B, 5秒后触发一次
    HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);                  // 使能WAKEUP引脚 (PA0上升沿触发)

    /* 进入 STANDBY 待机模式 */
    HAL_PWR_EnterSTANDBYMode();                                // 进入 Standby 模式

    /* 注意:以下代码永远不会被执行。唤醒后是复位重启 */
    printf("② 此行永远不会执行!\r\n");
}

重要 1:唤醒源

函数里,示例了两个唤醒源:RTC闹钟B、唤醒引脚PA0 。(Standby 仅有两个唤醒源)

① RTC闹钟B,设置为5秒后触发。

② WAKEUP 唤醒引脚。在STM32F407上,它固定是PA0。使能 WAKEUP 引脚后,无需配置PA0的 GPIO 模式和中断,硬件会自动检测PA0的电平变化(上升沿唤醒)。很多板商的开发板上都已引出 PA0 作为按键,闲时是低电平,当按键按下时PA0是高电平(唤醒 Standby)。

重要2: 清除唤醒标志

每次进入Standby前,必须清除PWR 的 WU 唤醒标志,否则可能无法进入 (立刻退出)。

重要3:这个函数永远不会运行到底

进入Standby待机模式后,芯片就关闭内核供电、停止工作,不再执行下面行的代码。

直到被唤醒,程序复位重新运行。

因此,上面函数进入Standby模式后的下面行,永远也不会被执行。这是Standby 与 Sleep、Stop的一个重要区别!

2. 唤醒后的处理

StandBy 模式 仅支持两个唤醒源:WAKEUP引脚、RTC闹钟。

程序唤醒后 (即复位运行),可以通过硬件标志 PWR_FLAG_SB,得知复位来源:待机模式唤醒、正常上电复位 。

具体操作:

  • main()函数,在外设初始化后,编写以下代码:
  • 1- 判断 复位源
  • 2- 调用 EnterStandbyMode(), 进入待机模式
cpp 复制代码
/* 判断复位来源 */
if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) )                  // 待机唤醒后的复位 
{
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);                 // 清除待机唤醒标志; 注意先清标志再干活 
    // TODO: 在这里添加唤醒后的特殊处理                // 执行待机唤醒的特定任务
    printf("\r系统是从 STANDBY 待机模式 唤醒!\r\n");
}
else                                                   // 正常上电复位 
{
    printf("\r系统是正常上电启动!\r\n");              // 打印提示
    /* TODO: 在这里执行完整初始化 */                   // 执行完整初始化、任务
}
  

/* 准备进入 Standby 待机模式 */
HAL_Delay(1000);
EnterStandbyMode();                                    // 进入 Standby 待机模式

/* 下面的代码永远不会运行 */
 

添加完成后,位置参考如下图:

这里只是示例。真实项目改为由特定条件进入Standby。


四、 验证 & 测试

现在,Standby 模 的所有工作:清除标志、进入、唤醒、判断复位源,都已处理完毕。

编译、烧录后,串口助手输出如下图:

  • 程序上电运行后,判断复位源
  • 1秒后,准备进入Standby模式
  • 进入前:设置闹钟B 5秒后触发、使能WAKEUP引脚
  • (进入了Standby,直到被 闹钟 或 WAKEUP 唤醒)
  • 注意:图中可以看到,即使被闹钟唤醒,但唤醒后没有执行闹钟B回调函数里的printf。因为 Standby 唤醒后只能是从头运行程序 !!

五、常见问题 & 避坑指南

1. 无法进入 STANDBY 模式(电流依然较高)

可能原因:

  • 未清除 PWR_FLAG_WU 唤醒标志,导致进入 STANDBY 后立即被唤醒。
  • 外部中断或 RTC 闹钟频繁触发,导致刚进入就被唤醒。
  • PA0 引脚悬空,受噪声影响误触发。

解决方法:

  • 在 EnterStandbyMode() 函数开头调用 __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU)。
  • 确保唤醒源在进入前已配置正确,且不会在短时间内再次触发。
  • 对 PA0 引脚加上拉电阻。

2. 唤醒后 RTC 时间错乱

原因:

  • 待机模式下,RTC 会继续运行,但如果使用 LSI,其精度较低,长时间待机可能导致时间漂移。

解决:

  • 如需高精度时间,使用外部 LSE 晶振。唤醒后应重新读取 RTC 时间,无需重新设置。

3. 仿真器无法烧录、无法连接

参考第二节"烧录问题"的解决方法。

4. PA0 唤醒引脚与外部中断冲突

如果既配置了 PA0 为 WKUP 引脚,又使能了 EXTI 中断,可能会产生双重唤醒。建议仅使用 WKUP 功能,无需配置 EXTI。

5. 如何测试电流

开发板断开USB供电。

万用表调至mA档,串联在电源回路 (红笔接5V电源正极,黑笔压在开发板5V排针,板子GND接电源GND)。


文毕,欢迎指正、交流。~~

相关推荐
广药门徒2 小时前
PADS 改变飞线方向 改变同网络既定路径规划 改变VIRTUAL HOLE连接路径 修复差分信号自动规划飞线错误问题的办法
嵌入式硬件
猪猪童鞋2 小时前
PADS安装包资源分享
嵌入式硬件
Zarek枫煜2 小时前
zig与c3的算法 -- 静态队列
开发语言·stm32·单片机·嵌入式硬件·算法·51单片机
Topplyz2 小时前
为什么MCU监测电压时,有时不直接使用电阻分压,而是要使用运放?
单片机·嵌入式硬件
F137298015572 小时前
12V降5V,10A大功率电源芯片WD5030K
stm32·单片机·嵌入式硬件·51单片机
电子工程师成长日记-C512 小时前
51单片机非接触红外测温(蓝牙传输)
单片机·嵌入式硬件·51单片机
qq_389600133 小时前
pads-logic 学习笔记
笔记·嵌入式硬件·学习·硬件工程·pcb工艺
蜕变的小白4 小时前
嵌入式硬件的学习----ARM
arm开发·嵌入式硬件·学习·arm
倔强的石头1064 小时前
【Linux指南】基础IO系列(二):C 语言标准库 IO 接口实战 —— 从 fopen 到 feof 全解析
linux·c语言·单片机