STM32F103ZET6通用定時器


 1、通用定時器簡介 

  通用定時器是由一個可編程預分頻器驅動的16位自動裝載計數器構成。通用定時器可以應用於多種場合,如測量輸入信號的脈沖長度(輸入捕獲)或者產生輸出波形(輸出比較和PWM)。使用通用定時器的預分頻器和RCC時鍾控制器的預分頻器,脈沖長度和輸出波形周期可以在幾個微秒到幾個毫秒間調整。

  STM32內有多個通用定時器,每個通用定時器都是完全獨立的,沒有互相共享任何資源。

  通用定時器的主要功能包括:

  16位向上、向下、向上/向下自動裝載計數器。

  16位可編程(可以實時修改)預分頻器,計數器時鍾頻率的分頻系數為1~65536之間的任意數值。

  4個獨立通道可以實現4路:輸入捕獲、輸出比較、PWM輸出、單脈沖模式輸出。

  使用外部信號控制定時器和定時器互連的同步電路。

  支持針對定位的增量(正交)編碼器和霍爾傳感器電路。

  通用定時器框圖如下:

2、通用定時器的時基單元

  通用定時器的時基單元主要由一個16位計數器和與其相關的自動裝載寄存器。這個計數器可以向上計數、向下計數或者向上向下雙向計數。通用定時器的計數器的時鍾由預分頻器分頻得到,至於預分頻器之前的時鍾在時鍾選擇的時候回說到。

  通用定時器的計數器、自動裝載寄存器和預分頻器寄存器可以由軟件讀寫,在計數器運行時仍可以讀寫。

  如下圖紅色框部分就是通用定時器的時基部分:

 

  時基單元包含:

  CNT計數器(TIMx_CNT)。

  PSC預分頻器(TIMx_PSC)。

  自動重裝載寄存器(TIMx_ARR)。

  CNT 計數器和自動重裝載寄存器:

  TIMx_ARR寄存器是預先裝載的,寫或讀TIMX_ARR寄存器將訪問預裝載寄存器。通用定時器根據TIMx_CR1寄存器中的ARPE位,來決定寫入TIMx_ARR寄存器的值是立即生效還是要等到更新事件(溢出)后才生效。在計數器運行的過程中,ARPE位的作用如下:

  當ARPE = 0時,寫入TIMx_ARR寄存器的值立即生效,即TIMx_CNT計數器的計數范圍立馬更新。其時序圖如下:

 

  當ARPE = 1時,寫入TIMx_ARR寄存器的值不會立馬生效,TIMx_CNT計數器的計數范圍還是跟原來一樣,等到TIMx_CNT計數溢出的時候,寫入TIMx_ARR寄存器的值才生效,即溢出之后TIMx_CNT計數器的計數范圍才會更新。其時序圖如下:

 

  從圖中可以到,計數器TIMx_CNT由預分頻器輸出的CK_CNT時鍾驅動,只有當設置了TIMx_CR1寄存器中的計數器使能位CEN時,CK_CNT才有效,而且真正的計數器使能信號是在CEN位被置位后的一個是時鍾周期。

  PSC預分頻器:

  在通用定時器框圖中,PSC預分頻器的時鍾來源是CK_PSC,預分頻器可以將CK_PSC的時鍾頻率按1到65536之間的任意值分頻,然后將分頻后的時鍾CK_CNT輸出到CNT計數器,來用驅動CNT計數器計數。

  預分頻由16位的TIMx_PSC寄存器控制,TIMx_PSC寄存器是自帶緩沖器,TIMx_PSC寄存器能在計數器計數的過程中被改變,但是新的預分頻器參數只有到下一次溢出之后才被更新。

  要注意,由於TIMx_PSC寄存器帶有緩沖功能,在初始化給TIMx_PSC賦值的時候,預分頻器的系數是不會立馬生效的,必須要等到溢出之后才會更新預分頻器的系數。比如說IC上電時,給TIMx_PSC賦值4(即5分頻),但是定時器剛開始運行時的預分頻系數其實還是0(即1分頻),只有當TIMx_CNT計數溢出一次之后,預分頻系數才會更新為4(即5分頻),如果需要立即更新預分頻器的系數,可以將TIMx_EGR的bit0位UG置位,這樣將產生一個更新事件,計數器會被清0,而且預分頻系數會被更新,但是這時候如果開啟了中斷,就會進入一次中斷。

  如果開啟了中斷,在置位UG位時,不想進入中斷,則可以置位TIMx_CR1寄存器中的UDIS位,置位UDIS位,可以禁止更新事件,但是當計數器溢出時,預分頻器系數還是會更新,計數器也會清0,只是不會置位UIF標志,即不會進入中斷。

  如下圖是在計數器計數的過程中,改變預分頻器的值的時序圖:

  在圖中,當計數器計數到F8時,將TIMx_PSC寄存器的值從0改到3,即1分頻改到4分頻,當計數到F9的時候,預分頻器使用的參數還是0,即還是1分頻沒有變,只有當計數器寄存器溢出清0之后,預分頻器使用的參數才是3,即變為4分頻。

  在圖中,CK_PSC是預分頻器的輸入時鍾,CEN是定時器的使能信號,計數器寄存器就是TIMx_CNT,更新事件(UEV)是溢出。預分頻控制寄存器是TIMx_PSC,預分頻緩沖器是看不見到的。

  通用定時器可以通過TIMx_CR1寄存器中的UDIS位禁止更新事件(即產生溢出中斷),但是UDIS只是禁止更新事件並不會停止定時器的計數器工作,計數器溢出時還是會更新到TIMx_ARR的數值。UDIS禁止更新事件后,如果更新預分頻器的數值和TIMx_ARR寄存器的數值(ARPE=1),就算計數器溢出也不會更新預分頻器和TIMx_ARR寄存器(ARPE=1)的數值,只有UDIS解除禁止更新事件后,產生更新事件是時才會更新預分頻器和TIMx_ARR寄存器(ARPE=1)的數值。

  當發生一個更新事件(溢出中斷)時,所有的寄存器都被更新,硬件同時置位TIMx_SR寄存器中的更新標志UIF位,同時預分頻器的緩沖區的值被TIMx_PSC寄存器的值更新,而且如果APRE=1,則自動裝載影子寄存器被更改數值后的TIMx_ARR寄存器更新。

  通用定時器的計數器工作模式:

  通用定時器的計數器可以設定為3種工作方式。有向上計數模式、向下計數模式、中央對齊模式(向上/向下計數)。

  向上計數模式:

  在向上計數模式中,定時器的TIMx_CNT寄存器的值從0開始遞增計數,當TIMx_CNT的值等於TIMx_ARR寄存器的值的時候會產生一個溢出信號,計數器清0,重新開始計數。

  每當計數器溢出時就是產生一個更新信號,TIMx_SR寄存器中的溢出標志位會置位,如果使能了溢出中斷,就會進入中斷。

  如下圖是在向上計數模式中,TIMx_PSC = 3(4分頻),TIMx_ARR = 0x36時,定時器的計數時序圖:

  從上圖可以看到,當計數器計數到TIMx_ARR寄存器的值0x36時,計數器溢出,同時產生更新事件(UEV),並且TIMx_SR寄存器的更新中斷標志位UIF被置位。

  向下計數模式:

  在向下計數模式中,定時器的TIMx_CNT從TIMx_ARR寄存器獲取初值,然后從該值向遞減,當減到0時又會從TIMx_ARR寄存器獲取初值並產生一個計數器向下溢出事件。

  如下圖是在向下計數模式中,TIMx_PSC = 2(3分頻),TIMx_ARR = 0x36時,定時器的計數時序圖:

  從上圖可以看到,當計數器計數到0時,計數器溢出,TIMx_ARR的值0x36重新給計數器寄存器賦值,同時產生更新事件(UEV),並且TIMx_SR寄存器的更新中斷標志位UIF被置位。

  中央對齊模式:

  中央對齊模式也稱為向上/向下計數模式,在該模式中,計數器從0開始計數到TIMx_ARR寄存器值-1的數值后產生一個計數器溢出事件,然后向下計數器到1並且產生一個計數器下溢事件,然后計數器再從0開始重新計數。

  在中央對齊模式,不能寫入TIMx_CR1中的DIR方向位,DIR方向位由硬件更新並指示當前的計數器計數的方向。

  如下圖是在中央對齊模式中,TIMx_PSC = 0(1分頻),TIMx_ARR = 0x06時,定時器的計數時序圖:

 

  從上圖可以看到,當計數器從0開始向上計數到0x05時,計數器向上溢出,同時產生更新事件(UEV),並且TIMx_SR寄存器的更新中斷標志位UIF被置位,然后計數器又會從0x06開始向下計數,當計數器的值向下計數到0x01時,計數器向上溢出,同時產生更新事件(UEV),並且TIMx_SR寄存器的更新中斷標志位UIF被置位。也就是說在一個周期內會引發兩次溢出。

