定時器最基本的功能就是定時處理事情,比如定時發送USART資料、定時采集AD資料、定時檢測IO口電位、還可以通過IO口輸出波形等,可以實作非常豐富的功能,定時器是一個很強大的外設,不同行業使用的方式不同,知識面很廣,
01、定時器介紹
首先我們可以在STM32F207資料手冊找到定制器的資源,從下圖可以看到STM32F207一共10個通用定時器,2個高級定時器,2個基本定時器,
不同定時器的區別
在STM32F207的用戶參考手冊中可以看到定時器的基本框圖,下圖是定時器1&8的看圖,
由上圖看出,不同暫存器具有不同的引數,位數的區別,計數模式的區別,DMA請求的區別,通道得的區別,互補輸出的區別和其他,在具體專案中選擇哪個定時器,需要看具體的應用場景,下文主要講解定時器的基礎定時功能,選擇定時器3,其他定時器原理是相同的,理解定時器3的定時功能,其他定時器也就能理解了,對于STM32系列的單片機,外設基本都是一致的,并且其他家的MCU也是類似的,國內的有兆易創新、新唐科技、上海靈動微電子等等,
02、時鐘源
定時器基本定時功能框圖,
①CK_PSC是定時器時鐘TIMxCLK,經APB1預分頻器后分頻提供,
②定時器時鐘經過PSC 預分頻器之后,即CK_CNT,用來驅動計數器計數,
③計數器CNT 是一個16 位的計數器,向上,向下,向上/下計數模式,最大計數值為65535,當計數達到自動重裝載暫存器的時候產生更新事件,并清零從頭開始計數,
④自動重裝載暫存器ARR 是一個16位的暫存器,這里面裝著計數器能計數的最大數值,當計數到這個值的時候,如果使能了中斷的話,定時器就產生溢位中斷,
定時器說白了就是個計數器,就像我們用心跳粗略估算時間一樣,心臟跳動粗略可以認為是1s,那么我們計時60次心跳就過了60秒,其中CK_CNT時鐘就類似心跳,CNT計數器就類似心跳次數,舉一個極端簡單的例子,我們要實作60秒定時,CK_CNT是1s,我們設定CNT計數器向上計數開啟中斷,因為只有溢位時,也就是計數到65535時才會有中斷,那么我們設定CNT計數器為65535-60=65475,開始及時,那么60秒后就會產生中斷,我們設定自動重裝載暫存器ARR也為65475,當CNT計數器溢位時,自動重裝載暫存器ARR就會自動裝載到CNT計數器中,就能實作自動回圈定時60秒,
經過上面分析,精確定時的關鍵在于CK_CNT的頻率,而CK_CNT是由定時器時鐘分頻而來的,那么我們就要知道timer3的定時器時鐘,我們就要看時鐘系統部分,具體看文章《STM32F207時鐘系統決議》,這篇文章主要講解了系統的120M時鐘如何從外部的25M的晶振得到的,其中說到APB外設時鐘的問題,
定時器在APB定時器時鐘下,具體在APB1還是在APB2時鐘下我們可以從STM32F207資料手冊上看到,圖片名字STM32F20xblock diagram,
從上文我們看timer3是在APB1下的,
那么我們來分析APB1的頻率
從上圖看出,APB1定時器的從系統120M時鐘(系統時鐘可配置的,我們使用默認的120M時鐘)經過AHB分頻,APB分頻得到的,
在這里說上圖紅框中的“錯誤”,萌新可能不太理解,首先手冊中少了個右括號,修改后應該為:
if(APBx presc == 1) X1 else X2
也就是說
APB分頻系數如果是1,頻率不變,APB輸出的頻率就是APB下面時鐘的頻率,
APB分頻系數不是1,頻率X2,APB輸出的頻率乘以2是APB下面時鐘的頻率,
下面我們分析APB1時鐘,從system_stm32f2xx.c中的SetSysClock函式中如下
/* HCLK = SYSCLK / 1*/ RCC->CFGR |= RCC_CFGR_HPRE_DIV1; /* PCLK2 = HCLK / 2*/ RCC->CFGR |=RCC_CFGR_PPRE2_DIV2; /* PCLK1 = HCLK / 4*/ RCC->CFGR|= RCC_CFGR_PPRE1_DIV4;
可以看到AHB分頻系數是1,APB1分頻系數是4,
timer3的時鐘為120M/1/4*2= 60MHZ,
這里有個疑問,ST提供的system_stm32f2xx.c注釋為什么是HCLK,PCLK2,PCLK1,卻沒有上文提到的APB,AHB字眼,具體看下我之前寫過的文章《STM32F207時鐘系統決議》,
其實我們出了分析代碼,system_stm32f2xx.c檔案頭也是有注釋的,方便查看,
當然,這要求我們的外部晶振是25M的,且system_stm32f2xx.c是沒有被修改過的,如果大家需要修改這個檔案單片機超頻運行,建議把檔案頭的注釋修改,養成一個良好的習慣,
03、時基單元
可編程高級定時器控制模塊主要是一個帶有相關自動多載16位計數器,這個計數器可以向上計數,向下計數或者交替遞增和遞減計數,計數器時鐘可以通過一個分頻器分頻,
計數器的自動多載暫存器和預分頻暫存器可以通過軟體讀寫,即使當計數器正在運行也可以讀寫,
時基單元包括
-
計數器暫存器 (TIMx_CNT)
-
預分頻器暫存器 (TIMx_PSC)
-
自動多載暫存器 (TIMx_ARR)
-
重復計數器暫存器 (TIMx_RCR)
自動多載暫存器是預裝載的,從自動多載暫存器寫入或讀取會訪問預裝載暫存器,預裝載暫存器的內容既可以直接傳送到影子暫存器,也可以在每次發生更新事件(UEV)時傳送到影子暫存器,這取決于TIMx_CR1 暫存器中的自動多載預裝載使能位(ARPE),當計數器達到上溢值(或者在遞減計數時達到下溢值)并且TIMx_CR1 暫存器中的UDIS 位為0時,將發送更新事件,該更新事件也可由軟體產生,
計數器由預分頻器輸出CK_CNT 提供時鐘,僅當TIMx_CR1 暫存器中的計數器啟動位(CEN)置1 時,才會啟動計數器,
預分頻器說明
預分頻器可對計數器時鐘頻率進行分頻,分頻系數介于1 和65536 之間,該預分頻器基于TIMx_PSC暫存器中的16 位暫存器所控制的16位計數器,由于該控制暫存器具有緩沖功能,因此可對預分頻器進行實時更改,而新的預分頻比將在下一更新事件發生時被采用,
下圖以一些示例說明在預分頻比實時變化時計數器的行為,
預分頻器分頻由1 變為2 時的計數器時序圖
預分頻器分頻由1 變為4 時的計數器時序圖
04、計數模式
4.1、向上計數模式
在向上計數模式中,計數器從0增加到自動多載值(TIMx_ARR暫存器的值),然后從0重新開始并產生一個計數器溢位事件,
如果使用重復計數器,則當遞增計數的重復次數達到重復計數器暫存器中編程的次數加一次(TIMx_RCR+1)后,將生成更新事件(UEV),否則,將在每次計數器上溢時產生更新事件,
將TIMx_EGR暫存器的UG位置1通過軟體或使用從模式控制器時,也將產生更新事件,
通過軟體將TIMx_CR1暫存器中的UDIS位置1可禁止UEV事件,這可避免向預裝載暫存器寫入新值時更新影子暫存器,在UDIS位寫入0之前不會產生任何更新事件,不過,計數器和預分頻器計數器都會重新從0開始計數(而預分頻比保持不變),此外,如果TIMx_CR1暫存器中的URS位(更新請求選擇)已置1,則將UG位置1會生成更新事件UEV,但不會將UIF標志置1(因此,不會發送任何中斷或DMA請求),這樣一來,如果在發生捕獲事件時將計數器清零,將不會同時產生更新中斷和捕獲中斷,
發生更新事件時,將更新所有暫存器且將更新標志(TIMx_SR暫存器中的UIF位)置1取決于URS位)
-
重復計數器中將重新裝載TIMx_RCR暫存器的內容
-
自動多載影子暫存器將以預裝載值 (TIMx_ARR) 進行更新
-
預分頻器的緩沖區中將重新裝載預裝載值(TIMx_PSC暫存器的內容)
計數器時序圖,1 分頻內部時鐘
計數器時序圖,2 分頻內部時鐘
從上面兩圖看出,中斷標志是需要軟體清除的
計數器時序圖,ARPE=0 時更新事件(TIMx_ARR 未預裝載)
從上面兩圖看出,向上計數,還沒有到達0x36,就把自動多載暫存器修改為0x36,就會在計數到0x36時產生動作,
計數器時序圖,ARPE=1 時更新事件(TIMx_ARR 預裝載)
從上面兩圖看出,向上計數,還沒有到達0x36,就把自動多載預裝載暫存器修改為0x36,就不會在計數到0x36時產生動作,會在這個時將自動多載預裝載暫存器值賦給自動多載影子暫存器,
4.2、向下計數模式
在向下計數模式中,計數器從自動多載值(TIMx_ARR暫存器的值)向下計數到0,然后從自動多載值(重新開始并產生一個計數器溢位事件,
如果使用重復計數器,則當遞減計數的重復次數達到重復計數器暫存器中編程的次數加一次(TIMx_RCR+1)后,將生成更新事件(UEV),否則,將在每次計數器下溢時產生更新事件,
將TIMx_EGR 暫存器的UG 位置1(通過軟體或使用從模式控制器)時,也將產生更新事件,
通過軟體將TIMx_CR1 暫存器中的UDIS 位置1 可禁止UEV 更新事件,這可避免向預裝載暫存器寫入新值時更新影子暫存器,在UDIS 位寫入0之前不會產生任何更新事件,不過,計數器會重新從當前自動多載值開始計數,而預分頻器計數器則重新從0 開始計數(但預分頻比保持不變),
此外,如果TIMx_CR1 暫存器中的URS 位(更新請求選擇)已置1,則將UG 位置1 會生成更新事件UEV,但不會將UIF 標志置1(因此,不會發送任何中斷或DMA 請求),這樣一來,如果在發生捕獲事件時將計數器清零,將不會同時產生更新中斷和捕獲中斷,
發生更新事件時,將更新所有暫存器且將更新標志(TIMx_SR 暫存器中的UIF 位)置1(取決于 URS 位):
-
重復計數器中將重新裝載 TIMx_RCR 暫存器的內容
-
預分頻器的緩沖區中將重新裝載預裝載值( TIMx_PSC 暫存器的內容)
-
自動多載活動暫存器將以預裝載值( TIMx_ARR 暫存器的內容)進行更新,注意,自動多載暫存器會在計數器多載之前得到更新,因此,下一個計數周期就是我們所希望的新的周期長度
以下各圖以一些示例說明當TIMx_ARR=0x36 時不同時鐘頻率下計數器的行為
計數器時序圖,1 分頻內部時鐘
計數器時序圖,2 分頻內部時鐘
計數器時序圖,未使用重復計數器時更新事件
4.3、中央對齊(向上/向下計數模式)
在中心對齊模式下,計數器從0 開始計數到自動多載值(TIMx_ARR 暫存器的內容)-1,生成計數器上溢事件;然后從自動多載值開始向下計數到1 并生成計數器下溢事件,之后從0開始重新計數,
當TIMx_CR1 暫存器中的CMS位不為“00”時,中心對齊模式有效,將通道配置為輸出模式時,其輸出比較中斷標志將在以下模式下置1,即:計數器遞減計數(中心對齊模式1,CMS=“01”)、計數器遞增計數(中心對齊模式2,CMS =“10”)以及計數器遞增/遞減計數(中心對齊模式3,CMS =“11”),
在此模式下,TIMx_CR1 暫存器的DIR 方向位不可寫入值,而是由硬體更新并指示當前計數器方向,
每次發生計數器上溢和下溢時都會生成更新事件,或將TIMx_EGR 暫存器中的UG 位置1(通過軟體或使用從模式控制器)也可以生成更新事件,這種情況下,計數器以及預分頻器計數器將重新從0 開始計數,
通過軟體將TIMx_CR1 暫存器中的UDIS 位置1 可禁止UEV 更新事件,這可避免向預裝載暫存器寫入新值時更新影子暫存器,在UDIS 位寫入0 之前不會產生任何更新事件,不過,計數器仍會根據當前自動多載值進行遞增和遞減計數,
此外,如果TIMx_CR1 暫存器中的URS 位(更新請求選擇)已置1,則將UG 位置1 會生成UEV 更新事件,但不會將UIF 標志置1(因此,不會發送任何中斷或DMA 請求),這樣一來,如果在發生捕獲事件時將計數器清零,將不會同時產生更新中斷和捕獲中斷,
發生更新事件時,將更新所有暫存器且將更新標志(TIMx_SR 暫存器中的UIF 位)置1(取決于URS 位):
-
重復計數器中將重新裝載 TIMx_RCR 暫存器的內容
-
預分頻器的緩沖區中將重新裝載預裝載值( TIMx_PSC 暫存器的內容)
-
自動多載活動暫存器將以預裝載值( TIMx_ARR 暫存器的內容)進行更新,注意,如果更新操作是由計數器上溢觸發的,則自動多載暫存器在多載計數器之前更新,因此,下一個計數周期就是我們所希望的新的周期長度(計數器被多載新的值),
以下各圖以一些示例說明不同時鐘頻率下計數器的行為
計數器時序圖,1 分頻內部時鐘,TIMx_ARR = 0x6
計數器時序圖,2 分頻內部時鐘
計數器時序圖,ARPE=1 時的更新事件(計數器下溢)
計數器時序圖,ARPE=1 時的更新事件(計數器上溢)
05、基礎定時代碼
10ms中斷配置代碼
關于設定分頻值
TIM3CLK = 2 * PCLK1=2*HCLK / 4= HCLK / 2 = SystemCoreClock /2=60MHZ
所以下圖紅框內就是TIM3CLK
這里的值是分頻系數=TIM3CLK/定時器實際頻率,所以定時器頻率是10000,也就是說除數就是定時器頻率,一個clk是1/10000s,定時時間=1/10000*定時器多載值,根據上面的配置,定時器多載值是100,也就是定時器中斷周期是=1/10000*100=0.01s=10ms,也就是100HZ,
如果在定時器翻轉LED燈,那么LED燈閃爍頻率是50Hz,
上面的的分頻值當然可以直接賦值5999,如果想修改為定時器頻率為1000,那么還要重新計算,如果按照上面的寫法,直接將除數修改為1000即可,
看到這里大家會有疑問,給的多載值明明是99,分頻率值也減去1,下面將說明分頻值和自動多載周期值都需要減去1的原因,
自動多載值:因為從0開始計算,賦值10,從0開始計數到10是11次,
分頻值:在TIMx_PSC暫存器有以下描述,
特別說明
時鐘分頻因子
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV2;
其實仔細看過技術手冊后發現這句話與PWM輸出實驗其實是沒關系的,這句話是設定定時器時鐘(CK_INT)頻率與數字濾波器(ETR,TIx)使用的采樣頻率之間的分頻比例的(與輸入捕獲相關),0表示濾波器的頻率和定時器的頻率是一樣的,
首先這個colck_division時鐘分割系數并不是對定時器的時鐘頻率進行分割,我們都知道輸入捕獲模式下有一個數字濾波器,這個數字濾波器可以通過配置暫存器改變他的采樣頻率,從而將一些頻率濾除,
具體細節在輸入捕獲中詳解,
我們也可以根據定時器的計數器的特性,使用查詢計數器的方法實作精確延時,具體請看《STM32延時函式的四種方法》,
定時器代碼開源地址:
https://github.com/strongercjd/STM32F207VCT6
點擊查看本文所在的專輯,STM32F207教程
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/256599.html
標籤:其他
上一篇:KubeSphere 開源 KubeEye:Kubernetes 集群自動巡檢工具
下一篇:Linux服務器高并發調優實戰
