【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 總結

本章節就為大家講解這么多,低功耗定時器在低功耗場合比較有用,如果有低功耗方面的項目需求,可以考慮使用這個定時器。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM