STM32中使用低功耗定时器延时

此篇文章在2022年5月19日被记录

上文说了STM32L4的几种低功耗模式,将其应用起来作为一个低功耗的延时方案。

为什么使用低功耗定时器,在追求长时间续航时,单片机有时需要切换到低功耗模式或者停止模式下,在这种模式下,系统主时钟关闭,有一些依赖于系统主时钟的应用程序,可能会发生出现某些奇怪的情况。因此在休眠唤醒后对主时钟进行校准,防止出现莫名其妙的BUG。

LPTIM全称:Low Power TIM ,我们将其运行在计数模式下,其时钟源可以选择低速时钟(单片机在STOP模式下,低速时钟依然运行),在cubemx中打开定时器,预分频器选择1,这样的话计数时间最长,也就是从0到65535需要计数2秒,触发源选择软件。

img

开启LPTIM的中断,我们将由溢出中断来唤醒系统。生成代码:
使用HAL_LPTIM_TimeOut_Start_IT(&hlptim1, 0, 32767);代码开启定时器,预分频系数选择0,最大计数值为65535,在一分频的情况下最高两秒产生中断。
时钟配置界面,给LPTIM配置为内部低速定时器,其他部分按照自己需求配置:

img

任何中断可以把单片机从STOP模式下唤醒,切记打开定时器中断:

img

如果涉及到休眠模式,可以将所有没用到的引脚设置为浮空模式,可以降低上下拉电阻带来的功耗消耗:

img

其他的设置按照需求或者个人的习惯来就好。生成代码。将C文件与头文件添加到工程中:

/*
 * LP_Delay.c
 *
 *  Created on: 2022年5月19日
 *      Author: 
 */
#include "LP_Delay.h"
#include "lptim.h"
#include "stdio.h"
/*
 * 函数说明:在休眠状态下延时,旨在降低空显时间的功耗
 * 传入参数:毫秒  范围0~2000
 * 返回值:传入值
 * */
uint16_t Sleep_Delayms(uint16_t ms)
{
	uint16_t cnt=ms*32767/1000;
	__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI);  // 设定唤醒后的时钟源
	HAL_LPTIM_MspInit(&hlptim1);//定时器初始化
	HAL_LPTIM_TimeOut_Start_IT(&hlptim1, 0, cnt);//设置中断计数值
	__HAL_RCC_PWR_CLK_ENABLE();  // 打开电源控制时钟
	SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |0| SysTick_CTRL_ENABLE_Msk;//这里很重要,不然休眠会被提前中断
	HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
	return ms;
}
/*
 * 函数说明:LPTIM1回调函数
 * */
void HAL_LPTIM_CompareMatchCallback(LPTIM_HandleTypeDef *hlptim)
{
	HAL_LPTIM_MspDeInit(&hlptim1);  // 关闭LP定时器
	SystemClock_Config(); // 配置系统时钟
	SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; // 打开Systick的中断
	SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk; // 退出中断时不再自动进入低功耗模式
	//printf("In the EXTI to wake up!\r\n");
}




LP_Delay.h
/*
 * LP_Dealy.h
 *
 *  Created on: 2022年5月19日
 *      Author: shumei
 */

#ifndef LP_DELAY_LP_DEALY_H_
#define LP_DELAY_LP_DEALY_H_

#include "main.h"

uint16_t Sleep_Delayms(uint16_t ms);
void HAL_LPTIM_CompareMatchCallback(LPTIM_HandleTypeDef *hlptim);
#endif /* LP_DELAY_LP_DEALY_H_ */

引用示例:

While(1)
{
	Sleep_Delayms(200);
	  //HAL_Delay(1000);
	  HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
	  printf("%d\r\n",HAL_GetTick());
}

可以将系统心跳打印出来,并判断与HAL_Delay延时函数的区别。

注意:并不是简单的引用HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);函数就达到低功耗了,实际上的低功耗都是一点一点抠出来的,比如,使用的外设Deinit掉,没有用到的引脚都改为浮空模式。

-------------------------------------------次日更新-------------------------------

由于我们已经知道了在STOP2模式下,可以被任何中断唤醒,因此在实际使用中可能会产生提前退出延时的情况,因此进行一个判断,如果是LPTIM产生的溢出中断,那么定时器计数值为0,如果不为零,算出实际延时时间,并返回数值。
更新后的代码:

/*
 * 函数说明:在休眠状态下延时,旨在降低空显时间的功耗
 * 传入参数:毫秒  范围0~2000
 * 返回值:传入值
 * */
uint16_t Sleep_Delayms(uint16_t ms)
{
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,1);
	uint16_t cnt=(ms-1)*32767/1000;
	__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI);  // 设定唤醒后的时钟源
	HAL_LPTIM_MspInit(&hlptim1);//定时器初始化
	__HAL_RCC_PWR_CLK_ENABLE();  // 打开电源控制时钟
	SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |0| SysTick_CTRL_ENABLE_Msk;//这里很重要,不然休眠会被提前中断
	HAL_LPTIM_TimeOut_Start_IT(&hlptim1, 0, cnt);//设置中断计数值

	HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);//进入到休眠模式

	if(!HAL_LPTIM_ReadCounter(&hlptim1))
	{
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,0);
		return ms;
	}
	else
	{
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,0);
		ms=HAL_LPTIM_ReadCounter(&hlptim1)*1000/32768;
		return ms;
	}
	return ms;
}
posted @ 2024-12-10 14:45  shumei52  阅读(319)  评论(0)    收藏  举报