背景
上一講 STM32 CubeMX 學習:外部中斷的使用 介紹了如何配置以及操作GPIO外部中斷。
這一講我們介紹定時器的有關概念,並對其中一種進行示范。
HOST-OS : Windows-10
STM32 Cube :v5.6
MCU : STM32F429
LIB : stm32cube_fw_f4_v1250
知識
STM32中,有基本定時器(Basic timer)、通用定時器(General-purpose timer)、高級定時器(Advanced-control timer)三類TIM定時器。
- 基本定時器 是16位的只能向上計數的定時器,只能用於定時。
- 通用定時器和高級定時器有更多的功能,如還可以進行輸出比較、輸入捕捉等功能。
定時器種類 | 位數 | 計數器模式 | 產生DMA請求 | 捕獲/比較通道 | 互補輸出 | 特殊應用場景 |
---|---|---|---|---|---|---|
高級定時器 | 16 | 向上,向下,向上/下 | 可以 | 4 | 有 | 帶可編程死區的互補輸出 |
通用定時器 | 32 | 向上,向下,向上/下 | 可以 | 4 | 無 | 通用。定時計數,PWM輸出,輸入捕獲,輸出比較 |
通用定時器 | 16 | 向上,向下,向上/下 | 可以 | 4 | 無 | 通用。定時計數,PWM輸出,輸入捕獲,輸出比較 |
通用定時器 | 16 | 向上 | 沒有 | 2 | 無 | 通用。定時計數,PWM輸出,輸入捕獲,輸出比較 |
基本定時器 | 16 | 向上,向下,向上/下 | 可以 | 0 | 無 | 主要應用於驅動DAC(TIM 6,7 獨有) |
如何知道STM32什么芯片擁有多少個定時器,每一個定時器對應了什么什么種類的定時器。
- 在ST官網查找有關的芯片手冊,根據下載的芯片手冊中的目錄(Contents)可以看到:
- SMT32F4系列共有15個定時器:高級定時器(TIM1、TIM8);通用定時器(TIM 2 ~ 5、TIM 9 ~ 14);基本定時器(TIM6、TIM7)。
Contents STM32F427xx STM32F429xx
3.22 Timers and watchdogs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.22.1 Advanced-control timers (TIM1, TIM8) . . . . . . . . . . . . . . . . . . . . . . . 36
3.22.2 General-purpose timers (TIMx) . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.22.3 Basic timers TIM6 and TIM7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.22.4 Independent watchdog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.22.5 Window watchdog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.22.6 SysTick timer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
定時器的有關功能
基本定時器就是單純的定時計數器;通用定時器多了四個通道,相對應的增加了功能;高級定時器具有基本,通用定時器的所有的功能,並且添加了其他功能。
基本定時器功能(TIM6、TIM7):
- 16位向上、向下、向上/下自動裝載計數器
- 16位可編程(可以實時修改)預分頻器,計數器時鍾頻率的分頻系數為1~65535之間的任意數值
- 觸發DAC的同步電路 (此項是TIM6/7獨有功能)
- 位於APB1總線上
通用定時器(TIM2~TIM5)的主要功能:
- 16位向上、向下、向上/下自動裝載計數器
- 16位可編程(可以實時修改)預分頻器,計數器時鍾頻率的分頻系數為1~65535之間的任意數值
- 4 個獨立通道(TIMx_CH1~4)可以用作:
- 測量輸入信號的脈沖長度( 輸入捕獲)
- 輸出比較
- 單脈沖模式輸出
- PWM輸出(邊緣或中間對齊模式)
- 支持針對定位的增量(正交)編碼器和霍爾傳感器電路
- 如下事件發生時產生中斷/DMA:
- 更新:計數器向上溢出/向下溢出,計數器初始化(通過軟件或者內部/外部觸發)
- 觸發事件(計數器啟動、停止、初始化或者由內部/外部觸發計數)
- 輸入捕獲
- 輸出比較
- 位於APB1總線上
高級定時器(TIM1,TIM8)的主要功能:
- 高級定時器具有基本,通用定時器的所有的功能,
- 還具有控制交直流電動機所有的功能,
- 輸出6路互補帶死區的信號,剎車功能等等
- 位於APB2總線上
STM32 APB1和APB2的區別如下:(要結合時鍾樹來理解APB, Advanced Peripheral Bus)
一般APB1和APB2上的時鍾都是系統時鍾經過 AHB(Advanced High performance Bus) Prescaler 分頻得到 HCLK(High performance Bus Clock 高級高性能總線時鍾)。
- HCLK 經過APB1 Prescaler 得到APB1時鍾,而總線下TIMER的時鍾源為APB1的2倍
- HCLK 經過APB2 Prescaler 得到APB2時鍾,而總線下TIMER的時鍾源為APB2的2倍
AHB,是Advanced High performance Bus的縮寫,譯作高級高性能總線,這是一種“系統總線”,主要用於高性能模塊(如CPU、DMA和DSP等)之間的連接。
1)所負責端口不同:
- APB2負責AD,I/O,高級TIM,串口1。
- APB1負責DA,USB,SPI,I2C,CAN,串口2345,普通TIM。
2)所支持速度不同:APB2支持高速狀態下的工作,APB1支持低速狀態下的工作。
時鍾源
時鍾需要時鍾源來驅動。計數器時鍾可以由下列時鍾源提供:
- 內部時鍾(CK_INT)
- 外部時鍾模式1:外部捕捉比較引腳(TIx)
- 外部時鍾模式2:外部觸發輸入(ETR) (僅適用於TIM 2,3,4)
- 內部觸發輸入(ITRx):使用一個定時器作為另外一個定時器的預分頻器(例如配置TimerA作為TimerB的預分頻器)
定時器有關框圖
基本定時器主要由下面三個寄存器組成。
- 計數器寄存器 (TIMx_CNT)
- 預分頻器寄存器 (TIMx_PSC)
- 自動重載寄存器 (TIMx_ARR)
關於定時器配置的一些參數
雖然有3類定時器但,不管怎樣,只要是配置作為定時器,那么便 總是 與 基本定時器是類似的。
在下文配置的時候要注意:我們配置的是進入定時器中斷的頻率,然后要定的時間要跟據這個頻率來定時的。
Prescaler(PSC): 定時器預分頻設置,用來設置TIMx_PSC的值,16位,設置 0~65535 以達到 1 至 65536 的分頻。
Couter Mode : 定時器的計數方式,基本定時器只能向上(UP)計數(即TIMx_CNT只能從0開始遞增,無須初始化)
http://www.waveshare.net/study/article-642-1.html
定時器有如下3種計數模式:
- 遞增計數模式:計數器從 0 計數到自動重載值(TIMx_ARR寄存器的值),然后重新從 0 開始計數並生成計數器上溢事件。
- 遞減計數模式:計數器從自動重載值(TIMx_ARR)開始遞減到 0,然后重新從自動重載值開始計數並生成計數器下溢事件。
- 中心對齊模式:也叫 向上向下計數,計數器從 0 開始計數到自動重載值(TIMx_ARR) – 1 ,生成計數器上溢事件;然后從自動重載值開始向下計數到 1 並生成計數器下溢事件。之后從0 開始重新計數。
Couter Period : 定時器周期,16位,設置 0~65535 以達到 1 至 65536 的周期。每當定時器達到 設定值時,置位。
假設現在HCLK為 168 MHZ,設置了下面的值:
預分頻(PSC):167,那么分頻以后的時鍾是: 168 MHz / (167 + 1 ) = 1 MHz
如果 定時器周期(Period) 的 值 設置為999,定時器產生中斷的頻率 為:1MHz/1000 = 1Khz,即 1 ms 的定時周期。
那么也就有:\[發生中斷的時間 = (PSC + 1) * ( Period + 1)/定時器的頻率 \]
InternalCLock Division(CKD): 內部時鍾分頻因子,與PWM輸出實驗其實是沒關系的,指設置定時器時鍾(CK_INT)頻率與數字濾波器(ETR,TIx)使用的采樣頻率之間的分頻比例的(與輸入捕獲相關)。
Auto-reload preload :自動重載。一般每次觸發以后需要重新填充。
ARM中,有的邏輯寄存器在物理上對應2個寄存器,一個是程序員可以寫入或讀出的寄存器,稱為preload register(預裝載寄存器),另一個是程序員看不見的、但在操作中真正起作用的寄存器,稱為shadow register(影子寄存器);
設計preload register和shadow register的好處是:所有真正需要起作用的寄存器(shadow register)可以在同一個時間(發生更新事件時)被更新為所對應的preload register的內容,這樣可以保證多個通道的操作能夠准確地同步。如果沒有shadow register,或者preload register和shadow register是直通的,即軟件更新preload register時,同時更新了shadow register,因為軟件不可能在一個相同的時刻同時更新多個寄存器,結果造成多個通道的時序不能同步,如果再加上其它因素(例如中斷),多個通道的時序關系有可能是不可預知的。
Trigger Output Parameters : 觸發輸出 (TRGO) ,當定時器的定時時間到達的時候輸出一個信號(如:定時器更新產生TRGO信號來觸發ADC的同步轉換)
Repetition Counter:重復計數器(RCR -8 bits),屬於高級控制寄存器專用寄存器位,利用它可以非常容易控制輸出 PWM 的個數。
Master/Slave Mode(MSM bit) :主從模式
定時器一般是通過軟件設置而啟動,STM32的每個定時器也可以通過外部信號觸發而啟動,還可以通過另外一個定時器的某一個條件被觸發而啟動。這里所謂某一個條件可以是定時到時間、定時器超時、比較成功等許多條件。
這種通過一個定時器觸發另一個定時器的工作方式稱為定時器的同步,發出觸發信號的定時器工作於主模式,接受觸發信號而啟動的定時器工作於從模式。
定時器的四種主從機模式:外部觸發模式1、IRC重置模式、門控模式、觸發模式。
CubeMx 對 定時器的配置 (以TIM6 為例)
1)在Pinout & Configuration中,選擇一個 定時器 (例如 TIM6)
2)"Mode":勾選 "Activated"
3)"Configuration " - "Parameter Settings"中 :
- PSC : 167
- Counter Mode: Up
- Counter Period: 999
- auto-reload preload: Enable
- Trigger Event Selection : Reset
- "Configuration " - "NVIC Settings"中 : 勾選 "Enabled" (開啟中斷)
5)右上角,"GENERATE CODE"
源碼分析
通過配置以后,在main函數中會有對應的定時器初始化函數,在新版的CubeMx中如果配置了中斷,那么響應的中斷函數HAL_TIM_Base_Start_IT
也可以看到。
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM6_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim6);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
9 static void TIM_DMAPeriodElapsedCplt(DMA_HandleTypeDef *hdma)
8 {
7 TIM_HandleTypeDef *htim = (TIM_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
6
5 htim->State = HAL_TIM_STATE_READY;
4
3 #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
2 htim->PeriodElapsedCallback(htim);
1 #else
5747 HAL_TIM_PeriodElapsedCallback(htim);
1 #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
2 }
由於 DMA的機制這里還未涉及,所以不討論 DMA 中斷的機制。有關文件:Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c
、Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c
HAL_TIM_DMABurst_WriteStart 中注冊了 TIM_DMAPeriodElapsedCplt 作為 hdma->XferCpltCallback的回調函數
HAL_DMA_IRQHandler() -> hdma->XferCpltCallback(hdma); -> TIM_DMAPeriodElapsedCplt() -> HAL_TIM_PeriodElapsedCallback()
添加代碼
/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM6){
// do_something();
}
}
/* USER CODE END 0 */
運行,即可