#stm32低功耗实验——pvd

电源控制(PWR)简介

电源控制部分(PWR)概述了不同电源域的电源架构以及电源配置控制器。PWR 的内容比较多,我们把它们的主要特性概括为以下 3 点:
电源系统:USB 稳压器、内核域(VCORE)、VDD 域、备份域、模拟域(VDDA)。
电源监控:POR/PDR 监控器、BOR 监控器、PVD 监控器、AVD 监控器、VBAT 阈值、
温度阈值。
电源管理:VBAT 电池充电、工作模式、电压调节控制、低功耗模式。
下面将分别对这 3 个特性进行简单介绍

电源系统 框图

#stm32低功耗实验——pvd_第1张图片
① 电池备份区域(后备供电区域)
电池备份区域也就是后备供电区域,使用电池或者其他电源连接到 VBAT脚上,当 VDD断电时,可以保存备份寄存器的内容和维持 RTC 的功能。同时 VBAT 引脚也为 RTC、SRAM 和 LSE振荡器供电,这保证了当主要电源被切断时,RTC 能够继续工作。 切换到 VBAT供电由复位模块中的掉电复位功能控制。
② 电压调节器(VDD /1.2V 供电区域)
嵌入式线性调压器为备份域和待机电路以外的所有数字电路供电。调压器输出电压约为1.2 V。此调压器需要将两个外部电容连接到专用引脚 VCAP_1 和 VCAP_2,所有封装(芯片)都配有这两个引脚。为激活或停用调压器,必须将特定引脚连接到 VSS 或 VDD。具体引脚与封装有关。通过软件激活时,调压器在复位后始终处于使能状态
根据应用模式的不同,可采用三种不同的模式工作。在运转模式下,调节器以正常功耗模式为内核、内存和外设提供 1.2V;在停止模式下,调节器以低功耗模式提供 1.2V 电源,以保存寄存器和 SRAM 的内容。在待机模式下,调节器停止供电,除了备用电路和备份域外,寄存器和 SRAM 的内容全部丢失。
③ 独立的 A/D 转换器供电和参考电压(VDDA 供电区域)
为了提高转换精度,ADC 配有独立电源,可以单独滤波并屏蔽 PCB 上的噪声。ADC 电源电压从单独的 VDDA 引脚接入,VSSA 提供了独立的电源接地连接。为了确保测量低电压时具有更高的精度,用户可以再 VREF 上连接到单独的 ADC 外部参考电压输入,VREF 电压介于1.8V 到 VDDA 之间

电源监控

我们主要关注 PVD 监控器,此外还需要知道上电复位(POR)/掉电复位(PDR)。

上电复位(POR)/掉电复位(PDR)

上电时,当 VDD 低于指定 VPOR 阈值时,系统无需外部复位电路便会保持复位模式。一旦VDD电源电压高于 VPOR阈值,系统便会退出复位状态,芯片正常工作。掉电时,当 VDD低于指	定 VPDR阈值时,系统就会保持复位模式。

#stm32低功耗实验——pvd_第2张图片
图上应该画错了第一个应该是POR
也就是在POR>VDD>PDR 复位

欠压复位(BOR)

上电期间,欠压复位(BOR)将使系统保持复位状态,直到 VDD电源电压达到指定的 VBOR阈
值。VBOR阈值通过系统选项字节(某些寄存器的 BOR_LEV 位)进行配置。默认情况下,BOR
关闭。可选择以下可编程 VBOR阈值:

在这里插入图片描述
#stm32低功耗实验——pvd_第3张图片
也就是在VDD

可编程电压检测器(PVD)

上面介绍的 POR、PDR 以及 BOR 功能都是设置电压阈值与外部供电电压 VDD比较,当 VDD低于设置的电压阈值时,就会直接进入复位状态,防止电压不足导致的误操作。
下面介绍可编程电压检测器(PVD),它可以实时监视 VDD的电压,方法是将 VDD与 PWR控制寄存器(PWR_CR1)中的 PLS[2:0]位所选的 VPVD阈值进行比较。当检测到电压低于 VPVD阈值时,如果使能 EXTI16 线中断(即使能 PVD & AVD 中断),可以产生 PVD 中断,具体取决于 EXTI16 线配置为检测上升还是下降沿,然后在复位前,在中断服务程序中执行紧急关闭系统等任务。PVD 阀值检测波形,如图 29.1.2.1 所示

#stm32低功耗实验——pvd_第4张图片

PVD 阀值有 8 个等级,有上升沿和下降沿的区别,分别就是图 29.1.2.3 中 PVDrise 电压为上升沿阀值,PVDfall 为下降沿阀值,具体如表 29.1.2.2 所示。

#stm32低功耗实验——pvd_第5张图片

电源管理

电源管理的部分我们要关注低功耗模式,在 STM32 的正常工作中,具有四种工作模式,运行、睡眠、停止以及待机。在上电复位后,STM32 处于运行状态时,当内核不需要继续运行,就可以选择进入后面的三种模式降低功耗。这三种低功耗模式电源消耗不同、唤醒时间不同和唤醒源不同,我们要根据自身的需要选择合适的低功耗模式
#stm32低功耗实验——pvd_第6张图片
下面对睡眠模式、停止模式和待机模式的进入及退出方法进行介绍。

睡眠模式

进入睡眠模式,CPU 时钟关闭,但是其他所有的外设仍可以运行,所以任何中断或事件都可以唤醒睡眠模式。有两种方式进入睡眠模式,这两种方式进入的睡眠模式唤醒的方法不同,分别是 WFI(wait for interrupt)和 WFE(wait for event),即由等待“中断”唤醒和由“事件”唤醒。下面我们看看睡眠模式进入及退出方法
#stm32低功耗实验——pvd_第7张图片
睡眠模式有两种立即睡眠和退出时睡眠(响应中断后睡眠)