3、通用定時器的時鍾選擇

  通用定時器的計數器可以選擇不同的時鍾來源,用來驅動計數器計數。計數器時鍾的來源有以下幾種:

  內部時鍾(CK_INT)。

  外部時鍾模式1:外部輸入腳(TIx)。

  外部時鍾模式2:外部觸發輸入(ETR)。

  內部觸發輸入(ITRx):使用一個定時器作為另一個定時器的預分頻器,如可以配置一個定時器T1而作為另一個定時器T2的預分頻器。

  如下圖紅色框部分就是通用定時器的時鍾選擇框圖:

 

  內部時鍾源(CK_INT):

  從時鍾選擇框圖中可以看到,內部時鍾源(CK_INT)來自RCC的TIMx_CLK,即定時器本身的驅動時鍾。

  當禁止從模式控制器(TIMx_SMCR寄存器的SMS=000),則預分頻的時鍾源CK_PSC由內部時鍾源(CK_INT)驅動。定時器的實際控制位為CEN位、DIR位和UG位,並且只能被軟件修改(UG位仍被自動清除)。只要CEN位被置1,預分頻器的時鍾CK_PSC就由內部時鍾CK_INT提供。  

  通用定時器的內部時鍾來源於APB1總線時鍾,但是通用定時器的內部時鍾是根據APB1總線時鍾是否分頻來決定的,如果APB1總線時鍾預分頻系數為1,則通用定時器的內部時鍾就是APB1總線時鍾;但是如果APB1總線時鍾的分頻系數為2,則通用定時器的內部時鍾就是APB1總線時鍾的2倍。

  下圖顯示了控制電路和向上計數器在一般模式下,不帶預分頻器時(分頻系數為0)的操作。

  如圖所示,只有當CEN位被置位高電平的時候,預分頻器的時鍾CK_PSC和計數器的時鍾CK_CNT才開始工作。

  外部時鍾源模式1:

  如下圖是TI2FP2作為驅動定時器計數器計數的連接示意圖:

 

  如圖,當選擇外部時鍾1驅動計數器時,預分頻器的時鍾來源於TRGI的上升沿。當TIMx_SMCR寄存器的SMS[2:0]位設為“111”時,則選擇外部時鍾模式1作為預分頻器時鍾CK_PSC的輸入源,即選擇TRGI的上升沿驅動計數器。

  從圖中還可以看到,TRGI具有多種輸入源,通過TIMx_SMCR寄存器的TS[2:0]位來選擇,如下:

  當TS[2:0] = 000時,選擇內部觸發0(ITR0,對應TIM1)作為計數器的驅動時鍾。

  當TS[2:0] = 001時,選擇內部觸發1(ITR1,對應TIM12)作為計數器的驅動時鍾。

  當TS[2:0] = 010時,選擇內部觸發2(ITR2,對應TIM3)作為計數器的驅動時鍾。

  當TS[2:0] = 011時,選擇內部觸發3(ITR3,對應TIM4)作為計數器的驅動時鍾。

  當TS[2:0] = 100時,選擇TI1的邊沿檢測器TI1F_ED作為計數器的驅動時鍾。

  當TS[2:0] = 101時,選擇濾波后的定時器輸入TI1FP1作為計數器的驅動時鍾。

  當TS[2:0] = 110時,選擇濾波后的定時器輸入TI2FP2作為計數器的驅動時鍾。

  當TS[2:0] = 111時,選擇外部觸發輸入ETRF作為計數器的驅動時鍾。

  需要注意的是,TS[2:0]位只能在未用到(如SMS=000)時被改變,以避免在改變時產生錯誤的邊沿檢測。

  TRGI在不同模式的作用也不一樣,可以通過TIMx_SMCR寄存器的SMS[2:0]位進行控制。SMS[2:0]位還控制着其他功能,但這里只針對TRGI說明,其它的可以看TIMx_SMCR寄存器,如下:

  當SMS[2:0] = 100時,定時器的工作模式被選為復位模式,當被選中的TRGI輸入上升沿時會重新初始化計數器,並且產生一個更新寄存器的信號。

  當SMS[2:0] = 101時,定時器的工作模式被選為門控模式,當TRGI輸入高電平時,計數器的時鍾開啟(即計數器開始計數),當TRGI輸入變為低電平時,計數器會停止工作,但是計數器不會復位,也就是說在這個模式,計數器的開關收TRGI控制。

  當SMS[2:0] = 110時,定時器的工作模式被選為觸發模式,當TRGI產生一個上升沿的時候,計數器會被觸發並開啟計數,但是計數器只是被觸發啟動,並不會復位,在這個模式,TRGI產生上升沿來開啟計數器,但是不能關閉計數器。

  當SMS[2:0] = 111時,定時器的工作模式被選為外部時鍾模式1,在該模式,計數器是根據TRGI的上升沿來計數的。

  如果要使計數器在TI2輸入端的上升沿計數,即使用TI2FP2作為驅動計數器計數的時鍾源,配置如下:

  配置TIMx_CCMR1寄存器的CC2S=01,將通道2設為輸入,並且映射到TI2上。

  配置TIMx_CCMR1寄存器的IC2F[3:0],選擇輸入濾波器的帶寬,也可以設置成不需要濾波器。

  配置TIMx_CCER寄存器的CC2P=0,使邊沿檢測器識別上升沿。

  配置TIMx_SMCR寄存器的TS=110,選擇TI2FP2作為TRGI的輸入源。

  配置TIMx_SMCR寄存器的SMS=111,選擇外部時鍾模式1作為定時器的時鍾來源。

  設置TIMx_CR寄存器的CEN=1,啟動定時器的計數器開始工作。

  配置完之后,當通道2的腳位輸入上升沿的時候,計數器會計數一次,並且TIMx_SR寄存器的TIF位會被置位。需要注意的是TIF需要軟件清除,如下圖是外部時鍾模式1的控制時序:

 

  從圖中看到,每當TI2產生一次上升沿的時候,計數器就會計數一次,但是TI2產生上升沿到計數器計數之間是有一定的延時的,這個延時時間取決於TI2輸入端的重新同步電路。

  用STM32F103ZET6的代碼來說明外部時鍾模式1,使用通用定時器TIM3的通道2來驅動TIM3計數器計數,TIM3的通道2對應的腳位是PA7,用一個IO口與PA7相連,這里用PF6口,實現當PF6產生一個上升沿的時候,TIM3的計數器就會計數一次。代碼如下:

 1 //外部時鍾模式1代碼
 2 void TIM3_TEST(void)  3 {
 5     RCC->APB2ENR |= 1<<2;   //開啟GPIOA的時鍾
 6     RCC->APB2ENR |= 1<<7;   //開啟GPIOF的時鍾
 7     
 8     RCC->APB1ENR |= 1<<1;   //開啟TIM3的時鍾 
 9     
10     GPIOA->CRL &= 0x0FFFFFFF; 11     GPIOA->CRL |= 0x80000000;//設置GPIOA7為輸入
12     GPIOA->ODR &= ~(1<<7);//開啟GPIOA7的下拉
13        
14     TIM3->PSC = 0;//設置TIM3的預分頻器系數為1分頻
15     TIM3->ARR = 10;//設置TIM3的自動重載值為10
16     TIM3->CNT = 0;//清除計數器的值
17     
18     TIM3->CR1 &= ~(0x03<<5);//配置CMS=00,選擇定時器的計數模式為邊沿模式
19         
20     TIM3->CR1 &= ~(1<<4);//配置DIR=0,選擇定時器的計數方向為向上計數 
21     
22     TIM3->CCMR1 &= ~(0x03<<8); 23     TIM3->CCMR1 |= (0x01<<8); //配置CC2S = 01,設置CC2通道為輸入,IC2映射到TI2上
24     
25     TIM3->CCMR1 &= ~(0x0F<<12);//配置IC2F = 000,使通道2的濾波為無濾波。
26 
27     TIM3->CCMR1 &= ~(0x03<<10);//配置IC2PSC = 00,使通道2的輸入預分頻系數為不分頻
28     
29     TIM3->CCER &= ~(1<<5);//配置CC2P = 0,選擇捕獲通道2的上升沿
30 
31     TIM3->SMCR &= ~(0x07<<4); 32     TIM3->SMCR |= (0x06<<4);//配置TS=110,選擇濾波后的定時器輸入TI2FP2作為外部時鍾模式1的時鍾
33     
34     TIM3->SMCR &= ~(0x07<<0); 35     TIM3->SMCR |= (0x07<<0);//配置SMS=111,選擇外部時鍾模式1作為定時器計數器的驅動 
36     
38     TIM3->CR1 |= (1<<0);//配置CEN=1,啟動定時器工作
39 }

  還需要配置GPIOF6口為輸出,這里沒有列出來,可以通過一個按鍵控制GPIOF6的的輸出,當按鍵按下的時候,讓GPIOF6輸出一個高脈沖,因為GPIOF6與GPIOA7相連,每當GPIOF6輸出一個高電平,GPIOA7就會產生一個上升沿,這時候TIM3_CNT的值就會加1,當TIM3_CNT遞增超過TIM3_ARR的值時,就會產生溢出從而使TIM3_CNT重新初始化。

  外部時鍾源模式2:

  通用定時器除了具有4個通道的輸入/輸出腳之外,還有一個ETR引腳,這個ETR引腳是外部時鍾源模式2的輸入腳位,如下圖是外部時鍾源模式2的示意圖:

  ETR腳位是外部時鍾模式2的輸入源。

  TIMx_SMCR寄存器的bit15的ETP位決定ETR引腳是上升沿觸發還是下降沿觸發。

  TIMx_SMCR寄存器的bit13~bit12的ETPS[1:0]位決定觸發信號的分頻系數。

  TIMx_SMCR寄存器的bit11~bit8的ETF[3:0]位決定對ETR信號采樣的頻率和數字濾波的帶寬。

  TIMx_SMCR寄存器的bit14的ECE位用來使能外部時鍾模式2,使得計數器由ERTF信號上的任意有效邊沿驅動。

  如要讓計數器在ETR腳位每產生2個上升沿計數一次,可以同如下配置:

  配置TIMx_SMCR寄存器中的ETF[3:0]=000,選擇不濾波。

  配置TIMx_SMCR寄存器的ETPS[1:0]=01,選擇2分頻。

  配置TIMx_SMCR寄存器的ETP=0,選擇上升沿觸發。

  配置TIMx_SMCR寄存器的ECE=1,開啟外部時鍾模式2.

  置位TIMx_CR1寄存器中的CEN位,啟動計數器。

  工作時序如下:

 

  從圖中可以看到,ETR產生兩個上升沿的時候,計數器才計數一次。

  配置TIM3的定時器的時鍾源為外部時鍾源模式2,讓計數器在ETR腳位每產生一次上升沿時就計數一次,TIM3定時器的ETR腳對應的IO是GPIOD2,代碼如下:

 1 void TIM3_TEST(void)  2 {  3     RCC->APB2ENR |= 1<<5;   //開啟GPIOD的時鍾
 4     RCC->APB2ENR |= 1<<7;   //開啟GPIOF的時鍾
 5     
 6     RCC->APB1ENR |= 1<<1;   //開啟TIM3的時鍾 
 7     
 8     GPIOD->CRL &= 0xFFFFF0FF;  9     GPIOD->CRL |= 0x00000800;//設置GPIOD2為輸入
10     GPIOD->ODR &= ~(1<<2);//開啟GPIOD2的下拉
11        
12     TIM3->PSC = 0;//設置TIM3的預分頻器系數為1分頻
13     TIM3->ARR = 10;//設置TIM3的自動重載值為10
14     TIM3->CNT = 0;//清除計數器的值
15     
16     TIM3->CR1 &= ~(0x03<<5);//配置CMS=00,選擇定時器的計數模式為邊沿模式
17         
18     TIM3->CR1 &= ~(1<<4);//配置DIR=0,選擇定時器的計數方向為向上計數 
19 
20     TIM3->SMCR &= ~(0x0F<<8); 21     TIM3->SMCR |= (0x00<<8);//配置ETF=0000,選擇外部觸發濾波為無濾波器
22     
23     TIM3->SMCR &= ~(0x03<<12); 24     TIM3->SMCR |= (0x01<<12);//配置ETPS=00,選擇外部觸發預分頻為關閉預分頻器 
25     
26     TIM3->SMCR &= ~(1<<15);//配置ETP=0,選擇ETR不反相,上升沿觸發 
27     
28     TIM3->SMCR |= (1<<14);//配置ECE=1,使能外部時鍾源模式2
29          
30     TIM3->CR1 |= (1<<0);//配置CEN=1,啟動定時器工作
31 }

  可以讓一個IO口與GPIOD2相連,然后每隔一段時間讓這個IO口輸出一個高脈沖,查看TIM3_CNT的值是否有變化。

