一、核心原理与硬件基础
1. 待机模式(Standby Mode)简介
待机模式是STM32的最低功耗模式,核心特性:
- 功耗极低:典型电流<2μA(仅保留备份域和待机电路,SRAM/寄存器内容丢失)。
- 唤醒后复位 :退出待机模式时,系统执行硬件复位,程序从头开始执行(需通过复位标志判断唤醒事件)。
- 唤醒源:支持外部WKUP引脚上升沿、RTC闹钟、IWDG复位、NRST引脚复位等。
2. 关键寄存器与库函数
| 模块 | 寄存器/函数 | 功能 |
|---|---|---|
| 电源控制(PWR) | PWR_EnterSTANDBYMode() |
进入待机模式(标准库函数) |
PWR_GetFlagStatus(PWR_FLAG_SB) |
检查是否由待机模式唤醒(复位标志) | |
PWR_ClearFlag(PWR_FLAG_SB) |
清除待机唤醒标志 | |
| 复位控制(RCC) | RCC_GetFlagStatus(RCC_FLAG_PORRST) |
检查复位源(上电/待机唤醒/看门狗等) |
3. 唤醒源配置(以WKUP引脚为例)
- WKUP引脚:PA0(默认),高电平(上升沿)触发唤醒,需配置为输入模式并使能唤醒功能。
- 其他唤醒源:RTC闹钟(需配置RTC时钟和闹钟事件)、外部中断(需配置EXTI线并允许中断唤醒)。
二、硬件设计方案
1. 核心硬件需求
- STM32主控:任意带PWR模块的型号(如F103C8T6、F407ZGT6)。
- 唤醒按键:轻触按键接PA0(WKUP引脚)和GND,按下时PA0变为高电平(上升沿唤醒)。
- 状态指示:LED接PB0(唤醒后点亮,提示系统复位)。
- 电源测量:万用表(测量待机电流,验证低功耗效果)。
2. 电路连接要点
- WKUP按键:PA0引脚接按键一端,按键另一端接GND,PA0内部上拉(或外部10kΩ上拉至3.3V),按下时PA0=0V,释放时PA0=3.3V(上升沿唤醒)。
- LED指示:PB0接LED阳极,LED阴极接GND(串联220Ω限流电阻),STM32输出高电平时点亮。
三、软件设计与核心代码(标准库版)
1. 系统架构
- 初始化阶段:配置系统时钟、GPIO(WKUP引脚、LED)、PWR(使能WKUP唤醒)。
- 主循环:检测按键(非WKUP键)触发进入待机模式,或执行其他低功耗任务。
- 唤醒后处理:系统复位后,通过PWR_FLAG_SB标志判断是否为待机唤醒,点亮LED提示。
2. 核心代码实现
2.1 头文件与宏定义(standby_wakeup.h)
c
#ifndef __STANDBY_WAKEUP_H
#define __STANDBY_WAKEUP_H
#include "stm32f10x.h"
// 引脚定义
#define WKUP_PIN GPIO_Pin_0
#define WKUP_PORT GPIOA
#define LED_PIN GPIO_Pin_0
#define LED_PORT GPIOB
// 函数声明
void System_Init(void); // 系统初始化(时钟、GPIO、PWR)
void Enter_Standby_Mode(void); // 进入待机模式
void Wakeup_Handler(void); // 唤醒后处理(复位时调用)
#endif /* __STANDBY_WAKEUP_H */
2.2 源文件实现(standby_wakeup.c)
c
#include "standby_wakeup.h"
#include "stm32f10x_pwr.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
/**
* @brief 系统初始化(时钟、GPIO、PWR)
* @param 无
* @retval 无
*/
void System_Init(void) {
// 1. 配置系统时钟(72MHz,F103C8T6)
RCC_DeInit(); // 复位RCC
RCC_HSEConfig(RCC_HSE_ON); // 使能外部高速时钟(8MHz)
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); // 等待HSE就绪
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // PLL=8MHz×9=72MHz
RCC_PLLCmd(ENABLE); // 使能PLL
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // 等待PLL就绪
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 系统时钟=PLL
RCC_HCLKConfig(RCC_SYSCLK_Div1); // HCLK=72MHz
RCC_PCLK1Config(RCC_HCLK_Div2); // PCLK1=36MHz
RCC_PCLK2Config(RCC_HCLK_Div1); // PCLK2=72MHz
// 2. 配置GPIO(WKUP引脚:PA0输入,LED:PB0推挽输出)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
// WKUP引脚(PA0):输入模式(上拉,默认高电平,按下接地)
GPIO_InitStruct.GPIO_Pin = WKUP_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(WKUP_PORT, &GPIO_InitStruct);
// LED引脚(PB0):推挽输出
GPIO_InitStruct.GPIO_Pin = LED_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED_PORT, &GPIO_InitStruct);
GPIO_ResetBits(LED_PORT, LED_PIN); // 初始熄灭
// 3. 配置PWR(使能WKUP唤醒功能)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); // 使能PWR时钟
PWR_WakeUpPinCmd(ENABLE); // 使能WKUP引脚唤醒(PA0)
}
/**
* @brief 进入待机模式
* @param 无
* @retval 无
*/
void Enter_Standby_Mode(void) {
// 1. 关闭外设时钟(降低功耗)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, DISABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, DISABLE); // 仅保留PWR时钟
// 2. 清除唤醒标志(避免误触发)
PWR_ClearFlag(PWR_FLAG_WU); // 清除唤醒标志
PWR_ClearFlag(PWR_FLAG_SB); // 清除待机标志
// 3. 进入待机模式(标准库函数)
PWR_EnterSTANDBYMode(); // 执行后系统进入待机,仅WKUP引脚可唤醒
}
/**
* @brief 唤醒后处理(系统复位时调用)
* @param 无
* @retval 无
*/
void Wakeup_Handler(void) {
// 检查是否由待机模式唤醒(PWR_FLAG_SB标志置位)
if (PWR_GetFlagStatus(PWR_FLAG_SB) != RESET) {
PWR_ClearFlag(PWR_FLAG_SB); // 清除待机标志
GPIO_SetBits(LED_PORT, LED_PIN); // 点亮LED提示唤醒成功
// 可添加其他唤醒后操作(如串口打印、状态恢复)
}
}
2.3 主程序调用示例(main.c)
c
#include "stm32f10x.h"
#include "standby_wakeup.h"
#include "delay.h" // 简单延时函数(需自行实现)
int main(void) {
System_Init(); // 系统初始化
Wakeup_Handler(); // 唤醒后处理(首次上电不执行,唤醒后执行)
// 主循环:检测普通按键(PC13)触发进入待机
while (1) {
if (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13) == Bit_RESET) { // 按键按下(低电平)
Delay_ms(20); // 消抖
if (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13) == Bit_RESET) {
Enter_Standby_Mode(); // 进入待机模式
}
}
// 其他低功耗任务(如传感器采集,此处省略)
}
}
四、关键注意事项
1. 待机模式进入步骤
- 关闭外设时钟:除PWR外,关闭其他外设时钟(如GPIO、UART),减少漏电流。
- 清除唤醒标志 :通过
PWR_ClearFlag()清除PWR_FLAG_WU和PWR_FLAG_SB,避免历史标志干扰。 - 使能唤醒源 :通过
PWR_WakeUpPinCmd(ENABLE)使能WKUP引脚,或配置RTC闹钟。 - 调用
PWR_EnterSTANDBYMode():执行后系统立即进入待机,程序停止运行。
2. 唤醒后处理
- 系统复位 :退出待机模式时,STM32执行硬件复位,程序从
main()函数重新执行。 - 判断唤醒源 :通过
PWR_GetFlagStatus(PWR_FLAG_SB)检查是否由待机唤醒(标志在复位后由硬件置位)。 - 状态恢复:唤醒后需重新初始化外设(如时钟、GPIO),因待机模式会丢失SRAM/寄存器内容。
3. 常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 无法进入待机模式 | 未使能PWR时钟或未调用PWR_EnterSTANDBYMode |
检查RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE)是否执行 |
| 唤醒后无反应 | 未清除PWR_FLAG_SB或未检测标志 |
在main()开头调用Wakeup_Handler(),检查标志 |
| 待机电流过大 | 外设未完全关闭(如ADC、DMA时钟) | 关闭所有非必要外设时钟,确保仅PWR工作 |
参考代码 STM32 待机并唤醒实验(库函数) www.youwenfan.com/contentcst/133694.html
五、系统调试与优化
1. 调试步骤
| 阶段 | 操作 | 工具 |
|---|---|---|
| 硬件检查 | 测量PA0电压(按下按键时应为3.3V,释放时0V) | 万用表、示波器 |
| 待机电流测试 | 进入待机后,测量VCC电流(应<2μA) | 万用表(电流档,串联测量) |
| 唤醒测试 | 按下WKUP按键,观察LED是否点亮(唤醒成功) | 肉眼观察、逻辑分析仪(复位信号) |
2. 低功耗优化
- 关闭未用外设 :进入待机前,通过
RCC_APBxPeriphClockCmd(DISABLE)关闭所有非必要外设时钟。 - 降低IO功耗 :将未用GPIO配置为模拟输入模式(减少漏电流),避免浮空。
- 使用RTC唤醒:若需定时唤醒,可配置RTC闹钟(如每小时唤醒一次),替代按键唤醒。
六、扩展应用
- 电池供电设备:如无线传感器节点,待机时仅保留RTC运行,定时唤醒采集数据。
- 远程唤醒:通过WKUP引脚外接无线模块(如433MHz接收器),接收指令后唤醒系统。
- 多唤醒源融合:同时配置WKUP引脚、RTC闹钟、IWDG复位,实现多条件唤醒。
七、总结
本实验通过标准库函数 实现了STM32的待机模式与WKUP引脚唤醒,核心步骤包括PWR配置 、外设关闭 、进入待机 及唤醒后复位处理。待机模式适用于电池供电场景,可将系统功耗降至μA级,配合定时唤醒或外部触发,实现"休眠-工作"循环。