stm32中的电源管理

STM32系列的MCU都有电源管理功能,本文将介绍stm32系列MCU的电源管理系统。

前言

在stm32中主要通过引脚VDD来从外部获取电源,在stm32内部有电源监控器用于检测VDD引脚的电压,以实现复位功能和掉电紧急处理功能。

电源监控器

stm32通过这个物理结构来监视电源的情况。

上电复位状态和掉电复位状态

当检测到VDD的电压低于阈值VPOR及VPDR时,无需外部电路辅助,STM32芯片会自动保持在复位状态,防止因电压不足强行工作而带来严重的后果。 见图 POR与PDR ,在刚开始电压低于VPOR时(约1.92V), STM32保持在上电复位状态(POR,Power On Reset),当VDD电压持续上升至大于VPOR时,芯片开始正常运行,而在芯片正常运行的时候, 当检测到VDD电压下降至低于VPDR阈值(约1.88V),会进入掉电复位状态(PDR,Power Down Reset)。

可编程电压检测器PVD

上述POR、PDR功能是使用其电压阈值与外部供电电压VDD比较,当低于工作阈值时,会直接进入复位状态,这可防止电压不足导致的误操作。 除此之外,STM32还提供了可编程电压检测器PVD,它也是实时检测VDD的电压,当检测到电压低于编程的VPVD阈值时, 会向内核产生一个PVD中断(EXTI16线中断)以使内核在复位前进行紧急处理。该电压阈值可通过电源控制寄存器PWR_CSR设置。

其作用就是动态检测VDD,当VDD的值不在设置的范围内时就会产生一个内核中断,并且进入中断处理函数

可编程电压检测器PVD的编程

直接使用函数PWR_PVDLevelConfig()设置等级,参数可选项如下:

1
2
3
4
5
6
7
8
@arg PWR_PVDLevel_2V2: PVD detection level set to 2.2V
@arg PWR_PVDLevel_2V3: PVD detection level set to 2.3V
@arg PWR_PVDLevel_2V4: PVD detection level set to 2.4V
@arg PWR_PVDLevel_2V5: PVD detection level set to 2.5V
@arg PWR_PVDLevel_2V6: PVD detection level set to 2.6V
@arg PWR_PVDLevel_2V7: PVD detection level set to 2.7V
@arg PWR_PVDLevel_2V8: PVD detection level set to 2.8V
@arg PWR_PVDLevel_2V9: PVD detection level set to 2.9V

如:

1
2
3
 /* 配置PVD级别PWR_PVDLevel_2V6 (PVD检测电压的阈值为2.6V,VDD电压低于2.6V时产生PVD中断) */
/*具体级别根据自己的实际应用要求配置*/
PWR_PVDLevelConfig(PWR_PVDLevel_2V6);

stm32中的电源管理系统

从上图我们知道smt32中的电源管理主要是三个部分:

  • ADC电源及参考电压(VDDA供电区域)
  • 调压器供电电路(VDD/1.8V供电区域)
  • 备份域电路(后备供电区域)

ADC电源

上图中的VDDA供电区域。为了提高转换精度,STM32的ADC配有独立的电源接口,方便进行单独的滤波。 ADC的工作电源使用VDDA引脚输入,使用VSSA作为独立的地连接, VREF引脚则为ADC提供测量使用的参考电压。

调压器电路

调在STM32的电源系统中调压器供电的电路是最主要的部分,调压器为备份域及待机电路以外的所有数字电路供电。

由于这个电压是1.8V所以这个区域也称之为1.8V供电区域

调压器可以运行在“运行模式”、“停止模式”以及“待机模式”。

  • 在运行模式下,1.8V域全功率运行;
  • 在停止模式下1.8V域运行在低功耗状态, 1.8V区域的所有时钟都被关闭,相应的外设都停止了工作,但它会保留内核寄存器以及SRAM的内容;
  • 在待机模式下,整个1.8V域都断电, 该区域的内核寄存器及SRAM内容都会丢失(备份区域的寄存器不受影响)。

备份域电路

STM32的LSE振荡器、RTC及备份寄存器这些器件被包含进备份域电路中,这 部分的电路可以通过STM32的VBAT引脚获取供电电源, 在实际应用中一般会使用3V的钮扣电池对该引脚供电。

stm32中的功耗模式

按功耗由高到低排列,STM32具有运行、睡眠、停止和待机四种工作模式。上电复位后STM32处于运行状态时,当内核不需要继续运行, 就可以选择进入后面的三种低功耗模式降低功耗,这三种模式中,电源消耗不同、唤醒时间不同、唤醒源不同,用户需要根据应用需求, 选择最佳的低功耗模式。

睡眠模式

这个模式下会关闭内核时钟,但是外设会正常运行。

睡眠模式相关编程

我们知道在睡眠模式中,直接使用编译器指令WFIWFE就可以直接进入睡眠模式,但是其他两个模式不可以。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
while(1)
{
/*********执行任务***************************/
printf("\r\n STM32正常运行,亮绿灯\r\n");

LED_GREEN;
Delay(0x3FFFFF);

/*****任务执行完毕,进入睡眠降低功耗***********/


printf("\r\n 进入睡眠模式,按KEY1或KEY2按键可唤醒\r\n");

//使用红灯指示,进入睡眠状态
LED_RED;
//进入睡眠模式
__WFI(); //WFI指令进入睡眠

//等待中断唤醒 K1或K2按键中断

/***被唤醒,亮蓝灯指示***/
LED_BLUE;
Delay(0x1FFFFF);

printf("\r\n 已退出睡眠模式\r\n");
//继续执行while循环

}

进入模式就是函数__WFI()或者是__WFE()

退出模式就是中断或者是时间,决定于进入模式时使用的函数

