STM32电源管理—实现低功耗

注: 本文是学习野火的指南针开发板过程的学习笔记,可能有误,详细请看B站野火官方配套视频教程(这个教程真的讲的很详细,请给官方三连吧)

在响应绿色发展的同时,在很多应用场合中都对电子设备的功耗要求非常苛刻,如某些传感器信息采集设备,仅靠小型的电池提供电源,要求工作长达数年之久,且期间不需要任何维护;由于智慧穿戴设备的小型化要求,电池体积不能太大导致容量也比较小,所以也很有必要从控制功耗入手,提高设备的续行时间。

01 STM32的电源管理简介

STM32有专门的电源管理外设监控电源并管理设备的运行模式,确保系统正常运行,并尽量降低器件的功耗。

电源监控器:

STM32芯片主要通过引脚VDD从外部获取电源,在它的内部具有电源监控器用于检测VDD的电压,以实现复位功能及掉电紧急处理功能,保证系统可靠地运行。

1. 上电复位与掉电复位(POR与PDR)

POR、PDR功能是使用其电压阈值与外部供电电压VDD比较,当低于工作阈值时,会直接进入复位状态,这可防止电压不足导致的误操作

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

2.可编程电压检测器PVD

STM32还提供了可编程电压检测器PVD,它也是实时检测VDD的电压

当检测到电压低于编程的VPVD阈值时,会向内核产生一个PVD中断(EXTI16线中断)以使内核在复位前进行紧急处理。该电压阈值可通过电源控制寄存器PWR_CSR设置。

使用PVD可配置8个等级,如下表。其中的上升沿和下降沿分别表示类似前面图中的VDD电压上升过程及下降过程的阈值:

|--------------|--------|---------|---------|---------|--------|
| 阈值等级 | 条件 | 最小值 | 典型值 | 最大值 | 单位 |
| 级别 0 | 上升沿 | 2.1 | 2.18 | 2.26 | V |
| 级别 0 | 下降沿 | 2 | 2.08 | 2.16 | V |
| 级别 1 | 上升沿 | 2.19 | 2.28 | 2.37 | V |
| 级别 1 | 下降沿 | 2.09 | 2.18 | 2.27 | V |
| 级别 2 | 上升沿 | 2.28 | 2.38 | 2.48 | V |
| 级别 2 | 下降沿 | 2.18 | 2.28 | 2.38 | V |
| 级别 3 | 上升沿 | 2.38 | 2.48 | 2.58 | V |
| 级别 3 | 下降沿 | 2.28 | 2.38 | 2.48 | V |
| 级别 4 | 上升沿 | 2.47 | 2.58 | 2.69 | V |
| 级别 4 | 下降沿 | 2.37 | 2.48 | 2.59 | V |
| 级别 5 | 上升沿 | 2.57 | 2.68 | 2.79 | V |
| 级别 5 | 下降沿 | 2.47 | 2.58 | 2.69 | V |
| 级别 6 | 上升沿 | 2.66 | 2.78 | 2.9 | V |
| 级别 6 | 下降沿 | 2.56 | 2.68 | 2.8 | V |
| 级别 7 | 上升沿 | 2.76 | 2.88 | 3 | V |
| 级别 7 | 下降沿 | 2.66 | 2.78 | 2.9 | V |

STM32的电源系统:

为了方便进行电源管理,STM32把它的外设、内核等模块跟据功能划分了供电区域,其内部电源区域划分如图:

STM32的电源系统主要分为备份域电路、内核电路以及ADC电路三部分,介绍如下:

  • ADC电源及参考电压(VDDA供电区域):
    为了提高转换精度,STM32的ADC配有独立的电源接口,方便进行单独的滤波。ADC的工作电源使用VDDA引脚输入,使用VSSA作为独立的地连接,VREF引脚则为ADC提供测量使用的参考电压。
    • 调压器供电电路( V DD /1.8V 供电区域):
      在 STM32 的电源系统中调压器供电的电路是最主要的部分,调压器为备份域及待机电路的所有数字电路供电,其中包括内核、数字外设以及 RAM ,调压器的输出电压约为 1.8V ,因而使用调压器供电的这些电路区域被称为 1.8V 域。

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

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

