第31章 TIM—基本定時器
全套200集視頻教程和1000頁PDF教程請到秉火論壇下載:www.firebbs.cn
野火視頻教程優酷觀看網址:http://i.youku.com/firege
本章參考資料:《STM32F4xx 中文參考手冊》、《STM32F4xx規格書》、庫幫助文檔《stm32f4xx_dsp_stdperiph_lib_um.chm》。
學習本章時,配合《STM32F4xx 中文參考手冊》基本定時器章節一起閱讀,效果會更佳,特別是涉及到寄存器說明的部分。
特別說明,本書內容是以STM32F42x系列控制器資源講解。
31.1 TIM簡介
定時器(Timer)最基本的功能就是定時了,比如定時發送USART數據、定時采集AD數據等等。如果把定時器與GPIO結合起來使用的話可以實現非常豐富的功能,可以測量輸入信號的脈沖寬度,可以生產輸出波形。定時器生產PWM控制電機狀態是工業控制普遍方法,這方面知識非常有必要深入了解。
STM32F42xxx系列控制器有2個高級控制定時器、10個通用定時器和2個基本定時器,還有2個看門狗定時器。看門狗定時器不在本章討論范圍,有專門講解的章節。控制器上所有定時器都是彼此獨立的,不共享任何資源。各個定時器特性參考表 01。
表 01 各個定時器特性
定時器類型 |
Timer |
計數器分辨率 |
計數器類型 |
預分頻系數 |
DMA請求生成 |
捕獲/比較通道 |
互補輸出 |
最大接口時鍾(MHz) |
最大定時器時鍾(MHz) |
高級控制 |
TIM1和TIM8 |
16位 |
遞增、遞減、遞增/遞減 |
1~65536(整數) |
有 |
4 |
有 |
90 (APB2) |
180 |
通用 |
TIM2,TIM5 |
32位 |
遞增、遞減、遞增/遞減 |
1~65536(整數) |
有 |
4 |
無 |
45 (APB1) |
90/180 |
TIM3,TIM4 |
16位 |
遞增、遞減、遞增/遞減 |
1~65536(整數) |
有 |
4 |
無 |
45 (APB1) |
90/180 |
|
TIM9 |
16位 |
遞增 |
1~65536(整數) |
無 |
2 |
無 |
90 (APB2) |
180 |
|
TIM10,TIM11 |
16位 |
遞增 |
1~65536(整數) |
無 |
1 |
無 |
90 (APB2) |
180 |
|
TIM12 |
16位 |
遞增 |
1~65536(整數) |
無 |
2 |
無 |
45 (APB1) |
90/180 |
|
TIM13,TIM14 |
16位 |
遞增 |
1~65536(整數) |
無 |
1 |
無 |
45 (APB1) |
90/180 |
|
基本 |
TIM6和TIM7 |
16位 |
遞增 |
1~65536(整數) |
有 |
0 |
無 |
45 (APB1) |
90/180 |
其中最大定時器時鍾可通過RCC_DCKCFGR寄存器配置為90MHz或者180MHz。
定時器功能強大,這一點透過《STM32F4xx中文參考手冊》講解定時器內容就有160多頁就顯而易見了。定時器篇幅長,內容多,對於新手想完全掌握確實有些難度,特別參考手冊是先介紹高級控制定時器,然后介紹通用定時器,最后才介紹基本定時器。實際上,就功能上來說通用定時器包含所有基本定時器功能,而高級控制定時器包含通用定時器所有功能。所以高級控制定時器功能繁多,但也是最難理解的,本章我們先選擇最簡單的基本定時器進行講解。
31.2 基本定時器
基本定時器比高級控制定時器和通用定時器功能少,結構簡單,理解起來更容易,我們就開始先講解基本定時器內容。基本定時器主要兩個功能,第一就是基本定時功能,生成時基,第二就是專門用於驅動數模轉換器(DAC)。關於驅動DAC具體應用參考DAC章節。
控制器有兩個基本定時器TIM6和TIM7,功能完全一樣,但所用資源彼此都完全獨立,可以同時使用。在本章內容中,以TIMx統稱基本定時器。
基本上定時器TIM6和TIM7是一個16位向上遞增的定時器,當我在自動重載寄存器(TIMx_ARR)添加一個計數值后並使能TIMx,計數寄存器(TIMx_CNT)就會從0開始遞增,當TIMx_CNT的數值與TIMx_ARR值相同時就會生成事件並把TIMx_CNT寄存器清0,完成一次循環過程。如果沒有停止定時器就循環執行上述過程。這些只是大概的流程,希望大家有個感性認識,下面細講整個過程。
31.3 基本定時器功能框圖
基本定時器的功能框圖包含了基本定時器最核心內容,掌握了功能框圖,對基本定時器就有一個整體的把握,在編程時思路就非常清晰,見圖 01。
首先先看圖 01中綠色框內容,第一個是帶有陰影的方框,方框內容一般是一個寄存器名稱,比如圖中主體部分的自動重載寄存器(TIMx_ARR)或PSC預分頻器(TIMx_PSC),這里要特別突出的是陰影這個標志的作用,它表示這個寄存器還自帶有影子寄存器,在硬件結構上實際是有兩個寄存器,源寄存器是我們可以進行讀寫操作,而影子寄存器我們是完全無法操作的,有內部硬件使用。影子寄存器是在程序運行時真正起到作用的,源寄存器只是給我們讀寫用的,只有在特定時候(特定事件發生時)才把源寄存器的值拷貝給它的影子寄存器。多個影子寄存器一起使用可以到達同步更新多個寄存器內容的目的。
接下來是一個指向右下角的圖標,它表示一個事件,而一個指向右上角的圖標表示中斷和DMA輸出。這個我們把它放在圖中主體更好理解。圖中的自動重載寄存器有影子寄存器,它左邊有一個帶有"U"字母的事件圖標,表示在更新事件生成時就把自動重載寄存器內容拷貝到影子寄存器內,這個與上面分析是一致。寄存器右邊的事件圖標、中斷和DMA輸出圖標表示在自動重載寄存器值與計數器寄存器值相等時生成事件、中斷和DMA輸出。
圖 01 基本定時器功能框圖
1. ①時鍾源
定時器要實現計數必須有個時鍾源,基本定時器時鍾只能來自內部時鍾,高級控制定時器和通用定時器還可以選擇外部時鍾源或者直接來自其他定時器等待模式。我們可以通過RCC專用時鍾配置寄存器(RCC_DCKCFGR)的TIMPRE位設置所有定時器的時鍾頻率,我們一般設置該位為默認值0,使得表 01中可選的最大定時器時鍾為90MHz,即基本定時器的內部時鍾(CK_INT)頻率為90MHz。
基本定時器只能使用內部時鍾,當TIM6和TIM7控制寄存器1(TIMx_CR1)的CEN位置1時,啟動基本定時器,並且預分頻器的時鍾來源就是CK_INT。對於高級控制定時器和通用定時器的時鍾源可以來找控制器外部時鍾、其他定時器等等模式,較為復雜,我們在相關章節會詳細介紹。
2. ②控制器
定時器控制器控制實現定時器功能,控制定時器復位、使能、計數是其基礎功能,基本定時器還專門用於DAC轉換觸發。
3. ③計數器
基本定時器計數過程主要涉及到三個寄存器內容,分別是計數器寄存器(TIMx_CNT)、預分頻器寄存器(TIMx_PSC)、自動重載寄存器(TIMx_ARR),這三個寄存器都是16位有效數字,即可設置值為0至65535。
首先我們來看圖 01中預分頻器PSC,它有一個輸入時鍾CK_PSC和一個輸出時鍾CK_CNT。輸入時鍾CK_PSC來源於控制器部分,基本定時器只有內部時鍾源所以CK_PSC實際等於CK_INT,即90MHz。在不同應用場所,經常需要不同的定時頻率,通過設置預分頻器PSC的值可以非常方便得到不同的CK_CNT,實際計算為:fCK_CNT等於fCK_PSC/(PSC[15:0]+1)。
圖 02是將預分頻器PSC的值從1改為4時計數器時鍾變化過程。原來是1分頻,CK_PSC和CK_CNT頻率相同。向TIMx_PSC寄存器寫入新值時,並不會馬上更新CK_CNT輸出頻率,而是等到更新事件發生時,把TIMx_PSC寄存器值更新到影子寄存器中,使其真正產生效果。更新為4分頻后,在CK_PSC連續出現4個脈沖后CK_CNT才產生一個脈沖。
圖 02 基本定時器時鍾源分頻
在定時器使能(CEN置1)時,計數器COUNTER根據CK_CNT頻率向上計數,即每來一個CK_CNT脈沖,TIMx_CNT值就加1。當TIMx_CNT值與TIMx_ARR的設定值相等時就自動生成事件並TIMx_CNT自動清零,然后自動重新開始計數,如此重復以上過程。為此可見,我們只要設置CK_PSC和TIMx_ARR這兩個寄存器的值就可以控制事件生成的時間,而我們一般的應用程序就是在事件生成的回調函數中運行的。在TIMx_CNT遞增至與TIMx_ARR值相等,我們叫做為定時器上溢。
自動重載寄存器TIMx_ARR用來存放於計數器值比較的數值,如果兩個數值相等就生成事件,將相關事件標志位置位,生成DMA和中斷輸出。TIMx_ARR有影子寄存器,可以通過TIMx_CR1寄存器的ARPE位控制影子寄存器功能,如果ARPE位置1,影子寄存器有效,只有在事件更新時才把TIMx_ARR值賦給影子寄存器。如果ARPE位為0,修改TIMx_ARR值馬上有效。
4. 定時器周期計算
經過上面分析,我們知道定時事件生成時間主要由TIMx_PSC和TIMx_ARR兩個寄存器值決定,這個也就是定時器的周期。比如我們需要一個1s周期的定時器,具體這兩個寄存器值該如何設置內。假設,我們先設置TIMx_ARR寄存器值為9999,即當TIMx_CNT從0開始計算,剛好等於9999時生成事件,總共計數10000次,那么如果此時時鍾源周期為100us即可得到剛好1s的定時周期。
接下來問題就是設置TIMx_PSC寄存器值使得CK_CNT輸出為100us周期(10000Hz)的時鍾。預分頻器的輸入時鍾CK_PSC為90MHz,所以設置預分頻器值為(9000-1)即可滿足。
31.4 定時器初始化結構體詳解
標准庫函數對定時器外設建立了四個初始化結構體,基本定時器只用到其中一個即TIM_TimeBaseInitTypeDef,該結構體成員用於設置定時器基本工作參數,並由定時器基本初始化配置函數TIM_TimeBaseInit調用,這些設定參數將會設置定時器相應的寄存器,達到配置定時器工作環境的目的。這一章我們只介紹TIM_TimeBaseInitTypeDef結構體,其他結構體將在相關章節介紹。
初始化結構體和初始化庫函數配合使用是標准庫精髓所在,理解了初始化結構體每個成員意義基本上就可以對該外設運用自如了。初始化結構體定義在stm32f4xx_tim.h文件中,初始化庫函數定義在stm32f4xx_tim.c文件中,編程時我們可以結合這兩個文件內注釋使用。
代碼清單 01 定時器基本初始化結構體
1 typedef struct {
2 uint16_t TIM_Prescaler; // 預分頻器
3 uint16_t TIM_CounterMode; // 計數模式
4 uint32_t TIM_Period; // 定時器周期
5 uint16_t TIM_ClockDivision; // 時鍾分頻
6 uint8_t TIM_RepetitionCounter; // 重復計算器
7 } TIM_TimeBaseInitTypeDef;
(1) TIM_Prescaler:定時器預分頻器設置,時鍾源經該預分頻器才是定時器時鍾,它設定TIMx_PSC寄存器的值。可設置范圍為0至65535,實現1至65536分頻。
(2) TIM_CounterMode:定時器計數方式,可是在為向上計數、向下計數以及三種中心對齊模式。基本定時器只能是向上計數,即TIMx_CNT只能從0開始遞增,並且無需初始化。
(3) TIM_Period:定時器周期,實際就是設定自動重載寄存器的值,在事件生成時更新到影子寄存器。可設置范圍為0至65535。
(4) TIM_ClockDivision:時鍾分頻,設置定時器時鍾CK_INT頻率與數字濾波器采樣時鍾頻率分頻比,基本定時器沒有此功能,不用設置。
(5) TIM_RepetitionCounter:重復計數器,屬於高級控制寄存器專用寄存器位,利用它可以非常容易控制輸出PWM的個數。這里不用設置。
雖然定時器基本初始化結構體有5個成員,但對於基本定時器只需設置其中兩個就可以,想想使用基本定時器就是簡單。
31.5 基本定時器定時實驗
在DAC轉換中幾乎都用到基本定時器,使用有關基本定時器觸發DAC轉換內容在DAC章節講解即可,這里就利用基本定時器實現簡單的定時功能。
我們使用基本定時器循環定時0.5s並使能定時器中斷,每到0.5s就在定時器中斷服務函數翻轉RGB彩燈,使得最終效果RGB彩燈暗0.5s,亮0.5s,如此循環。
31.5.1 硬件設計
基本定時器沒有相關GPIO,這里我們只用定時器的定時功能,無效其他外部引腳,至於RGB彩燈硬件可參考GPIO章節。
31.5.2 軟件設計
這里只講解核心的部分代碼,有些變量的設置,頭文件的包含等並沒有涉及到,完整的代碼請參考本章配套的工程。我們創建了兩個文件:bsp_basic_tim.c和bsp_basic_tim.h文件用來存基本定時器驅動程序及相關宏定義,中斷服務函數放在stm32f4xx_it.h文件中。
1. 編程要點
(1) 初始化RGB彩燈GPIO;
(2) 開啟基本定時器時鍾;
(3) 設置定時器周期和預分頻器;
(4) 啟動定時器更新中斷,並開啟定時器;
(5) 定時器中斷服務函數實現RGB彩燈翻轉。
2. 軟件分析
宏定義
代碼清單 02 宏定義
1 #define BASIC_TIM TIM6
2 #define BASIC_TIM_CLK RCC_APB1Periph_TIM6
3
4 #define BASIC_TIM_IRQn TIM6_DAC_IRQn
5 #define BASIC_TIM_IRQHandler TIM6_DAC_IRQHandler
使用宏定義非常方便程序升級、移植。
NCIV配置
代碼清單 03 NVIC配置
1 static void TIMx_NVIC_Configuration(void)
2 {
3 NVIC_InitTypeDef NVIC_InitStructure;
4 // 設置中斷組為0
5 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
6 // 設置中斷來源
7 NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM_IRQn;
8 // 設置搶占優先級
9 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
10 // 設置子優先級
11 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
12 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
13 NVIC_Init(&NVIC_InitStructure);
14 }
實驗用到定時器更新中斷,需要配置NVIC,實驗只有一個中斷,對NVIC配置沒什么具體要求。
基本定時器模式配置
代碼清單 04 基本定時器模式配置
1 static void TIM_Mode_Config(void)
2 {
3 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
4
5 // 開啟TIMx_CLK,x[6,7]
6 RCC_APB1PeriphClockCmd(BASIC_TIM_CLK, ENABLE);
7
8 /* 累計 TIM_Period個后產生一個更新或者中斷*/
9 //當定時器從0計數到4999,即為5000次,為一個定時周期
10 TIM_TimeBaseStructure.TIM_Period = 5000-1;
11
12 //定時器時鍾源TIMxCLK = 2 * PCLK1
13 // PCLK1 = HCLK / 4
14 // => TIMxCLK=HCLK/2=SystemCoreClock/2=90MHz
15 // 設定定時器頻率為=TIMxCLK/(TIM_Prescaler+1)=10000Hz
16 TIM_TimeBaseStructure.TIM_Prescaler = 9000-1;
17
18 // 初始化定時器TIMx, x[2,3,4,5]
19 TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseStructure);
20
21
22 // 清除定時器更新中斷標志位
23 TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);
24
25 // 開啟定時器更新中斷
26 TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);
27
28 // 使能定時器
29 TIM_Cmd(BASIC_TIM, ENABLE);
30 }
使用定時器之前都必須開啟定時器時鍾,基本定時器屬於APB1總線外設。
接下來設置定時器周期數為4999,即計數5000次生成事件。設置定時器預分頻器為(9000-1),基本定時器使能內部時鍾,頻率為90MHz,經過預分頻器后得到10KHz的頻率。然后就是調用TIM_TimeBaseInit函數完成定時器配置。
TIM_ClearFlag函數用來在配置中斷之前清除定時器更新中斷標志位,實際是清零TIMx_SR寄存器的UIF位。
使用TIM_ITConfig函數配置使能定時器更新中斷,即在發生上溢時產生中斷。
最后使用TIM_Cmd函數開啟定時器。
定時器中斷服務函數
代碼清單 05 定時器中斷服務函數
1 void BASIC_TIM_IRQHandler (void)
2 {
3 if ( TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET ) {
4 LED1_TOGGLE;
5 TIM_ClearITPendingBit(BASIC_TIM , TIM_IT_Update);
6 }
7 }
我們在TIM_Mode_Config函數啟動了定時器更新中斷,在發生中斷時,中斷服務函數就得到運行。在服務函數內我們先調用定時器中斷標志讀取函數TIM_GetITStatus獲取當前定時器中斷位狀態,確定產生中斷后才運行RGB彩燈翻轉動作,並使用定時器標志位清除函數TIM_ClearITPendingBit清除中斷標志位。
主函數
代碼清單 06 主函數
1 int main(void)
2 {
3
4 LED_GPIO_Config();
5
6 /* 初始化基本定時器定時,1s產生一次中斷 */
7 TIMx_Configuration();
8
9 while (1) {
10 }
11 }
實驗用到RGB彩燈,需要對其初始化配置。LED_GPIO_Config函數是定義在bsp_led.c文件的完成RGB彩燈GPIO初始化配置的程序。
TIMx_Configuration函數是定義在bsp_basic_tim.c文件的一個函數,它只是簡單的先后調用TIMx_NVIC_Configuration和TIM_Mode_Config兩個函數完成NVIC配置和基本定時器模式配置。
31.5.3 下載驗證
保證開發板相關硬件連接正確,把編譯好的程序下載到開發板。開始RGB彩燈是暗的,等一會RGB彩燈變為紅色,再等一會又暗了,如此反復。如果我們使用表鍾與RGB彩燈閃爍對比,可以發現它是每0.5s改變一次RGB彩燈狀態的。
31.6 每課一問
1. 計算基本定時器一次最長定時時間,如果需要使用基本定時器產生100s周期事件有什么辦法實現?
2. 修改實驗程序,在保使其每0.5s翻轉一次LED1的同時在每10s翻轉LED2。