3.3V
│
┌─────────┼──────────┐
│ │ │
VDD VDDA VREF VBAT
(主电源) (模拟电源) (参考电压) (备份电池)
│ │ │ │
│ ┌────┘ │ ┌────┘
│ │ │ │
├─ 内置稳压器 ── 1.8V内核 ─┤
│ │
└─── BKP + RTC ───────────┘
| 电源引脚 | 说明 |
|---|---|
| VDD | 3.3V 主数字电源 |
| VDDA | 3.3V 模拟电源 (ADC/DAC/PLL) |
| VREF | ADC 参考电压 (部分封装内部接 VDDA) |
| VBAT | 备份电池 (RTC + BKP 后备供电) |
1. 配置 Flash 等待周期 (72MHz 需 2 个等待周期)
2. 修改 HCLK 预分频 (AHB)
3. 修改 APB1/APB2 预分频
4. 修改 PLL 倍频系数 (或直接使用 HSI/HSE)
┌─────────────────┐
│ 睡眠 Sleep │
│ CPU 停,外设正常 │
│ 任意中断唤醒 │
└────────┬────────┘
│
┌────────▼────────┐
│ 停止 Stop │
│ HSI/HSE/PLL 停 │
│ SRAM/寄存器保留 │
│ EXTI/外部中断唤醒 │
└────────┬────────┘
│
┌────────▼────────┐
│ 待机 Standby │
│ 全部停 (包括调压器)│
│ SRAM/寄存器丢失 │
│ WKUP/RTC/复位唤醒│
└─────────────────┘
| 特性 | Sleep | Stop | Standby |
|---|---|---|---|
| CPU | 停 | 停 | 停 |
| HSI/HSE/PLL | 运行 | 停 | 停 |
| 电压调节器 | 运行 | 低功耗/运行 | 停 |
| SRAM/寄存器 | 保留 | 保留 | 丢失 |
| 备份域 | 保留 | 保留 | 保留 |
| 唤醒源 | 任意中断 | EXTI (GPIO/RTC) | WKUP/RTC/NRST |
| 唤醒后 | 从中断处继续 | 重新配置时钟 | 相当于复位 |
电流对比 (典型值):
| 函数 | 说明 |
|---|---|
void PWR_DeInit(void) |
复位 PWR 寄存器 |
void PWR_BackupAccessCmd(FunctionalState NewState) |
使能备份域访问 |
void PWR_PVDCmd(FunctionalState NewState) |
使能电源电压检测 |
void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel) |
配置 PVD 阈值 |
void PWR_WakeUpPinCmd(FunctionalState NewState) |
使能 WKUP 引脚 (PA0) |
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint32_t PWR_STOPEntry) |
进入停止模式 |
void PWR_EnterSTANDBYMode(void) |
进入待机模式 |
void PWR_EnterSleepMode(void) |
进入睡眠模式 (实际用 __WFI() 更方便) |
PWR_EnterSTOPMode 参数:
| 参数 | 可选值 | 说明 |
|---|---|---|
| PWR_Regulator | PWR_Regulator_ON |
调压器运行 (唤醒快) |
PWR_Regulator_LowPower |
调压器低功耗 (省电) | |
| PWR_STOPEntry | PWR_STOPEntry_WFI |
WFI 指令进入 |
PWR_STOPEntry_WFE |
WFE 指令进入 |
| 函数 | 说明 |
|---|---|
__WFI(void) |
汇编 WFI 指令,进入 Sleep/Stop |
__WFE(void) |
汇编 WFE 指令 |
__SEV(void) |
汇编 SEV 指令 (发送事件) |
SCB->SCR |
系统控制寄存器 (SLEEPONEXIT 位) |
/*------------------------------------------------
* SetClock_36MHz.c
*------------------------------------------------*/
#include "stm32f10x.h"
void SetSysClockTo36MHz(void)
{
/* 1. Flash 等待周期:36MHz 需 1 个等待周期 */
FLASH_SetLatency(FLASH_Latency_1);
/* 2. 修改 AHB 预分频:HCLK = SYSCLK / 2 = 36MHz */
RCC->CFGR &= ~RCC_CFGR_HPRE;
RCC->CFGR |= RCC_CFGR_HPRE_Div2;
/* 3. APB1 = HCLK / 1 = 36MHz (APB1 最高 36MHz) */
RCC->CFGR &= ~RCC_CFGR_PPRE1;
RCC->CFGR |= RCC_CFGR_PPRE1_Div1;
/* 4. APB2 = HCLK / 1 = 36MHz */
RCC->CFGR &= ~RCC_CFGR_PPRE2;
RCC->CFGR |= RCC_CFGR_PPRE2_Div1;
}
int main(void)
{
SetSysClockTo36MHz();
/* 此时系统时钟为 36MHz */
while (1);
}
/*------------------------------------------------
* SleepMode_Example.c
* 睡眠模式,PA0 外部中断唤醒
*------------------------------------------------*/
#include "stm32f10x.h"
void GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void EXTI_Config(void)
{
EXTI_InitTypeDef EXTI_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
NVIC_InitTypeDef NVIC_InitStruct;
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);
}
void EXTI0_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line0) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line0);
/* 唤醒后从此继续执行 (不是 main 开头) */
}
}
int main(void)
{
GPIO_Config();
EXTI_Config();
while (1)
{
/* 进入睡眠模式 (Sleep) */
__WFI();
/* 中断唤醒后继续往下执行 */
}
}
/*------------------------------------------------
* StopMode_Example.c
* 停止模式,PA0 (WKUP) 上升沿唤醒
* 注意:唤醒后必须重新配置系统时钟!
*------------------------------------------------*/
#include "stm32f10x.h"
void SystemClock_Reconfig(void)
{
/* 重新配置系统时钟到 72MHz */
/* 省略标准 SystemInit() 调用,或调用 HSI/HSE+PLL 启动函数 */
SystemInit();
}
int main(void)
{
/* 使能 WKUP 引脚 (PA0) */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_WakeUpPinCmd(ENABLE);
while (1)
{
/* 进入停止模式 (调压器低功耗, WFI) */
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
/* ---- 唤醒后从这里继续 ---- */
SystemClock_Reconfig(); // ★ 必须重新配置时钟
/* 继续其他操作 */
}
}
/*------------------------------------------------
* StandbyMode_Example.c
* 待机模式,RTC 闹钟 5 秒后唤醒
* 注意:待机唤醒 = 复位,从 main 开头执行!
*------------------------------------------------*/
#include "stm32f10x.h"
void RTC_ConfigForStandby(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
{
/* 初始化 RTC: LSE, 1Hz */
RCC_LSEConfig(RCC_LSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_SetPrescaler(32767);
RTC_WaitForLastTask();
/* 设置闹钟 (当前时间 + 5 秒) */
RTC_SetAlarm(RTC_GetCounter() + 5);
RTC_WaitForLastTask();
BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
}
else
{
/* 已配置,等 RTC 同步 */
RTC_WaitForSynchro();
/* 唤醒后 (待机=复位) 需重新设置闹钟 */
RTC_SetAlarm(RTC_GetCounter() + 5);
RTC_WaitForLastTask();
}
}
int main(void)
{
/* 重启后检查是否是待机唤醒 */
if (RCC_GetFlagStatus(RCC_FLAG_SFTRST) || RCC_GetFlagStatus(RCC_FLAG_PORRST) ||
RCC_GetFlagStatus(RCC_FLAG_PINRST))
{
/* 上电复位,正常启动 */
}
if (RCC_GetFlagStatus(RCC_FLAG_WU) != RESET)
{
/* 待机唤醒复位 */
RCC_ClearFlag();
}
SystemInit();
RTC_ConfigForStandby();
/* 使能 WKUP (待机模式也需) */
PWR_WakeUpPinCmd(ENABLE);
/* 5 秒后闹钟触发唤醒 */
PWR_EnterSTANDBYMode();
/* ---- 不会执行到这里 ---- */
while (1);
}
待机模式相当于复位
停止模式唤醒后需重配时钟
SystemInit() 配置系统时钟WKUP 引脚是 PA0
PWR_WakeUpPinCmd(ENABLE) 固定使用 PA0SLEEPONEXIT 位
SCB->SCR |= 1 << 1 设置 SLEEPONEXITPVD (可编程电压检测)
停止模式调试
DBGMCU_Config(DBGMCU_STOP, ENABLE) 保持调试PWR 时钟必须使能
PWR_EnterSTOPMode() / PWR_EnterSTANDBYMode() 前RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE)WFI 与 WFE 区别
WFI (Wait For Interrupt): 有中断挂起时退出WFE (Wait For Event): 有事件挂起时退出__SEV() 发送事件唤醒 WFE