4、通用定時器的工作模式

   輸入捕獲模式:

  關於輸入捕獲模式,可以查看:https://www.cnblogs.com/h1019384803/p/11297118.html    

  PWM輸入模式:

  通用定時器在該模式下可以捕獲PWM的周期和占空比。

  由於在PWM輸入模式下,需要用到從模式控制器,但是只有TI1FP1和TI2FP2連接到了從模式控制器,所以PWM輸入模式只能使用TIMx_CH1和TIMx_CH2信號。

  在PWM輸入模式中,兩個ICx信號被映射值同一個TIx輸入。這兩個ICx信號的邊沿信號設置為極性相反。

  因為一個通道可以產生兩個信號供給不同的輸入源,比如TI1可以產生TI1FP1和TI1FP2,這兩個信號是一樣的,只是輸出的方向不一樣。

  比如要測量輸入到TI1FP上的PWM周期和占空比,它的大概工作原理是,將通道1和通道2同時映射到TI1上,這樣TI1FP1作為通道1的輸入源,TI1FP2作為通道2的輸入源。同時設置通道1為上升沿觸發捕獲,通道2為下降沿觸發捕獲。

  從外部時鍾模式1中的介紹可以知道,TI1FP1可以作為TRQI的輸入源,而TRGI在從模式中的復位模式下產生上升沿會重新初始化計數器,並產生一個更新寄存器的信號。

  這樣當通道1的產生上升沿的時候,首先會捕獲當前計數器TIMx_CNT的值到TIMx_CCR1,然后計數器會被重新初始化(清零或重新賦值自動重裝載值),當通道1產生下降沿的時候,會捕獲當前計數器的TIMx_CNT的值到TIMx_CCR2,TIMx_CCRx2的值就是高電平的時間,當通道1再次產生上升沿的時候,捕獲到的TIMx_CCRx1的值就是PWM的周期。