在图中后备供电区域的左侧有一个电源开关结构,它的功能类似下图的双二极管,在它的"1"处连接了VBAT电源,"2"处连接了VDD主电源(一般为3.3V),右侧"3"处引出到备份域电路中。当VDD主电源存在时,由于VDD电压较高,备份域电路通过VDD供电,节省钮扣电池的电源,仅当VDD掉电时,备份域电路由钮扣电池通过VBAT供电,保证电路能持续运行,从而可利用它保留关键数据。


02 STM32的功耗模式

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

这三种低功耗模式层层递进,运行的时钟或芯片功能越来越少,因而功耗越来越低。

1.睡眠模式

在睡眠模式中,仅关闭了内核时钟,内核停止运行,但其片上外设,CM3核心的外设全都还照常运行。 有两种方式进入睡眠模式,它的进入方式决定了从睡眠唤醒的方式,分别是WFI(wait for interrupt)和WFE(wait for event),即由等待"中断"唤醒和由"事件"唤醒。睡眠模式的各种特性见下表:

2.停止模式

在停止模式中,进一步关闭了其它所有的时钟,于是所有的外设都停止了工作,但由于其1.8V区域的部分电源没有关闭,还保留了内核的寄存器、内存的信息,所以从停止模式唤醒,并重新开启时钟后,还可以从上次停止处继续执行代码。停止模式可以由任意一个外部中断(EXTI)唤醒,在停止模式中可以选择电压调节器为开模式或低功耗模式。停止模式的各种特性见下表:

3.待机模式

待机模式,它除了关闭所有的时钟,还把1.8V区域的电源也完全关闭了,也就是说,从待机模式唤醒后,由于没有之前代码的运行记录,只能对芯片复位,重新检测boot条件,从头开始执行程序。它有四种唤醒方式,分别是WKUP(PA0)引脚的上升沿,RTC闹钟事件,NRST引脚的复位和IWDG(独立看门狗)复位。

在以上讲解的睡眠模式、停止模式及待机模式中,若备份域电源正常供电,备份域内的RTC都可以正常运行,备份域内的寄存器的数据会被保存,不受功耗模式影响。


03电源管理相关的库函数及命令

STM32标准库对电源管理提供了完善的函数及命令,使用它们可以方便地进行控制。

配置PVD监控功能

PVD可监控VDD的电压,当它低于阈值时可产生PVD中断以让系统进行紧急处理,这个阈值可以直接使用库函数PWR_PVDLevelConfig配置成前面阈值表中说明的阈值等级。

进入睡眠------WFI与WFE命令

在前面可了解到进入各种低功耗模式时都需要调用WFI或WFE命令,它们实质上都是内核指令,在库文件core_cm3.h中把这些指令封装成了函数:

对于这两个指令,应用时只需要知道,调用它们都能进入低功耗模式,需要使用函数的格式"__WFI();"和"__WFE();"来调用(因为__wfi及__wfe是编译器内置的函数,函数内部使用调用了相应的汇编指令)。

进入停止模式

直接调用WFI和WFE指令可以进入睡眠模式,而进入停止模式则还需要在调用指令前设置一些寄存器位,STM32标准库把这部分的操作封装到PWR_EnterSTOPMode函数中了,它的定义如下:

cs 复制代码
1 /**
2 * @brief 进入停止模式
3 *
4 * @note 在停止模式下所有 I/O 的会保持在停止前的状态
5 * @note 从停止模式唤醒后,会使用 HSI 作为时钟源
6 * @note 调压器若工作在低功耗模式,可减少功耗,但唤醒时会增加延迟
7 * @param PWR_Regulator: 设置停止模式时调压器的工作模式
8 * @arg PWR_MainRegulator_ON: 调压器正常运行
9 * @arg PWR_Regulator_LowPower: 调压器低功耗运行
10 * @param PWR_STOPEntry: 设置使用 WFI 还是 WFE 进入停止模式
11 * @arg PWR_STOPEntry_WFI: WFI 进入停止模式
12 * @arg PWR_STOPEntry_WFE: WFE 进入停止模式13 * @retval None
14 */
15 void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry)
16 {
17 uint32_t tmpreg = 0;
18 /* 检查参数 */
19 assert_param(IS_PWR_REGULATOR(PWR_Regulator));
20 assert_param(IS_PWR_STOP_ENTRY(PWR_STOPEntry));
21
22 /* 设置调压器的模式 ------------*/
23 tmpreg = PWR->CR;
24 /* 清除 PDDS 及 LPDS 位 */
25 tmpreg &= CR_DS_MASK;
26 /* 根据 PWR_Regulator 的值 (调压器工作模式) 配置 LPDS,MRLVDS 及 LPLVDS 位 */
27 tmpreg |= PWR_Regulator;
28 /* 写入参数值到寄存器 */
29 PWR->CR = tmpreg;
30 /* 设置内核寄存器的 SLEEPDEEP 位 */
31 SCB->SCR |= SCB_SCR_SLEEPDEEP;
32
33 /* 设置进入停止模式的方式-----------------*/
34 if (PWR_STOPEntry == PWR_STOPEntry_WFI) {
35 /* 需要中断唤醒 */
36 __WFI();
37 } else {
38 /* 需要事件唤醒 */
39 __WFE();
40 }
41
42 /* 以下的程序是当重新唤醒时才执行的,清除 SLEEPDEEP 位的状态 */
43 SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP);
44 }

这个函数有两个输入参数,分别用于控制调压器的模式及选择使用WFI或WFE停止,代码中先是根据调压器的模式配置PWR_CR寄存器,再把内核寄存器的SLEEPDEEP位置1,这样再调用WFI或WFE命令时,STM32就不是睡眠,而是进入停止模式了。函数结尾处的语句用于复位SLEEPDEEP位的状态,由于它是在WFI及WFE指令之后的,所以这部分代码是在STM32被唤醒的时候才会执行。

要注意的是进入停止模式后,STM32的所有I/O都保持在停止前的状态,而当它被唤醒时,STM32使用HSI作为系统时钟(8MHz)运行,由于系统时钟会影响很多外设的工作状态,所以一般我们在唤醒后会重新开启HSE,把系统时钟设置回原来的状态。

进入待机模式

STM32标准库也提供了控制进入待机模式的函数,其定义如下:

cs 复制代码
1 /**
2 * @brief 进入待机模式
3 * @note 待机模式时,除以下引脚,其余引脚都在高阻态:
4 * -复位引脚
5 * - RTC_AF1 引脚 (PC13) (需要使能侵入检测、时间戳事件或 RTC 闹钟事件)
6 * - RTC_AF2 引脚 (PI8) (需要使能侵入检测或时间戳事件)
7 * - WKUP 引脚 (PA0) (需要使能 WKUP 唤醒功能)
8 * @note 在调用本函数前还需要清除 WUF 寄存器位
9 * @param None
10 * @retval None
11 */
12 void PWR_EnterSTANDBYMode(void)
13 {
14 /* 清除 Wake-up 标志 */
15 PWR->CR |= PWR_CR_CWUF;
16 /* 选择待机模式 */
17 PWR->CR |= PWR_CR_PDDS;
18 /* 设置内核寄存器的 SLEEPDEEP 位 */
19 SCB->SCR |= SCB_SCR_SLEEPDEEP;
20 /* 存储操作完毕时才能进入待机模式,使用以下语句确保存储操作执行完毕 */
21 #if defined ( __CC_ARM )
22 __force_stores();
23 #endif
24 /* 等待中断唤醒 */
25 __WFI();
26 }

该函数中先配置了PDDS寄存器位及SLEEPDEEP寄存器位,接着调用__force_stores函数确保存储操作完毕后再调用WFI指令,从而进入待机模式。这里值得注意的是,待机模式也可以使用WFE指令进入的,如果您有需要可以自行修改。 在进入待机模式后,除了被使能了的用于唤醒的I/O,其余I/O都进入高阻态,而从待机模式唤醒后,相当于复位STM32芯片,程序重新从头开始执行。


04电源管理实验

PWR---睡眠模式(如何控制 STM32 进入低功耗睡眠模式。

程序设计:

cs 复制代码
int main()
{

(1) 初始化用于唤醒的中断按键;
.............................................................................. 
while(1)
  {	
		/*********执行任务***************************/
		printf("\r\n STM32正常运行,亮绿灯\r\n");
	
		LED_GREEN;	
		Delay(0x3FFFFF);
(2) 进入睡眠状态;
		/*****任务执行完毕,进入睡眠降低功耗***********/
		
		
		printf("\r\n 进入睡眠模式,按KEY1或KEY2按键可唤醒\r\n");

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

(3) 使用按键中断唤醒芯片;
		//由于 WFI 睡眠模式可以使用任意中断唤醒,所以我们可以使用按键中断唤醒。
		//等待中断唤醒  K1或K2按键中断	
		
		/***被唤醒,亮蓝灯指示***/
		LED_BLUE;	
		Delay(0x1FFFFF);		
			
		printf("\r\n 已退出睡眠模式\r\n");
		//继续执行while循环

  }
}
/*按键中断部分*/
void KEY1_IRQHandler(void)
{
  //确保是否产生了EXTI Line中断
	if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) 
	{
		LED_BLUE;		
		printf("\r\n KEY1 按键中断唤醒 \r\n");    
		EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);     
	}  
}

void KEY2_IRQHandler(void)
{
  //确保是否产生了EXTI Line中断
	if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) 
	{
		LED_BLUE;
		printf("\r\n KEY2 按键中断唤醒 \r\n");   
    //清除中断标志位
		EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);     
	}  
}

注意 : 当系统处于睡眠模式低功耗状态时 ( 包括后面讲解的停止模式及待机模式 ) ,使用 DAP下载器是无法给芯片下载程序的,所以下载程序时要先把系统唤醒。或者使用如下方法:按着板子的复位按键,使系统处于复位状态,然后点击电脑端的下载按钮下载程序,这时再释放复位按键,就能正常给板子下载程序了。

PWR---停止模式实验(解如何进入停止模式及唤醒后的状态恢复。

与睡眠模式不一样,系统从停止模式被唤醒时,是使用 HSI 作为系统时钟的,在 STM32F103 中, HSI 时钟一般为 8MHz ,与我们常用的 72MHz 相关太远,它会影响各种外设的工作频率。所以在系统从停止模式唤醒后,若希望各种外设恢复正常的工作状态,就要恢复停止模式前使用的系统时钟,本实验中定义了一个 SYSCLKConfig_STOP 函数,用于恢复系统时钟:

cs 复制代码
/**
  * @brief  停机唤醒后配置系统时钟:
这个函数主要是调用了各种 RCC 相关的库函数,
开启了 HSE 时钟、使能 PLL 并且选择 PLL 作
为时钟源,从而恢复停止前的时钟状态。
  * @param  None
  * @retval None
  */
static void SYSCLKConfig_STOP(void)
{
  /* After wake-up from STOP reconfigure the system clock */
  /* 使能 HSE */
  RCC_HSEConfig(RCC_HSE_ON);
  
  /* 等待 HSE 准备就绪 */
  while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET)
  {
  }
  
  /* 使能 PLL */ 
  RCC_PLLCmd(ENABLE);
  
  /* 等待 PLL 准备就绪 */
  while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
  {
  }
  
  /* 选择PLL作为系统时钟源 */
  RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  
  /* 等待PLL被选择为系统时钟源 */
  while (RCC_GetSYSCLKSource() != 0x08)
  {
  }
}

