高級定時器
高級控制定時器(TIM1 和 TIM8)和通用定時器在基本定時器的基礎上引入了外部引腳,可以實現輸入捕獲和輸出比較功能。
高級控制定時器比通用定時器增加了可編程死區互補輸出、重復計數器、帶剎車(斷路)功能,這些功能都是針對工業電機控制方面。
高級控制定時器時基單元包含:
①16 位自動重裝載寄存器ARR,
②16 位的計數器CNT,可向上/下計數
③16位可編程預分頻器 PSC,預分頻器時鍾源有多種可選,有內部的時鍾、外部時鍾
④還有一個 8 位的重復計數器 RCR,這樣最高可實現 40 位的可編程定時(僅高級定時器獨有)
功能框圖:
高級定時器的定時器的時鍾來源(有四個時鍾來源):
內部時鍾源 CK_INT
外部時鍾模式 1:外部輸入引腳 TIx(x=1,2,3,4)
外部時鍾模式 2:外部觸發輸入 ETR
內部觸發輸入(ITRx)
高級定時器時鍾掛載在APB2上
1)內部時鍾源CK_INT 內部時鍾 CK_INT來自於芯片內部,等於72M(一般情況下,我們都是使用內部時鍾)
對應於寄存器配置位
當從模式控制寄存器 TIMx_SMCR 的 SMS 位等於 000 時,則使用內部時鍾。
2)外部時鍾模式 1:外部輸入引腳 TIx(x=1,2,3,4)
①:時鍾信號輸入引腳
當使用外部時鍾模式 1 的時候,時鍾信號來自於定時器的輸入通道,總共有 4 個,分別為TI1/2/3/4,即TIMx_CH1/2/3/4。具體使用哪一路信號,由TIM_CCMRx的位CCxS[1:0]配置,其中 CCMR1 控制 TI1/2,CCMR2 控制 TI3/4。
②:濾波器
如果來自外部的時鍾信號的頻率過高或者混雜有高頻干擾信號的話,我們就需要使用濾波器對信號重新采樣,來達到降頻或者去除高頻干擾的目的,具體的由 TIMx_CCMRx的位 ICxF[3:0]配置。
③:邊沿檢測
邊沿檢測的信號來自於濾波器的輸出,在成為觸發信號之前,需要進行邊沿檢測,決定是上升沿有效還是下降沿有效,具體的由 TIMx_CCER的位 CCxP 和 CCxNP 配置。
④:觸發選擇
當使用外部時鍾模式 1時,觸發源有兩個,一個是濾波后的定時器輸入 1(TI1FP1)和濾波后的定時器輸入 2(TI2FP2),具體的由TIMxSMCR 的位 TS[2:0]配置。
⑤:從模式選擇
選定了觸發源信號后,最后我們需把信號連接到 TRGI 引腳,讓觸發信號成為外部時鍾模式1的輸入,最終等於CK_PSC,然后驅動計數器CNT計數。具體的配置TIMx_SMCR的位 SMS[2:0]為 111 即可選擇外部時鍾模式 1。
⑥:使能計數器
經過上面的 5 個步驟之后,最后我們只需使能計數器開始計數,外部時鍾模式 1 的配置就算完成。使能計數器由 TIMx_CR1 的位 CEN 配置。
3)外部時鍾模式 2:外部觸發輸入 ETR
①:時鍾信號輸入引腳
當使用外部時鍾模式 2 的時候,時鍾信號來自於定時器的特定輸入通道 TIMx_ETR,只有 1 個。
②:外部觸發極性
來自 ETR 引腳輸入的信號可以選擇為上升沿或者下降沿有效,具體的由 TIMx_SMCR的位 ETP 配置。
③:外部觸發預分頻器
由於ETRP 的信號的頻率不能超過 TIMx_CLK(72M)的 1/4,當觸發信號的頻率很高的情況下,就必須使用分頻器來降頻,具體的由 TIMx_SMCR 的位 ETPS[1:0]配置。
④:濾波器
如果 ETRP 的信號的頻率過高或者混雜有高頻干擾信號的話,我們就需要使用濾波器對 ETRP 信號重新采樣,來達到降頻或者去除高頻干擾的目的。具體的由 TIMx_SMCR 的位 ETF[3:0]配置,其中的 fDTS 是由內部時鍾 CK_INT 分頻得到,具體的由 TIMx_CR1的位CKD[1:0]配置。
⑤:從模式選擇
經過濾波器濾波的信號連接到ETRF引腳后,觸發信號成為外部時鍾模式2的輸入,最終等於CK_PSC,然后驅動計數器 CNT 計數。具體的配置TIMx_SMCR 的位 ECE 為 1 即可選擇外部時鍾模式 2。
⑥:使能計數器
經過上面的 5 個步驟之后,最后我們只需使能計數器開始計數,外部時鍾模式 2 的配置就算完成。使能計數器由 TIMx_CR1 的位 CEN 配置。
4)內部觸發輸入
內部觸發輸入是使用一個定時器作為另一個定時器的預分頻器。硬件上高級控制定時器和通用定時器在內部連接在一起,可以實現定時器同步或級聯。主模式的定時器可以對從模式定時器執行復位、啟動、停止或提供時鍾。
控制器:
高級控制定時器控制器部分包括觸發控制器、從模式控制器以及編碼器接口。觸發控制器用來針對片內外設輸出觸發信號,比如為其它定時器提供時鍾和觸發 DAC/ADC 轉換。 編碼器接口專門針對編碼器計數而設計。從模式控制器可以控制計數器復位、啟動、遞增/遞減、計數。
時基單元:
高級控制定時器時基單元功能包括四個寄存器,分別是計數器寄存器(CNT)、預分頻器寄存器(PSC)、自動重載寄存器(ARR)和重復計數器寄存器(RCR)。
預分頻器 PSC
預分頻器 PSC,有一個輸入時鍾 CK_PSC 和一個輸出時鍾 CK_CNT。輸入時鍾CK_PSC 就是上面時鍾源的輸出,輸出 CK_CNT 則用來驅動計數器 CNT 計數。通過設置預分頻器 PSC 的值可以得到不同的 CK_CNT,實際計算為:f CK_CNT 等於 f CK_PSC /(PSC[15:0]+1),可以實現 1 至 65536 分頻。
計數器 CNT
高級控制定時器的計數器有三種計數模式,分別為遞增計數模式、遞減計數模式和遞增/遞減(中心對齊)計數模式。
(1) 遞增計數模式下,計數器從 0 開始計數,每來一個 CK_CNT 脈沖計數器就增加 1,直到計數器的值與自動重載寄存器 ARR 值相等,然后計數器又從 0 開始計數並生成計數器上溢事件,計數器總是如此循環計數。如果禁用重復計數器,在計數器生成上溢事件就馬上生成更新事件(UEV);如果使能重復計數器,每生成一次上溢事件重復計數器內容就減 1,直到重復計數器內容為 0 時才會生成更新事件。
(2) 遞減計數模式下,計數器從自動重載寄存器 ARR 值開始計數,每來一個 CK_CNT 脈沖計數器就減 1,直到計數器值為 0,然后計數器又從自動重載寄存器 ARR 值開始遞減計數並生成計數器下溢事件,計數器總是如此循環計數。如果禁用重復計數器,計數器生成下溢事件就馬上生成更新事件;如果使能重復計數器,每生成一次下溢事件重復計數器內容就減 1,直到重復計數器內容為 0 時才會生成更新事件。
(3) 中心對齊模式下,計數器從 0 開始遞增計數,直到計數值等於(ARR-1)值生成計數器上溢事件,然后從 ARR 值開始遞減計數直到 1 生成計數器下溢事件。然后又從 0 開始計數,如此循環。每次發生計數器上溢和下溢事件都會生成更新事件。
自動重載寄存器 ARR
自動重載寄存器 ARR 用來存放與計數器 CNT 比較的值,如果兩個值相等就遞減重復計數器。可以通過 TIMx_CR1寄存器的 ARPE位控制自動重載影子寄存器功能
如果 ARPE位置 1,自動重載影子寄存器有效,只有在事件更新時才把 TIMx_ARR 值賦給影子寄存器。
如果 ARPE 位為 0,則修改 TIMx_ARR 值馬上有效。
重復計數器 RCR
在基本/通用定時器發生上/下溢事件時直接就生成更新事件,但對於高級控制定時器卻不是這樣,高級控制定時器在硬件結構上多出了重復計數器,在定時器發生上溢或下溢事件是遞減重復計數器的值,只有當重復計數器為 0 時才會生成更新事件。在發生 N+1 個上溢或下溢事件(N 為 RCR 的值)時產生更新事件。
輸入捕獲功能:
可以對輸入的信號的上升沿,下降沿或者雙邊沿進行捕獲。
1)測量輸入信號的脈寬
2)測量PWM輸入信號的頻率和占空比
輸入捕獲的大概的原理:
當捕獲到信號的跳變沿的時候,把計數器 CNT 的值鎖存到捕獲寄存器 CCR 中,把前后兩次捕獲到的 CCR 寄存器中的值相減,就可以算出脈寬或者頻率。(如果捕獲的脈寬的時間長度>你的捕獲定時器的周期,就會發生溢出,這個需要做額外的處理)
①輸入通道(脈沖信號輸入)
需要被測量的信號從定時器的外部引腳 TIMx_CH1/2/3/4 進入,通常叫 TI1/2/3/4
②輸入濾波器和邊沿檢測器
當輸入的信號存在高頻干擾的時候,我們需要對輸入信號進行濾波,即進行重新采樣,根據采樣定律,采樣的頻率必須大於等於兩倍的輸入信號。比如輸入的信號為 1M,又存在高頻的信號干擾,那么此時就很有必要進行濾波,我們可以設置采樣頻率為 2M,這樣可以在保證采樣到有效信號的基礎上把高於 2M 的高頻干擾信號過濾掉。 濾波器的配置由 CR1 寄存器的位 CKD[1:0]和 CCMR1/2 的位 ICxF[3:0]控制。從 ICxF位的描述可知,采樣頻率 f SAMPLE 可以由 f CK_INT 和 f DTS 分頻后的時鍾提供,其中是 f CK_INT 內部時鍾,f DTS 是 f CK_INT 經過分頻后得到的頻率,分頻因子由 CKD[1:0]決定,可以是不分頻,2 分頻或者是 4 分頻。
邊沿檢測器用來設置信號在捕獲的時候是什么邊沿有效,可以是上升沿,下降沿,或者是雙邊沿,具體的由 CCER 寄存器的位 CCxP 和 CCxNP 決定。
③捕獲通道
捕獲通道就是圖中的 IC1/2/3/4,每個捕獲通道都有相對應的捕獲寄存器 CCR1/2/3/4,當發生捕獲的時候,計數器 CNT 的值就會被鎖存到捕獲寄存器中。
輸入通道和捕獲通道的區別:輸入通道是用來輸入信號的,捕獲通道是用來捕獲輸入信號的通道,一個輸入通道的信號可以同時輸入給兩個捕獲通道。比如輸入通道 TI1 的信號經過濾波邊沿檢測器之后的 TI1FP1 和 TI1FP2 可以進入到捕獲通道 IC1和 IC2,其實這就是我們后面要講的 PWM 輸入捕獲,只有一路輸入信號(TI1)卻占用了兩個捕獲通道(IC1 和 IC2)。當只需要測量輸入信號的脈寬時候,用一個捕獲通道即可。輸入通道和捕獲通道的映射關系具體由寄存器 CCMRx 的位 CCxS[1:0]配置。
④預分頻器
ICx 的輸出信號會經過一個預分頻器,用於決定發生多少個事件時進行一次捕獲。具體的由寄存器 CCMRx 的位 ICxPSC 配置,如果希望捕獲信號的每一個邊沿,則不分頻。
⑤捕獲寄存器
經過預分頻器的信號 ICxPS 是最終被捕獲的信號,當發生捕獲時(第一次),計數器CNT 的值會被鎖存到捕獲寄存器 CCR 中,還會產生 CCxI 中斷,相應的中斷位 CCxIF(在SR 寄存器中)會被置位,通過軟件或者讀取 CCR 中的值可以將 CCxIF清 0。如果發生第二次捕獲(即重復捕獲:CCR 寄存器中已捕獲到計數器值且 CCxIF 標志已置 1),則捕獲溢出標志位 CCxOF(在 SR 寄存器中)會被置位,CCxOF 只能通過軟件清零。
輸出比較功能:
輸出比較就是通過定時器的外部引腳對外輸出控制信號,有凍結、將通道 X(x=1,2,3,4)設置為匹配時輸出有效電平、無效電平、翻轉、強制變為無效電平、強制變為有效電平、PWM1 和 PWM2 這八種模式,具體使用哪種模式由寄存器 CCMRx 的位 OCxM[2:0]配置。其中 PWM 模式是輸出比較中的特例,使用的也最多。
①比較寄存器
當計數器 CNT 的值跟比較寄存器 CCR 的值相等的時候,輸出參考信號 OCxREF 的信號的極性就會改變,其中 OCxREF=1(高電平)稱之為有效電平,OCxREF=0(低電平)稱之為無效電平,並且會產生比較中斷 CCxI,相應的標志位 CCxIF(SR 寄存器中)會置位。然后 OCxREF 再經過一系列的控制之后就成為真正的輸出信號 OCx/OCxN。
②死區發生器
在生成的參考波形 OCxREF 的基礎上,可以插入死區時間,用於生成兩路互補的輸出信號 OCx 和 OCxN,死區時間的大小具體由 BDTR 寄存器的位 DTG[7:0]配置。死區時間的大小必須根據與輸出信號相連接的器件及其特性來調整。
MOS開關和關閉需要時間-->(由 MOS 管的工藝決定)
在這個半橋驅動電路中,如果想讓 Q1 截止 Q2 導通,要先讓Q1 截止一段時間之后,再等一段時間才讓 Q2 導通,那么這段等待的時間就稱為死區時間,如果 Q1 關閉之后,馬上打開 Q2,那么此時一段時間內相當於 Q1 和 Q2 都導通了,這樣電路會短路。
針對上面的半橋驅動電路而畫的帶死區插入的 PWM 信號,圖中的死區時間要根據 MOS 管的工藝來調節:
③輸出控制
在輸出比較的輸出控制中,參考信號OCxREF在經過死區發生器之后會產生兩路帶死區的互補信號 OCx_DT 和 OCxN_DT(通道 1~3 才有互補信號,通道4沒有,其余跟通道1~3 一樣),這兩路帶死區的互補信號然后就進入輸出控制電路,如果沒有加入死區控制,那么進入輸出控制電路的信號就直接是OCxREF。
進入輸出控制電路的信號會被分成兩路,一路是原始信號,一路是被反向的信號,具體的由寄存器 CCER 的位 CCxP 和 CCxNP 控制。經過極性選擇的信號是否由 OCx 引腳輸出到外部引腳 CHx/CHxN 則由寄存器 CCER 的位 CxE/CxNE 配置。 如果加入了斷路(剎車)功能,則斷路和死區寄存器 BDTR 的 MOE、OSSI和 OSSR 這三個位會共同影響輸出的信號。
④輸出引腳
輸出比較的輸出信號最終是通過定時器的外部 IO 來輸出的,分別為 CH1/2/3/4,其中前面三個通道還有互補的輸出通道 CH1/2/3N。
斷路功能: 就是電機控制的剎車功能。
使能斷路功能時,根據相關控制位狀態修改輸出信號電平。在任何情況下,OCx 和 OCxN 輸出都不能同時為有效電平,這關系到電機控制常用的 H 橋電路結構原因。
斷路源可以是時鍾故障事件,由內部復位時鍾控制器中的時鍾安全系統(CSS)生成,也可以是外部斷路輸入 IO,兩者是或運算關系。 系統復位啟動都默認關閉斷路功能,將斷路和死區寄存器(TIMx_BDTR)的 BKE 為置 1,使能斷路功能。可通過 TIMx_BDTR 寄存器的 BKP 位設置設置斷路輸入引腳的有效電平,設置為 1 時輸入 BRK 為高電平有效,否則低電平有效。
發送斷路時,將產生以下效果:
①TIMx_BDTR寄存器中主輸出模式使能(MOE)位被清零,輸出處於無效、空閑或復位狀態;
②根據相關控制位狀態控制輸出通道引腳電平;當使能通道互補輸出時,會根據情況自動控制輸出通道電平;
③將TIMx_SR寄存器中的BIF位置 1,並可產生中斷和DMA傳輸請求。
④如果TIMx_BDTR寄存器中的自動輸出使能(AOE)位置1,則MOE位會在發生下一個UEV事件時自動再次置 1。
結構體:
時基結構體
1 1 typedef struct 2 2 { 3 3 uint16_t TIM_Prescaler; //16位 預分頻值 4 4 uint16_t TIM_CounterMode; //計數模式(向上、向下...) 基本定時器只能向上,故不用設置 5 5 uint16_t TIM_Period; //16位 定時器周期 ARR自動重裝值 6 6 uint16_t TIM_ClockDivision; //時鍾分頻 設置定時器時鍾 CK_INT 頻率與數字濾波器采樣時鍾頻率分頻比,基本定時器沒有此功能,不用設置 7 7 uint8_t TIM_RepetitionCounter; //重復計數器,只有TIM1和TIM8才有 利用它可以非常容易控制輸出 PWM 的個數 8 8 9 9 } TIM_TimeBaseInitTypeDef;
輸出比較結構體
1 typedef struct 2 { 3 uint16_t TIM_OCMode; //比較輸出模式選擇,總共有八種,常用的為 PWM1/PWM2。它設定CCMRx 寄存器 OCxM[2:0]位的值 4 uint16_t TIM_OutputState; //比較輸出使能,決定最終的輸出比較信號 OCx 是否通過外部引腳輸出 5 uint16_t TIM_OutputNState; //比較互補輸出使能,決定 OCx 的互補信號 OCxN 是否通過外部引腳輸出 6 uint16_t TIM_Pulse; //比較輸出脈沖寬度,實際設定比較寄存器 CCR 的值,決定脈沖寬度。可設置范圍為 0 至 65535 7 uint16_t TIM_OCPolarity; //比較輸出極性,可選 OCx 為高電平有效或低電平有效。它決定着定時器通道有效電平 8 uint16_t TIM_OCNPolarity; // 比較互補輸出極性,可選 OCxN 為高電平有效或低電平有效 9 uint16_t TIM_OCIdleState; //空閑狀態時通道輸出電平設置,可選輸出 1 或輸出 0 10 uint16_t TIM_OCNIdleState; //空閑狀態時互補通道輸出電平設置,可選輸出 1 或輸出 0 11 } TIM_OCInitTypeDef;
帶死區和剎車功能的互補輸出實驗:
1 void PWM_OC_IN(void) 2 { 3 GPIO_InitTypeDef GPIO_InitStructure; 4 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 5 TIM_OCInitTypeDef TIM_OCInitStructure; 6 TIM_BDTRInitTypeDef TIM_BDTRInitStructure; 7 8 9 //時鍾配置 10 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);// 默認復用 11 12 13 //復用管腳配置--輸出比較通道 14 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; 15 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出模式 16 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //輸出速度頻率 17 GPIO_Init(GPIOA, &GPIO_InitStructure); //GPIOA 18 19 //輸出比較通道互補通道初始化 20 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; 21 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出模式 22 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //輸出速度頻率 23 GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB 24 25 //輸出比較通道剎車通道 26 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; 27 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出模式 28 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //輸出速度頻率 29 GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB 30 GPIO_ResetBits(GPIOB,GPIO_Pin_12);//默認輸出低電平 31 32 33 //時基配置 34 TIM_TimeBaseStructure.TIM_Prescaler = 0; //預分頻 --72MHZ來驅動 35 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計數模式 36 TIM_TimeBaseStructure.TIM_Period = 7199; //TimerPeriod; //ARR (占空比CCR/AAR)10kHz 37 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //定時器濾波,通常為0,這里死區時間用到 38 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;//配置寄存器TIM_RCR(重復次數寄存器) 39 TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); 40 41 42 43 //輸出比較功能配置 44 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //pwm1模式 45 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比較輸出使能 46 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;//比較輸出互補輸出使能 47 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//!!!!!!高電平有效!!!!! 48 TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;//!!!!!!高電平有效!!!!! 49 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;//經死區后輸出高電平 50 TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;//經死區后輸出低電平 51 TIM_OCInitStructure.TIM_Pulse = 1500; //Channel1Pulse(CCR); 52 TIM_OC1Init(TIM1, &TIM_OCInitStructure); //通道1 53 54 //使能TIM的ARR和CRR,以及使能TIM定時器,開啟pwm輸出 55 TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIM1的寄存器ARR的預裝載功能,disable時將會使改變ARR值時立即生效 56 TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //使能TIM1通道1的CCR的預裝載功能,disable時將會使改變CRR值時立即生效 57 58 59 //剎車和死區結構體初始化 60 TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;//運行狀態下關閉狀態選擇 61 TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;//空閑狀態下關閉狀態選擇 62 TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;//鎖定配置級別 63 TIM_BDTRInitStructure.TIM_DeadTime = 11; //輸出比較信號死區時間配置,具體如何計算可參考BDTR:UTG[7:0]的描述 64 //這里配置的死區時間為152ns 65 TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;//斷路控制使能 66 //當BKIN引腳--PB12檢測到高電平時,輸出比較信號被禁止,就好像是剎車一樣 67 TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;//斷路輸入極性-高電平 68 TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;//自動輸出使能 69 TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); 70 71 72 TIM_Cmd(TIM1, ENABLE);//計數使能 73 TIM_CtrlPWMOutputs(TIM1, ENABLE);//主輸出使能,當使用的是通用定時器時,這句話不要 74 75 }
輸出捕獲實驗:
1 /******************************************************************* 2 *@使用TIM5的輸入捕獲功能進行按鍵按下的時間---高電平的時間(按鍵下拉) 3 *@輸入捕獲引腳--PA0 5 *@注意:這里的溢出中斷和捕獲中斷屬於不同的兩個中斷 8 *******************************************************************/ 9 10 11 //定時器輸入捕獲用戶自定義變量結構體聲明 12 typedef struct 13 { 14 u8 Capture_FinishFlag; //捕獲結束標志位 15 u8 Capture_StartFlag; //捕獲開始標志位 16 u16 Capture_CcrValue; //捕獲寄存器的值 17 u16 Capture_Period; //自動重裝載寄存器更新標志 18 }TIM_ICUserValueTypeDef; 20 TIM_ICUserValueTypeDef TIM_ICUserValueStructure;//結構體初始化 21 22 void GET_PluseWidth(void) 23 { 24 GPIO_InitTypeDef GPIO_InitStructure; 25 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 26 TIM_ICInitTypeDef TIM_ICInitStructure; 27 NVIC_InitTypeDef NVIC_InitStructure; 28 29 //RCC configuration 30 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); 31 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); 32 33 //GPIO configuration 34 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 35 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入模式 36 GPIO_Init(GPIOA, &GPIO_InitStructure); //GPIOA 37 38 39 //值得注意的是input capture period(1us*(65535+1)=65.536ms) > 捕獲脈寬的時間,當小於時會溢出,需額外處理 40 TIM_TimeBaseStructure.TIM_Prescaler = 72-1; //預分頻 --1MHZ來驅動 41 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計數模式 42 TIM_TimeBaseStructure.TIM_Period =0xFFFF; //TimerPeriod; //ARR 43 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //定時器濾波,通常為0 44 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;//配置寄存器TIM_RCR(重復次數寄存器) 45 TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); 46 47 //中斷優先級配置 48 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); 49 NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; 50 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0; 51 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //響應優先級 52 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 53 NVIC_Init(&NVIC_InitStructure); 54 55 56 TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//輸入捕獲的通道,由具體的GPIO來配置 57 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//捕獲信號極性配置 58 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//輸入通道與捕獲通道的映射關系,有直連和非直連 59 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//輸入的需要被捕獲的信號的分頻系數 60 TIM_ICInitStructure.TIM_ICFilter = 0x0;//輸入的需要被捕獲的信號的濾波系數 61 TIM_ICInit(TIM5, &TIM_ICInitStructure); 62 63 TIM_ClearFlag(TIM5, TIM_FLAG_Update|TIM_FLAG_CC1);//清除TIM5的更新標志位和捕獲標志位 64 TIM_ITConfig(TIM5, TIM_IT_Update|TIM_IT_CC1, ENABLE);//開啟更新中斷和捕獲中斷 65 66 TIM_Cmd(TIM5, ENABLE); 67 } 68 69 //中斷服務函數 70 void TIM5_IRQHandler(void) 71 { 72 //被捕獲的信號周期大於定時器的最長定時時,定時器就會溢出,產生更新中斷 73 //特殊處理;把這個最長的定時周期加到捕獲信號的時間里面去 74 if(TIM_GetITStatus(TIM5,TIM_IT_Updata) != RESET)//產生中斷 75 { 76 TIM_ICUserValueStructure.Capture_Period ++; 77 TIM_ClearITPendingBit(TIM5,TIM_FLAG_Update); //清中斷標志位 78 } 79 80 //第一次捕獲中斷 81 if(TIM_GetITStatus(TIM5,TIM_IT_CC1)!=RESET)//產生捕獲中斷 82 { 83 if(TIM_ICUserValueStructure.Capture_StartFlag ==0) 84 { 85 TIM_SetCounter(TIM5,0);//計數器清0 86 TIM_ICUserValueStructure.Capture_Period =0;//自動重裝載寄存器更新標志清零 87 TIM_ICUserValueStructure.Capture_CcrValue =0;//捕獲比較寄存器的值的變量清0 88 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);//當第一次捕獲到上升沿時,就把捕獲邊沿配置為下降沿 89 TIM_ICUserValueStructure.Capture_StartFlag =1; //開始捕獲標志位置1 90 } 91 else//第二次捕獲 92 { 93 //獲取捕獲比較寄存器的值,這個值就是捕獲到的高電平的時間的值 94 TIM_ICUserValueStructure.Capture_CcrValue =TIM_GetCapture1(TIM5); 95 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising);//當第二次捕獲到下降沿時,就把捕獲邊沿配置為上升沿,進行新一輪捕獲 96 TIM_ICUserValueStructure.Capture_StartFlag =0;//開始捕獲標志位置0 97 TIM_ICUserValueStructure.Capture_FinishFlag =1;//捕獲完成標志位置1 98 } 99 TIM_ClearITPendingBit(TIM5,TIM_IT_CC1); //清中斷標志位 100 } 101 }
main:
1 int main(void) 2 { 3 u32 time; 4 u32 TIM_Psclk =72000000/72; 5 Usart_init();//初始化串口 6 GET_PluseWidth();//初始化定時器5 7 8 while(1) 9 { 10 if(TIM_ICUserValueStructure.Capture_FinishFlag ==1) 11 { 12 time = TIM_ICUserValueStructure.Capture_Period *(0xFFFF+1) + (TIM_ICUserValueStructure.Capture_CcrValue +1);//計算高電平的計數器值 13 printf("測得按下的時間:%d.%d\n",time/TIM_Psclk,time%Psclk);//打印高電平脈寬時間 14 15 TIM_ICUserValueStructure.Capture_FinishFlag =0; 16 } 17 } 19 }