STM32进入Standby模式并唤醒

项目背景

设备具备电池、电源适配器两种供电方式,实现出厂时最低功耗(即进入待机模式),到用户开始使用时需要手动唤醒,开始复位运行。在检测到设备是交流供电时,设备全速运行;电测到是电池供电时,定时采集数据,采集完毕进入停止模式,定时器唤醒等待下次数据采集。(stm32f103ret6)
备注:本节只记录待机模式的进入和唤醒,停止模式的实现方式见STM32进入STOP模式并唤醒实验总结

用待机模式的理由及与停止模式的区别

  1. 选用待机模式

设备出厂,电池装在电路板上,封闭在模具当中,在到用户开始使用之前,必须保持最低功耗。停止模式下CPU电流消耗在20uA左右,而待机模式的电流消耗只有2uA。

  1. 和停止模式的区别

图
因为SRAM和寄存器的内容会保存,即能PC指针能记录程序当前运行的位置,从停止模式唤醒时,能继续沿着到时进入停止模式处继续往下运行。(故运行时,设备检测到是电池供电时,选用停止模式:采集完数据进入停止模式,2小时后(根据需求自定义)定时唤醒采集,依此循环)

图2
SRAM和寄存器内容不会保存,即待机模式唤醒相当于系统复位,从头运行(设备测试完成,整机入库时,通过外部按键等方式触发进入待机模式)
图3

待机模式实现

图4
进入待机模式三个步骤说明:

1.将系统控制寄存器第二位置1,当进入深度睡眠时,允许停止系统时钟(系统控制寄存器参考《Cortex-M3权威指南》)
图5
2.使能PWR_CR的PDDS位,使得深度休眠时进入待机模式
3.清除WUF唤醒标志(WUF标志由硬件置位,当系统是WKUP唤醒复位而不是上电等复位时会置位。应用中可以用来读取PWR_CSR的WUF位是否为1来判断系统复位是不是待机唤醒)
4.
以上三个步骤由库函数PWR_EnterSTANDBYMode()实现
图5

进入待机模式
void Standby_Entering(void)
{
	RCC_APB2PeriphResetCmd(0x01fc, DISABLE);		//准备进入待机模式,复位所有IO,降低功耗(参照手册,根据需要复位对应IO)
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//需要配置电源控制寄存器,所以使能时钟,否则不能正常使用命令进入待机状态和唤醒
	PWR_WakeUpPinCmd(ENABLE);					//使能WKUP引脚唤醒功能,否则WKUP引脚上升沿不能唤醒
	PWR_EnterSTANDBYMode();					//进入待机模式
}

void Standby_Configure(void)
{
	GPIO_InitTypeDef	GPIO_InitStructure;
	//EXTI_InitTypeDef  EXTI_InitStructure;
	//NVIC_InitTypeDef NVIC_InitStructure;
	
	GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IPD;
	GPIO_Init(WAKEUP_PORT, &GPIO_InitStructure);

/*如果PA0只是用于唤醒,这部分可以不要,唤醒不是中断,中断控制器已经停止工作,如果正常模式下需要用到,可根据需要添加,这时候是中断事件
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
	EXTI_InitStructure.EXTI_Line = EXTI_Line0;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;   
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    
	NVIC_Init(&NVIC_InitStructure); 
	*/
}
中断处理(注:唤醒之后相当于复位,不会执行中断函数里的内容)
void EXTI0_IRQHandler(void)
{
	EXTI_ClearITPendingBit(EXTI_Line0);		//清除LINE0上的中断标志位
}

void main(void)
{
	...
	Standby_Configure();
	...
	//读取PWR_CSR的WUF位检测复位来源,这也就是为什么在进入待机模式之前需要清除WUF唤醒标志,这样检测到唤醒标志就能确定发生了唤醒复位
	
	if(PWR_GetFlagStatus(PWR_FLAG_WU) == SET)//从待机唤醒后,除了电源控制/状态寄存器(PWR_CSR),所有寄存器被复位
	{
		//是待机唤醒复位,可帮助调试
	}
	else
	{
		//上电复位、软件复位等非唤醒复位
	}
	while(1)
	{
		if(外部按键标志)				//根据硬件和个人需求确定什么时候进入待机模式
		{
			Standby_Entering();
		}

		//数据采集、发送
		//进入停止模式
		//定时从停止模式唤醒	
	}
}
发布了9 篇原创文章 · 获赞 12 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/lmx11040101/article/details/104496637
今日推荐