怎樣做已有網(wǎng)站的編輯維護(hù)四川聚順成網(wǎng)絡(luò)科技有限公司
本內(nèi)容基于江協(xié)科技STM32視頻內(nèi)容,整理而得。
文章目錄
- 1. TIM
- 1.1 TIM定時(shí)器
- 1.2 定時(shí)器類型
- 1.3 基本定時(shí)器
- 1.4 通用定時(shí)器
- 1.4 高級(jí)定時(shí)器
- 1.5 定時(shí)中斷基本結(jié)構(gòu)
- 1.6 預(yù)分頻器時(shí)序
- 1.7 計(jì)數(shù)器時(shí)序
- 1.8 計(jì)數(shù)器無預(yù)裝時(shí)序
- 1.9 計(jì)數(shù)器有預(yù)裝時(shí)序
- 1.10 RCC時(shí)鐘樹
- 2. TIM庫函數(shù)及代碼
- 2.1 TIM庫函數(shù)
- 2.2 6-1定時(shí)器中斷代碼
- 2.2.1 硬件電路:
- 2.2.2 代碼流程
- 2.2.3 代碼
- 2.3 6-2定時(shí)器外部時(shí)鐘代碼
- 2.3.1 硬件電路
- 2.3.2 代碼流程
- 2.3.3 代碼
1. TIM
1.1 TIM定時(shí)器
- 定時(shí)器可以對(duì)輸入的時(shí)鐘進(jìn)行計(jì)數(shù),并在計(jì)數(shù)值達(dá)到設(shè)定值時(shí)觸發(fā)中斷
- 16位計(jì)數(shù)器、預(yù)分頻器、自動(dòng)重裝寄存器的時(shí)基單元,在72MHz計(jì)數(shù)時(shí)鐘下可以實(shí)現(xiàn)最大59.65s的定時(shí)。1/(72/65536/65536)(計(jì)數(shù)器就是用來執(zhí)行計(jì)數(shù)定時(shí)的一個(gè)寄存器,每來一個(gè)時(shí)鐘,計(jì)數(shù)器加1。預(yù)分頻器可以對(duì)計(jì)數(shù)器的時(shí)鐘進(jìn)行分頻,讓計(jì)數(shù)更加靈活。自動(dòng)重裝寄存器就是計(jì)數(shù)的目標(biāo)值,就是想要計(jì)多少個(gè)時(shí)鐘申請(qǐng)中斷。這些寄存器構(gòu)成了定時(shí)器最核心的部分,把這一塊電路稱為時(shí)基單元)
- 不僅具備基本的定時(shí)中斷功能,而且還包含內(nèi)外時(shí)鐘源選擇、輸入捕獲、輸出比較、編碼器接口、主從觸發(fā)模式等多種功能。
- 根據(jù)復(fù)雜度和應(yīng)用場(chǎng)景分為高級(jí)定時(shí)器、通用定時(shí)器、基本定時(shí)器三種類型。
1.2 定時(shí)器類型
類型 | 編號(hào) | 總線 | 功能 |
---|---|---|---|
高級(jí)定時(shí)器 | TIM1、TIM8 | APB2 | 擁有通用定時(shí)器全部功能,并額外具有重復(fù)計(jì)數(shù)器、死區(qū)生成、互補(bǔ)輸出、剎車輸入等功能 |
通用定時(shí)器 | TIM2、TIM3、TIM4、TIM5 | APB1 | 擁有基本定時(shí)器全部功能,并額外具有內(nèi)外時(shí)鐘源選擇、輸入捕獲、輸出比較、編碼器接口、主從觸發(fā)模式等功能 |
基本定時(shí)器 | TIM6、TIM7 | APB1 | 擁有定時(shí)中斷、主模式觸發(fā)DAC的功能 |
- STM32F103C8T6定時(shí)器資源:TIM1、TIM2、TIM3、TIM4
- DAC:數(shù)模轉(zhuǎn)換器
1.3 基本定時(shí)器
主要功能:
- 16位自動(dòng)重裝載累加計(jì)數(shù)器
- 16位可編程預(yù)分頻器,用于對(duì)輸入的時(shí)鐘按系數(shù)為1~65536之間的任意數(shù)值分頻
- 觸發(fā)DAC的同步電路
- 在更新事件(計(jì)數(shù)器溢出)時(shí)產(chǎn)生中斷/DMA請(qǐng)求
-
預(yù)分頻器PSC
預(yù)分頻器之前連接的就是基準(zhǔn)計(jì)數(shù)時(shí)鐘的輸入。由于基本定時(shí)器只能選擇內(nèi)部時(shí)鐘,因此可以認(rèn)為預(yù)分頻器的輸入線是連接到內(nèi)部時(shí)鐘(CK_INT)。
內(nèi)部時(shí)鐘的來源是RCC的TIMxCLK,這里的頻率值一般都是系統(tǒng)的主頻72MHz。
預(yù)分頻器寫0,就是不分頻;寫1就是2分頻,輸出頻率=輸入頻率/2=36MHz。
寫2就是3分頻,輸出= 輸入/3。所以預(yù)分頻器的值和實(shí)際的分頻系數(shù)相差了1,實(shí)際分頻系數(shù)=預(yù)分頻器的值 + 1。預(yù)分頻器是16位的,所以最大值可以寫65535,也就是65536分頻。 -
計(jì)數(shù)器CNT
計(jì)數(shù)器可以對(duì)預(yù)分頻后的計(jì)數(shù)時(shí)鐘進(jìn)行計(jì)數(shù),計(jì)數(shù)時(shí)鐘每來一個(gè)上升沿,計(jì)數(shù)器的值就加1。計(jì)數(shù)器也是16位的,所以里面的值可以從0一直加到65535。如果再加的話,計(jì)數(shù)器就會(huì)回到0重新開始。所以計(jì)數(shù)器的值在計(jì)數(shù)過程中會(huì)不斷自增運(yùn)行,當(dāng)自增運(yùn)行到目標(biāo)值時(shí),會(huì)產(chǎn)生中斷,那就完成了定時(shí)的任務(wù)。所以還需要一個(gè)存儲(chǔ)目標(biāo)值的寄存器,那就是自動(dòng)重裝寄存器了。 -
自動(dòng)重裝寄存器
自動(dòng)重裝寄存器也是16位的,它存的就是要寫入的計(jì)數(shù)目標(biāo)。在運(yùn)行的過程中,計(jì)數(shù)值不斷自增,自動(dòng)重裝值是固定的目標(biāo),當(dāng)計(jì)數(shù)值等于自動(dòng)重裝值時(shí),也就是計(jì)時(shí)時(shí)間到了。那它就會(huì)產(chǎn)生一個(gè)中斷信號(hào),并且清零計(jì)數(shù)器,計(jì)數(shù)器自動(dòng)開始下一次的計(jì)數(shù)計(jì)時(shí)。 -
U和UI箭頭
圖上畫的一個(gè)向上的折現(xiàn)箭頭,就代表這里會(huì)產(chǎn)生中斷信號(hào),像這種計(jì)數(shù)值等于自動(dòng)重裝值產(chǎn)生的中斷,一般把它叫做“更新中斷”。這個(gè)更新中斷之后就會(huì)通往NVIC,我們?cè)倥渲煤肗VIC的定時(shí)器通道,那定時(shí)器的更新中斷就能夠得到CPU的響應(yīng)了。向下的箭頭,代表的是會(huì)產(chǎn)生一個(gè)事件,這里對(duì)應(yīng)的事件就叫做“更新事件”。更新事件不會(huì)觸發(fā)中斷,但可以觸發(fā)內(nèi)部其他電路的工作。
1.4 通用定時(shí)器
主要功能:
-
16位向上、向下、向上/向上 自動(dòng)重裝載累加計(jì)數(shù)器
-
16位可編程預(yù)分頻器,用于對(duì)輸入的時(shí)鐘按系數(shù)為1~65536之間的任意數(shù)值分頻
-
4個(gè)獨(dú)立通道:
- 輸入捕獲
- 輸出比較
- PWM生成(邊緣或中間對(duì)齊模式)
- 單脈沖模式輸出
-
使用外部信號(hào)控制定時(shí)器和定時(shí)器互連的同步電路
-
如下事件發(fā)生時(shí)產(chǎn)生中斷/DMA:
- 更新:計(jì)數(shù)器向上溢出/向下溢出,計(jì)數(shù)器初始化(通過軟件或內(nèi)部/外部觸發(fā))
- 觸發(fā)事件(計(jì)數(shù)器啟動(dòng)、停止、初始化或者由內(nèi)部/外部觸發(fā)計(jì)數(shù))
- 輸入捕獲
- 輸出比較
-
支持針對(duì)定位的增量(正交)編碼器和霍爾傳感器電路
-
觸發(fā)輸入作為外部時(shí)鐘或者按周期的電流管理
-
CNT計(jì)數(shù)器
CNT計(jì)數(shù)器支持向上計(jì)數(shù)模式、向下計(jì)數(shù)模式、中央對(duì)齊模式。向下計(jì)數(shù)模式就是從重裝值開始,向下自減,減到0之后,回到重裝值同時(shí)申請(qǐng)中斷。中央對(duì)齊模式是從0開始,先向上自增,計(jì)到重裝值,申請(qǐng)中斷,然后再向下自減,減到0,再申請(qǐng)中斷。 -
時(shí)鐘源
通用定時(shí)器的時(shí)鐘源不僅可以選擇內(nèi)部72MHz時(shí)鐘,還可以選擇外部時(shí)鐘。
(1)第一個(gè)外部時(shí)鐘就是來自TIMx_ETR引腳上的外部時(shí)鐘,也就是可以在TIM2的ETR引腳即PA0上接一個(gè)外部方波時(shí)鐘,然后配置一下內(nèi)部的極性選擇、邊沿檢測(cè)和預(yù)分頻器電路,以及輸入濾波電路,這兩塊電路可以對(duì)外部時(shí)鐘進(jìn)行一定的整形。因?yàn)槭峭獠恳_的時(shí)鐘,所以難免有一些毛刺,那這些電路就可以對(duì)輸入的波形進(jìn)行濾波。濾波后的信號(hào),兵分兩路,上面一路ETRF進(jìn)入觸發(fā)控制器,緊跟著就可以選擇作為時(shí)基單元的時(shí)鐘了。這一路也叫做“外部時(shí)鐘模式2”。
(2)TRGI也可以提供外部時(shí)鐘,主要用作觸發(fā)輸入使用的,這個(gè)觸發(fā)輸入可以觸發(fā)定時(shí)器的從模式。當(dāng)TRGI當(dāng)作外部時(shí)鐘來使用時(shí),這一路就叫做“外部時(shí)鐘模式1”。通過這一路的外部時(shí)鐘有哪些呢?第一個(gè)就是ETR引腳的信號(hào)。第二個(gè)是ITR信號(hào),這一部分的時(shí)鐘信號(hào)是來自其他定時(shí)器的。主模式的TRGO可以通向其他定時(shí)器,通向其他定時(shí)器的時(shí)候,就接到了其他定時(shí)器的ITR引腳上來了,ITR0到ITR3分別來自其他4個(gè)定時(shí)器的TRGO輸出。也可以選擇TI1F_ED,這里連接的是輸入捕獲單元的CH1引腳,也就是從CH1引腳獲得時(shí)鐘,這里后綴加一個(gè)ED(Edge)就是邊沿的意思。還可以通過TI1FP1和TI2FP2獲得,TI1FP1是連接到了CH1引腳的時(shí)鐘,TI2FP2連接到了CH2引腳的時(shí)鐘。
總結(jié):外部時(shí)鐘模式1的輸入可以是ETR引腳、其他定時(shí)器、CH1引腳的邊沿、CH1引腳和CH2引腳。 -
輸出比較電路
下面的右邊部分是輸出比較電路,總共有四個(gè)通道,分別對(duì)應(yīng)CH1到CH4的引腳,可以用于輸出PWM波形,驅(qū)動(dòng)電機(jī)。 -
輸入捕獲電路
左邊是輸入捕獲電路,也是有四個(gè)通道,對(duì)應(yīng)的也是CH1到CH4的引腳,可以用于測(cè)輸入方波的頻率等。 -
捕獲/比較寄存器
中間的寄存器是捕獲/比較寄存器,是輸入捕獲和輸出比較電路共用的,因?yàn)檩斎氩东@和輸出比較不能同時(shí)使用,所以這里寄存器是共用的,引腳也是共用的。
1.4 高級(jí)定時(shí)器
主要功能:
- 16位向上、向下、向上/向上 自動(dòng)重裝載累加計(jì)數(shù)器
- 16位可編程預(yù)分頻器,用于對(duì)輸入的時(shí)鐘按系數(shù)為1~65536之間的任意數(shù)值分頻
- 4個(gè)獨(dú)立通道:
- 輸入捕獲
- 輸出比較
- PWM生成(邊緣或中間對(duì)齊模式)
- 單脈沖模式輸出
- 死區(qū)時(shí)間可編程的互補(bǔ)輸出
- 使用外部信號(hào)控制定時(shí)器和定時(shí)器互連的同步電路
- 允許在指定數(shù)據(jù)的計(jì)數(shù)器周期之后更新定時(shí)器寄存器的重復(fù)計(jì)數(shù)器
- 剎車輸入信號(hào)可以將定時(shí)器輸出信號(hào)置于復(fù)位狀態(tài)或者一個(gè)已知狀態(tài)
- 如下事件發(fā)生時(shí)產(chǎn)生中斷/DMA:
- 更新:計(jì)數(shù)器向上溢出/向下溢出,計(jì)數(shù)器初始化(通過軟件或內(nèi)部/外部觸發(fā))
- 觸發(fā)事件(計(jì)數(shù)器啟動(dòng)、停止、初始化或者由內(nèi)部/外部觸發(fā)計(jì)數(shù))
- 輸入捕獲
- 輸出比較
- 剎車信號(hào)輸入
- 支持針對(duì)定位的增量(正交)編碼器和霍爾傳感器電路
- 觸發(fā)輸入作為外部時(shí)鐘或者按周期的電流管理
-
重復(fù)次數(shù)計(jì)數(shù)器
和通用定時(shí)器的區(qū)別:第一個(gè)是在申請(qǐng)中斷的地方增加了一個(gè)重復(fù)次數(shù)計(jì)數(shù)器,有了這個(gè)計(jì)數(shù)器之后,就可以實(shí)現(xiàn)每隔幾個(gè)計(jì)數(shù)周期才發(fā)生一次更新事件和更新中斷。原來的結(jié)構(gòu)是每個(gè)計(jì)數(shù)周期完成后就都會(huì)發(fā)生更新,這就相當(dāng)于對(duì)輸出的更新信號(hào)又做了一次分頻。 -
DTG死區(qū)生成器和互補(bǔ)輸出
下面是高級(jí)定時(shí)器對(duì)輸出比較模塊的升級(jí)了,DTG(dead time generate)是死區(qū)生成電路。右邊的輸出引腳由原來的一個(gè)變?yōu)榱藘蓚€(gè)互補(bǔ)的輸出,可以輸出一對(duì)互補(bǔ)的PWM波,這些電路是為了驅(qū)動(dòng)三相無刷電機(jī)的,比如四軸飛行器、電動(dòng)車的后輪、電鉆等,里面都可能是三相無刷電機(jī)。因?yàn)槿酂o刷電機(jī)的驅(qū)動(dòng)電路一般需要3個(gè)橋臂,每個(gè)橋臂2個(gè)大功率開關(guān)管來控制,所以總共需要6個(gè)大功率開關(guān)管。因此這里的輸出PWM引腳的前三路就變?yōu)榱嘶パa(bǔ)的輸出。另外,為了防止互補(bǔ)輸出的PWM驅(qū)動(dòng)橋臂時(shí),在開關(guān)切換的瞬間,由于器件的不理想,造成短暫的直通現(xiàn)象,所以前面就加上了死區(qū)生成電路。在開關(guān)切換的瞬間,產(chǎn)生一定時(shí)長的死區(qū),讓橋臂的上下管全都關(guān)斷,防止直通現(xiàn)象。 -
剎車輸入
最后一部分就是剎車輸入的功能了,這個(gè)是為了給電機(jī)驅(qū)動(dòng)提供安全保障的。如果外部引腳BKIN(Break IN)產(chǎn)生了剎車信號(hào),或內(nèi)部時(shí)鐘失效,產(chǎn)生了故障,那么控制電路就會(huì)自動(dòng)切斷電機(jī)的輸出,防止意外的發(fā)生。
1.5 定時(shí)中斷基本結(jié)構(gòu)
運(yùn)行控制:控制寄存器中的一些位,如啟動(dòng)停止、向上或向下計(jì)數(shù)等。
右邊就是計(jì)時(shí)時(shí)間到,產(chǎn)生更新中斷后的信號(hào)去向,如果是高級(jí)定時(shí)器的話,還會(huì)多一個(gè)重復(fù)計(jì)數(shù)器。中斷信號(hào)會(huì)先在狀態(tài)寄存器里置一個(gè)中斷標(biāo)志位,這個(gè)標(biāo)志位會(huì)通過中斷輸出控制,到NVIC申請(qǐng)中斷。中斷輸出控制就是一個(gè)中斷輸出的允許位,如果需要某個(gè)中斷,就記得允許一下。
1.6 預(yù)分頻器時(shí)序
- 計(jì)數(shù)器計(jì)數(shù)頻率:CK_CNT = CK_PSC / (PSC + 1)
- CK_PSC:預(yù)分頻器時(shí)鐘,內(nèi)部時(shí)鐘就是72MHz。
- CNT_EN:計(jì)數(shù)器使能,高電平計(jì)數(shù)器正常運(yùn)行,低電平計(jì)數(shù)器停止。
- CK_CNT:計(jì)數(shù)器時(shí)鐘,它既是預(yù)分頻器的時(shí)鐘輸出,也是計(jì)數(shù)器的時(shí)鐘輸入。
- 在開始時(shí),計(jì)數(shù)器未使能,計(jì)數(shù)器時(shí)鐘不運(yùn)行。使能后,前半段,實(shí)際分頻系數(shù)為1(PSC=0),計(jì)數(shù)器的時(shí)鐘等于預(yù)分頻器前的時(shí)鐘;后半段,實(shí)際分頻系數(shù)為2(PSC=1)了,計(jì)數(shù)器的時(shí)鐘也就變?yōu)轭A(yù)分頻器前時(shí)鐘的一半了。在計(jì)數(shù)器時(shí)鐘的驅(qū)動(dòng)下,下面的計(jì)數(shù)器寄存器也跟隨時(shí)鐘的上升沿不斷自增,在中間的這個(gè)位置FC之后,計(jì)數(shù)值變?yōu)?了,從這里可以推斷出ARR自動(dòng)重裝值就是FC。當(dāng)計(jì)數(shù)值計(jì)到和重裝值相等,并且下一個(gè)時(shí)鐘來臨時(shí),計(jì)數(shù)值才清零,同時(shí)下面產(chǎn)生一個(gè)更新事件,這就是一個(gè)計(jì)數(shù)周期的工作流程。
- 下面的三行描述的是預(yù)分頻寄存器的一種緩沖機(jī)制,也就是這個(gè)預(yù)分頻寄存器實(shí)際上是有兩個(gè),一個(gè)是預(yù)分頻控制寄存器,是供我們讀寫用的,它并不直接決定分頻系數(shù)。另外還有一個(gè)緩沖寄存器或者說是影子寄存器:預(yù)分頻緩沖器,這個(gè)緩沖寄存器才是真正起作用的寄存器,比如我們?cè)谀硞€(gè)時(shí)刻,把預(yù)分頻寄存器由0改成了1,如果在此時(shí)立刻改變時(shí)鐘的分頻系數(shù),那么就會(huì)導(dǎo)致在一個(gè)計(jì)數(shù)周期內(nèi),前半部分和后半部分的頻率不一樣。因此設(shè)計(jì)了緩沖器,當(dāng)計(jì)數(shù)計(jì)到一半的時(shí)候改變了分頻值,這個(gè)變化并不會(huì)立刻生效,而是會(huì)等到本次計(jì)數(shù)周期結(jié)束時(shí),產(chǎn)生了更新事件,預(yù)分頻寄存器的值才會(huì)被傳遞到緩沖寄存器里,才會(huì)生效。
- 最后一行可以看出:預(yù)分頻器內(nèi)部也是靠計(jì)數(shù)來分頻的,當(dāng)預(yù)分頻值為0時(shí),計(jì)數(shù)器就一直為0,直接輸出原頻率;當(dāng)預(yù)分頻值為1時(shí),計(jì)數(shù)器就0、1、0、1、0、1這樣計(jì)數(shù),在回到0時(shí),輸出1個(gè)脈沖,這樣輸出頻率就是輸入頻率的2分頻,預(yù)分頻器的值和實(shí)際的分頻系數(shù)之間有一個(gè)數(shù)的偏移。
1.7 計(jì)數(shù)器時(shí)序
- 計(jì)數(shù)器溢出頻率:CK_CNT_OV = CK_CNT / (ARR + 1)= CK_PSC / (PSC + 1) / (ARR + 1)
- CK_INT:內(nèi)部時(shí)鐘72MHz;
- CNT_EN:計(jì)數(shù)器使能,上升沿有效;
- CK_CNT:計(jì)數(shù)器時(shí)鐘,因?yàn)榉诸l系數(shù)為2,所以這個(gè)頻率是CK_INT除2。然后計(jì)數(shù)器在這個(gè)時(shí)鐘每個(gè)上升沿自增,當(dāng)增到0036的時(shí)候,發(fā)生溢出。計(jì)到36之后,再來一個(gè)上升沿,計(jì)數(shù)器清零,計(jì)數(shù)器溢出,產(chǎn)生一個(gè)更新事件脈沖,另外還會(huì)置一個(gè)更新中斷標(biāo)志(UIF),更新中斷標(biāo)志(UIF)置1了,就會(huì)申請(qǐng)中斷,中斷響應(yīng)后,需要在中斷程序中手動(dòng)清零。
1.8 計(jì)數(shù)器無預(yù)裝時(shí)序
更改了自動(dòng)加載寄存器,由FF改成了36,那計(jì)數(shù)值的目標(biāo)值就由FF變成了36,所以這里計(jì)到36之后,就直接更新開始下一輪的計(jì)數(shù),
1.9 計(jì)數(shù)器有預(yù)裝時(shí)序
在計(jì)數(shù)的中途,把計(jì)數(shù)目標(biāo)值由F5改成了36。下面有個(gè)影子寄存器,這個(gè)影子寄存器才是真正起作用的,它還是F5,所以現(xiàn)在計(jì)數(shù)的目標(biāo)還是計(jì)到F5,產(chǎn)生更新事件,同時(shí),要更改的36才被傳遞到影子寄存器,在下一個(gè)計(jì)數(shù)周期這個(gè)更改的36才有效,所以這個(gè)引入影子寄存器的目的實(shí)際上是為了同步,就是讓值的變化和更新事件同步發(fā)生,防止在運(yùn)行途中,更改造成錯(cuò)誤。
1.10 RCC時(shí)鐘樹
-
時(shí)鐘源
在時(shí)鐘產(chǎn)生電路,有四個(gè)震蕩源:
(1)HSI:內(nèi)部的8MHz高速RC振蕩器;
(2)HSE:外部的4~16MHz高速石英晶體振蕩器,也就是晶振,一般都是接8MHz;
(3)LSE:外部的32.768KHz低速晶振,這個(gè)一般是給RTC提供時(shí)鐘的;
(4)LSI:最后是內(nèi)部的40KHz低速RC振蕩器,這個(gè)可以給看門狗提供時(shí)鐘。
上面兩個(gè)高速晶振是用提供系統(tǒng)時(shí)鐘的,AHB、APB2、APB1的時(shí)鐘都是來源于這兩個(gè)高速晶振,只不過是外部的石英振蕩器比內(nèi)部的RC振蕩器更加穩(wěn)定,所以一般都是用外部晶振。 -
ST配置時(shí)鐘
在SystemInit函數(shù)里,ST配置時(shí)鐘:首先會(huì)啟動(dòng)內(nèi)部時(shí)鐘HSI,選擇內(nèi)部8MHz為系統(tǒng)時(shí)鐘,暫時(shí)以內(nèi)部8MHz的時(shí)鐘運(yùn)行。然后再啟動(dòng)外部時(shí)鐘,配置外部時(shí)鐘進(jìn)入PLL鎖相環(huán)進(jìn)行倍頻,8MHz倍頻9倍,就得到72MHz,等到鎖相環(huán)輸出穩(wěn)定后,選擇鎖相環(huán)輸出為系統(tǒng)時(shí)鐘,這樣就把系統(tǒng)時(shí)鐘由8MHz切換為了72MHz。 -
CSS時(shí)鐘安全系統(tǒng)
CSS(clock security system):時(shí)鐘安全系統(tǒng),也是負(fù)責(zé)切換時(shí)鐘的,可以監(jiān)測(cè)外部時(shí)鐘的運(yùn)行狀態(tài),一旦外部時(shí)鐘失效,就會(huì)自動(dòng)把外部時(shí)鐘切換回內(nèi)部時(shí)鐘,保證系統(tǒng)時(shí)鐘的運(yùn)行,防止程序卡死造成事故。 -
時(shí)鐘分配電路
- AHB總線: 首先系統(tǒng)時(shí)鐘72MHz進(jìn)入AHB總線,AHB總線有個(gè)預(yù)分頻器,在SystemInit里配置的分配系數(shù)為1,那AHB的時(shí)鐘就是72MHz。
- APB1總線:這里配置的分配系數(shù)為2,所以APB1總線的時(shí)鐘為72MHz/2=36MHz。下面的如果APB1預(yù)分頻系數(shù)=1,則頻率不變,否則頻率
*2
,然后右邊,是單獨(dú)為定時(shí)器2-7開通的,因?yàn)檫@里預(yù)分頻系數(shù),我們給的是2,所以這里頻率要再*2
,所以通向定時(shí)器2~7的時(shí)鐘為72MHz。因此無論是高級(jí)定時(shí)器、通用定時(shí)器還是基本定時(shí)器,它們的內(nèi)部基準(zhǔn)時(shí)鐘都是72MHz。 - APB2總線:APB2的分頻系數(shù)為1,所以時(shí)鐘為72MHz。然后接在APB2上的時(shí)鐘也單開了一路,即如果APB2預(yù)分頻系數(shù)=1,則頻率不變,否則頻率
*2
。因?yàn)榉诸l系數(shù)給的是1,所以定時(shí)器1和8的時(shí)鐘就是72MHz。 - 時(shí)鐘輸出部分都有一個(gè)與門進(jìn)行輸出控制,控制位寫的是外部時(shí)鐘使能,這就是我們?cè)僭诔绦蛑袑慠CC_APB2/1PeriphClockCmd作用的地方,打開時(shí)鐘,就是在這個(gè)位置寫1,讓左邊的時(shí)鐘能夠通過與門輸出給外設(shè)。
2. TIM庫函數(shù)及代碼
2.1 TIM庫函數(shù)
// 恢復(fù)缺省配置
void TIM_DeInit(TIM_TypeDef* TIMx);// 時(shí)基單元初始化
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);// 結(jié)構(gòu)體變量賦一個(gè)默認(rèn)值
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);// 使能計(jì)數(shù)器---運(yùn)行控制
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);// 使能中斷輸出---中斷輸出控制
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);/*-----------------時(shí)基單元的時(shí)鐘選擇---------*/
// 選擇內(nèi)部時(shí)鐘
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);// 選擇ITRx其他定時(shí)器的時(shí)鐘
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);// 選擇TIx捕獲通道的時(shí)鐘
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,uint16_t TIM_ICPolarity, uint16_t ICFilter);// 選擇ETR通過外部時(shí)鐘模式1輸入的時(shí)鐘
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);// 選擇ETR通過外部時(shí)鐘模式2輸入的時(shí)鐘
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);/*--------------------------------------------------------*/
// 不是用來選擇時(shí)鐘的,單獨(dú)用來配置ETR引腳的預(yù)分頻器、極性、濾波參數(shù)的
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);// 用來單獨(dú)寫預(yù)分頻值的
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);// 用來改變計(jì)數(shù)器的計(jì)數(shù)模式
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);// 自動(dòng)重裝器預(yù)裝功能配置
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);// 給計(jì)數(shù)器寫入一個(gè)值
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);// 給自動(dòng)重裝器寫入一個(gè)值
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);// 獲取當(dāng)前計(jì)數(shù)器的值
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);// 獲取當(dāng)前的預(yù)分頻器的值
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);/*-------------獲取標(biāo)志位和清除標(biāo)志位的------------*/
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
2.2 6-1定時(shí)器中斷代碼
2.2.1 硬件電路:
實(shí)現(xiàn)功能:定時(shí)1s,并在OLED上顯示Num值(中斷觸發(fā)次數(shù),也即定時(shí)時(shí)間)
2.2.2 代碼流程
-
定時(shí)器代碼
- 開啟時(shí)鐘RCC,定時(shí)器的基準(zhǔn)時(shí)鐘和整個(gè)外設(shè)的工作時(shí)鐘都會(huì)同時(shí)打開了;
- 選擇時(shí)基單元的時(shí)鐘源,對(duì)于定時(shí)中斷,選擇內(nèi)部時(shí)鐘源;
- 配置時(shí)基單元,包括預(yù)分頻器、自動(dòng)重裝器、計(jì)數(shù)模式等–用結(jié)構(gòu)體;
- 配置中斷輸出控制,允許更新中斷輸出到NVIC;
- 配置NVIC,在NVIC中打開定時(shí)器中斷的通道,并分配一個(gè)優(yōu)先級(jí);
- 運(yùn)行控制;
整個(gè)模塊配置完成后,還需要使能一下計(jì)數(shù)器,要不然計(jì)數(shù)器是不會(huì)運(yùn)行的。當(dāng)定時(shí)器使能后,計(jì)數(shù)器就開始計(jì)數(shù)了,當(dāng)計(jì)數(shù)器更新時(shí),觸發(fā)中斷,最后再寫一個(gè)定時(shí)器的中斷函數(shù),這樣這個(gè)中斷函數(shù)就每隔一段時(shí)間就能自動(dòng)執(zhí)行一次了。
-
中斷函數(shù)
- 判斷是否進(jìn)入定時(shí)器TIM2的中斷,然后清除中斷標(biāo)志位。
- 使定時(shí)器每秒自動(dòng)加一下Num變量
-
ARR和PSC設(shè)置
- ARR=10000 - 1;PSC = 7200 - 1;
- 定時(shí)器時(shí)鐘CK_CNT =72M / (PSC + 1) = 10000 ;
- 定時(shí)頻率 = CK_CNT / (ARR + 1) = 1。定時(shí)1s,也就是定時(shí)頻率為1Hz。
預(yù)分頻是對(duì)72M進(jìn)行7200分頻,得到的就是10K的計(jì)數(shù)頻率,在10K的頻率下,計(jì)10000個(gè)數(shù),就是1s的時(shí)間。(在1s的時(shí)間內(nèi)計(jì)10000個(gè)數(shù),當(dāng)計(jì)到10000個(gè)數(shù)后,自動(dòng)清0,同時(shí)申請(qǐng)中斷,在OLED顯示屏上就是顯示Num值每1s加1)。也可以更改ARR和PSC的值。
- main函數(shù)
- OLED顯示Num值。
2.2.3 代碼
- Timer.c代碼
#include "stm32f10x.h" // Device header/*** 函 數(shù):定時(shí)中斷初始化* 參 數(shù):無* 返 回 值:無*/
void Timer_Init(void)
{/*開啟時(shí)鐘*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //開啟TIM2的時(shí)鐘/*配置時(shí)鐘源*/TIM_InternalClockConfig(TIM2); //選擇TIM2為內(nèi)部時(shí)鐘,若不調(diào)用此函數(shù),TIM默認(rèn)也為內(nèi)部時(shí)鐘/*時(shí)基單元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定義結(jié)構(gòu)體變量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時(shí)鐘分頻,選擇不分頻,此參數(shù)用于配置濾波器時(shí)鐘,不影響時(shí)基單元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //計(jì)數(shù)器模式,選擇向上計(jì)數(shù)TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1; //計(jì)數(shù)周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1; //預(yù)分頻器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重復(fù)計(jì)數(shù)器,高級(jí)定時(shí)器才會(huì)用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //將結(jié)構(gòu)體變量交給TIM_TimeBaseInit,配置TIM2的時(shí)基單元 /*中斷輸出配置*/TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除定時(shí)器更新標(biāo)志位//TIM_TimeBaseInit函數(shù)末尾,手動(dòng)產(chǎn)生了更新事件//若不清除此標(biāo)志位,則開啟中斷后,會(huì)立刻進(jìn)入一次中斷//如果不介意此問題,則不清除此標(biāo)志位也可TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //開啟TIM2的更新中斷/*NVIC中斷分組*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC為分組2//即搶占優(yōu)先級(jí)范圍:0~3,響應(yīng)優(yōu)先級(jí)范圍:0~3//此分組配置在整個(gè)工程中僅需調(diào)用一次//若有多個(gè)中斷,可以把此代碼放在main函數(shù)內(nèi),while循環(huán)之前//若調(diào)用多次配置分組的代碼,則后執(zhí)行的配置會(huì)覆蓋先執(zhí)行的配置/*NVIC配置*/NVIC_InitTypeDef NVIC_InitStructure; //定義結(jié)構(gòu)體變量NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //選擇配置NVIC的TIM2線NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC線路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //指定NVIC線路的搶占優(yōu)先級(jí)為2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC線路的響應(yīng)優(yōu)先級(jí)為1NVIC_Init(&NVIC_InitStructure); //將結(jié)構(gòu)體變量交給NVIC_Init,配置NVIC外設(shè)/*TIM使能*/TIM_Cmd(TIM2, ENABLE); //使能TIM2,定時(shí)器開始運(yùn)行
}
- main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"uint16_t Num; //定義在定時(shí)器中斷里自增的變量int main(void)
{/*模塊初始化*/OLED_Init(); //OLED初始化Timer_Init(); //定時(shí)中斷初始化/*顯示靜態(tài)字符串*/OLED_ShowString(1, 1, "Num:"); //1行1列顯示字符串Num:while (1){OLED_ShowNum(1, 5, Num, 5); //不斷刷新顯示Num變量}
}/*** 函 數(shù):TIM2中斷函數(shù)* 參 數(shù):無* 返 回 值:無* 注意事項(xiàng):此函數(shù)為中斷函數(shù),無需調(diào)用,中斷觸發(fā)后自動(dòng)執(zhí)行* 函數(shù)名為預(yù)留的指定名稱,可以從啟動(dòng)文件復(fù)制* 請(qǐng)確保函數(shù)名正確,不能有任何差異,否則中斷函數(shù)將不能進(jìn)入*/
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) //判斷是否是TIM2的更新事件觸發(fā)的中斷{Num ++; //Num變量自增,用于測(cè)試定時(shí)中斷TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除TIM2更新事件的中斷標(biāo)志位//中斷標(biāo)志位必須清除//否則中斷將連續(xù)不斷地觸發(fā),導(dǎo)致主程序卡死}
}
2.3 6-2定時(shí)器外部時(shí)鐘代碼
2.3.1 硬件電路
- 將對(duì)射式紅外傳感器接在PA0引腳,即TIM2_CH1_ETR,時(shí)鐘配置為外部時(shí)鐘模式2。
- 每次對(duì)傳感器進(jìn)行遮擋時(shí),計(jì)數(shù)值CNT(TIM_GetCounter(TIM2))加1,當(dāng)加到ARR時(shí),觸發(fā)中斷,使Num值加1。
- 在OLED顯示屏上顯示Num和CNT的值。
2.3.2 代碼流程
- 定時(shí)器代碼
- 開啟時(shí)鐘RCC,TIM2和GPIOA。
- 配置GPIO,為上拉輸入。
- 選擇時(shí)基單元的時(shí)鐘源,外部時(shí)鐘模式2,時(shí)鐘從TIM2_ETR引腳輸入;
- 配置時(shí)基單元,包括預(yù)分頻器、自動(dòng)重裝器、計(jì)數(shù)模式等–用結(jié)構(gòu)體;
- 配置中斷輸出控制,允許更新中斷輸出到NVIC;
- 配置NVIC,在NVIC中打開定時(shí)器中斷的通道,并分配一個(gè)優(yōu)先級(jí);
- 運(yùn)行控制;
- ARR和PSC
- ARR = 10 - 1; PSC = 1 - 1;
- 因?yàn)闆]有進(jìn)行分頻,所以對(duì)射式紅外傳感器每遮擋一次,計(jì)數(shù)值CNT加1,當(dāng)計(jì)數(shù)值加到9后,自動(dòng)清零,同時(shí)申請(qǐng)中斷,Num++。
- main函數(shù)
- 實(shí)現(xiàn)在OLED顯示屏上顯示Num和CNT的值。
2.3.3 代碼
- Timer.c
#include "stm32f10x.h" // Device header/*** 函 數(shù):定時(shí)中斷初始化* 參 數(shù):無* 返 回 值:無* 注意事項(xiàng):此函數(shù)配置為外部時(shí)鐘,定時(shí)器相當(dāng)于計(jì)數(shù)器*/
void Timer_Init(void)
{/*開啟時(shí)鐘*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //開啟TIM2的時(shí)鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟GPIOA的時(shí)鐘/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //將PA0引腳初始化為上拉輸入/*外部時(shí)鐘配置*/TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);//選擇外部時(shí)鐘模式2,時(shí)鐘從TIM_ETR引腳輸入//注意TIM2的ETR引腳固定為PA0,無法隨意更改//最后一個(gè)濾波器參數(shù)加到最大0x0F,可濾除時(shí)鐘信號(hào)抖動(dòng)/*時(shí)基單元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定義結(jié)構(gòu)體變量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時(shí)鐘分頻,選擇不分頻,此參數(shù)用于配置濾波器時(shí)鐘,不影響時(shí)基單元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //計(jì)數(shù)器模式,選擇向上計(jì)數(shù)TIM_TimeBaseInitStructure.TIM_Period = 10 - 1; //計(jì)數(shù)周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //預(yù)分頻器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重復(fù)計(jì)數(shù)器,高級(jí)定時(shí)器才會(huì)用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //將結(jié)構(gòu)體變量交給TIM_TimeBaseInit,配置TIM2的時(shí)基單元 /*中斷輸出配置*/TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除定時(shí)器更新標(biāo)志位//TIM_TimeBaseInit函數(shù)末尾,手動(dòng)產(chǎn)生了更新事件//若不清除此標(biāo)志位,則開啟中斷后,會(huì)立刻進(jìn)入一次中斷//如果不介意此問題,則不清除此標(biāo)志位也可TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //開啟TIM2的更新中斷/*NVIC中斷分組*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC為分組2//即搶占優(yōu)先級(jí)范圍:0~3,響應(yīng)優(yōu)先級(jí)范圍:0~3//此分組配置在整個(gè)工程中僅需調(diào)用一次//若有多個(gè)中斷,可以把此代碼放在main函數(shù)內(nèi),while循環(huán)之前//若調(diào)用多次配置分組的代碼,則后執(zhí)行的配置會(huì)覆蓋先執(zhí)行的配置/*NVIC配置*/NVIC_InitTypeDef NVIC_InitStructure; //定義結(jié)構(gòu)體變量NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //選擇配置NVIC的TIM2線NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC線路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //指定NVIC線路的搶占優(yōu)先級(jí)為2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC線路的響應(yīng)優(yōu)先級(jí)為1NVIC_Init(&NVIC_InitStructure); //將結(jié)構(gòu)體變量交給NVIC_Init,配置NVIC外設(shè)/*TIM使能*/TIM_Cmd(TIM2, ENABLE); //使能TIM2,定時(shí)器開始運(yùn)行
}/*** 函 數(shù):返回定時(shí)器CNT的值* 參 數(shù):無* 返 回 值:定時(shí)器CNT的值,范圍:0~65535*/
uint16_t Timer_GetCounter(void)
{return TIM_GetCounter(TIM2); //返回定時(shí)器TIM2的CNT
}
- main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"uint16_t Num; //定義在定時(shí)器中斷里自增的變量int main(void)
{/*模塊初始化*/OLED_Init(); //OLED初始化Timer_Init(); //定時(shí)中斷初始化/*顯示靜態(tài)字符串*/OLED_ShowString(1, 1, "Num:"); //1行1列顯示字符串Num:OLED_ShowString(2, 1, "CNT:"); //2行1列顯示字符串CNT:while (1){OLED_ShowNum(1, 5, Num, 5); //不斷刷新顯示Num變量OLED_ShowNum(2, 5, Timer_GetCounter(), 5); //不斷刷新顯示CNT的值}
}/*** 函 數(shù):TIM2中斷函數(shù)* 參 數(shù):無* 返 回 值:無* 注意事項(xiàng):此函數(shù)為中斷函數(shù),無需調(diào)用,中斷觸發(fā)后自動(dòng)執(zhí)行* 函數(shù)名為預(yù)留的指定名稱,可以從啟動(dòng)文件復(fù)制* 請(qǐng)確保函數(shù)名正確,不能有任何差異,否則中斷函數(shù)將不能進(jìn)入*/
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) //判斷是否是TIM2的更新事件觸發(fā)的中斷{Num ++; //Num變量自增,用于測(cè)試定時(shí)中斷TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除TIM2更新事件的中斷標(biāo)志位//中斷標(biāo)志位必須清除//否則中斷將連續(xù)不斷地觸發(fā),導(dǎo)致主程序卡死}
}