打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
stm32 低功耗设计[操作寄存器+库函数]-Changing's Blog
stm32的低功耗模式有三种:
  • 睡眠模式(内核停止,外设运行)
  • 停机模式(所有时钟都停止)
  • 待机模式(1.8V内核电源也关闭)
在这三种模式中,最低功耗的是待机模式,在此模式下,最低只需要2uA左右的电流。整个1.8V供电区被断电,PLL、HSI、HSE振荡器都被关闭。SRAM和寄存器内容丢失。停机模式是次低功耗的的,其典型的电流损耗在20uA左右。最后就是睡眠模式。
stm32低功耗一览表
这三种低功耗模式,唤醒后程序都会初始化运行。在例子中做了一番论证,结果如此。
直接操作寄存器
进入待机模式的通用步骤,其中涉及到2个寄存器,也就是电源控制寄存器(PWR_CR)和电源控制/状态寄存器(PWR_CSR)。
电源控制寄存器(PWR_CR),该寄存器的各位描述如下:
这是一个低9位有效的寄存器。
  • DBP[8]:取消后备区域的写保护 位 8 在复位后,RTC和后备寄存器处于被保护状态以防意外写入。0:禁止写入RTC和后备寄存器  1:允许写入RTC和后备寄存器 
  • PLS[ 7:5 ]:PVD电平选择。 这些位用于选择电源电压监测器的电压阀值。
                000:2.2V         100:2.6V             001:2.3V         101:2.7V
                010:2.4V         110:2.8V             011:2.5V         111:2.9V 
  • PVDE[4]:电源电压监测器(PVD)使能。  0:禁止PVD 1:开启PVD
  • CSBF[3]:清除待机位,始终读出为0。 0:无功效  1:清除SBF待机位(写)
  • CWUF[2]:清除唤醒位,始终读出为0。 0:无功效 1:2个系统时钟周期后清除WUF唤醒位(写)
  • PDDS[1]:掉电深睡眠,与LPDS位协同操作。 0:当CPU进入深睡眠时进入停机模式,调压器的状态由LPDS位控制。 1:CPU进入深睡眠时进入待机模式。
  • LPDS[0]:深睡眠下的低功耗。PDDS=0时,与PDDS位协同操作 0:在停机模式下电压调压器开启 1:在停机模式下电压调压器处于低功耗模式

电源控制寄存器(PWR_CR),该寄存器的各位描述如下:
低9位有效的寄存器,只用了4位,其他位保留
  • EWUP[8]:使能WKUP引脚 ,在系统复位时清除这一位。 
  • PVDO[2]:PVD输出 ,当PVD被PVDE位使能后该位才有效。 
  • SBF[1]:待机标志。
  • WUF[0]:唤醒标志。 
待机函数实现:(参见 system.c文件)

