這一課我們將介紹CKS32F4XX系列產品的定時器使用,CKS32F4XX的定時器功能十分強大,包含2個高級控制定時器,8個普通定時器,2個基礎定時器,以及兩個看門狗定時器和一個系統定時器,總共15個定時器之多。關于定時器部分內容的講解我們將分3個部分展開,本節將介紹定時器的基本特征和定時操作。
1、計數器分辨率:指定時器一個計數周期,例如同樣是84Mhz的工作時鐘,
對于TIM2,其分辨率的范圍為:1*(1000ns/ 84)~(2^32)*(1000ns/84);
對于TIM3,其分辨率的范圍為:1*(1000ns/84)~(2^16)*(1000ns/84)。
2、計數器類型:這個參數按照計數的方向來劃分:
向上計數指的是從0開始到1,2...直到自己設置的計數上限值N,達到后再次從0開始計數,周而復始;
向下計數指的是從設置的計數上限值N開始到N-1,N-2,...直到0,達到后再次從N開始計數,周而復始;向上向下計數指的是從0,1,2...N,然后再從N,N-1,N-2...0,周而復始。
3、預分頻系數:可以通過設置該系數來配置時基,如定時器工作在84Mhz下,配置不分頻則一個計數時基為11.9ns,配置成2分頻則一個計數時基為23.8ns。
4、產生DMA請求:定時器的更新會發出DMA請求,這是因為在DMA通道中為Timer預留了一個通道。
5、捕獲比較通道:捕獲就是定時器可以捕捉到通道的上升沿或者下降沿信號,比較就是定時器可以將計數器的值和裝載值做比較,關于這部分將會在下后續章節展開。
6、互補輸出:互補輸出指的是輸出的兩個通道兩個波形完全相反,通常運用在橋式電路中的互補PWM輸出,這一部分將在后續章節展開。
7、最大接口時鐘和最大工作時鐘:定時器的時鐘來源是APB,通過APB預分頻器的配置,最大工作時鐘可以是PCLKx的兩倍。
CKS32F4XX定時器的定時操作
定時器的定時操作原理其實很簡單,就像家里用的微波爐一樣,需要加熱食物時,先設定一個加熱時間,然后按下開關,開始計時,當達到我們設置的定時時間以后,微波爐就會停止工作,并會有一個聲音提示我們,定時時間到了。當然,在完成定時操作之前,必須要對Timer進行一些配置,下面我們以timer3為例,為大家演示。
1、Timer3時鐘使能
TIM3時鐘來自于APB1域,我們通過APB1總線下的時鐘使能函數來使能TIM3的時鐘。調用的函數是:
//>>使能TIM3時鐘 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);typedefstruct
2、定時器參數初始化
在庫函數中定時器的初始化通過TIM_TimeBaseInit實現的:
voidTIM_TimeBaseInit(TIM_TypeDef*TIMx, TIM_TimeBaseInitTypeDef*TIM_TimeBaseInitStruct);
參數結構體指針,結構體類型為TIM_TimeBaseInitTypeDef,下面是結構體的定義:
typedefstruct { uint16_tTIM_Prescaler; uint16_tTIM_CounterMode; uint16_tTIM_Period; uint16_tTIM_ClockDivision; uint8_tTIM_RepetitionCounter; }TIM_TimeBaseInitTypeDef;typedefstruct
這個結構體一共有5個成員變量,要說明的是,對于通用定時器只有前面四個參數有用,最后參數TIM_RepetitionCounter是高級定時器才有用的,后續章節會詳解,在此不贅述。
第一個參數TIM_Prescaler是用來設置分頻系數的,對應上表中的預分頻系數。
第二個參數TIM_CounterMode是用來設置計數方式,如上表所述,可以設置為向上計數,向下計數方式還有向上向下計數(中央對齊計數)方式,比較常用的是向上計數TIM_CounterMode_Up和向下計數 TIM_CounterMode_Down。
第三個參數是設置自動重載計數周期值,可以通俗的理解成要定時的次數,這個是根據定時時間和時基做除法換算得到的,比如定時器現在計數1次,時間經過了250ns,要定時100us,那自動重載計數周期值為400。
第四個參數是用來設置時鐘分頻因子,這個參數與定時器的其他功能有密切,本節操作先按照TIM_CKD_DIV1來配置(不分頻)。
針對TIM3初始化范例代碼格式:
TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period=5000; TIM_TimeBaseStructure.TIM_Prescaler=7199; TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure);
3、設置TIM3_DIER允許更新中斷
因為我們要達到定時時間到后有一個到時提醒的效果,這就需要用到TIM3的更新中斷,在庫函數里面定時器中斷使能是通過TIM_ITConfig函數來實現的:
voidTIM_ITConfig(TIM_TypeDef*TIMx,uint16_tTIM_IT,FunctionalStateNewState);
第一個參數是選擇定時器號,取值為 TIM1~TIM17。
第二個參數非常關鍵,是用來指明我們使能的定時器中斷的類型,定時器中斷的類型有很多種,包括更新中斷TIM_IT_Update,觸發中斷TIM_IT_Trigger,以及輸入捕獲中斷等等。
第三個參數就很簡單了,就是失能還是使能。
例如我們要使能TIM3的更新中斷,格式為:
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
4、TIM3中斷優先級設置
在定時器中斷使能之后,因為要產生中斷,必不可少的要設置NVIC(向量中斷控制器)來設置中斷優先級。關于NVIC_Init函數實現中斷優先級的設置請到NVIC章節參考,這里就不重復講解。
5、使能TIM3
配置好定時器后,不要忘記開啟定時器,就像按下微波爐的開關一樣,定時器才會進入工作狀態,在固件庫里面使能定時器的函數是通過TIM_Cmd函數來實現的:
voidTIM_Cmd(TIM_TypeDef*TIMx,FunctionalStateNewState)
這個函數非常簡單,比如我們要使能定時器3,方法為:
//>>使能TIMx外設 TIM_Cmd(TIM3,ENABLE);
6、編寫中斷服務函數
最后,要編寫定時器中斷服務函數,類似于聽到微波爐結束工作的聲音后,我們需要進行把加熱的食物取出或者繼續加熱等操作,通過該函數來處理定時器產生的相關中斷。在中斷產生后,通過狀態寄存器的值來判斷此次產生的中斷屬于什么類型。然后執行相關的操作,我們這里使用的是更新(溢出)中斷,在處理完中斷之后應,該向TIM3_SR的最低位寫0,來清除該中斷標志,在固件庫函數里面,用來讀取中斷狀態寄存器的值判斷中斷類型的函數是:ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t)
該函數的作用是,判斷定時器TIMx的中斷類型 TIM_IT是否發生中斷。比如,我們要判斷定時器3 是否發生更新(溢出)中斷,方法為:
if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET){}IT_Update)!=RESET){}
固件庫中清除中斷標志位的函數是:
voidTIM_ClearITPendingBit(TIM_TypeDef*TIMx,uint16_tTIM_IT)
該函數的作用是,清除定時器TIMx的中斷TIM_IT 標志位。使用起來非常簡單,比如我們在TIM3的溢出中斷發生后,我們要清除中斷標志位,方法是:
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
這里需要說明一下,固件庫還提供了兩個函數用來判斷定時器狀態以及清除定時器狀態標
志位的函數TIM_GetFlagStatus 和TIM_ClearFlag,他們的作用和前面兩個函數的作用類似。只 是在TIM_GetITStatus函數中會先判斷這種中斷是否使能,使能了才去判斷中斷標志位,而TIM_GetFlagStatus 直接用來判斷狀態標志位。通過以上幾個步驟,我們就可以達到我們的目的了,使用通用定時器的更新中斷,來實現定時并產生定時中斷信號。
代碼實例
/**通用定時器3中斷初始化
>>arr:自動重裝值。psc:時鐘預分頻數
>>定時器溢出時間計算方法:Tout=((arr+1)*(psc+1))/Ft us.
>>Ft=定時器工作頻率,單位:Mhz
這里使用的是定時器3**/
voidTIM3_Int_Init(u16arr,u16psc) { TIM_TimeBaseInitTypeDefTIM_TimeBaseInitStructure; NVIC_InitTypeDefNVIC_InitStructure; //>>①使能TIM3時鐘 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //>>自動重裝載值 TIM_TimeBaseInitStructure.TIM_Period=arr; //>>定時器分頻 TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //>>向上計數模式 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //②初始化定時器TIM3 TIM_TimeBaseInit(TIM3, TIM_TimeBaseInitStructure); //③允許定時器3更新中斷 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //定時器3中斷 NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //搶占優先級1 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //響應優先級3 NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03;NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //④初始化NVIC NVIC_Init( NVIC_InitStructure); //⑤使能定時器3 TIM_Cmd(TIM3,ENABLE); } //⑥定時器3中斷服務函數 voidTIM3_IRQHandler(void) { //>>溢出中斷 if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) { } //>>清除中斷標志位 TIM_ClearITPendingBit(TIM3,TIM_IT_Update); }
這里列出了一個中斷服務函數和一個定時器3中斷初始化函數,中斷服務函數中,在每次中斷后,判斷 TIM3的中斷類型,如果中斷類型正確,則執行自己需要執行的操作并清除中斷標志,TIM3_Int_Init 函數就是執行我們上面介紹的那5個步驟,使得 TIM3開始工作,并開啟中斷。這里我們分別用標號①~⑤來標注定時器初始化的五個步驟。該函數的2 個參數用來設置TIM3的溢出時間。假設系統初始化 SystemInit函數里面已經初始化APB1的時鐘為 4分頻,所以APB1的時鐘為42M,這也是timer3的最大接口時鐘,而從CKS32F4的內部時鐘樹圖得知:當APB1的時鐘分頻數為1的時候,TIM2~7以及TIM12~14的時鐘為APB1的時鐘,而如果APB1的時鐘分頻數不為1,那么TIM2~7以及TIM12~14的時鐘頻率將為APB1時鐘的兩倍。因此,TIM3的時鐘為84M,再根據我們設計的arr和psc的值,就可以計算中斷時間了。計算公式如下:
Tout=((arr+1)*(psc+1))/Tclk;
其中:
Tclk:TIM3的輸入時鐘頻率(單位為Mhz)。
Tout:TIM3溢出時間(單位為us)。
本節我們介紹了CKS32F4XX各定時器概況,以及如何設置最基礎的定時功能,包括開啟定時器的時鐘,配置定時器的時基,定時次數以及計數的方向等,此外定時器其他的功能如輸入捕獲,比較輸出和PWM輸出等功能將會在后續章節展開。
來源:中科芯MCU
審核編輯:湯梓紅
-
mcu
+關注
關注
146文章
17123瀏覽量
350982 -
中斷
+關注
關注
5文章
898瀏覽量
41470 -
定時器
+關注
關注
23文章
3246瀏覽量
114719 -
Timer
+關注
關注
1文章
64瀏覽量
12784
發布評論請先 登錄
相關推薦
評論