一、电源框图
电压调节器是 STM32 的电源系统中最核心部分,连接 VDD 供电区域和 1.8 供电区域。
二、电源管理

立即睡眠 |
在执行 WFI 或 WFE 指令时立即进入睡眠模式。 |
退出时睡眠 |
在退出优先级最低的中断服务程序后才进入睡眠模式。 |
进入方式 |
内核寄存器的SLEEPDEEP = 0 ,然后调用WFI或WFE指令即可进入睡眠模式; 另外若内核寄存器的SLEEPONEXIT=0时,进入“立即睡眠”模式,SLEEPONEXIT=1时,进入“退出时睡眠”模式。 |
唤醒方式 |
如果是使用WFI指令睡眠的,则可使用任意中断唤醒; 如果是使用WFE指令睡眠的,则由事件唤醒。 |
睡眠时 |
关闭内核时钟,内核停止,而外设正常运行,在软件上表现为不再执行新的代码。这个状态会保留睡眠前的内核寄存器、内存的数据。 |
唤醒延迟 |
无延迟。 |
唤醒后 |
若由中断唤醒,先进入中断,退出中断服务程序后,接着执行WFI指令后的程序;若由事件唤醒,直接接着执行WFE后的程序。 |
只需要调用这个函数,选择一下进入模式,中断进入/时间进入。
PWR_SLEEPENTRY_WFI: enter SLEEP mode with WFI instruction
PWR_SLEEPENTRY_WFE: enter SLEEP mode with WFE instruction
HAL_PWR_EnterSLEEPMode(uint32_t Regulator, uint8_t SLEEPEntry)
2.2、停止模式
调压器低功耗模式 |
在停止模式下调压器可工作在正常模式或低功耗模式,可进一步降低功耗 |
FLASH掉电模式 |
在停止模式下FLASH可工作在正常模式或掉电模式,可进一步降低功耗 |
进入方式 |
内核寄存器的SLEEPDEEP =1,PWR_CR寄存器中的PDDS=0,然后调用WFI或WFE指令即可进入停止模式; PWR_CR 寄存器的LPDS=0时,调压器工作在正常模式,LPDS=1时工作在低功耗模式; |
唤醒方式 |
如果是使用WFI指令睡眠的,可使用任意EXTI线的中断唤醒; 如果是使用WFE指令睡眠的,可使用任意配置为事件模式的EXTI线事件唤醒。 |
停止时 |
内核停止,片上外设也停止。这个状态会保留停止前的内核寄存器、内存的数据。 |
唤醒延迟 |
基础延迟为HSI振荡器的启动时间,若调压器工作在低功耗模式,还需要加上调压器从低功耗切换至正常模式下的时间,若FLASH工作在掉电模式,还需要加上FLASH从掉电模式唤醒的时间。 |
用KEY0来进入停止模式,然后使用任意外部中断唤醒。
uint8_t KEY0_Scan(void) {
static uint8_t key_pressed = 0;
if (HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4) == GPIO_PIN_RESET) {
HAL_Delay(20);
if (HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4) == GPIO_PIN_RESET && key_pressed == 0) {
key_pressed = 1;
while (HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4) == GPIO_PIN_RESET);
printf("按键0触发了,进入停止模式\n");
I2C_Write(0,I2C_Wbuf, strlen((char*)I2C_Wbuf) + 1);
HAL_PWR_EnterSTOPMode(1, PWR_SLEEPENTRY_WFI);
return 1;
}
} else {
key_pressed = 0;
}
return 0;
}
退出停止模式
因为停止模式,会关闭HSE和PLL,所以在退出时,必须重新开启HSE和PLL。
void CLK_Resume()
{
//使能HSE
__HAL_RCC_HSE_CONFIG(RCC_HSE_ON);
while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
{
}
//使能PLL
__HAL_RCC_PLL_ENABLE();
while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)
{
}
//选择PLL作为系统时钟
__HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_PLLCLK);
while(__HAL_RCC_GET_SYSCLK_SOURCE() != 0x08 )
{
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_2)
{
CLK_Resume();
printf("退出停止模式\n");
key_pressed_flag = 1;
key_debounce_start = HAL_GetTick();
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_2);
}
}
现象:

进入方式 |
内核寄存器的SLEEPDEEP =1,PWR_CR寄存器中的PDDS=1,PWR_CR寄存器中 |
唤醒方式 |
通过WKUP引脚的上升沿,RTC闹钟、唤醒、入侵、时间戳事件或NRST引脚外部复位 |
待机时 |
内核停止,片上外设也停止;内核寄存器、内存的数据会丢失;除复位引脚、 |
唤醒延迟 |
芯片复位的时间 |
唤醒后 |
相当于芯片复位,在程序表现为从头开始执行代码。 |
//下述代码实现了,按键1进入待机模式,并且用中断0进行唤醒,唤醒后相当于重新上电。
uint8_t key_pressed_flag = 0;
uint32_t key_debounce_start = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) //将PA0配置为中断模式
{
if(GPIO_Pin == GPIO_PIN_0)
{
HAL_ResumeTick(); //恢复systick中断,否则不能使用HAL_Delay
printf("退出待机模式\n");
key_pressed_flag = 1;
key_debounce_start = HAL_GetTick();
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
}
}
void KEYUP_Scan(void)
{
if (key_pressed_flag == 1)
{
if (HAL_GetTick() - key_debounce_start > 20)
{
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET)
{
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET)
{
if (HAL_GetTick() - key_debounce_start > 1000)
{
break;
}
}
printf("按键2触发!LED状态已翻转\n");
}
key_pressed_flag = 0;
}
}
}
uint8_t KEY1_Scan(void) {
static uint8_t key_pressed = 0;
if (HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3) == GPIO_PIN_RESET) {
HAL_Delay(20);
if (HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3) == GPIO_PIN_RESET && key_pressed == 0) {
key_pressed = 1;
while (HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3) == GPIO_PIN_RESET);
printf("按键1触发了,进入待机模式\n");
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); //使能唤醒引脚
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
HAL_PWR_EnterSTANDBYMode(); //进入到待机模式
return 1;
}
} else {
key_pressed = 0;
}
return 0;
}
void Key_Process(void)
{
KEY1_Scan();
KEYUP_Scan();
}