STM32f103 利用LSI时钟配置RTC闹钟中断唤醒待机模式(包含标准库代码)

一个小项目需要使用纽扣电池为单片机供电,为了保证续航时间,需要配置单片机在无数据接受时运行在低功耗模式。本科接触单片机从来不需要考虑功耗,对单片机如何进入低功耗,通过那种方式如何唤醒,低功耗模式下单片机的运行状态缺乏了解。记录一下对stm32低功耗模式学习。

目的

考虑最小系统实际硬件,最大程度降低功耗,使单片机在无数据采集情况下运行在待机模式。当运行在低功耗模式时,使用固定周期RTC闹钟中断唤醒单片机,检查是否有数据接受,若无数据接受则继续运行待机模式。

低功耗模式的选择

查阅资料,stm32f103具备三种低功耗模式,分别是

  • 睡眠模式
  • 停止模式
  • 待机模式

睡眠模式

单片机工作状态:单片机内核停止工作,但所有外设包括核心外设,系统时钟依然保持运行。I/O引脚保持在运行时的状态

进入方式:具备两种进入方式 SLEEP_NOW 和SLEEP_EXIT,区别在与进入睡眠模式是否等待中断处理程序执行完毕。可以通过WFI或者WFE进入,区别在于等待中断还是等待事件。

唤醒方式:可以通过任一中断唤醒,或者唤醒事件唤醒。

睡眠模式运行的好处在于对内核以外的时钟没有影响,能最大化保持当前运行的状态,但电压调节器依然保持开启,尤其在本次项目中,功耗最大的ADC采集与蓝牙发送并没有关闭,单片机功耗降低并不明显。

停止模式

单片机工作状态:在睡眠模式的基础上,加入对外设时钟的控制。进一步降低功耗,通过配置电压调节器运行在正常或者低功耗模式。1.8V区域的时钟都停止运行,锁相环,HSI(高速内部时钟),HSE(高速外部时钟)停止运行,但SRAM和寄存器内容保留。与睡眠模式相同,所有I/O引脚保持运行时的状态。

进入方式:同样可以通过WFI或者WFE进入停止模式,但是需要注意,当进入停止模式时,所有的外部中断请求位都需要清除,RTC闹钟标志同样需要清除。

唤醒模式:同样可以通过中断或者唤醒事件唤醒 。需要注意,当退出停止模式时,系统时钟为HSI RC振荡器,如果单片机初始时钟源与其不同,需要重新配置时钟源,保证退出停止模式后单片机时序正常。

停止模式可以通过配置电压调节器运行在低功耗模式下,进一步降低功耗,但退出停止模式时,需要一端启动时间,不适合对时间精度要求高的系统。

考虑配置停止模式时代码的繁琐,需要自行停止外设时钟,清零中断、RTC闹钟中断标志位,关闭系统定时器,清空数值,自行关闭功耗最大ADC采集和串口发送中断,并且唤醒时还需要重新选用HSE作为时钟源,功耗相对于待机模式也不是最低,所以不采用停止模式。

待机模式

单片机工作状态:待机模式关闭电压调节器,1.8v区域停止供电,所以PLL、HSI、HSE振荡器也被断电,只有LSI(内部低速时钟)或者LSE(外部低速时钟)可以保持运行,SRAM和寄存器内容丢失,但备份域的寄存器和待机电路依然保持运行状态。

与睡眠模式与停止模式不同的是,待机模式下除了唤醒引脚和复位引脚或者自己设置的TAMPER引脚之外,所有i/o口处于高阻态,最大化降低功耗。

进入方式:WFI或WFE进入。需要注意使能电源控制寄存器相关位,保持备份区域运行。

唤醒方式:1.外部复位引脚唤醒(其他唤醒方式唤醒等同于单片机复位)2.独立看门狗复位唤醒(采用的LSI时钟,所以不会被关闭)3.唤醒引脚外部中断触发(注意使能该引脚外部中断)4.RTC闹钟事件中断唤醒