停止模式

这个模式下会关闭所有的时钟,但是内核、备份域中的寄存器中的值仍然会被保存下来。所以从停止模式退出来之后可以继续执行后面的代码。

停止模式可以由任意一个外部中断(EXTI)唤醒,在停止模式中可以选择电压调节器为开模式或低功耗模式。

注意点:

  • 在这个模式下,当退出状态的时候HSI会被自动选择为系统时钟。所以我们需要自己调回至HSE。在上图中的唤醒延迟中有写道

停止模式相关编程

编程实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
while(1)
{
/*********执行任务***************************/
printf("\r\n STM32正常运行,亮绿灯\r\n");

LED_GREEN;
Delay(0x3FFFFF);

/*****任务执行完毕,进入停止降低功耗***********/

printf("\r\n 进入停止模式,按KEY1或KEY2按键可唤醒\r\n");

//使用红灯指示,进入停止状态
LED_RED;

/* 进入停止模式,设置电压调节器为低功耗模式,等待中断唤醒 */
PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);


//等待中断唤醒 K1或K2按键中断

/*********************被唤醒***********************/

//获取刚被唤醒时的时钟状态
//时钟源
clock_source_wakeup = RCC_GetSYSCLKSource ();
//时钟频率
RCC_GetClocksFreq(&clock_status_wakeup);

//从停止模式下被唤醒后使用的是HSI时钟,此处重启HSE时钟,使用PLLCLK
SYSCLKConfig_STOP();

//获取重新配置后的时钟状态
//时钟源
clock_source_config = RCC_GetSYSCLKSource ();
//时钟频率
RCC_GetClocksFreq(&clock_status_config);

//因为刚唤醒的时候使用的是HSI时钟,会影响串口波特率,输出不对,所以在重新配置时钟源后才使用串口输出。
printf("\r\n重新配置后的时钟状态:\r\n");
printf(" SYSCLK频率:%d,\r\n HCLK频率:%d,\r\n PCLK1频率:%d,\r\n PCLK2频率:%d,\r\n 时钟源:%d (0表示HSI,8表示PLLCLK)\n",
clock_status_config.SYSCLK_Frequency,
clock_status_config.HCLK_Frequency,
clock_status_config.PCLK1_Frequency,
clock_status_config.PCLK2_Frequency,
clock_source_config);

printf("\r\n刚唤醒的时钟状态:\r\n");
printf(" SYSCLK频率:%d,\r\n HCLK频率:%d,\r\n PCLK1频率:%d,\r\n PCLK2频率:%d,\r\n 时钟源:%d (0表示HSI,8表示PLLCLK)\n",
clock_status_wakeup.SYSCLK_Frequency,
clock_status_wakeup.HCLK_Frequency,
clock_status_wakeup.PCLK1_Frequency,
clock_status_wakeup.PCLK2_Frequency,
clock_source_wakeup);

/*指示灯*/
LED_BLUE;
Delay(0x1FFFFF);

printf("\r\n 已退出停止模式\r\n");
//继续执行while循环

}

编程注意点:

  • 直接使用函数PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI)进入停止模式,不需要提前的配置。
    • PWR_Regulator_LowPower作用是设置电压调节器为低功耗模式
    • PWR_STOPEntry_WFI作用时依靠中断来退出模式
  • 每次唤醒之后需要重新设置好系统时钟

待机模式

这个模式下关闭所有的外设、时钟,还把1.8V区域的电源也完全关闭了。但是如果备份域的电源还有电的话,备份域内的RTC都可以正常运行,备份域内的寄存器的数据会被保存,不受功耗模式影响。所以从这个模式下退出时,就相当于复位,程序会从头开始执行。

注意点:

  • 待机模式下可以使用WKUP引脚来退出模式,但前提是需要使用函数PWR_WakeUpPinCmd (ENABLE);使能WKUP引脚。

待机模式相关编程

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//检测复位来源
if(PWR_GetFlagStatus(PWR_FLAG_WU) == SET)
{
LED_BLUE;
printf("\r\n 待机唤醒复位 \r\n");
}
else
{
LED_GREEN;
printf("\r\n 非待机唤醒复位 \r\n");
}

while(1)
{
// K2 按键长按进入待机模式
if(KEY2_LongPress())
{

printf("\r\n 即将进入待机模式,进入待机模式后可按KEY1唤醒,唤醒后会进行复位,程序从头开始执行\r\n");
LED_RED;
Delay(0xFFFF);

/*清除WU状态位*/
PWR_ClearFlag (PWR_FLAG_WU);

/* 使能WKUP引脚的唤醒功能 ,使能PA0*/
PWR_WakeUpPinCmd (ENABLE);

/* 进入待机模式 */
PWR_EnterSTANDBYMode();
}

}

编程步骤:

  • 最开始时需要检测复位来源通过PWR_GetFlagStatus()函数。
  • 在进入模式之前需要完成好相关的配置
    • 清除WU状态位,其作用是其必须被设置为0才可以进入待机模式
    • 使能WKUP引脚的唤醒功能,这个引脚的功能是其必须上升,才可以退出模式
  • 最后使用函数PWR_EnterSTANDBYMode()进入待机模式

编程总结

函数:

PWR_ClearFlag()

1
2
3
4
5
void PWR_ClearFlag(uint32_t PWR_FLAG)

//PWR_FLAG_WU: Wake Up flag,唤醒标致
//PWR_FLAG_SB: StandBy flag,待机标致
//这些都在定义的函数中的注释中有说明

stm32中的电源管理
https://ysc2.github.io/ysc2.github.io/2024/01/31/stm32中的电源管理/
作者
Ysc
发布于
2024年1月31日
许可协议