PWM輸入模式時序如下:

 

  從圖中可以看到當TI1產生上升沿時,TIMx_CNT的值會被IC1捕獲,然后復位計數器,當TI1產生下降沿時,TIMx_CNT的值會被IC2捕獲。這樣就可以得出PWM的周期和占空比。

  配置步驟如下:

  通過TIMx_CCMR1寄存器的CC1S位配置通道1為輸入,並且映射到TI1上。

  通過TIMx_CCER寄存器的CC1P位配置TI1FP1的有效極性是上升沿。

  通過TIMx_CCMR1寄存器的CC2S位配置通道2為輸入,並且映射到TI1上。

  通過TIMx_CCER寄存器的CC2P位配置TI1FP2的有效極性是下降沿。

  通過TIMx_SMCR寄存器中的TS位選擇TI1FP1作為TRGI的輸入源。

  通過TIMx_SMCR寄存器中的SMS位選擇從模式控制器為復位模式。

  通過TIMx_CCER寄存器中的CC1E位和CC2E位使能通道1和通道2的輸入捕獲功能。

  以下代碼是TIM3使用通道1的PA6測量輸入PA6的PWM波形的周期和占空比的配置程序:

 1 void TIM3_TEST(void)  2 {  3     RCC->APB2ENR |= 1<<2;   //開啟GPIOA的時鍾 
 4     RCC->APB1ENR |= 1<<1;   //開啟TIM3的時鍾 
 5     
 6     GPIOA->CRL &= 0xF0FFFFFF;  7     GPIOA->CRL |= 0x08000000;//設置GPIOA6為輸入
 8     GPIOA->ODR &= ~(1<<6);//開啟GPIOA6的下拉
 9        
10     TIM3->PSC = 71;//設置TIM3的預分頻器系數為1分頻
11     TIM3->ARR = 60000;//設置TIM3的自動重載值為60000,計數周期是60ms
12     TIM3->CNT = 0;//清除計數器的值
13 
14     TIM3->EGR |= (1<<0);//配置UG=1,產生一個軟件溢出中斷,更新計數器和預分頻器的數值
15     TIM3->SR = 0; 16     
17     TIM3->CR1 &= ~(0x03<<5);//配置CMS=00,選擇定時器的計數模式為邊沿模式
18     TIM3->CR1 &= ~(1<<4);//配置DIR=0,選擇定時器的計數方向為向上計數 
19     
20     TIM3->CCMR1 &= ~(0x03<<0); 21     TIM3->CCMR1 |= (0x01<<0);//配置CC1S=01,選擇CC1通道為輸入,並映射到TI1上
22 
23     TIM3->CCMR1 &= ~(0x03<<2); 24     TIM3->CCMR1 |= (0x00<<2);//配置IC1PSC=00,選擇通道1的預分頻為1
25 
26     TIM3->CCMR1 &= ~(0x0F<<4); 27     TIM3->CCMR1 |= (0x00<<4);//配置IC1F=0000,選擇通道1的濾波為無濾波
28     
29     TIM3->CCER &= ~(1<<1);//配置CC1P=0,選擇通道1捕獲發生在上升沿
30     
31     TIM3->CCMR1 &= ~(0x03<<8); 32     TIM3->CCMR1 |= (0x02<<8);//配置CC2S=01,選擇CC2通道為輸入,並映射到TI1上
33 
34     TIM3->CCMR1 &= ~(0x03<<10); 35     TIM3->CCMR1 |= (0x00<<10);//配置IC2PSC=00,選擇通道2的預分頻為1
36 
37     TIM3->CCMR1 &= ~(0x0F<<12); 38     TIM3->CCMR1 |= (0x00<<12);//配置IC2F=0000,選擇通道2的濾波為無濾波
39     
40     TIM3->CCER |= (1<<5);//配置CC2P=0,選擇通道2捕獲發生在上升沿 
41     
42     TIM3->SMCR &= ~(0x07<<4); 43     TIM3->SMCR |= (0x05<<4);//配置TS=101,選擇TI1FP1作為從模式控制器的觸發源
44     
45     TIM3->SMCR &= ~(0x07<<0); 46     TIM3->SMCR |= (0x04<<0);//配置SMS=100,選擇從模式控制器為復位模式 
47     
48     TIM3->CCER |= (1<<0);//配置CC1E=1,使能通道1的捕獲功能
49     TIM3->CCER |= (1<<4);//配置CC2E=1,使能通道2的捕獲功能
50 
51     TIM3->DIER |= (1<<1); 52     TIM3->DIER |= (1<<2); 53 
54     TIM3->CR1 |= (1<<0);//配置CEN=1,啟動定時器工作
55     
56     HAL_NVIC_SetPriority(TIM3_IRQn,2,1); 57  HAL_NVIC_EnableIRQ(TIM3_IRQn); 58 }

  強制輸出模式:

  當將通用定時器的通道配置為輸出的時候,捕獲/比較寄存器TIMx_CCRx的值將不斷的與TIMx_CNT寄存器的值比較,使得輸出通道的電平根據比較值的不同產生相應的電平變換。

  強制輸出模式是指在通道配置為輸出的時候,通過軟件強制輸出通道輸出指點狀態的電平,而不依賴於輸出比較寄存器和計數器間的比較結果。

  通道是輸入還是輸出是通過TIMx_CCMRx寄存器中的CCxS位來決定的,當CCxS=00時,通道被配置成輸出。

  當通道設置為輸出時,TIMx_CCMRx寄存器中的OCxM位可以將通道配置成不同的模式,這里只說明強制輸出模式:

  當OCxM = 100時,強制通道輸出無效電平。

  當OCxM = 101時,強制通道輸出有效電平。

  有效電平和無效電平是根據TIMx_CCER寄存器的CCxP位來決定的,如下:

  當CCxP = 0時,高電平是有效電平,低電平是無效電平。

  當CCxP = 1時,低電平是有效電平,高電平是無效電平

  在強制輸出模式下,只是將輸出通道的狀態強制為了指定的狀態,但是在TIMx_CCRx影子寄存器和計數器之間的比較仍然在進行,當比較匹配時,相應的標志也會被修改。

  PWM輸出模式:  

  關於PWM輸出模式,可以查看:https://www.cnblogs.com/h1019384803/p/11266546.html

  單脈沖模式:

  通過置位TIMx_CR1寄存器的bit3位OPM可以讓定時器工作在單脈沖模式。當定時器工作在單脈沖模式下時,在定時器的計數器溢出更新事件時,會清除CEN位,即會停止定時器的計數器計數。

  可以通過從模式控制器啟動計數器,在輸出比較模式或PWM模式下產生脈沖波形,如果將OPM置為1,就可以讓計數器自動的在更新事件時停止。

  如下圖是選擇TI2作為定時器的從模式觸發,當TI2產生一個上升沿時,觸發定時器開始計數,剛開始計數的時候,TIMx_CNT<TIMx_CCRx,所以OC1輸出低電平,當TIMx_CNT>=TIMx_CCRx時,OC1輸出高電平,當TIMx_CNT計數溢出時,TIMx_CNT會重新賦值,TIMx_CNT<TIMX_CCRx,OC1輸出低電平,同時由於工作在單脈沖模式,計數器會停止工作,這樣OC1就完成了一次脈沖的輸出。

 

  如圖,當TI2輸入腳上檢測到一個上升沿時,經過tDELAY延時(這個時間是TIMx_CNT計數到與TIMx_CCRx匹配的時間)之后,在OC1上產生一個長度為tPULSE時間(這個時間是TIMx_CNT從與TIMx_CCRx匹配到溢出的時間)的正脈沖。

  假如使用TI2FP2觸發定時器開始工作,配置如下:

  將TI2FP2映射到TI2上,即配置TIMx_CCMR1寄存器中的CC2S=01。

  配置TIMx_CCER寄存器中的CC2P=0,使TI2FP22能夠檢測上升沿。

  配置TIMx_SMCR寄存器中的TS=110,讓TI2FP2作為從模式控制器的觸發,即作為TRGI的輸入源。

  配置TIMx_SMCR寄存器中的SMS=110,讓從模式控制器工作在觸發模式,即讓TI2FP2作為從模式控制器的觸發信號,用來啟動計數器。

  單脈沖模式的波形由寫入比較寄存器TIMx_CCRx的數值和時鍾頻率,還有計數器預分頻器來決定。

  tDELAY由寫入TIMx_CCR1寄存器中的值定義。

  tPULSE由自動裝載值和比較值之間的差值定義,即TIMx_ARR-TIMx_CCRx。

  假定當發生比較匹配時要產生從0到1的波形,當計數器到達預裝載值時要產生一個從1到0的波形;首先要置TIMx_CCMR1 寄存器的OC1M=”111”,進入PWM模式2;根據需要有選擇的使能預裝載寄存器;置TIMx_CCMR1中的OC1PE=1和TIMx_CR1寄存器中的ARPE;然后在TIMx_CCR1寄存器中填寫比較值,在TIMx_ARR寄存器中填寫自動裝載值,修改UG位來產生一個更新事件,然后等待在TI2上的一個外部觸發事件。

  因為只需要產生一個脈沖,所以將TIMx_CR1寄存器的OPM位置1,在更新事件是停止計數器工作。

  OCx輸出快速使能:

  在單脈沖的模式下,在TIx輸入腳檢測到相應的邊沿信號時,CEN被置位,計數器開始工作。然后計數器和比較值見得比較操作產生了輸出的轉換。但是這些操作需要一定的時鍾周期,因此它現在了可得到的最小延時tDELAY(比如說已檢測到TIx的邊沿信號就要TIMx_CNT跟TIMx_CCRx匹配,但是匹配要一定的時間),如果要以最小延時輸出波形,可以設置TIMx_CCMRx寄存器的OC型FE位;此時OCxREF被強制響應激勵而不再依賴比較的結果,輸出的波形與比較匹配時的波形一樣。需要注意的是OCxFE只在通道配置位PWM1和PWM2模式時起作用。

  在外部事件時清除OCxREF信號: 

  對於一個給定的通道,設置TIMx_CCMRx寄存器中的OCxCE位為1時,能夠用ETRF輸入端的高電平把OCxREF信號拉低,OCxREF信號將保持為低知道發生下一次的更新事件。也就是說如果輸出通道正處於比較輸出的狀態,可以通過給ETR腳一個高電平,讓OCxREF輸出低電平。

  這個功能只能用於輸出比較和PWM模式,而不能用於強制模式。

  下圖是當定時器處於PWM模式時,ETRF輸入高電平時,根據OCxCE的狀態不同,OCxREF的輸出狀態也不一樣。

  從圖中可以看到,當OCxCE=0時,OCxREF的輸出不受ETRF的影響;當OCxCE=1時,在ETRF保持為低電平的時候,OCxREF正常輸出PWM信號,在ETRF保持為高電平的時候,OCxREF被強制為低電平,在ETRF變為低電平之后且定時器溢出更新才會恢復正常的PWM輸出。