待机模式唤醒后,单片机相当于复位后运行,考虑本次项目对数据连续性并无要求,同时所有高功耗外设不需要自行关闭,唤醒后时钟源不需要自行重新配置,程序简洁,所以采用待机模式。

时钟源的选择

STM32f103的时钟树架构包含HSI、HSE、LSI、LSE、PLL。依据速率分为高速与低速时钟,依据晶体位置分为外部与内部时钟。

贴一张网络上的时钟树图片,从图中可以看出RTC时钟可以来自40khz的LSI与32.768khz的LSE,区别在于LSI在长时间运行后精度下降。在待机模式下HSE与HSI均被关闭,即所有外设时钟均无法运行。考虑最小系统实际硬件,并没有添加LSE外部晶振,所以只能选择LSI作为RTC时钟源,同时,本次项目对休眠时间精度要求不高。所以选择LSI作为RTC时钟源,并不会影响到实际功能的实现。

唤醒方式的选择

项目为了小型化,并没有外接唤醒引脚与复位引脚,只能选择看门狗与RTC闹钟中断唤醒,本次选择固定周期RTC中断唤醒,唤醒后检查是否有数据,若无数据则继续进入待机模式,保证正常功能的同时最大化降低最小系统的功耗。

代码配置

借鉴网络上现有的配置代码资源,更改RTC时钟源为内部时钟源,配置代码如下:

RTC时钟初始化:

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP|RCC_APB1Periph_PWR,ENABLE);
	PWR_BackupAccessCmd(ENABLE);
	if(PWR_GetFlagStatus(PWR_FLAG_SB)!=RESET) //如果现在处于待机模式
	{
		PWR_ClearFlag(PWR_FLAG_SB);            //清除待机模式
		RTC_ITConfig(RTC_IT_SEC, ENABLE);	    //打开RTC中断
		RTC_WaitForSynchro();
	}
	else
	{
			BKP_DeInit();	
			RCC_LSICmd(ENABLE); //设置内部低速晶振(LSI)
		while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY ) == RESET)	
			{
			
			}
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);		
		RCC_RTCCLKCmd(ENABLE);	
		RTC_WaitForLastTask();	
		RTC_WaitForSynchro();		
		RTC_ITConfig(RTC_IT_SEC, ENABLE);	//使能秒中断
		RTC_WaitForLastTask();	
		RTC_ITConfig(RTC_IT_ALR, ENABLE);	//使能闹钟中断
		RTC_EnterConfigMode(); 
		RTC_SetCounter(0);
 
		RTC_WaitForLastTask();	
		RTC_SetPrescaler(40000); //40k内部低速时钟	
		RTC_WaitForLastTask();
		RTC_ExitConfigMode();
	}

需要注意使能电源时钟和背部时钟,允许背部区域擦写(一二行)

使能RTC闹钟中断,配置完毕后注意退出配置模式

由于采用的LSI作为时钟源,RTC_SetPrescaler分频配置为40000,以或得1hz频率,即以秒作为计数单位

配置NVIC中断:

	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;		
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;	
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		
	NVIC_Init(&NVIC_InitStructure);	

注意中断优先级的设置,否则导致单片机休眠时间混乱。

中断服务函数:

void RTC_IRQHandler(void)
{

  if(RTC_GetITStatus(RTC_IT_ALR)!=RESET)
	{
	  if(RTC_GetCounter()>1000) RTC_SetCounter(0); 
		 
	}	

	
	RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW|RTC_IT_ALR);
	RTC_WaitForLastTask();

 
}

由于RTC计数值有上限,所以在中断服务函数中清空一次当前计数值。

休眠模式调用:

	if(Standby==0) //休眠模式条件满足
	{
		
	 Standby=WAKEUP_TIME;		
	 RTC_ClearFlag(RTC_FLAG_SEC);
	 while(RTC_GetFlagStatus(RTC_FLAG_SEC)==RESET);
	 RTC_SetAlarm(RTC_GetCounter()+STANDBY_TIME);  //闹钟在此时刻加上STANDBY_TIME秒
	 RTC_WaitForLastTask();
	 PWR_EnterSTANDBYMode();	 //进入低功耗模式

	}