停止模式

进入停止模式,所有的时钟都关闭,所有的外设也就停止了工作。但是 VDD电源是没有关
闭的,所以内核的寄存器和内存信息都保留下来,等待重新开启时钟就可以从上次停止的地方
继续执行程序。
(相当于暂停)
值得注意的是:当电压调节器处于低功耗模式下,当系统从停止模式退出时,将会有一段
额外的启动延时。如果在停止模式期间保持内部调节器开启,则退出启动时间会缩短,但相应
的功耗会增加
#stm32低功耗实验——pvd_第8张图片

待机模式

待机模式可实现最低功耗。该模式是在 CM4 深睡眠模式时关闭电压调节器,整个 1.8V 供
电区域被断电。PLL、HSI 和 HSE 振荡器也被断电。除备份域(RTC 寄存器、RTC 备份寄存器
和备份 SRAM)和待机电路中的寄存器外,SRAM 和其他寄存器内容都将丢失。不过如果我们
使能了备份区域(备份 SRAM、RTC、LSE),那么待机模式下的功耗,将达到 6uA 左右。
#stm32低功耗实验——pvd_第9张图片
在这里插入图片描述

PVD 电压监控实验

PWR 寄存器

PWR控制寄存器(PWR_CR)

#stm32低功耗实验——pvd_第10张图片
位[7:5]PLS 用于设置 PVD 检测的电压阀值,就是前面我们介绍 PVD 的 8 个等级阀值选择。
PVDE 位,用于使能或者禁止 PVD 检测,显然我们要使能 PVD 检测,该位置 1。

EXTI 中断屏蔽寄存器(EXTI_IMR)

#stm32低功耗实验——pvd_第11张图片
比如:要使用到 EXTI16 线中断,所以 MR16 位要置 1,即开放来自 EXTI16 线的中断请求。

EXTI 上升沿触发选择寄存器(EXTI_RTSR)

#stm32低功耗实验——pvd_第12张图片
比如使用到 EXTI16 线中断,所以 TR16 位要置 1,即允许 EXTI16 线上的下降沿触发。

EXTI 下降沿触发选择寄存器(EXTI_FTSR)

#stm32低功耗实验——pvd_第13张图片
比如:用到 EXTI16 线中断,所以 TR16 位要置 1,即允许 EXTI16 线上的下降沿触发。

EXTI 挂起寄存器(EXTI_PR)

#stm32低功耗实验——pvd_第14张图片
比如:在 PVD 中断服务函数里面,我们记得要对 PR16 位写 1,来清除 EXTI16 线的中断标志。

代码

	/* Includes ------------------------------------------------------------------*/
#include "pwr.h"
#include "usart.h"
#include "stdio.h"

/**
 * @brief       初始化PVD电压监视器
 * @param       pls: 电压等级(PWR_PVD_detection_level)
 *   @arg       PWR_PVDLEVEL_0,2.2V;
 *   @arg       PWR_PVDLEVEL_1,2.3V;
 *   @arg       PWR_PVDLEVEL_2,2.4V;
 *   @arg       PWR_PVDLEVEL_3,2.5V;
 *   @arg       PWR_PVDLEVEL_4,2.6V;
 *   @arg       PWR_PVDLEVEL_5,2.7V;
 *   @arg       PWR_PVDLEVEL_6,2.8V;
 *   @arg       PWR_PVDLEVEL_7,2.9V;
 * @retval      无
 */
void pwr_pvd_init(uint32_t pls)
{
	PWR_PVDTypeDef pvd_handle={0};
	__HAL_RCC_PWR_CLK_ENABLE();
	pvd_handle.PVDLevel=pls;//电压等级
	pvd_handle.Mode=PWR_PVD_MODE_IT_RISING_FALLING;//边沿触发
	HAL_PWR_ConfigPVD(&pvd_handle);
	
	HAL_NVIC_SetPriority(PVD_IRQn,3,0);
	HAL_NVIC_EnableIRQ(PVD_IRQn);
	HAL_PWR_EnablePVD();
	
}
/**
 * @brief       PVD中断服务函数
 * @param       无
 * @retval      无
 */
void PVD_IRQHandler(void) //断电上电时会触发中断
{
	HAL_PWR_PVD_IRQHandler();//注意没有形参

}

void HAL_PWR_PVDCallback(void)
{
	/*PWR_CSR位 2 PVDO:PVD 输出 (PVD output)
此位通过硬件置 1 和清零。仅当通过 PVDE 位使能 PVD 时此位才有效。
0:VDD 高于 PLS[2:0] 位选择的 PVD 阈值。
1:VDD 低于 PLS[2:0] 位选择的 PVD 阈值。
注意:PVD 在进入待机模式时停止。因此,进入待机模式或执行复位后,此位等于 0,直到 
PVDE 位置 1。*/
	if(__HAL_PWR_GET_FLAG(PWR_FLAG_PVDO))
	{
		printf("pvd low voltage!\r\n");
	}
	else
	{
			printf("pvd low ok!\r\n");
	}
}
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
#include "stdio.h"
#include "usart.h"
#include "pwr.h"
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();


  MX_GPIO_Init();
	usart_Init();
	pwr_pvd_init(PWR_PVDLEVEL_7);
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	printf("demo!!!\r\n");
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

你可能感兴趣的:(stm32,嵌入式硬件,单片机)