STM32中使用低功耗的延时方法
上文说了STM32L4的几种低功耗模式,将其应用起来作为一个低功耗的延时方案。
为什么使用低功耗定时器,在追求长时间续航时,单片机有时需要切换到低功耗模式或者停止模式下,在这种模式下,系统主时钟关闭,有一些依赖于系统主时钟的应用程序,可能会发生出现某些奇怪的情况。因此在休眠唤醒后对主时钟进行校准,防止出现莫名其妙的BUG。
LPTIM全称:Low Power TIM ,我们将其运行在计数模式下,其时钟源可以选择低速时钟(单片机在STOP模式下,低速时钟依然运行),在cubemx中打开定时器,预分频器选择1,这样的话计数时间最长,也就是从0到65535需要计数2秒,触发源选择软件。
开启LPTIM的中断,我们将由溢出中断来唤醒系统。生成代码:
使用HAL_LPTIM_TimeOut_Start_IT(&hlptim1, 0, 32767);
代码开启定时器,预分频系数选择0,最大计数值为65535,在一分频的情况下最高两秒产生中断。
时钟配置界面,给LPTIM配置为内部低速定时器,其他部分按照自己需求配置:
任何中断可以把单片机从STOP模式下唤醒,切记打开定时器中断:
如果涉及到休眠模式,可以将所有没用到的引脚设置为浮空模式,可以降低上下拉电阻带来的功耗消耗:
其他的设置按照需求或者个人的习惯来就好。生成代码。将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;
}
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。