通过数据检测判断是否满足进入休眠模式条件,WAKEUP_TIME为持续检测时间,STANDBY_TIME为休眠时间。通过宏定义配置,注意时间单位。

调试注意事项

通过debug调试,在RTC中断服务函数可以设置一个自加量去观察是否能够进入中断和观察进入中断时间是否准确。

需要注意不确定休眠时间的时候,最好注释掉进入低功耗模式,在没有RTC闹钟中断唤醒,并且复位引脚没有引出,单片机无法复位。进入低功耗模式后,debug会停止,并且程序也无法重新下载。所以在确定RTC闹钟中断能够正常运行后,再开启低功耗模式。

分享一个进入低功耗模式后无法使用SWD下载程序的方法,使用USB为st_link供电,当插入USB供电的一瞬间,按下下载按钮,实验过能成功下载程序。

具体运行功耗与休眠模式功耗差别,由于手头缺乏测量设备,缺乏具体测量,通过周期性唤醒休眠,在无法通过唤醒引脚唤醒的情况下,能够最大程度降低功耗。

  • 1
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是基于STM32CubeMX和HAL库的RTC定时唤醒代码: 1. 首先,在STM32CubeMX中配置RTC模块。打开“Pinout & Configuration”窗口,选择“RTC”模块,并确保“RTC Clock Source”被配置为“LSE”(低速外部晶体)或“LSI”(低速内部晶体),这取决于你的硬件。接下来,打开“Configuration”选项卡,启用“RTC”和“RTC Wakeup”,然后设置你需要的唤醒周期。最后,生成代码。 2. 在生成的代码中,打开“main.c”文件,找到“MX_RTC_Init”函数。在此函数中,你可以设置RTC时钟源、时钟预分频器和时钟分频器。例如,如果你使用的是LSE晶体,你可以设置如下的代码: ``` /* Enable the LSE clock */ RCC_OscInitTypeDef RCC_OscInitStruct; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.LSEState = RCC_LSE_ON; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /* Configure the RTC clock source */ RCC_PeriphCLKInitTypeDef RCC_RTCCLKInit; RCC_RTCCLKInit.PeriphClockSelection = RCC_PERIPHCLK_RTC; RCC_RTCCLKInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; if (HAL_RCCEx_PeriphCLKConfig(&RCC_RTCCLKInit) != HAL_OK) { Error_Handler(); } /* Enable the RTC peripheral clock */ __HAL_RCC_RTC_ENABLE(); ``` 此外,你还可以设置RTC唤醒定时器的时钟预分频器和分频器。例如,如果你需要1秒钟的唤醒周期,你可以设置如下的代码: ``` /* Configure the RTC wakeup timer */ hrtc.Init.HourFormat = RTC_HOURFORMAT_24; hrtc.Init.AsynchPrediv = 0x7F; hrtc.Init.SynchPrediv = 0x00FF; hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; if (HAL_RTC_Init(&hrtc) != HAL_OK) { Error_Handler(); } /* Configure the RTC wakeup timer with a 1-second period */ RTC_WakeUpTypeDef RTC_InitStruct; RTC_InitStruct.WakeUpClock = RTC_WAKEUPCLOCK_RTCCLK_DIV16; RTC_InitStruct.WakeUpTime = 0x7FFF; /* 1 second */ if (HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, &RTC_InitStruct) != HAL_OK) { Error_Handler(); } ``` 3. 最后,在“RTC_WKUP_IRQHandler”中断处理程序中添加你需要执行的代码。例如,你可以使用GPIO口控制LED灯的状态: ``` void RTC_WKUP_IRQHandler(void) { HAL_RTCEx_DeactivateWakeUpTimer(&hrtc); HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0xFFFF, RTC_WAKEUPCLOCK_RTCCLK_DIV16); } ``` 此代码将在RTC唤醒时将LED灯的状态切换为反转,并重新设置RTC唤醒定时器。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值