第41章 电源管理—实现低功耗

41.1 STM32 的电源管理简介

1.1电源监控器
1.1.1上电复位与掉电复位 (POR 与 PDR)

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

在这里插入图片描述

1.1.2 可编程电压检测器 PVD

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

在这里插入图片描述

1.2 STM32 的电源系统

STM32 把它的外设、内核等模块跟据功能划分了供电区域

在这里插入图片描述

STM32 的电源系统主要分为备份域电路内核电路以及 ADC 电路三部分

(1) ADC 电源及参考电压(VDDA 供电区域)

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

(2) 调压器供电电路(VDD/1.8V 供电区域)

在 STM32 的电源系统中调压器供电的电路是最主要的部分,调压器为备份域及待机电路以外的所有数字电路供电,其中包括内核、数字外设以及 RAM,调压器的输出电压约为 1.8V,因而使用调压器供电的这些电路区域被称为 1.8V 域。调压器可以运行在“运行模式”、“停止模式”以及“待机模式”。在运行模式下,1.8V域全功率运行;在停止模式下 1.8V 域运行在低功耗状态,1.8V 区域的所有时钟都被关闭,相应的外设都停止了工作,但它会保留内核寄存器以及 SRAM 的内容;在待机模式下,整个 1.8V 域都断电,该区域的内核寄存器及 SRAM 内容都会丢失 (备份区域的寄存器不受影响)。

(3) 备份域电路(后备供电区域)

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

1.3 STM32 的功耗模式

在这里插入图片描述

1.3.1 睡眠模式

在这里插入图片描述

1.3.2 停止模式

在这里插入图片描述

1.3.3 待机模式

在这里插入图片描述

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

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

2.1 配置 PVD 监控功能
2.2 WFI 与 WFE 命令
2.3 进入停止模式
2.4 进入待机模式

41.3 PWR—睡眠模式实验

3.1 硬件设计
3.2 软件设计
3.2.1 程序设计要点

(1) 初始化用于唤醒的中断按键;

(2) 进入睡眠状态;

(3) 使用按键中断唤醒芯片;

3.2.2 代码分析

(1)main 函数

/**

#include "stm32f10x.h"
#include "./led/bsp_led.h"
#include "./usart/bsp_usart.h"
#include "./Key/bsp_exti.h"


static void Delay(__IO u32 nCount);


/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */
int main(void)
{ 
	
	LED_GPIO_Config();	
	
  /*初始化USART1*/
  USART_Config();		
	
	/* 初始化按键为中断模式,按下中断后会进入中断服务函数	*/
	EXTI_Key_Config(); 
	
	printf("\r\n 欢迎使用野火  STM32  开发板。\r\n");
  printf("\r\n 野火STM32 睡眠模式例程\r\n");
	
	printf("\r\n 实验说明:\r\n");

	printf("\r\n 1.本程序中,绿灯表示STM32正常运行,红灯表示睡眠状态,蓝灯表示刚从睡眠状态被唤醒\r\n");
	printf("\r\n 2.程序运行一段时间后自动进入睡眠状态,在睡眠状态下,可使用KEY1或KEY2唤醒\r\n");
	printf("\r\n 3.本实验执行这样一个循环:\r\n ------》亮绿灯(正常运行)->亮红灯(睡眠模式)->按KEY1或KEY2唤醒->亮蓝灯(刚被唤醒)-----》\r\n");
	printf("\r\n 4.在睡眠状态下,DAP下载器无法给STM32下载程序,\r\n 可按KEY1、KEY2唤醒后下载,\r\n 或按复位键使芯片处于复位状态,然后在电脑上点击下载按钮,再释放复位按键,即可下载\r\n");

  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循环

  }

}

static void Delay(__IO uint32_t nCount)	 //简单的延时函数
{
	for(; nCount != 0; nCount--);
}



/*********************************************END OF FILE**********************/

其他配置在这里插入图片描述

41.4 PWR—停止模式实验

4.1 硬件设计
4.2 软件设计
4.2.1 程序设计要点

(1) 初始化用于唤醒的中断按键;

(2) 选择电压调节器的工作模式并进入停止状态;

(3) 使用按键中断唤醒芯片;

(4) 重启 HSE 时钟,使系统完全恢复停止前的状态。

4.2.2 代码分析

(1)重启 HSE 时钟

(2)main函数


/**

#include "stm32f10x.h"
#include "./led/bsp_led.h"
#include "./key/bsp_exti.h" 
#include "./usart/bsp_usart.h"



static void Delay(__IO u32 nCount);
static void SYSCLKConfig_STOP(void);


/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */ 
int main(void)
{	

	RCC_ClocksTypeDef clock_status_wakeup,clock_status_config;
	uint8_t clock_source_wakeup,clock_source_config; 

	
	LED_GPIO_Config();	
	
  /*初始化USART1*/
  USART_Config();		
	
	/* 初始化按键中断,按下按键后会进入中断服务程序	*/
	EXTI_Key_Config(); 
	
	printf("\r\n 欢迎使用野火  STM32  开发板。\r\n");
  printf("\r\n 野火STM32 停止模式例程\r\n");
	
	printf("\r\n 实验说明:\r\n");

	printf("\r\n 1.本程序中,绿灯表示STM32正常运行,红灯表示停止状态,蓝灯表示刚从停止状态被唤醒\r\n");
	printf("\r\n 2.在停止状态下,可使用KEY1或KEY2唤醒\r\n");
	printf("\r\n 3.本实验执行这样一个循环:\r\n ------》亮绿灯(正常运行)->亮红灯(停止模式)->按KEY1或KEY2唤醒->亮蓝灯(刚被唤醒)-----》\r\n");
	printf("\r\n 4.在停止状态下,DAP下载器无法给STM32下载程序,\r\n 可按KEY1、KEY2唤醒后下载,\r\n 或按复位键使芯片处于复位状态,然后在电脑上点击下载按钮,再释放复位按键,即可下载\r\n");

  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循环

  }
}


static void Delay(__IO uint32_t nCount)	 //简单的延时函数
{
	for(; nCount != 0; nCount--);
}



/**
  * @brief  停机唤醒后配置系统时钟: 使能 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)
  {
  }
}
/*********************************************END OF FILE**********************/

其他配置在这里插入图片描述

41.5 PWR—待机模式实验

5.1 硬件设计
5.2 软件设计
5.2.1 程序设计要点

(1) 清除 WUF 标志位;

(2) 使能 WKUP 唤醒功能;

(3) 进入待机状态。

5.2.2 代码分析

(1)main 函数

/**


#include "stm32f10x.h"
#include "./led/bsp_led.h"
#include "./key/bsp_key.h" 
#include "./usart/bsp_usart.h"


static void Delay(__IO u32 nCount);
static uint8_t KEY2_LongPress(void);


/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */ 
int main(void)
{	
		/* 使能电源管理单元的时钟,必须要使能时钟才能进入待机模式 */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR , ENABLE);

	LED_GPIO_Config();	
	
  /*初始化USART1*/
  USART_Config();			

	/*初始化按键,不需要中断,仅初始化KEY2即可,只用于唤醒的PA0引脚不需要这样初始化*/
	Key_GPIO_Config();   
	
	printf("\r\n 欢迎使用野火  STM32  开发板。\r\n");
  printf("\r\n 野火STM32 待机模式例程\r\n");
	
	printf("\r\n 实验说明:\r\n");

	printf("\r\n 1.本程序中,绿灯表示本次复位是上电或引脚复位,红灯表示即将进入待机状态,蓝灯表示本次是待机唤醒的复位\r\n");
	printf("\r\n 2.长按KEY2按键后,会进入待机模式\r\n");
	printf("\r\n 3.在待机模式下,按KEY1按键可唤醒,唤醒后系统会进行复位,程序从头开始执行\r\n");
	printf("\r\n 4.可通过检测WU标志位确定复位来源\r\n");
	
	printf("\r\n 5.在待机状态下,DAP下载器无法给STM32下载程序,需要唤醒后才能下载");

	
	//检测复位来源
	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(0x4FFFF);
			
			/*清除WU状态位*/
			PWR_ClearFlag (PWR_FLAG_WU);
			
			/* 使能WKUP引脚的唤醒功能 ,使能PA0*/
			PWR_WakeUpPinCmd (ENABLE);
			
			/* 进入待机模式 */
			PWR_EnterSTANDBYMode();
		}

  }
}


static void Delay(__IO uint32_t nCount)	 //简单的延时函数
{
	for(; nCount != 0; nCount--);
}



 /**
  * @brief  用于检测按键是否被长时间按下
  * @param  无
  * @retval 1 :按键被长时间按下  0 :按键没有被长时间按下
  */
static uint8_t KEY2_LongPress(void)
{			
	uint8_t downCnt =0;																				//记录按下的次数
	uint8_t upCnt =0;																					//记录松开的次数			

	while(1)																										//死循环,由return结束
	{	
		Delay(0x2FFFF);																					//延迟一段时间再检测

		if(GPIO_ReadInputDataBit ( KEY2_GPIO_PORT, KEY2_GPIO_PIN ) == SET)	//检测到按下按键
		{
			downCnt++;																					//记录按下次数
			upCnt=0;																						//清除按键释放记录

			if(downCnt>=100)																		//按下时间足够
			{
				return 1; 																				//检测到按键被时间长按下
			}
		}
		else 
		{
			upCnt++; 																						//记录释放次数
			if(upCnt>5)																					//连续检测到释放超过5次
			{
				return 0;																				//按下时间太短,不是按键长按操作
			}
		}//	if(GPIO_ReadInputDataBit 
	}//while
}
/*********************************************END OF FILE**********************/

其他配置
在这里插入图片描述

41.6 PWR—PVD 电源监控实验

6.1 硬件设计

在这里插入图片描述

6.2 软件设计
6.2.1 程序设计要点
6.2.2 代码分析

(1)初始化 PVD

(2)PVD 中断服务函数

(3)main 函数

/**

#include "stm32f10x.h"
#include "./led/bsp_led.h"
#include "./key/bsp_key.h" 
#include "./usart/bsp_usart.h"
#include "./pvd/bsp_pvd.h"



/*
*【 !】实验操作:
* 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,电压太高会烧坏实验板!!
*/
/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */ 
int main(void)
{	
		LED_GPIO_Config();	
	
	//亮绿灯,表示正常运行
	LED_GREEN; 
	
	//配置PVD,当电压过低时,会进入中断服务函数,亮红灯
	PVD_Config();
	
  while(1)
  {			
		
		/*正常运行的程序*/

  }
}



/*********************************************END OF FILE**********************/

温馨提示详情请看《stm32实战开发指南》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

入世浮尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值