完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980
第36章 STM32H7的LPTIM低功耗定时器基础知识和HAL库API
本章节为大家讲解LPTIM1 – LPTIM5共计5个定时器的基础知识和对应的HAL库API。
36.1 初学者重要提示
36.2 低功耗定时器基础知识
36.3 低功耗定时器的HAL库用户
36.4 源文件stm32h7xx_hal_lptim.c
36.5 总结
36.1 初学者重要提示
- 使用LPTIM的好处是系统处于睡眠、停机状态依然可以正常工作(除了待机模式)。停机状态可以正常工作的关键是LSE,LSI时钟不会被关闭,同时也可以选择使用外部时钟源。
- 重点学习本章的2.9小节,对于LPTIM的认识起到至关重要的作用。
36.2 低功耗定时器基础知识
下面将低功耗定时器应用中要用到的基础知识做个介绍。
36.2.1 定时器的硬件框图
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解定时器的基本功能,然后再看手册了解细节。
下面我们直接看最复杂的LPTIM1&LPTIM2框图:
通过这个框图,我们可以得到如下信息:
- lptim_pclk接口
主要用于LPTIM的寄存器提供时钟,寄存器操作需要高速时钟,不能像LPTIM的其它部分一样使用LSI,LSE等低速时钟。
- lptim_it接口
用于触发中断。
- lptim_ker_ck接口
内核时钟,供lptim使用。lptim_ker_tim接入到CLKMUX双路选择器的一个输入端,另一个输入端是LPTIM_IN1或者LPTIM_IN2的输入。也就是说LPTIM的计数器可以选择lptim_ker_ck,也可以选择LPTIM_IN1或者LPTIM_IN。
注意:CLKMUX双路选择器对应的是CFGR寄存器的bit0:CKSEL,用于控制内核时钟选择由内部时钟源(APB时钟或LSE、LSI和HSI等任何其他内置振荡器)提供时钟。也可以选择由外部时钟源通过 LPTIM 外部 Input提供时钟。
Count mode对应的是CFGR寄存器的bit23:COUNTMODE计数模式位,用于选择 LPTIM 使用哪个时钟源来为计数器提供时钟。可以选择计数器在每个内部时钟脉冲后递增,或者在 LPTIM 外部 Input上的每个有效时钟脉冲后递增。
- lptim_wkup
用于将系统从睡眠或者停机模式唤醒。
- lptim_out和LPTIM_OUT
lptim_out表示计数器输出,用于内部触发。
LPTIM_OUT表示GPIO的输出通道,用于PWM。
- LPTIM_ETR
通过GPIO为LPTIM提供外部触发。
- lptim_ext_trigx
LPTIM的计数器既可以通过软件启动,也可以通过外部触发启动,有8种触发方式可供选择,以LPTIM1为例,支持的触发如下:
- LPTIM_IN1,lptim_in1_mux1,lptim_in1_mux2和lptim_in1_mux3
LPTIM_IN2实际对应的是多路选择器的mux0,通过GPIO输入。
lptim_in1_mux1到lptim_in1_mux3对应的是内部输入,以LPTIM1为例,支持的输入信号如下:
- LPTIM_IN2,lptim_in2_mux1,lptim_in2_mux2和lptim_in2_mux3
LPTIM_IN2实际对应的是多路选择器的mux0,通过GPIO输入。
lptim_in2_mux1到lptim_in2_mux3对应的是内部输入,以LPTIM1为例,支持的输入信号如下:
- Glitch filter(干扰滤波器)
从框图中可以看到有三组Glitch filter,LPTIM_IN1和LPTIM_IN2接入多路选择器后各有一组,LPTIM_ETR接入后,也有一组。Glitch filter的作用是避免任何毛刺和噪声干扰在 LPTIM 内部传播,从而防止产生意外计数或触发。
注意:使用Glitch filter要向LPTIM 提供内部时钟源。
36.2.2 低功耗定时器的基本功能
LPTIM1 – LPTIM5都是16位的低功耗定时器(自动重载寄存器、比较寄存器和计数器都是16位的),相比TIM1 – TIM17这种通用定时器,在睡眠或者停机模式下依然可以工作(待机模式除外)。低功耗模式下要工作,就必然要支持低速时钟LSI、LSE或者外部输入时钟,这点是与通用定时器的本质区别。同时LPTIM的中断还可以唤醒停机模式,这点比较重要(休眠模式是任何中断都可以唤醒的,而停机模式可以LPTIM中断唤醒)。
以下几点是大家在使用中必须要了解到的:
1、 TIM1 – TIM17有专门的分频寄存器,而LPTIM1 – LPTIM5的分频是几种固定的值。
2、 低功耗定时器支持以下6种模式:
- PWM模式
- 单脉冲模式
- 单次模式
在此模式下,当满足匹配条件时,输出可以切换高低电平(如果输出极性配置为高,则为低电平至高电平变化,反之亦然)。
- 编码器模式
- 超时模式
有效的边沿触发输入可复位定时器。第一个触发事件将启动计时器,任何连续触发事件将重置计数器并重新开始。
- 计数器模式:
计数器可用于计算来自Input1的外部事件或用于计算内部时钟周期。
36.2.3 低功耗定时器时钟选择问题(重要)
这个知识点比较重要,可以帮助大家更好的理解LPTIM。下面先看框图:
首先将框图里面两个最重要的标识跟寄存器对上号。
1、lptim_ker_ck接口
内核时钟,供lptim使用。lptim_ker_tim接入到CLKMUX双路选择器的一个输入端,另一个输入端是LPTIM_IN1或者LPTIM_IN2的输入。也就是说LPTIM的计数器可以选择lptim_ker_ck,也可以选择LPTIM_IN1或者LPTIM_IN。
2、最关键的地方来了
(1) CLKMUX多路选择器对应的是CFGR寄存器的bit0:CKSEL
- 用于控制内核时钟选择由内部时钟源(APB时钟或LSE、LSI和HSI等任何其他内置振荡器)提供时钟。
- 也可以选择由外部时钟源通过 LPTIM 外部 Input提供时钟。
(2) Count mode对应的是CFGR寄存器的bit23:COUNTMODE计数模式位,用于选择 LPTIM 使用哪个时钟源来为计数器提供时钟。
- 可以选择计数器在每个内部时钟脉冲后递增。
- 或者在 LPTIM 外部 Input上的每个有效时钟脉冲后递增。
3、应用的时候,我们可以选择
(1) CKSEL = 0 , COUNTMODE = 0
表示LPTIM内核时钟使用的内部时钟源,计数器通过内部时钟脉计数。
(2) CKSEL = 0 , COUNTMODE = 1
表示LPTIM内核时钟使用的内部时钟源,计数器通过外部输入脉冲计数。
(3) CKSEL = 1 , COUNTMODE = x
表示LPTIM内核时钟使用的外部时钟源,计数器通过外部输入脉冲计数。
36.2.4 干扰滤波器(Glitch filter)
Glitch filter干扰滤波器的作用是避免任何毛刺和噪声干扰在 LPTIM 内部传播,从而防止产生意外计数或触发。
实现原理就是LPTIM的CFGR寄存器有专门的控制位TRGFLT[1:0](用于滤波外部触发信号)和CKFLT[1:0](用于滤波外部输入时钟)来控制信号,其有效电平变化必须至少稳定2/4/8个时钟周期才能将其视为有效触发。
比如下面的截图,配置为稳定2个时钟周期才算有效信号。
36.2.5 单次触发和连续模式
单次触发的含义就是定时器由触发事件启动,当达到 ARR 值时停止,效果如下:
连续模式的含义是定时器由触发事件启动,并且直到被禁止才会停止,效果如下:
36.2.6 溢出模式
注:这个模式用来做停机模式唤醒比较方便。
检测引脚第1次检查到触发信号,LPTIM就开始工作了,在溢出时间内检测到的触发信号都将复位计数,定时器重新开始工作。如果溢出内没有再接收到触发信号,仅进入溢出中断。
36.2.7 波形输出
通过下面的截图,可以让大家对低功耗定时器的波形输出效果有个全面认识。
LPTIM_ARR是自动重载寄存器,Compare是比较寄存器。当定时器的计数器达到Compare后,GPIO输出高电平还是低电平,是由CFGR寄存器的bit2:1:WAVPOL波形极性决定的。
以PWM输出为例:
- 如果WAVPOL = 0表示计数器的数值介于Compare和LPTIM_ARR之间时,GPIO输出高电平。其它时间是低电平。
- 如果WAVPOL = 1表示计数器的数值介于Compare和LPTIM_ARR之间时,GPIO输出低电平。其它时间是高电平。
One–Shot效果跟PWM一样,不过GPIO仅输出1次脉冲。
Set–Once特殊些,计数到ARR后,GPIO输出结果将一直保持达到Compare寄存器数值的输出电平。
36.2.8 低功耗定时器LPTIM1 – LPTIM5的区别
关于这五个低功耗定时器的区别,可以直接通过参考手册里面的框图看它们的区别。我们这里也简单整理下:
- LPTIM1和LPTIM2的功能是一样的,且支持编码器模式,而LPTIM3,LPTIM4和LPTIM5均不支持。
- LPTIM3跟LPTIM1的区别是仅有1组LPTIM_IN输入,且不支持LTPTIM_ETR。
- LPTIM4和LPTIM5的功能是一样的,这两个功能最弱。跟LPTIM1的区别是没有LPTIM_IN输入端,也不支持LPTIM_ETR,仅有一个内部触发lptim_ext_trigx。
36.3 低功耗定时器的HAL库用法
低功耗定时器的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置GPIO、时钟,并根据需要配置NVIC,中断和DMA。下面我们逐一展开为大家做个说明。
36.3.1 定时器寄存器结构体LPTIM_TypeDef
低功耗定时器相关的寄存器是通过HAL库中的结构体LPTIM_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
typedef struct { __IO uint32_t ISR; /*!< LPTIM Interrupt and Status register, Address offset: 0x00 */ __IO uint32_t ICR; /*!< LPTIM Interrupt Clear register, Address offset: 0x04 */ __IO uint32_t IER; /*!< LPTIM Interrupt Enable register, Address offset: 0x08 */ __IO uint32_t CFGR; /*!< LPTIM Configuration register, Address offset: 0x0C */ __IO uint32_t CR; /*!< LPTIM Control register, Address offset: 0x10 */ __IO uint32_t CMP; /*!< LPTIM Compare register, Address offset: 0x14 */ __IO uint32_t ARR; /*!< LPTIM Autoreload register, Address offset: 0x18 */ __IO uint32_t CNT; /*!< LPTIM Counter register, Address offset: 0x1C */ uint16_t RESERVED1; /*!< Reserved, 0x20 */ __IO uint32_t CFGR2; /*!< LPTIM Option register, Address offset: 0x24 */ } LPTIM_TypeDef;
这个结构体的成员名称和排列次序和CPU的定时器寄存器是一 一对应的。
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
#define __O volatile /*!< Defines 'write only' permissions */ #define __IO volatile /*!< Defines 'read / write' permissions */
下面我们看下LPTIM1,LPTIM2,LPTIM3,LPTIM4和LPTIM5的定义,在stm32h743xx.h文件。
#define PERIPH_BASE ((uint32_t)0x40000000) #define D2_APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) #define D3_APB1PERIPH_BASE (PERIPH_BASE + 0x18000000) #define LPTIM1_BASE (D2_APB1PERIPH_BASE + 0x2400) #define LPTIM2_BASE (D3_APB1PERIPH_BASE + 0x2400) #define LPTIM3_BASE (D3_APB1PERIPH_BASE + 0x2800) #define LPTIM4_BASE (D3_APB1PERIPH_BASE + 0x2C00) #define LPTIM5_BASE (D3_APB1PERIPH_BASE + 0x3000) #define LPTIM1 ((LPTIM_TypeDef *) LPTIM1_BASE) <----- 展开这个宏,(TIM_TypeDef *) 0x40012400 #define LPTIM2 ((LPTIM_TypeDef *) LPTIM2_BASE) #define LPTIM3 ((LPTIM_TypeDef *) LPTIM3_BASE) #define LPTIM4 ((LPTIM_TypeDef *) LPTIM4_BASE) #define LPTIM5 ((LPTIM_TypeDef *) LPTIM5_BASE)
我们访问LPTIM的ISR寄存器可以采用这种形式:LPTIM->ISR = 0。
36.3.2 定时器句柄结构体LPTIM_HandleTypeDef
HAL库在LPTIM_TypeDef的基础上封装了一个结构体LPTIM_HandleTypeDef,定义如下:
typedef struct { LPTIM_TypeDef *Instance; /*!< Register base address */ LPTIM_InitTypeDef Init; /*!< LPTIM required parameters */ HAL_StatusTypeDef Status; /*!< LPTIM peripheral status */ HAL_LockTypeDef Lock; /*!< LPTIM locking object */ __IO HAL_LPTIM_StateTypeDef State; /*!< LPTIM peripheral state */ }LPTIM_HandleTypeDef;
这里重点介绍前两个参数,其它参数主要是HAL库内部使用的。
TIM_TypeDef *Instance
这个参数是寄存器的例化,方便操作寄存器,比如使能定时器的计数器。
SET_BIT(huart->Instance->CR, LPTIM_CR_CNTSTRT)。
LPTIM_InitTypeDef Init
这个参数是用户接触最多的,用于配置低功耗定时器的基本参数。
LPTIM_InitTypeDef结构体的定义如下:
typedef struct { LPTIM_ClockConfigTypeDef Clock; LPTIM_ULPClockConfigTypeDef UltraLowPowerClock; LPTIM_TriggerConfigTypeDef Trigger; uint32_t OutputPolarity; uint32_t UpdateMode; uint32_t CounterSource; uint32_t Input1Source; uint32_t Input2Source; }LPTIM_InitTypeDef;
- 成员Clock
用于设置时钟源和时钟分频,结构体变量LPTIM_ClockConfigTypeDef的定义如下。
typedef struct { uint32_t Source; uint32_t Prescaler; }LPTIM_ClockConfigTypeDef;
时钟源参数Source可以选择如下两种。
(1)#define LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC ((uint32_t)0x00U)
表示LPTIM 由内部时钟源(APB 时钟或APB 或 LSE、LSI和HSI等)提供时钟。
(2)#define LPTIM_CLOCKSOURCE_ULPTIM LPTIM_CFGR_CKSEL
表示LPTIM 由外部时钟源通过 LPTIM 外部 Input1 提供时钟。
分配参数Prescaler可以选择如下八种。
#define LPTIM_PRESCALER_DIV1 ((uint32_t)0x000000U) #define LPTIM_PRESCALER_DIV2 LPTIM_CFGR_PRESC_0 #define LPTIM_PRESCALER_DIV4 LPTIM_CFGR_PRESC_1 #define LPTIM_PRESCALER_DIV8 ((uint32_t)(LPTIM_CFGR_PRESC_0 | LPTIM_CFGR_PRESC_1)) #define LPTIM_PRESCALER_DIV16 LPTIM_CFGR_PRESC_2 #define LPTIM_PRESCALER_DIV32 ((uint32_t)(LPTIM_CFGR_PRESC_0 | LPTIM_CFGR_PRESC_2)) #define LPTIM_PRESCALER_DIV64 ((uint32_t)(LPTIM_CFGR_PRESC_1 | LPTIM_CFGR_PRESC_2)) #define LPTIM_PRESCALER_DIV128 ((uint32_t)LPTIM_CFGR_PRESC)
- 成员UltraLowPowerClock
此参数仅在使用超低功耗时钟源时使用,用于设置所选择的外部时钟,结构体变量LPTIM_ULPClockConfigTypeDef定义如下:
typedef struct { uint32_t Polarity; uint32_t SampleTime; }LPTIM_ULPClockConfigTypeDef;
时钟极性参数Polarity用于选择有效的时钟极性,如果使能了双边沿,Auxiliary Clock(一种低功耗振荡器)必须处于激活状态。
采样时间参数SampleTime用于配置时钟干扰滤波器。可以配置的参数如下:
#define LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION ((uint32_t)0x00000000U) #define LPTIM_CLOCKSAMPLETIME_2TRANSITIONS LPTIM_CFGR_CKFLT_0 #define LPTIM_CLOCKSAMPLETIME_4TRANSITIONS LPTIM_CFGR_CKFLT_1 #define LPTIM_CLOCKSAMPLETIME_8TRANSITIONS LPTIM_CFGR_CKFLT
- 成员Trigger
用于配置触发参数,结构体变量LPTIM_TriggerConfigTypeDef的定义如下:
typedef struct { uint32_t Source; uint32_t ActiveEdge; uint32_t SampleTime; }LPTIM_TriggerConfigTypeDef;
触发源参数Source支持的选择如下:
#define LPTIM_TRIGSOURCE_SOFTWARE ((uint32_t)0x0000FFFFU) #define LPTIM_TRIGSOURCE_0 ((uint32_t)0x00000000U) #define LPTIM_TRIGSOURCE_1 ((uint32_t)LPTIM_CFGR_TRIGSEL_0) #define LPTIM_TRIGSOURCE_2 LPTIM_CFGR_TRIGSEL_1 #define LPTIM_TRIGSOURCE_3 ((uint32_t)LPTIM_CFGR_TRIGSEL_0 | LPTIM_CFGR_TRIGSEL_1) #define LPTIM_TRIGSOURCE_4 LPTIM_CFGR_TRIGSEL_2 #define LPTIM_TRIGSOURCE_5 ((uint32_t)LPTIM_CFGR_TRIGSEL_0 | LPTIM_CFGR_TRIGSEL_2) #define LPTIM_TRIGSOURCE_6 ((uint32_t)LPTIM_CFGR_TRIGSEL_1 | LPTIM_CFGR_TRIGSEL_2) #define LPTIM_TRIGSOURCE_7 LPTIM_CFGR_TRIGSEL
参数ActiveEdge用于设置有效的触发边沿,可以选择上升沿,下降沿或者双边沿触发。
#define LPTIM_ACTIVEEDGE_RISING LPTIM_CFGR_TRIGEN_0 #define LPTIM_ACTIVEEDGE_FALLING LPTIM_CFGR_TRIGEN_1 #define LPTIM_ACTIVEEDGE_RISING_FALLING LPTIM_CFGR_TRIGEN
- 成员OutputPolarity
用于配置输出极性,可选择高电平或者低电平输出:
#define LPTIM_OUTPUTPOLARITY_HIGH ((uint32_t)0x00000000U) #define LPTIM_OUTPUTPOLARITY_LOW (LPTIM_CFGR_WAVPOL)
- 成员UpdateMode
用于配置是否立即更新自动重装寄存器和比较寄存器,可以选择立即更新,或者当前周期结束后更新。
#define LPTIM_UPDATE_IMMEDIATE ((uint32_t)0x00000000U) #define LPTIM_UPDATE_ENDOFPERIOD LPTIM_CFGR_PRELOAD
- 成员CounterSource
用于配置定时器计数器在每个内部事件或者外部事件后递增计数。可以选择内部或者外部。
#define LPTIM_COUNTERSOURCE_INTERNAL ((uint32_t)0x00000000U) #define LPTIM_COUNTERSOURCE_EXTERNAL LPTIM_CFGR_COUNTMODE
- 成员Input1Source
用于配置Input1的输入源,可以选择GPIO,比较器输出或者SAI FSA/FSB。
#define LPTIM_INPUT1SOURCE_GPIO ((uint32_t)0x00000000U) /*!< For LPTIM1, LPTIM2 and LPTIM3 */ #define LPTIM_INPUT1SOURCE_COMP1 LPTIM_CFGR2_IN1_SEL0 /*!< For LPTIM1 and LPTIM2 */ #define LPTIM_INPUT1SOURCE_COMP2 LPTIM_CFGR2_IN1_SEL1 /*!< For LPTIM2 and LPTIM2 */ #define LPTIM_INPUT1SOURCE_COMP1_COMP2 (LPTIM_CFGR2_IN1_SEL0|LPTIM_CFGR2_IN1_SEL1) /*!< For LPTIM2 */ #define LPTIM_INPUT1SOURCE_SAI1_FSA LPTIM_CFGR2_IN1_SEL0 /*!< For LPTIM3 */ #define LPTIM_INPUT1SOURCE_SAI1_FSB LPTIM_CFGR2_IN1_SEL1 /*!< For LPTIM3 */
- 成员Input2ource
用于配置Input2的输入源,可以选择GPIO和比较器。
注意,此参数仅用于编码器模式,也就是说仅支持LPTIM1和LPTIM2的例化。
#define LPTIM_INPUT2SOURCE_GPIO ((uint32_t)0x00000000U) /*!< For LPTIM1 and LPTIM2 */ #define LPTIM_INPUT2SOURCE_COMP2 LPTIM_CFGR2_IN2_SEL0 /*!< For LPTIM1 and LPTIM2 */
下面是LPTIM1的配置例子:
LPTIM_HandleTypeDef LptimHandle = {0}; LptimHandle.Instance = LPTIM1; /* 对应寄存器CKSEL,选择内部时钟源 */ LptimHandle.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC; LptimHandle.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1; /* 设置LPTIM时钟分频 */ LptimHandle.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;/* LPTIM计数器对内部时钟源计数 */ LptimHandle.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE; /* 软件触发 */ /* 计数器计数到比较寄存器和ARR自动重载寄存器之间数值,输出高电平 */ LptimHandle.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH; /* 比较寄存器和ARR自动重载寄存器选择更改后立即更新 */ LptimHandle.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE; LptimHandle.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO; LptimHandle.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO; if (HAL_LPTIM_Init(&LptimHandle) != HAL_OK) { Error_Handler(__FILE__, __LINE__); }
36.3.3 定时器的底层配置(GPIO、时钟、中断等)
HAL库有个自己的底层初始化回调函数,比如调用函数HAL_LPTIM_Init就会调用HAL_LPTIM_MspInit,此函数是弱定义的。
__weak void HAL_LPTIM_MspInit(LPTIM_HandleTypeDef *hlptim) { /* Prevent unused argument(s) compilation warning */ UNUSED(hlptim); /* NOTE : This function Should not be modified, when the callback is needed, the HAL_LPTIM_MspInit could be implemented in the user file */ }
用户可以在其它的C文件重定向,并将相对的底层初始化在里面实现。对应的底层复位函数HAL_LPTIM_MspDeInit是在函数 HAL_LPTIM_DeInit里面被调用的,也是弱定义的。
当然,用户也可以自己初始化,不限制必须在两个函数里面实现。
定时器外设的基本参数配置完毕后还不能使用,还需要配置GPIO、时钟、中断等参数,比如下面配置LPTIM1使用PD13做PWM输出。
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef GPIO_InitStruct; /* 使能LPTIM时钟 */ __HAL_RCC_LPTIM1_CLK_ENABLE(); /* 使能GPIO时钟 Enable GPIO PORT */ __HAL_RCC_GPIOD_CLK_ENABLE(); /* 配置PD13 */ GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; GPIO_InitStruct.Alternate = GPIO_AF1_LPTIM1; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); }
总结下来就是以下几点:
- 配置LPTIM时钟。
- 配置LPTIM所用到引脚和对应的GPIO时钟。
- 如果用到定时器中断,还需要通过NVIC配置中断。
关于这个底层配置有以下几点要着重说明下:
- 定时器所使用引脚的复用模式选择已经被HAL库定义好,放在了stm32h7xx_hal_gpio_ex.h文件里面。比如TIM1有一个复用,
#define GPIO_AF1_LPTIM1 ((uint8_t)0x01) /* LPTIM1 Alternate Function mapping */
但是却有4个输出通道,每个通道都有几个支持的输出引脚:
LPTIM1_OUT PG13
LPTIM1_OUT PD13
具体使用哪个,配置对应引脚的复用即可:
36.3.4 定时器的状态标志清除问题
下面我们介绍__HAL_LPTIM_GET_FLAG函数。这个函数用来检查定时器标志位是否被设置。
/** * @brief Check whether the specified LPTIM flag is set or not. * @param __HANDLE__: LPTIM handle * @param __FLAG__ : LPTIM flag to check * This parameter can be a value of: * @arg LPTIM_FLAG_DOWN : Counter direction change up Flag. * @arg LPTIM_FLAG_UP : Counter direction change down to up Flag. * @arg LPTIM_FLAG_ARROK : Autoreload register update OK Flag. * @arg LPTIM_FLAG_CMPOK : Compare register update OK Flag. * @arg LPTIM_FLAG_EXTTRIG : External trigger edge event Flag. * @arg LPTIM_FLAG_ARRM : Autoreload match Flag. * @arg LPTIM_FLAG_CMPM : Compare match Flag. * @retval The state of the specified flag (SET or RESET). */ #define __HAL_LPTIM_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->ISR &(__FLAG__)) == (__FLAG__))
当前做的应用程序,这几个中断标志暂时都还没有被用到。
与标志获取函数__HAL_TIM_GET_FLAG对应的清除函数是__HAL_LPTIM_CLEAR_FLAG:
/** * @brief Clear the specified LPTIM flag. * @param __HANDLE__: LPTIM handle. * @param __FLAG__ : LPTIM flag to clear. * This parameter can be a value of: * @arg LPTIM_FLAG_DOWN : Counter direction change up Flag. * @arg LPTIM_FLAG_UP : Counter direction change down to up Flag. * @arg LPTIM_FLAG_ARROK : Autoreload register update OK Flag. * @arg LPTIM_FLAG_CMPOK : Compare register update OK Flag. * @arg LPTIM_FLAG_EXTTRIG : External trigger edge event Flag. * @arg LPTIM_FLAG_ARRM : Autoreload match Flag. * @arg LPTIM_FLAG_CMPM : Compare match Flag. * @retval None. */ #define __HAL_LPTIM_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->ICR = (__FLAG__))
清除标志函数所支持的参数跟获取函数是一 一对应的。除了这两个函数,还是定时器的中断开启和中断关闭函数,有时候也要用到。
/** * @brief Enable the specified LPTIM interrupt. * @param __HANDLE__ : LPTIM handle. * @param __INTERRUPT__ : LPTIM interrupt to set. * This parameter can be a value of: * @arg LPTIM_IT_DOWN : Counter direction change up Interrupt. * @arg LPTIM_IT_UP : Counter direction change down to up Interrupt. * @arg LPTIM_IT_ARROK : Autoreload register update OK Interrupt. * @arg LPTIM_IT_CMPOK : Compare register update OK Interrupt. * @arg LPTIM_IT_EXTTRIG : External trigger edge event Interrupt. * @arg LPTIM_IT_ARRM : Autoreload match Interrupt. * @arg LPTIM_IT_CMPM : Compare match Interrupt. * @retval None. */ #define __HAL_LPTIM_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->IER |= (__INTERRUPT__)) /** * @brief Disable the specified LPTIM interrupt. * @param __HANDLE__ : LPTIM handle. * @param __INTERRUPT__ : LPTIM interrupt to set. * This parameter can be a value of: * @arg LPTIM_IT_DOWN : Counter direction change up Interrupt. * @arg LPTIM_IT_UP : Counter direction change down to up Interrupt. * @arg LPTIM_IT_ARROK : Autoreload register update OK Interrupt. * @arg LPTIM_IT_CMPOK : Compare register update OK Interrupt. * @arg LPTIM_IT_EXTTRIG : External trigger edge event Interrupt. * @arg LPTIM_IT_ARRM : Autoreload match Interrupt. * @arg LPTIM_IT_CMPM : Compare match Interrupt. * @retval None. */ #define __HAL_LPTIM_DISABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->IER &= (~(__INTERRUPT__)))
注意:操作定时器的寄存器不限制必须要用HAL库提供的API,比如要操作寄存器CR,直接调用LPTIM1->CR操作即可。
36.3.5 定时器初始化流程总结
使用方法由HAL库提供:
第1步:通过函数HAL_LPTIM_Init()做初始化,主要配置的内容如下:
- 支持LPTIM1 – LPTIM5
- Clock计数时钟
(1) Source,可以选择ULPTIM input (IN1)时钟输入,或者内部时钟,如APB, LSE, LSI ,MSI等。
(2) Prescaler,设置分频。
- UltraLowPowerClock 超低功耗时钟
只有在Clock计数时钟源选择了ULPTIM input,此参数才有意义。
(1) Polarity,计数单元有效的边沿极性。
(2) SampleTime,配置时钟干扰滤波器的时钟。
- Trigger计数器的触发
(1) Source,可以选择硬件触发或者软件触发。
(2) ActiveEdge,仅用于硬件触发,用来设置触发边沿(上升沿、下降沿或者双沿)。
(3) SampleTime,采样时间,用于配置触发干扰滤波器的时钟。
- OutputPolarity输出极性配置。
UpdateMode更新模式,用于配置是否立即更新自动重装寄存器和比较寄存器,可以选择立即更新,或者当前周期结束后更新。
- Input1Source用于配置Input1的输入源,可以选择GPIO,比较器输出或者SAI FSA/FSB。
- Input2Source用于配置Input2的输入源,可以选择GPIO和比较器。
注意,此参数仅用于编码器模式,也就是说仅支持LPTIM1和LPTIM2的例化。
第2步:低功耗定时器的底层配置是通过函数HAL_LPTIM_MspInit()实现:
- 使用函数__HAL_RCC_LPTIMx_CLK_ENABLE()使能定时器时钟。
- 使用函数__HAL_RCC_GPIOx_CLK_ENABLE使能GPIO时钟。
- 使用函数HAL_GPIO_Init配置GPIO。
- 如果调用函数HAL_LPTIM_PWM_Start_IT()使能了中断,需要调用HAL_NVIC_SetPriority()设置中断优先级,调用函数HAL_NVIC_EnableIRQ()使能中断,在中断服务程序里面调用 HAL_LPTIM_IRQHandler。
第3步:低功耗定时器支持的6种工作模式:
- PWM模式
启动此模式可调用HAL_LPTIM_PWM_Start()或 HAL_LPTIM_PWM_Start_IT()用于中断方式。
- 单脉冲模式
启动此模式可调用HAL_LPTIM_OnePulse_Start()或HAL_LPTIM_OnePulse_Start_IT()用于中断方式。
- 单次模式
在此模式下,当满足匹配条件时,输出可以切换高低电平(如果输出极性配置为高,则从低电平切至高电平,反之亦然)。启动此模式可调用HAL_LPTIM_SetOnce_Start()或 HAL_LPTIM_SetOnce_Start_IT()用于中断方式。
- 编码器模式
启动此模式可调用HAL_LPTIM_Encoder_Start()或HAL_LPTIM_Encoder_Start_IT()用于中断方式。
- 超时模式
有效的边沿触发输入可复位定时器。第一个触发事件将启动计时器,任何连续触发事件将重置计数器并重新开始。启动此模式可调用HAL_LPTIM_TimeOut_Start()或 HAL_LPTIM_TimeOut_Start_IT()用于中断方式。
- 计数器模式
计数器可用于计算来自Input1的外部事件或用于计算内部时钟周期。启动此模式可调用HAL_LPTIM_Counter_Start()或 HAL_LPTIM_Counter_Start_IT()用于中断方式。
第4步:停止任何模式:
用户可以通过调用相应的API来停止任何模式: HAL_LPTIM_Xxx_Stop 或 HAL_LPTIM_Xxx_Stop_IT(如果此模式已经在中断方式下启动)。
低功耗定时器常用的功能,通过上面这几步即可实现。
36.4 源文件stm32h7xx_hal_lptim.c
此文件涉及到的函数比较多,这里把我们几个常用的函数做个说明:
- HAL_LPTIM_Init
- HAL_LPTIM_PWM_Start
- HAL_LPTIM_TimeOut_Start_IT
- HAL_LPTIM_TimeOut_Stop_IT
36.4.1 函数HAL_LPTIM_Init
函数原型:
HAL_StatusTypeDef HAL_LPTIM_Init(LPTIM_HandleTypeDef *hlptim) { uint32_t tmpcfgr = 0; /* 检测是否是有效句柄 */ if(hlptim == NULL) { return HAL_ERROR; } /* 省略 */ if(hlptim->State == HAL_LPTIM_STATE_RESET) { /* 默认取消锁 */ hlptim->Lock = HAL_UNLOCKED; /* 初始化底层硬件 : GPIO, CLOCK, NVIC */ HAL_LPTIM_MspInit(hlptim); } /* 更改LPTIM状态 */ hlptim->State = HAL_LPTIM_STATE_BUSY; /* 获取LPTIMx CFGR数值 */ tmpcfgr = hlptim->Instance->CFGR; if ((hlptim->Init.Clock.Source) == LPTIM_CLOCKSOURCE_ULPTIM) { tmpcfgr &= (uint32_t)(~(LPTIM_CFGR_CKPOL | LPTIM_CFGR_CKFLT)); } if ((hlptim->Init.Trigger.Source) != LPTIM_TRIGSOURCE_SOFTWARE) { tmpcfgr &= (uint32_t)(~ (LPTIM_CFGR_TRGFLT | LPTIM_CFGR_TRIGSEL)); } /* 清除 CKSEL, PRESC, TRIGEN, TRGFLT, WAVPOL, PRELOAD & COUNTMODE 位 */ tmpcfgr &= (uint32_t)(~(LPTIM_CFGR_CKSEL | LPTIM_CFGR_TRIGEN | LPTIM_CFGR_PRELOAD | LPTIM_CFGR_WAVPOL | LPTIM_CFGR_PRESC | LPTIM_CFGR_COUNTMODE )); /* 设置初始化参数 */ tmpcfgr |= (hlptim->Init.Clock.Source | hlptim->Init.Clock.Prescaler | hlptim->Init.OutputPolarity | hlptim->Init.UpdateMode | hlptim->Init.CounterSource); if ((hlptim->Init.Clock.Source) == LPTIM_CLOCKSOURCE_ULPTIM) { tmpcfgr |= (hlptim->Init.UltraLowPowerClock.Polarity | hlptim->Init.UltraLowPowerClock.SampleTime); } if ((hlptim->Init.Trigger.Source) != LPTIM_TRIGSOURCE_SOFTWARE) { /* Enable External trigger and set the trigger source */ tmpcfgr |= (hlptim->Init.Trigger.Source | hlptim->Init.Trigger.ActiveEdge | hlptim->Init.Trigger.SampleTime); } /* 写入到配置寄存器 LPTIMx CFGR */ hlptim->Instance->CFGR = tmpcfgr; /* 配置LPTIM input 时钟源 */ if((hlptim->Instance == LPTIM1) || (hlptim->Instance == LPTIM2)) { assert_param(IS_LPTIM_INPUT1_SOURCE(hlptim->Instance,hlptim->Init.Input1Source)); assert_param(IS_LPTIM_INPUT2_SOURCE(hlptim->Instance,hlptim->Init.Input2Source)); /* 配置 LPTIM1/2 Input1 和 Input2 的时钟源 */ hlptim->Instance->CFGR2 = (hlptim->Init.Input1Source | hlptim->Init.Input2Source); } else { if(hlptim->Instance == LPTIM3) { assert_param(IS_LPTIM_INPUT1_SOURCE(hlptim->Instance,hlptim->Init.Input1Source)); /* 注,H7库V1.3.0版本这里是个bug,LPTIM3应该配置CFGR3寄存器 */ hlptim->Instance->CFGR2 = hlptim->Init.Input1Source; } } /* 更改LPTIM状态 */ hlptim->State = HAL_LPTIM_STATE_READY; /* 返回HAL_OK */ return HAL_OK; }
函数描述:
此函数用于初始化低功耗定时器的基本参数。
函数参数:
- 第1个参数是LPTIM_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。结构体变量成员的详细介绍看本章3.2小节。
- 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
注意事项:
- 函数HAL_LPTIM_MspInit用于初始化定时器的底层时钟、引脚等功能,需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
- 如果形参hlptim的结构体成员gState没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量LPTIM_HandleTypeDef LptimHandle。
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个HAL_LPTIM_STATE_RESET = 0x00U。
解决办法有四
方法1:用户自己初始定时器和涉及到的GPIO等。
方法2:定义LPTIM_HandleTypeDef LptimHandle为全局变量。
方法3:定义为局部变量要赋初始值LPTIM_HandleTypeDef LptimHandle = {0}。
方法4:下面的方法
if(HAL_LPTIM_DeInit(&LptimHandle)!= HAL_OK) { Error_Handler(); } if(HAL_LPTIM_Init(&LptimHandle)!= HAL_OK) { Error_Handler(); }
使用举例:
LPTIM_HandleTypeDef LptimHandle = {0}; LptimHandle.Instance = LPTIM1; /* 对应寄存器CKSEL,选择内部时钟源 */ LptimHandle.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC; LptimHandle.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1; /* 设置LPTIM时钟分频 */ LptimHandle.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;/* LPTIM计数器对内部时钟源计数 */ LptimHandle.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE; /* 软件触发 */ /* 计数器计数到比较寄存器和ARR自动重载寄存器之间数值,输出高电平 */ LptimHandle.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH; /* 比较寄存器和ARR自动重载寄存器选择更改后立即更新 */ LptimHandle.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE; LptimHandle.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO; LptimHandle.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO; if (HAL_LPTIM_Init(&LptimHandle) != HAL_OK) { Error_Handler(__FILE__, __LINE__); }
36.4.2 函数HAL_LPTIM_PWM_Start
函数原型:
HAL_StatusTypeDef HAL_LPTIM_PWM_Start(LPTIM_HandleTypeDef *hlptim, uint32_t Period, uint32_t Pulse) { /* 检查参数 */ assert_param(IS_LPTIM_INSTANCE(hlptim->Instance)); assert_param(IS_LPTIM_PERIOD(Period)); assert_param(IS_LPTIM_PULSE(Pulse)); /* 设置LPTIM的状态 */ hlptim->State= HAL_LPTIM_STATE_BUSY; /* 复位PWM模式的WAVE位 */ hlptim->Instance->CFGR &= ~LPTIM_CFGR_WAVE; /* 使能LPTIM */ __HAL_LPTIM_ENABLE(hlptim); /* 设置自动重载寄存器ARR数值 */ __HAL_LPTIM_AUTORELOAD_SET(hlptim, Period); /* 设置比较寄存器数值,用于PWM占空比配置 */ __HAL_LPTIM_COMPARE_SET(hlptim, Pulse); /* 定时器以连续模式运行 */ __HAL_LPTIM_START_CONTINUOUS(hlptim); /* 更改定时器状态 */ hlptim->State= HAL_LPTIM_STATE_READY; /* 返回HAL_OK */ return HAL_OK; }
函数描述:
调用函数HAL_LPTIM_Init配置了基础功能后,就可以调用此函数启动定时器PWM输出了。
函数参数:
- 第1个参数是LPTIM_HandleTypeDef类型结构体指针变量。
- 第2个参数是低功耗定时器的周期配置,范围0 – 0xFFFF。
- 第3个参数是低功耗定时器PWM的脉宽配置,范围0 -0xFFFF。
- 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
注意事项:
- 这里重点说下配置了第2个参数后,低功耗定时器的PWM输出频率是多少。比如LPTIM使用的是LSE时钟,频率32768Hz,第2个参数Period = 9。那么
PWM频率 = LSE / (Period + 1) = 32768 / (9 + 1) = 327Hz。
当第3个参数Pluse = 5
PWM占空比 = 1 – (Pluse + 1)/(Period + 1) = 1 – 5/10 = 50%
使用举例:
LptimHandle.Instance = LPTIM1; /* 对应寄存器CKSEL,选择内部时钟源 */ LptimHandle.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC; LptimHandle.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1; /* 设置LPTIM时钟分频 */ LptimHandle.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;/* LPTIM计数器对内部时钟源计数 */ LptimHandle.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE; /* 软件触发 */ /* 计数器计数到比较寄存器和ARR自动重载寄存器之间数值,输出高电平 */ LptimHandle.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH; /* 比较寄存器和ARR自动重载寄存器选择更改后立即更新 */ LptimHandle.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE; LptimHandle.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO; LptimHandle.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO; if (HAL_LPTIM_Init(&LptimHandle) != HAL_OK) { Error_Handler(__FILE__, __LINE__); } /* ARR是自动重装寄存器,对应函数HAL_LPTIM_PWM_Start的第2个参数 Compare是比较寄存器,对应函数HAL_LPTIM_PWM_Start的第3个参数 --------------------- LSE = 32768Hz 分频设置为LPTIM_PRESCALER_DIV1,即未分频 ARR自动重载寄存器 = 31 那么PWM频率 = LSE / (ARR + 1) = 32768Hz / (31 + 1) = 1024Hz 占空比 = 1 - (Comprare + 1)/ (ARR + 1) = 1 - (15 + 1)/(31 + 1) = 50% 占空比这里为什么要1减操作,而不是直接的(Comprare + 1)/ (ARR + 1),这是因为前面的配置中 计数器计数到比较寄存器和ARR自动重载寄存器之间数值,输出高电平。 */ if (HAL_LPTIM_PWM_Start(&LptimHandle, 31, 15) != HAL_OK) { Error_Handler(__FILE__, __LINE__); }
36.4.3 函数HAL_LPTIM_TimeOut_Start_IT
函数原型:
HAL_StatusTypeDef HAL_LPTIM_TimeOut_Start_IT(LPTIM_HandleTypeDef *hlptim, uint32_t Period, uint32_t Timeout) { /* 检查参数 */ assert_param(IS_LPTIM_INSTANCE(hlptim->Instance)); assert_param(IS_LPTIM_PERIOD(Period)); assert_param(IS_LPTIM_PULSE(Timeout)); /* 设置LPTIM的状态 */ hlptim->State= HAL_LPTIM_STATE_BUSY; /* 使能超时位TIMOUT */ hlptim->Instance->CFGR |= LPTIM_CFGR_TIMOUT; /* 使能比匹配中断 */ __HAL_LPTIM_ENABLE_IT(hlptim, LPTIM_IT_CMPM); /* 使能低功耗定时器 */ __HAL_LPTIM_ENABLE(hlptim); /* 设置自动重载寄存器ARR的数值 */ __HAL_LPTIM_AUTORELOAD_SET(hlptim, Period); /* 设置比较寄存器数值 */ __HAL_LPTIM_COMPARE_SET(hlptim, Timeout); /* 低功耗定时器以连续模式运行 */ __HAL_LPTIM_START_CONTINUOUS(hlptim); /* 设置定时器的状态 */ hlptim->State= HAL_LPTIM_STATE_READY; /* 返回HAL_OK */ return HAL_OK; }
函数描述:
调用函数HAL_LPTIM_Init配置了基础功能后,就可以调用此函数启动定时器的超时功能。
函数参数:
- 第1个参数是LPTIM_HandleTypeDef类型结构体指针变量。
- 第2个参数是低功耗定时器的周期配置,范围0 – 0xFFFF。
- 第3个参数是低功耗定时器的超时时间配置,范围0 -0xFFFF。
- 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
注意事项:
- 超时配置用不到第2个参数。
- 此函数开启的是比较匹配中断,所以实际的超时时间由Compare寄存器决定,即第3个参数。
使用举例:
/* ********************************************************************************************************* * 函 数 名: bsp_StartLPTIM * 功能说明: 启动LPTIM * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void bsp_StartLPTIM(void) { /* ARR是自动重装寄存器,对应函数HAL_LPTIM_TimeOut_Start_IT的第2个参数 Compare是比较寄存器,对应函数HAL_LPTIM_TimeOut_Start_IT的第3个参数 --------------------- LSE = 32768Hz 分频设置为LPTIM_PRESCALER_DIV8,即8分频(函数bsp_InitLPTIM里面做的初始化配置) ARR自动重载寄存器 = 32768 实际测试发现溢出中断与ARR寄存器无关,全部由第3个参数,Compare寄存器决定 LPTIM的计数器计数1次的时间是 1 / (32768 / 8) = 8 /32768。 第三个参数配置的是32767,那么计数到32767就是 (32767 + 1)*(8 /32768) = 8秒,计算的时候要加1。 */ if (HAL_LPTIM_TimeOut_Start_IT(&LptimHandle, 0, 32767) != HAL_OK) { Error_Handler(__FILE__, __LINE__); } } /* ********************************************************************************************************* * 函 数 名: LPTIM1_IRQHandler * 功能说明: LPTIM1中断服务程序 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void LPTIM1_IRQHandler(void) { if((LPTIM1->ISR & LPTIM_FLAG_CMPM) != RESET) { /* 清除比较匹配中断 */ LPTIM1->ICR = LPTIM_FLAG_CMPM; /* 关闭溢出中断 */ HAL_LPTIM_TimeOut_Stop_IT(&LptimHandle); bsp_LedToggle(4); } }
36.4.4 函数HAL_LPTIM_TimeOut_Stop_IT
函数原型:
HAL_StatusTypeDef HAL_LPTIM_TimeOut_Stop_IT(LPTIM_HandleTypeDef *hlptim) { /* 检查参数 */ assert_param(IS_LPTIM_INSTANCE(hlptim->Instance)); /* 设置LPTIM状态 */ hlptim->State= HAL_LPTIM_STATE_BUSY; /* 禁止低功耗定时器 */ __HAL_LPTIM_DISABLE(hlptim); /* 关闭TIMOUT位 */ hlptim->Instance->CFGR &= ~LPTIM_CFGR_TIMOUT; /* 关闭比较匹配中断 */ __HAL_LPTIM_DISABLE_IT(hlptim, LPTIM_IT_CMPM); /* 设置LPTIM状态 */ hlptim->State= HAL_LPTIM_STATE_READY; /* 返回HAL_OK */ return HAL_OK; }
函数描述:
此函数用于关闭低功耗定时器的超时模式。
函数参数:
- 第1个参数是TIM_LPHandleTypeDef类型结构体指针变量。
注意事项:
- 推荐在低功耗定时器的中断服务程序里面调用此函数进行关闭,这样可以及时的关闭。
使用举例:
/* ********************************************************************************************************* * 函 数 名: bsp_StartLPTIM * 功能说明: 启动LPTIM * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void bsp_StartLPTIM(void) { /* ARR是自动重装寄存器,对应函数HAL_LPTIM_TimeOut_Start_IT的第2个参数 Compare是比较寄存器,对应函数HAL_LPTIM_TimeOut_Start_IT的第3个参数 --------------------- LSE = 32768Hz 分频设置为LPTIM_PRESCALER_DIV8,即8分频(函数bsp_InitLPTIM里面做的初始化配置) ARR自动重载寄存器 = 32768 实际测试发现溢出中断与ARR寄存器无关,全部由第3个参数,Compare寄存器决定 LPTIM的计数器计数1次的时间是 1 / (32768 / 8) = 8 /32768。 第三个参数配置的是32767,那么计数到32767就是 (32767 + 1)*(8 /32768) = 8秒,计算的时候要加1。 */ if (HAL_LPTIM_TimeOut_Start_IT(&LptimHandle, 0, 32767) != HAL_OK) { Error_Handler(__FILE__, __LINE__); } } /* ********************************************************************************************************* * 函 数 名: LPTIM1_IRQHandler * 功能说明: LPTIM1中断服务程序 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void LPTIM1_IRQHandler(void) { if((LPTIM1->ISR & LPTIM_FLAG_CMPM) != RESET) { /* 清除比较匹配中断 */ LPTIM1->ICR = LPTIM_FLAG_CMPM; /* 关闭溢出中断 */ HAL_LPTIM_TimeOut_Stop_IT(&LptimHandle); bsp_LedToggle(4); } }
36.5 总结
本章节就为大家讲解这么多,低功耗定时器在低功耗场合比较有用,如果有低功耗方面的项目需求,可以考虑使用这个定时器。