main函数部分

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

由于 WFI 停止模式可以使用任意 EXTI 的中断唤醒,所以我们可以 使用按键中断唤醒

cs 复制代码
void KEY_IRQHandler(void)
{
  //确保是否产生了EXTI Line中断
	if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) 
	{
		LED_BLUE;
		//由于停止唤醒后使用的是HSI时钟,与原来使用的HSE时钟时的频率不一致,会影响波特率,若此处直接printf会乱码
		//printf("\r\n KEY2 按键中断唤醒 \r\n");   
    //清除中断标志位
		EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);     
	}  
}

当执行完中断服务函数后,会继续执行 WFI 指令 ( 即 PWR_EnterSTOPMode 函数 ) 后的代码。
为了更清晰地展示停止模式的影响,在刚唤醒后,我们定义了

cs 复制代码
	RCC_ClocksTypeDef clock_status_wakeup,clock_status_config;
	uint8_t clock_source_wakeup,clock_source_config; 

用于调用库函数 RCC_GetSYSCLKSourc以及 RCC_GetClocksFreq 获取刚唤醒后的系统的时钟源以及时钟频率,在使用 SYSCLKCon-fig_STOP 恢复时钟后,我们再次获取这些时状态,最后再通过串口打印出来。

cs 复制代码
//获取刚被唤醒时的时钟状态	
		//时钟源
		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);
cs 复制代码
//因为刚唤醒的时候使用的是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);

通过串口调试信息我们会知道刚唤醒时系统时钟使用的是 HSI 时钟,频率为 8MHz ,恢复后的系统时钟采用 HSE 倍频后的 PLL 时钟,时钟频率为 72MHz 。


PWR**---待机模式实验**(最低功耗的待机模式)

要强调的是,由于 WKUP 引脚 (PA0) 必须使用上升沿才能唤醒待机状态的系统,所以我们硬件设计的 PA0 引脚连接到按键 KEY1 ,且按下按键的时候会在 PA0 引脚产生上升沿,从而可实现唤醒的功能,按键的具体电路请查看配套的原理图。
1.程序首先使用库函数 RCC_APB1PeriphClockCmd 和参数 RCC_APB1Periph_PWR 初始化了源管理外设的时钟,要先使能该时钟,后面才能正常使用命令进入待机状态和唤醒。

cs 复制代码
	/* 使能电源管理单元的时钟,必须要使能时钟才能进入待机模式 */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR , ENABLE);

2.由于待机模式唤醒使用 WKUP 引脚并不需要特别的引脚初始化,所以我们调用普通的按键初始化函数即可(模式的 WKUP 唤醒不需要中断,也不需要像按键那样初始化)

cs 复制代码
int main(void)
{	
		/* 使能电源管理单元的时钟,必须要使能时钟才能进入待机模式 */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR , ENABLE);

	
	//检测复位来源
	if(PWR_GetFlagStatus(PWR_FLAG_WU) == SET)
	{
		LED_BLUE;
		printf("\r\n 待机唤醒复位 \r\n");
	}
	else
	{
		LED_GREEN;
		printf("\r\n 非待机唤醒复位 \r\n");
	}
	
  while(1)
  {
	
  }
}

3.在使用库函数 PWR_EnterSTANDBYMode发送待机命令前,要先使用库函数 PWR_ClearFlag 清除 PWR_FLAG_WU 标志位,并且使用库函数 PWR_WakeUpPinCmd 使能 WKUP 唤醒功能,这样进入待机模式后才能使用 WKUP 唤醒。

cs 复制代码
	/*清除WU状态位*/
			PWR_ClearFlag (PWR_FLAG_WU);
			
			/* 使能WKUP引脚的唤醒功能 ,使能PA0*/
			PWR_WakeUpPinCmd (ENABLE);
			
			/* 进入待机模式 */
			PWR_EnterSTANDBYMode();

在进入待机模式前我们控制了 LED 彩灯为红色,但在待机状态时,由于 I/O 口会处于高阻态,所以 LED 灯会熄灭。
按下 KEY1 按键,会使 PA0 引脚产生一个上升沿,从而唤醒系统。

系统唤醒后会进行复位,从头开始执行上述过程,与第一次上电时不同的是,这样的复位会使 PWR_FLAG_WU 标志位改为 SET 状态,所以这个时候 LED 彩灯会亮蓝色。(这也为什么我们可以从while循环外获取是否是待机启动)

PWR**---**PVD 电源监控实验(如何使用 PVD 监控供电电源,增强系统的鲁棒性

中使用 PVD 监控 STM32 芯片的 VDD 引脚,当监测到供电电压低于阈值时会产生 PVD 中断,系统进入中断服务函数进入紧急处理过程。所以进行这个实验时需要使用一个可调的电压源给实验板供电,改变给 STM32 芯片的供电电压,为此我们需要先了解实验板的电源供电系统,见图实验板的电源供电系统

整个电源供电系统主要分为以下五部分:

  • (1) 6-12V 的 DC 电源供电系统,这部分使用 DC 电源接口引入 6-12V 的电源,经过 RT7272 进行电压转换成 5V 电源,再与第二部分的"5V_USB"电源线连接在一起。

  • (2) 第二部分使用 USB 接口,使用 USB 线从外部引入 5V 电源,引入的电源经过电源开关及保险丝连接到"5V"电源线。

  • (3) 第三部分的是电源开关及保险丝,即当我们的实验板使用 DC 电源或"5V_USB"线供电时,可用电源开关控制通断,保险丝也会起保护作用。

  • (4) "5V"电源线遍布整个板子,板子上各个位置引出的标有"5V"丝印的排针都与这个电源线直接相连。5V 电源线给板子上的某些工作电压为 5V 的芯片供电。5V 电源还经过 LDO 稳压芯片,输出 3.3V 电源连接到"3.3V"电源线。

  • (5) 同样地,"3.3V"电源线也遍布整个板子,各个引出的标有"3.3V"丝印的排针都与它直接相连,3.3V 电源给工作电压为 3.3V 的各种芯片供电。STM32 芯片的 VDD 引脚就是直接与这个3.3V 电源相连的,所以通过 STM32 的 PVD 监控的就是这个"3.3V"电源线的电压。

当我们进行这个 PVD 实验时,为方便改变" 3.3V "电源线的电压,我们可以把可调电源通过实
验板上引出的" 5V "及" GND "排针给实验板供电,当可调电源电压降低时, LDO 在" 3.3V "电
源线的供电电压会随之降低,即 STM32 的 PVD 监控的 VDD 引脚电压会降低,这样我们就可以
模拟 VDD 电压下降的实验条件,对 PVD 进行测试了。不过,由于这样供电不经过保险丝,所以
在调节电压的时候要小心,不要给它供电远高于 5V ,否则可能会烧坏实验板上的芯片。

软件设计:

初始化 PVD
使用 PVD 功能前需要先初始化,我们把这部分代码封装到 PVD_Config 函数中

cs 复制代码
/**
  * @brief  配置PVD.
  * @param  None
  * @retval None
  */
void PVD_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  EXTI_InitTypeDef EXTI_InitStructure;

  /*使能 PWR 时钟 */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  
  /* 使能 PVD 中断 */
  NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
      
  /* 配置 EXTI16线(PVD 输出) 来产生上升下降沿中断*/
  EXTI_ClearITPendingBit(EXTI_Line16);
  EXTI_InitStructure.EXTI_Line = EXTI_Line16;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

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

  /* 使能PVD输出 */
  PWR_PVDCmd(ENABLE);
}