定時器和外部觸發的同步:  

  TIMx通用定時器有一個從模式控制器,TRGI作為從模式控制器的的輸入。如下圖:

  從模式控制器又可以根據TIMx_SMCR寄存器中SMS的設置,分為:復位模式、門控模式和觸發模式。

  定時器從模式:復位模式

  當發生一個觸發輸入事件時,計數器和它的預分頻器你能夠重新被初始化;同時,如果TIMx_CR1寄存器URS位為低,還會產生一個更新事件,然后TIMx_ARR和TIMx_CCRx的值會被更新。

  如使用TI1輸入端的上升沿觸發復位定時器的計數器的配置如下:

  配置TIMx_CCMR1寄存器的CC1S = 01,配置通道為輸入,並且映射到TI1上。

  配置TIMx_CCER寄存器的CC1P = 0,選擇TI1檢測上升沿信號。

  配置TIMx_CCMR1寄存器的IC1F = 0000,選擇TI1信號不濾波。

  配置TIMx_CCMR1寄存器的IC1PSC = 00,選擇TI1信號不分頻。

  配置TIMx_SMCR寄存器的TS = 101,選擇TI1FP1信號作為TRGI的輸入源。

  配置TIMx_SMCR寄存器的SMS = 100,選擇定時器為復位模式。

  配置TIMx_CR1寄存器的CEN = 1,啟動計數器。

  運行程序的時候,計數器開始依據內部時鍾計數,然后正常運轉知道TI1出現一個上升沿;此時,計數器被重新初始化后重新開始計數。同時,觸發標志(TIMx_SR寄存器中TIF位)被置位,根據TIMx_DIER寄存器中TIE位來決定是否產生中斷請求。

  需要注意的是輸入觸發計數器復位時會產生一個溢出中斷,如果使能了溢出中斷,則會運行中斷服務函數。

  如下圖是復位模式的時序圖:

  從圖中可以看到,當計數器遇到TI1的上升沿時,計數器會被清零重新開始計數。

    以下代碼是當TIM3的通道1的PA6輸入一個上升沿時,會復位TIM3計數器的配置程序:

 1 void TIM3_TEST(void)  2 {  3     RCC->APB2ENR |= 1<<2;   //開啟GPIOA的時鍾
 4     RCC->APB1ENR |= 1<<1;   //開啟TIM3的時鍾 
 5     
 6     GPIOA->CRL &= 0xF0FFFFFF;  7     GPIOA->CRL |= 0x08000000;//設置GPIOA6為輸入
 8     GPIOA->ODR &= ~(1<<6);//開啟GPIOA6的下拉
 9        
10     TIM3->PSC = 7199;//設置TIM3的預分頻器系數為7200分頻
11     TIM3->ARR = 60000;//設置TIM3的自動重載值為60000,計數周期是6s
12     TIM3->CNT = 0;//清除計數器的值
13     
14     TIM3->CR1 &= ~(0x03<<5);//配置CMS=00,選擇定時器的計數模式為邊沿模式
15     TIM3->CR1 &= ~(1<<4);//配置DIR=0,選擇定時器的計數方向為向上計數 
16 
17     TIM3->EGR |= (1<<0);//配置UG=1,產生一個軟件溢出中斷,更新計數器和預分頻器的數值
18     TIM3->SR = 0; 19     
20     TIM3->CCMR1 &= ~(0x03<<0); 21     TIM3->CCMR1 |= (0x01<<0);//配置CC1S=01,選擇CC1通道為輸入,並映射到TI1上
22 
23     TIM3->CCMR1 &= ~(0x03<<2); 24     TIM3->CCMR1 |= (0x00<<2);//配置IC1PSC=00,選擇通道1的預分頻為1
25 
26     TIM3->CCMR1 &= ~(0x0F<<4); 27     TIM3->CCMR1 |= (0x00<<4);//配置IC1F=0000,選擇通道1的濾波為無濾波
28     
29     TIM3->CCER &= ~(1<<1);//配置CC1P=0,選擇通道1捕獲發生在上升沿 
30       
31     TIM3->SMCR &= ~(0x07<<4); 32     TIM3->SMCR |= (0x05<<4);//配置TS=101,選擇TI1FP1作為從模式控制器的觸發源
33     
34     TIM3->SMCR &= ~(0x07<<0); 35     TIM3->SMCR |= (0x04<<0);//配置SMS=100,選擇從模式控制器為復位模式 
36     
37     TIM3->DIER |= (1<<0);//配置UIE=1,允許更新中斷
38 
39     TIM3->CR1 |= (1<<0);//配置CEN=1,啟動定時器工作
40      
41     HAL_NVIC_SetPriority(TIM3_IRQn,2,1); 42  HAL_NVIC_EnableIRQ(TIM3_IRQn); 43 }

  定時器從模式:門控模式

  在門控模式下,外部觸發信號可以控制定時器計數器的啟動和停止,比如說可以設置在外部觸發信號為低電平的時候啟動定時器計數;在外部觸發信號為高電平的時候停止定時器計數。

  如可以讓定時器的計數器只在TI1為低電平時向上計數,配置如下:

  配置TIMx_CCMR1寄存器的CC1S = 01,配置通道為輸入,並且映射到TI1上。

  配置TIMx_CCER寄存器的CC1P = 1,選擇TI1檢測下降沿信號。

  配置TIMx_CCMR1寄存器的IC1F = 0000,選擇TI1信號不濾波。

  配置TIMx_CCMR1寄存器的IC1PSC = 00,選擇TI1信號不分頻。

  配置TIMx_SMCR寄存器的TS = 101,選擇TI1FP1信號作為TRGI的輸入源。

  配置TIMx_SMCR寄存器的SMS = 101,選擇定時器為門控模式。

  配置TIMx_CR1寄存器的CEN = 1,啟動計數器,在門控模式下,如果CEN=0,則計數器不能啟動,不論觸發輸入低電平如何。

  只要TI1為低電平,計數器開始依據內部時鍾計數,在TI1FP變高時停止計數。當計數器開始或停止時都設置TIMx_SR中的TIF標置。如下圖:

  從圖中可以看到計數器只有在TI1為低電平的時候才計數,高電平時停止計數。

  以下代碼是使用TIM3的通道1的PA6來控制TIM3計數器的啟動和停止,當PA6為低電平時,TIM3計數器運行,當PA6為高電平時,TIM3計數器停止,程序如下:

 1 void TIM3_TEST(void)  2 {  3     RCC->APB2ENR |= 1<<2;   //開啟GPIOA的時鍾
 4     
 5     RCC->APB1ENR |= 1<<1;   //開啟TIM3的時鍾 
 6     
 7     GPIOA->CRL &= 0xF0FFFFFF;  8     GPIOA->CRL |= 0x08000000;//設置GPIOA6為輸入
 9     GPIOA->ODR &= ~(1<<6);//開啟GPIOA6的下拉
10        
11     TIM3->PSC = 7199;//設置TIM3的預分頻器系數為7200分頻
12     TIM3->ARR = 60000;//設置TIM3的自動重載值為60000,計數周期是6s
13     TIM3->CNT = 0;//清除計數器的值
14     
15     TIM3->CR1 &= ~(0x03<<5);//配置CMS=00,選擇定時器的計數模式為邊沿模式
16     TIM3->CR1 &= ~(1<<4);//配置DIR=0,選擇定時器的計數方向為向上計數 
17 
18     TIM3->EGR |= (1<<0);//配置UG=1,產生一個軟件溢出中斷,更新計數器和預分頻器的數值
19     TIM3->SR = 0; 20     
21     TIM3->CCMR1 &= ~(0x03<<0); 22     TIM3->CCMR1 |= (0x01<<0);//配置CC1S=01,選擇CC1通道為輸入,並映射到TI1上
23 
24     TIM3->CCMR1 &= ~(0x03<<2); 25     TIM3->CCMR1 |= (0x00<<2);//配置IC1PSC=00,選擇通道1的預分頻為1
26 
27     TIM3->CCMR1 &= ~(0x0F<<4); 28     TIM3->CCMR1 |= (0x00<<4);//配置IC1F=0000,選擇通道1的濾波為無濾波
29     
30     TIM3->CCER |= (1<<1);//配置CC1P=1,選擇通道1捕獲發生在下降沿 
31       
32     TIM3->SMCR &= ~(0x07<<4); 33     TIM3->SMCR |= (0x05<<4);//配置TS=101,選擇TI1FP1作為從模式控制器的觸發源
34     
35     TIM3->SMCR &= ~(0x07<<0); 36     TIM3->SMCR |= (0x05<<0);//配置SMS=101,選擇從模式控制器為門控模式 
37     
38     TIM3->DIER |= (1<<0);//配置UIE=1,允許更新中斷
39 
40     TIM3->CR1 |= (1<<0);//配置CEN=1,啟動定時器工作
41      
42     HAL_NVIC_SetPriority(TIM3_IRQn,2,1); 43  HAL_NVIC_EnableIRQ(TIM3_IRQn); 44 }

  從模式:觸發模式

  在觸發模式下,外部觸發信號輸入時,可以觸發定時器的計數器啟動。

  如讓計數器在TI2輸入的上升沿開始向上計數,配置如下:

  配置TIMx_CCMR1寄存器的CC2S = 01,配置通道為輸入,並且映射到TI2上。

  配置TIMx_CCER寄存器的CC2P = 1,選擇TI2檢測下降沿信號。

  配置TIMx_CCMR1寄存器的IC2F = 0000,選擇TI2信號不濾波。

  配置TIMx_CCMR1寄存器的IC2PSC = 00,選擇TI2信號不分頻。

  配置TIMx_SMCR寄存器的TS = 110,選擇TI2FP2信號作為TRGI的輸入源。

  配置TIMx_SMCR寄存器的SMS = 110,選擇定時器為觸發模式。

  當TI2上出現一個上升沿時,計數器開始在內部時鍾驅動下計數,同時設置TIF標志。如下圖:

  當TI2產生上升沿時,CEN位會被置位,計數器開始計數。

 

  以下代碼是使用TIM3的通道2的PA7輸入一個上升沿來觸發啟動TIM3計數器工作,程序如下:

 

 1 void TIM3_TEST(void)  2 {  3     RCC->APB2ENR |= 1<<2;   //開啟GPIOA的時鍾
 4     RCC->APB1ENR |= 1<<1;   //開啟TIM3的時鍾 
 5     
 6     GPIOA->CRL &= 0x0FFFFFFF;  7     GPIOA->CRL |= 0x80000000;//設置GPIOA7為輸入
 8     GPIOA->ODR &= ~(1<<7);//開啟GPIOA7的下拉
 9        
10     TIM3->PSC = 7199;//設置TIM3的預分頻器系數為7200分頻
11     TIM3->ARR = 60000;//設置TIM3的自動重載值為60000,計數周期是6s
12     TIM3->CNT = 0;//清除計數器的值
13     
14     TIM3->CR1 &= ~(0x03<<5);//配置CMS=00,選擇定時器的計數模式為邊沿模式
15     TIM3->CR1 &= ~(1<<4);//配置DIR=0,選擇定時器的計數方向為向上計數 
16 
17     TIM3->EGR |= (1<<0);//配置UG=1,產生一個軟件溢出中斷,更新計數器和預分頻器的數值
18     TIM3->SR = 0; 19     
20     TIM3->CCMR1 &= ~(0x03<<8); 21     TIM3->CCMR1 |= (0x01<<8);//配置CC2S=01,選擇CC2通道為輸入,並映射到TI2上
22 
23     TIM3->CCMR1 &= ~(0x03<<10); 24     TIM3->CCMR1 |= (0x00<<10);//配置IC2PSC=00,選擇通道2的預分頻為1
25 
26     TIM3->CCMR1 &= ~(0x0F<<12); 27     TIM3->CCMR1 |= (0x00<<12);//配置IC2F=0000,選擇通道2的濾波為無濾波
28     
29     TIM3->CCER &= ~(1<<5);//配置CC2P=0,選擇通道2捕獲發生在上升沿 
30       
31     TIM3->SMCR &= ~(0x07<<4); 32     TIM3->SMCR |= (0x06<<4);//配置TS=110,選擇TI2FP2作為從模式控制器的觸發源
33     
34     TIM3->SMCR &= ~(0x07<<0); 35     TIM3->SMCR |= (0x06<<0);//配置SMS=110,選擇從模式控制器為觸發模式 
36 
37     TIM3->DIER |= (1<<0);//配置UIE=1,允許更新中斷
38 
39     HAL_NVIC_SetPriority(TIM3_IRQn,2,1); 40  HAL_NVIC_EnableIRQ(TIM3_IRQn); 41 }