//THUMB指令不支持汇编内联//采用如下方法实现执行汇编指令WFI__asm void WFI_SET(void){	WFI;    }//进入待机模式	 //参数说明: //		 var = 0 ,设定为睡眠模式//       var = 1 ,设定为停机模式,电流消耗在20uA左右//		 var = 2 ,设定为待机模式,电流消耗在2uA左右void Sys_Standby(u8 var){		     	RCC->APB1ENR |= 1<<28;     		//使能电源时钟	    	switch(var)	{ 		case 0:{ break;	}			//WFI进入睡眠模式		case 1:{			 		//PDDS+LPDS+SLEEPDEEP+WFI进入停机模式						SCB->SCR |= 1<<2;		//使能SLEEPDEEP位 (SYS->CTRL)						PWR->CR	|= 1<<0;		//LPDS置位				PWR->CR |= 1<<1;        //PDDS置位				break;					} 				 				case 2:{			 		//PDDS+SLEEPDEEP+WFI进入待机模式			SCB->SCR |= 1<<2;		//使能SLEEPDEEP位 (SYS->CTRL)			PWR->CR|=1<<1;          //PDDS置位				break;					} 	}	PWR->CR  |= 1<<2;          		//清除Wake-up 标志	PWR->CSR |= 1<<8;          		//允许写入RTC和BKP寄存器	WFI_SET();				 		//执行WFI指令		 }		    //系统软复位void Sys_Soft_Reset(void){   	SCB->AIRCR =0X05FA0000|(u32)0x04;	  } 
代码如下:(system.h 和 stm32f10x_it.h 等相关代码参照 stm32 直接操作寄存器开发环境配置
User/main.c
#include <stm32f10x_lib.h>	#include "system.h" 	#include "wdg.h" #include "exti.h" #define LED1 PAout(4)#define LED2 PAout(5)#define PWR_MODE_Sleep 		0   	//开启睡眠模式#define PWR_MODE_STOP   	1 	  	//开启停机模式#define PWR_MODE_STANDBY 	0    	//开启待机模式void Gpio_Init(void);int main(void){				  	u32 i= 10,j=10;	Rcc_Init(9); 			 //系统时钟设置 	Exti_Init(GPIO_A,0,FTIR);  //设置PA1为下降沿触发,参数GPIO_x 和 FTIR 在system.h中有定义	Nvic_Init(0,0,EXTI0_IRQChannel,0);	  //设置外部中断   		Gpio_Init();	while(i--){	   			LED1 = !LED1;		delay(30000);   //延时30ms									  	}	#if PWR_MODE_Sleep    		//睡眠模式,外部中断唤醒后会复位		Sys_Standby(0);  		     #elif PWR_MODE_STOP       	//停机模式,外部中断唤醒,唤醒后复位                         		Sys_Standby(1);    #elif PWR_MODE_STANDBY     	//待机模式,由独立看门狗唤醒,唤醒后会初始化,LED闪烁5次后,暗一段时间	    Iwdg_Init(3,2000);      //设置为1.6s内不喂狗复位,使用独立看门狗唤醒,唤醒后复位        Sys_Standby(2);      #endif	while(j--){					//这段程序用于检验唤醒后是否会继续运行后面的程序,还是会导致复位	   			LED2 = !LED2;		delay(10000);   //延时10ms									  	}		}void Gpio_Init(void){	RCC->APB2ENR|=1<<2;    //使能PORTA时钟 		GPIOA->CRL&=0x0000FFFF; // PA0~3设置为浮空输入,PA4~7设置为推挽输出	GPIOA->CRL|=0x33334444; }
User/stm32f10x_it.c
#include "stm32f10x_it.h"#include "system.h"#define LED1 PAout(4)#define LED2 PAout(5)#define LED3 PAout(6)#define LED4 PAout(7)void EXTI0_IRQHandler(void){   	LED4 = !LED4;	EXTI->PR = 1<<0;    //清除中断标志位}

待机相关代码参见 system.c文件中

库函数操作
main.c
#include "stm32f10x.h"#include "stdio.h"#define	 PRINTF_ON  1void RCC_Configuration(void);void GPIO_Configuration(void);void NVIC_Configuration(void);void EXTI_Configuration(void);void IWDG_Configuration(void);#define PWR_MODE_Sleep 0    //开启睡眠模式#define PWR_MODE_DeepSleep 1    //开启停机模式#define PWR_MODE_STANDBY 0    //开启待机模式     vu32 DelayTime = 10000000;int main(void){  	RCC_Configuration();  	GPIO_Configuration();	NVIC_Configuration();	EXTI_Configuration();		SysTick_Config(10000000);		while(--DelayTime);   		#if PWR_MODE_Sleep	  //睡眠模式		PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFI);  //唤醒后时钟变为内置8MHz   	#elif PWR_MODE_DeepSleep	  //停机模式		PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);   //唤醒后时钟变为内置8MHz   	#elif PWR_MODE_STANDBY		 //待机模式	   	IWDG_Configuration();  	//设置为2s内不喂狗复位,使用独立看门狗唤醒 		PWR_EnterSTANDBYMode(); 	//唤醒后会初始化程序							 	#endif    	while(1);}void IWDG_Configuration(void){ 	RCC_LSICmd(ENABLE);                              //打开LSI    while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==RESET);	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);	IWDG_SetPrescaler(IWDG_Prescaler_32);	IWDG_SetReload(2000);	  //max 0xFFF  0~4095  	IWDG_ReloadCounter();	IWDG_Enable();}void GPIO_Configuration(void){  	GPIO_InitTypeDef GPIO_InitStructure;                                                                                        	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_7;  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;			  	GPIO_Init(GPIOA , &GPIO_InitStructure);  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;			  	GPIO_Init(GPIOA , &GPIO_InitStructure);  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;			  	GPIO_Init(GPIOA , &GPIO_InitStructure); 	  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;			  	GPIO_Init(GPIOA , &GPIO_InitStructure);    	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);}void RCC_Configuration(void){	/* 定义枚举类型变量 HSEStartUpStatus */	ErrorStatus HSEStartUpStatus;  	/* 复位系统时钟设置*/  	RCC_DeInit();  	/* 开启HSE*/  	RCC_HSEConfig(RCC_HSE_ON);  	/* 等待HSE起振并稳定*/  	HSEStartUpStatus = RCC_WaitForHSEStartUp();	/* 判断HSE起是否振成功,是则进入if()内部 */  	if(HSEStartUpStatus == SUCCESS)  	{    	/* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */    	RCC_HCLKConfig(RCC_SYSCLK_Div1);     	/* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */    	RCC_PCLK2Config(RCC_HCLK_Div1);     	/* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */    	RCC_PCLK1Config(RCC_HCLK_Div2);    	/* 设置FLASH延时周期数为2 */    	FLASH_SetLatency(FLASH_Latency_2);    	/* 使能FLASH预取缓存 */    	FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);    	/* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */    	RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);    	/* 使能PLL */     	RCC_PLLCmd(ENABLE);    	/* 等待PLL输出稳定 */    	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);    	/* 选择SYSCLK时钟源为PLL */    	RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);    	/* 等待PLL成为SYSCLK时钟源 */    	while(RCC_GetSYSCLKSource() != 0x08);  	}   	/* 打开APB2总线上的GPIOA时钟*/  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);	//RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);	//RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP|RCC_APB1Periph_WWDG, ENABLE);		} void USART_Configuration(void){	USART_InitTypeDef USART_InitStructure;	USART_ClockInitTypeDef USART_ClockInitStructure;	USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;	USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;	USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;                                                                                                                                                      	USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;	USART_ClockInit(USART1 , &USART_ClockInitStructure);	USART_InitStructure.USART_BaudRate = 9600;	USART_InitStructure.USART_WordLength = USART_WordLength_8b;	USART_InitStructure.USART_StopBits = USART_StopBits_1;	USART_InitStructure.USART_Parity = USART_Parity_No;	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;	USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;	USART_Init(USART1,&USART_InitStructure); 	USART_Cmd(USART1,ENABLE);}void EXTI_Configuration(void){	EXTI_InitTypeDef EXTI_InitStructure;		EXTI_InitStructure.EXTI_Line = EXTI_Line0;	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;	EXTI_InitStructure.EXTI_LineCmd = ENABLE;	EXTI_Init(&EXTI_InitStructure);	 	}void NVIC_Configuration(void){	NVIC_InitTypeDef NVIC_InitStructure;		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);		NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	NVIC_Init(&NVIC_InitStructure);}#if	 PRINTF_ONint fputc(int ch,FILE *f){	USART_SendData(USART1,(u8) ch);	while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);	return ch;}#endif
stm32f10x_it.c
#include "stm32f10x_it.h"#include "stdio.h"void EXTI0_IRQHandler(void){	GPIO_WriteBit(GPIOA,GPIO_Pin_7,Bit_SET);  		//EXTI_ClearFlag(EXTI_Line0);   //清除此中断标志位,系统由于唤醒将直接复位}void SysTick_Handler(void){   GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4)));}
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
cortex
STM32 待机唤醒 | Rming
STM32中断嵌套及外部中断全程攻略
STM32F103学习笔记(五) 外部中断
STM32
来跟大家简单说说STM8的停机模式吧!让大家少走点弯路!
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服