實(shí)驗(yàn)?zāi)繕?biāo):
通過(guò)CUbeMX+HAL,配置TIM1,1s中斷一次,閃爍LED。
一、常用型號(hào)的TIM時(shí)鐘頻率1. STM32F103系列:
所有 TIM 的時(shí)鐘頻率都是72MHz;
F103C8不帶基本定時(shí)器,F(xiàn)103RC及以上才帶基本定時(shí)器。
2、STM32F407系列:
TIM1、8、9、10、11的時(shí)鐘頻率是168MHz;
其它TIM的時(shí)鐘頻率是84MHz。
二、CubeMX配置 這里使用現(xiàn)有的CubeMX工程,略過(guò)工程配置部分。
如果學(xué)習(xí)如何新建CubeMX工程, 可以參考下面文章:
STM32CubeMX新建一個(gè)工程_STM32F103
STM32CubeMX新建一個(gè)工程_STM32F407
使用CubeMX對(duì)定時(shí)器進(jìn)行定時(shí)配置,過(guò)程相當(dāng)簡(jiǎn)單便捷。
我們只需配置幾個(gè)重要參數(shù):時(shí)鐘源、PSC、ARR、中斷。
1、主要參數(shù)配置
主要參數(shù)講解:
① Prescaler(預(yù)分頻系數(shù)):即PSC寄存器值。簡(jiǎn)單地理解:內(nèi)部時(shí)鐘分頻后再給CNT計(jì)數(shù)器使用,用于控制每一計(jì)數(shù)脈沖的時(shí)長(zhǎng)。按上文內(nèi)容得知,STM32F407的TIM1時(shí)鐘是168M,在設(shè)置預(yù)分頻為168后,計(jì)數(shù)脈沖頻率:168MHz÷168=1MHz,即每秒產(chǎn)生1百萬(wàn)個(gè)計(jì)數(shù)信號(hào),每個(gè)計(jì)數(shù)脈沖的時(shí)長(zhǎng):1秒/1M=1us。
② Counter Mode (計(jì)數(shù)方向): 向上計(jì)數(shù);
③ Counter Period (計(jì)數(shù)周期): 即ARR寄存器值,多少個(gè)計(jì)數(shù)脈沖作為1個(gè)波形周期。
④ Repetition Counter(重復(fù)計(jì)數(shù)器): 簡(jiǎn)單地理解,多少個(gè)周期才觸發(fā)1次中斷;
⑤ auto-reload preload (自動(dòng)重載值的預(yù)裝載): 當(dāng)改變周期值A(chǔ)RR時(shí),是否等到下一個(gè)更新事件再寫(xiě)入數(shù)值,使得數(shù)值的更改不影響執(zhí)行中的波形。
2、打開(kāi)中斷
高級(jí)定時(shí)器,和通用定時(shí)器不同,即使沒(méi)有使能通道,也有多種中斷。
本篇只使用了周期更新中斷,如下圖, 打勾: update interrupt (更新中斷) 。
當(dāng)計(jì)數(shù)器(CNT)的值,達(dá)到周期值(ARR)時(shí),就會(huì)觸發(fā)中斷。
注意:打勾中斷后,生成的代碼,只是幫我們添加了中斷的配置; 而中斷的開(kāi)啟,需要使用代碼“手動(dòng)”開(kāi)啟。
三、編寫(xiě)代碼 代碼共為3部分:初始化配置、開(kāi)啟TIM、中斷回調(diào)函數(shù)。
1、初始化配置
CubeMX根據(jù)我們的配置,已生成好了初始化代碼,我們不用管它。
如果想查看它的初始化實(shí)現(xiàn)過(guò)程,可以雙擊 "tim.c"。
2、開(kāi)啟TIM、中斷
謹(jǐn)記一個(gè),當(dāng)我們使用CubeMX配置外設(shè)功能時(shí),它只是根據(jù)參數(shù)的配置生成初始化代碼(即上面的第1步),而不會(huì)主動(dòng)開(kāi)啟外設(shè)功能,特別是中斷的開(kāi)啟,如TIM、ADC、UART等。
所以,我們需要在main.c中,“手動(dòng)”開(kāi)啟TIM1。
如下圖,在while前,添加:
HAL_TIM_Base_Start_IT(&htim1);
調(diào)用HAL_TIM_Base_Start_IT(&htim1)后,TIM1就會(huì)開(kāi)始工作。
下面是它的工作原理,硬件自動(dòng)運(yùn)行,不用干預(yù),我們只需大概地知道工作過(guò)程、原理:
① TIM會(huì)自動(dòng)檢測(cè)脈沖信號(hào),每來(lái)一個(gè)脈沖,計(jì)數(shù)器CNT就會(huì)硬件自動(dòng)加1。
② 當(dāng)寄存器CNT的計(jì)數(shù)值==設(shè)定的自動(dòng)重裝載值A(chǔ)RR,就會(huì)產(chǎn)生溢出中斷。
③ 發(fā)生溢出中斷時(shí),CNT值被硬件置0,開(kāi)始新一輪計(jì)數(shù); 硬件自動(dòng)找尋中斷服務(wù)函數(shù)入口。
使用CubeMX生成的HAL代碼,我們不需要像使用標(biāo)準(zhǔn)庫(kù)時(shí)那樣自己編寫(xiě)中斷函數(shù),CubeMX已幫我們整理好中斷函數(shù)的跳轉(zhuǎn),只需要重寫(xiě)中斷回調(diào)函數(shù)。
3、重寫(xiě)TIM1的中斷回調(diào)函數(shù)
按上面CubeMX的配置,我們使用了周期中斷(計(jì)數(shù)器CNT溢出),當(dāng)中斷觸發(fā)時(shí),硬件會(huì)自動(dòng)調(diào)用相關(guān)的中斷服務(wù)函數(shù),而中斷服務(wù)函數(shù)里,CubeMX的工程會(huì)調(diào)用回調(diào)函數(shù):
HAL_TIM_PeriodElapsedCallback();
即:即1周期結(jié)束,硬件自動(dòng)調(diào)用中斷服務(wù)函數(shù),繼而調(diào)用回調(diào)函數(shù),我們無(wú)需干預(yù)。
我們只需在工程中任意一個(gè)c文件里編寫(xiě)這個(gè)回調(diào)函數(shù)。
習(xí)慣上,會(huì)在main.c的尾部編寫(xiě)這個(gè)函數(shù)。
如下圖,我們?cè)趍ain.c的 注釋行 /* USER CODE BEGIN 4 */ 下面編寫(xiě)它。
如果工程中已有這個(gè)函數(shù),我們只需在函數(shù)內(nèi)增加TIM2的判斷部分;
如果工程中沒(méi)有這個(gè)函數(shù),增加即可。
注意:所有TIM的計(jì)數(shù)器溢出中斷(即1周期結(jié)束), 都會(huì)統(tǒng)一調(diào)用它。
在這個(gè)回調(diào)函數(shù)中,我們執(zhí)行的動(dòng)作是:每1000ms, 反轉(zhuǎn)PB2電平(LED)。
如果你的開(kāi)發(fā)板上,PB2引腳接的是 LED, 而且也初始化成輸出模式,它就會(huì)每1秒閃爍1次。
4、優(yōu)化思路:
上述操作,將會(huì)每1s進(jìn)入1000次中斷,當(dāng)發(fā)現(xiàn)變量cnt累加到1000后,才反轉(zhuǎn)LED。
頻繁地出入中斷,大大地浪費(fèi)著芯片運(yùn)行資源。本篇如此設(shè)計(jì),僅為了直觀地展示和理解。
我們?cè)谠O(shè)計(jì)時(shí),應(yīng)該盡量地節(jié)省運(yùn)行資源。
上面的定時(shí)操作,有多種優(yōu)化的方法:
方法1:原參數(shù)不改,重復(fù)計(jì)數(shù)器Repetition Counter改為1000, 即1000個(gè)周期才產(chǎn)生1次中斷;
方法2:psc改為16800(脈沖0.0001s),ARR改為10000(1萬(wàn)個(gè)脈沖組成1周期)
然后,修改回調(diào)函數(shù),取消計(jì)數(shù)判斷那部分。
這樣修改后,將會(huì)每1s進(jìn)入1次中斷,調(diào)用回調(diào)函數(shù)1次,能有效地節(jié)省運(yùn)行資源。
|