從模式:外部時鍾模式2+觸發模式

  外部時鍾模式2可以與另一種定時器從模式(外部時鍾模式1和編碼器模式除外)一起使用。這時ETR信號被用作外部時鍾的輸入來驅動計數器計數,然后用另一個輸入觸發定時器。因為ETR用來作為外部時鍾模式2的計數驅動,所以做好不要選擇ETR作為TRGI的輸入源。

  如選擇外部時鍾模式2作為定時器的時鍾驅動,然后在TI1產生一個上升沿后觸發定時器開始計數。配置如下:

  配置TIMx_SMCR寄存器的ETF = 0000,選擇ETR信號不濾波。

  配置TIMx_SMCR寄存器的ETPS = 00,選擇ETR信號不濾波。

  配置TIMx_SMCR寄存器的ETP = 0,選擇ETR信號檢測上升沿信號。

  配置TIMx_SMCR寄存器的ECE = 1,使能外部時鍾模式2。

  配置TIMx_CCMR1寄存器的CC1S = 01,配置通道為輸入,並且映射到TI1上。

  配置TIMx_CCER寄存器的CC1P = 0,選擇TI1檢測上升沿沿信號。

  配置TIMx_CCMR1寄存器的IC1F = 0000,選擇TI1信號不濾波。

  配置TIMx_CCMR1寄存器的IC1PSC = 00,選擇TI1信號不分頻。

  配置TIMx_SMCR寄存器的TS = 101,選擇TI1FP1信號作為TRGI的輸入源。

  配置TIMx_SMCR寄存器的SMS = 110,選擇定時器為觸發模式。

  當TI1上出現一個上升沿時,TIF標志被置位,計數器開始在ETR腳位的上升沿計數。如下圖:

  定時器同步:

  STM32的所有TIMx定時器在內部相連,用於定時器同步或鏈接。當一個定時器處於主模式時,主模式的定時器可以對處於從模式的定時器的計時器進行復位、啟動、停止或提供時鍾操作。

  如下圖是一個主定時器控制從定時器的例子:

 

  圖中定時器1作為主控制模式,定時器2作為從控制模式。主控制模式定時器輸出TRGO1信號作為從控制模式定時器的輸入源ITR1驅動定時器2的計數器。

  也就是說可以使用一個定時器作為另一個定時器的預分頻器,如可以配置TIM1作為TIM2的預分頻,配置如下:

  配置TIM1_CR2寄存器的MMS=010,讓定時器1工作在主模式,並且在每一個更新事件時輸出一個周期性的上升沿信號。

  配置TIM2_SMCR寄存器的TS=000,選擇連接定時器1的TRGO輸出至定時器2,並時定時器2使用ITR1作為內部觸發的從模式。

  配置TIM2_SMCR寄存器的SMS=111,將定時器2的時鍾選擇為外部時鍾模式1,這樣ITR1就是作為驅動TIM2計數器的時鍾源。

  最后置位TIM1_CR1的CEN位和TIM2_CR1的CEN,同時啟動兩個定時器。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM