• 【STM32H7教程】第36章 STM32H7的LPTIM低功耗定时器基础知识和HAL库API


    完整教程下载地址: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 初学者重要提示

    1.   使用LPTIM的好处是系统处于睡眠、停机状态依然可以正常工作(除了待机模式)。停机状态可以正常工作的关键是LSE,LSI时钟不会被关闭,同时也可以选择使用外部时钟源。
    2.   重点学习本章的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表示时间溢出。

    注意事项:

    1. 函数HAL_LPTIM_MspInit用于初始化定时器的底层时钟、引脚等功能,需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
    2. 如果形参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表示时间溢出。

    注意事项:

    1. 这里重点说下配置了第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表示时间溢出。

    注意事项:

    1. 超时配置用不到第2个参数。
    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类型结构体指针变量。

    注意事项:

    1. 推荐在低功耗定时器的中断服务程序里面调用此函数进行关闭,这样可以及时的关闭。

    使用举例:

    /*
    *********************************************************************************************************
    *    函 数 名: 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 总结

    本章节就为大家讲解这么多,低功耗定时器在低功耗场合比较有用,如果有低功耗方面的项目需求,可以考虑使用这个定时器。

  • 相关阅读:
    httpClient 中的post或者get请求
    java自带的http get/post请求servlet
    java文件的读写操作
    java文件创建和删除
    java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'waterQuality
    win10系统jdk安装和环境变量配置
    echarts报错Can't get dom width or height
    org.springframework.beans.factory.BeanCreationException
    jsp与后台交换数据(安全目录外)
    LeetCode —— Invert Binary Tree
  • 原文地址:https://www.cnblogs.com/armfly/p/12149170.html
Copyright © 2020-2023  润新知