|
目标实现:使用LPTIM1,在低功耗stop模式下定时1s,1s后将STM32从stop模式唤醒,并且点亮LED灯 1 LPTIM 介绍LPTIM,顾名思义,即低功耗定时器的意思,与普通定时器的差别是LPTIM在睡眠或者停机模式下依然可以工作(待机模式除外),支持低速时钟 LSI、 LSE 或者外部输入时钟。LPTIM是低功耗产品在低功耗功耗模式下定时的不二之选 支持芯片:并不是STM32的所有芯片都有LPTIM这个外设,,从官方资料可知,支持LPTIM的芯片有:STM32F410、STM32F413/423、STM32F7系列, STM32G0系列, STM32H7系列, STM32L0系列, STM32L4系列, STM32L4+系列, STM32L5系列, STM32WB系列
STM32L431芯片手册对LPTIM的介绍
, i2 t2 ]0 z8 i
2 LPTIM 功能LPTIM 低功耗定时器有以下 6 种模式: - 单脉冲模式
- PWM 模式
- 单次模式:在此模式下,当满足匹配条件时,输出可以切换高低电平(如果输出极性配置为高,则为低电平至高电平变化,反之亦然)
- 编码器模式
- 超时模式:有效的边沿触发输入可复位定时器。第一个触发事件将启动计时器,任何连续触发事件将重置计 数器并重新开始。
- 计数器模式:计数器可用于计算来自 Input1 的外部事件或用于计算内部时钟周期
1 n0 D& V- J8 z1 q C
主要有以下三个使用场景,本文将介绍LPTIM超时唤醒的应用: Asynchronous pulse counter in Stop mode(异步脉冲计数) PWM generator in Stop mode(PWM输出) Timeout wakeup mode(超时唤醒) ( D& b% {, P+ Y# }4 e) V( d* l
3 LPTIM初始化结构体介绍下LPTIM初始化结构体各个参数的含义及配置
3.1 Clock3.2 UltraLowPowerClock3.3 Trigger3.4 OutputPolarity- OutputPolarity 用于配置输出极性,可选择高电平或者低电平输出
7 V7 {3 w/ c8 [3 Q6 y% ?8 a
3.5 UpdateMode- UpdateMode用于配置是否立即更新自动重装寄存器和比较寄存器,可以选择立即更新,或者当前周期结束后更新
4 u" y7 R& t6 X$ p- W1 }. P
3.5 CounterSource- CounterSource用于配置定时器计数器在每个内部事件或者外部事件后递增计数,可以选择内部或者外部
-
# T8 U- q+ k& b- q* w 3.6 Input1Source- Input1Source用于配置 Input1 的输入源,可以选择 GPIO,比较器输出或者 SAI FSA/FSB
-
8 p, K8 ^+ Y O# L4 `; |3 T 3.7 Input2ource- Input2ource用于配置 Input2 的输入源,可以选择 GPIO 和比较器(注意:此参数仅用于编码器模式)
-
: b0 L c& H* G 3 LPTIM 超时唤醒应用需求:使用LPTIM1,在低功耗stop模式下定时1s,1s后将STM32从stop模式唤醒,并且点亮LED灯 3.1 LPTIM1时钟初始化- 配置LPTIM1时钟为LSE,即外部低速时钟32768Hz,也可配置为内部低速时钟LSI,修改对应配置即可 {! D9 X/ e& _% {, p2 [
RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct = {0};3 z% F( [$ m$ F2 M
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
" e3 @% Y3 [' W& ]' WRCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;' \8 x* u0 _* r8 _+ T9 S# N
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
& C7 C3 `5 }7 |! g- x5 gRCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;6 }) [. b& {, Y' _1 p8 }
if (HAL_RCC_OscConfig(&RCC_OscInitStruct)!= HAL_OK)1 F; D3 G& z! @
{- f5 I4 Z( |" N
Error_Handler(__FILE__, __LINE__);
2 F& |* i) e% W9 l; b}
, D4 u" G8 _6 y+ _3 A* [0 O5 \RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
' _+ H) D- C: t6 y$ T5 ?+ k; p5 {RCC_PeriphCLKInitStruct.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSE;
3 [) f& m% N' n# Z1 ]: r0 mHAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct);- t3 {% J0 } ~6 P; z
3.2 LPTIM1初始化- 按上面概述的参数配置,对LPTIM1进行配置如下
1 D) ]# d% C& L4 J+ \7 R LPTIM_HandleTypeDef hlptim1;
, Q3 I* z, n8 Y2 E' f6 f/ H
3 c8 C: r& [" h# z h$ y$ Y' ^void MX_LPTIM1_Init(void)
7 s* ?, W, T1 x2 N7 @: v; W; A; t3 z{
1 G8 A: ?+ ?3 d( _1 s hlptim1.Instance = LPTIM1;
: t6 k; p: j7 I4 A. y9 ] hlptim1.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC; //选择内部时钟源0 [- l! A* R% k- D
hlptim1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV64; //设置LPTIM时钟分频2 f+ y. V3 F; U& p
hlptim1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE; //设置软件触发
* [0 c! b" K J( u K& {. x hlptim1.Init.Trigger.ActiveEdge = LPTIM_ACTIVEEDGE_RISING; //设置上升沿触发# q$ T" q9 v+ ^ l/ c/ `6 l* a8 |
hlptim1.Init.Trigger.SampleTime = LPTIM_TRIGSAMPLETIME_DIRECTTRANSITION; //设置时钟干扰滤波器
3 c# L, y5 p) }9 ~ {3 c hlptim1.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH; //设置输出高电平
5 G8 {" y: y0 t$ l( a hlptim1.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE; //比较寄存器和ARR自动重载寄存器选择更改后立即更新
. v) o8 L9 \: V hlptim1.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL; //LPTIM计数器对内部时钟源计数. _: L% `. Y, Q# `5 u V! ?% R9 B
hlptim1.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO; //外部输入1,本配置未使用, T2 x4 ?0 \0 O1 c+ F4 S! ]3 l9 j' J
hlptim1.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO; //外部输入2,本配置未使用
" {: Q& t+ L4 d0 R- A5 I if (HAL_LPTIM_Init(&hlptim1) != HAL_OK)
& ?- Z& z! v' w7 t) M* d0 b {
+ y2 y& U& P6 s: }: J+ _+ E while (1)3 l2 r4 }+ i: @5 F/ W+ d
{+ B# N! M, {$ A3 k
Error_Handler(__FILE__, __LINE__);8 H4 U+ m2 ?) m( O
}2 A* Y7 `8 y6 L& Y
}
T4 F& w6 k6 h5 h r( A2 `7 T6 z}
1 [; a9 M+ e% K1 ]% `% I$ Y- 当 HAL_LPTIM_Init()运行时会调用 HAL_LPTIM_MspInit()函数,这是一个虚函数,还需要我们重新定义,开启LPTIM时钟及 LPTIM1_IRQn 初始化: |" U7 F/ S+ c; a. k# ~2 u' @1 H4 D
void HAL_LPTIM_MspInit(LPTIM_HandleTypeDef* hlptim)
" Y: p( r: z# R* o) r* ?{! x- @' o* ], z6 ~5 `/ x% }% N4 l8 F
if(hlptim->Instance==LPTIM1)4 R$ ?/ u4 m! i& r
{. D. S3 b, T6 B) c# b9 A
/* Peripheral clock enable */* T7 g& j+ M' B9 Y! s
__HAL_RCC_LPTIM1_CLK_ENABLE();
( [; ~* E' @9 b! S
- `' Z, Q" V- {% J& G$ s /* Peripheral interrupt init */
0 ?' `, @( C) ` HAL_NVIC_SetPriority(LPTIM1_IRQn, 0, 0);" b1 o) |9 {! p7 o4 R2 C8 _
HAL_NVIC_EnableIRQ(LPTIM1_IRQn);9 d5 a6 z z: @7 U" h* w
}
+ Q6 r6 t+ p- ?" Z3 V+ [$ R}
2 C" O2 D9 I% c# r0 s) ^3.3 中断函数- 编写中断回调函数,当定时时间到,点亮LED灯
8 w) ~5 X+ R$ I void LPTIM1_IRQHandler(void) t- q( u* x) N
{4 ?4 p6 L+ e( x$ e% c% E
HAL_LPTIM_IRQHandler(&hlptim1);" ?4 |+ C" C8 O! b q8 Y* x
}
7 A4 c6 D) J% `6 m1 R- \& p
) |. w1 W9 Y" v& U& @8 z7 s& Dvoid HAL_LPTIM_CompareMatchCallback(LPTIM_HandleTypeDef *hlptim)
. T- J$ }" h, O{' {' h: G$ D9 K5 p: n1 H
/* Timeout was reached, turn on LED */
$ [1 z! c0 ^! R8 M m5 J BSP_LED_On();5 {+ @3 _+ `! `% X! a, P1 V1 L$ v
}
. e- V7 u- a$ E" M( \' N' ~& M3.4 开启定时器- 开启定时器及进入stop模式1 {, J w6 A3 I1 Z7 f
#define PERIOD 65535
# H, F& _; T7 r#define PULSE 32767 ) U0 s9 E4 ~( Z4 m, K6 B) t, a
HAL_LPTIM_TimeOut_Start_IT(&hlptim1, PERIOD, PULSE);
@8 w ~# R) h i" y& ]7 q' v# l" |6 [" ?4 h) }
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);5 z3 T- t. T$ n1 \* ]: K, N
- 第1个参数是 LPTIM_HandleTypeDef 类型结构体指针变量
- 第2个参数是低功耗定时器的周期配置,范围 0 – 0xFFFF。
- 第3个参数是低功耗定时器的超时时间配置,范围 0 -0xFFFF。
- 返回值,返回 HAL_ERROR 表示配置失败,HAL_OK 表示配置成功,HAL_BUSY 表示忙(操作中),HAL_TIMEOUT 表示时间溢出
- 超时时间由 Compare 寄存器决定,即第3个参数,超时配置用不到第2个参数
- 超时时间计算方式:timeout = (Compare + 1) / LSE_Frequency,如配置Compare = 32767,LSE = 32768Hz,则超时时间为1s5 S% t- }$ k$ |4 j' b
4 踩坑记录在使用官方例程的时候,不能触发定时中断,将触发源由 LPTIM_TRIGSOURCE_0 改为 LPTIM_TRIGSOURCE_SOFTWARE 移植官方例程时,未在 stm32l4xx_hal_conf.h 文件内打开LPTIM 外设的宏定义,导致一直报错
配置定时时间时候,未注意到参数范围是 0 -0xFFFF ,导致达不到自己想要的定时时间,最大可配置为65535,在Prescaler参数配置为 LPTIM_PRESCALER_DIV1 1分频的时候,超时时间最大为(65535+1)/32768 = 2s
3 Z% ~5 M& n; E % o8 t; V9 d' }3 _
|