在这段代码中,执行的流程如下:
(1) 配置 PVD 的中断优先级。由于电压下降是非常危急的状态,所以请尽量把它配置成最高优先级。
(2) 配置了 EXTI16 线的中断源,设置 EXTI16 是因为 PVD 中断是通过 EXTI16 产生中断的 (GPIO的中断是 EXTI0-EXTI15) 。
(3) 使用库函数 PWR_PVDLevelConfig 设置 PVD 监控的电压阈值等级,各个阈值等级表示的电压值请查阅表 PVD 的阈值等级 或 STM32 的数据手册。
(4) 最后使用库函数 PWR_PVDCmd 使能 PVD 功能。

cs 复制代码
	/**
  * @brief  PVD中断请求
  * @param  None
  * @retval None
  */
void PVD_IRQHandler(void)
{
		/*检测是否产生了PVD警告信号*/
		if(PWR_GetFlagStatus (PWR_FLAG_PVDO)==SET)			
		{
			/* 亮红灯,实际应用中应进入紧急状态处理 */
			LED_RED; 
			
		}
    /* 清除中断信号*/
    EXTI_ClearITPendingBit(EXTI_Line16);

}

注意这个中断服务函数的名是 PVD_IRQHandler 而不是 EXTI16_IRQHandler(STM32 没有这样的中断函数名) ,示例中我们仅点亮了 LED 红灯,不同的应用中要根据需求进行相应的紧急处理。

主函数

本电源监控实验的 main 函数执行流程比较简单,仅调用了 PVD_Config 配置监控功能,当 VDD供电电压正常时,板子亮绿灯,当电压低于阈值时,会跳转到中断服务函数中,板子亮红灯

cs 复制代码
​int main(void)
{	
	LED_GPIO_Config();	
	//亮绿灯,表示正常运行
	LED_GREEN; 

	//配置PVD,当电压过低时,会进入中断服务函数,亮红灯
	PVD_Config();
	
  while(1)
  {			
		/*正常运行的程序*/
  }
}

【 !】实验操作:

1.使用外部可调电源,调节成5V输出,连接到实验板引出的 5V<--->GND排针给板子供电;

2.复位实验板,电压正常时板子上的LED彩灯应为绿色

3.向下调节可调电源的电压,大约当降至4.2V的时候,LED彩灯会转为红色。

(程序中控制PVD监控电压约为2.6V,当5V电源降至4.2V的时候,连接STM32的VDD电源(3.3V电源)会低于2.5V,产生PVD事件,在中断中控制亮红灯)
【 !!】注意事项:

使用可调电源给实验板供电,其它电源线都拔掉(包括下载器、USB线)。

由于直接接排针供电没有电路保护,调节电源时小心不要使供电电压远高于5V,电压太高会烧坏实验板!!

相关推荐
worthsen41 分钟前
RK3576 介绍
嵌入式硬件·芯片
end_SJ3 小时前
初学stm32 -- SysTick定时器
stm32·单片机·嵌入式硬件
Qingniu015 小时前
D9741是一块脉宽调制方三用于也收路像机和笔记本电的等设备上的直流转换器。在便携式的仪器设备上。
科技·单片机·电脑·笔记本电脑·电视摄像机·摇头机·白色家电
美式小田8 小时前
Cadence学习笔记 8 添加分页符
笔记·嵌入式硬件·学习·cadence
跟着杰哥学嵌入式8 小时前
stm32中有哪些库?其中标准库和HAL库有什么区别?
stm32·单片机·嵌入式硬件
美式小田8 小时前
Cadence学习笔记 9 器件封装匹配
笔记·嵌入式硬件·学习·cadence
学习噢学个屁10 小时前
基于51单片机的交通灯设计—夜间、紧急、复位、可调时间、四个数码管显示
c语言·单片机·嵌入式硬件·51单片机
电子绿洲10 小时前
DCDC Buck模式的电感值参数计算
单片机·嵌入式硬件
xxxx12344511 小时前
Linux-ubuntu之主频和时钟配置
linux·c语言·单片机·ubuntu
end_SJ11 小时前
初学stm32 --- NVIC中断
stm32·单片机·嵌入式硬件