完整教程下載地址: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 總結
本章節就為大家講解這么多,低功耗定時器在低功耗場合比較有用,如果有低功耗方面的項目需求,可以考慮使用這個定時器。