時鍾源
STM32包含了5個時鍾源,分別為HSI、HSE、LSI、LSE、PLL。
- HSI是高速內部時鍾、RC振盪器,頻率為8MHz;
- HSE是高速外部時鍾,即晶振,可接石英/陶瓷諧振器或接外部時鍾源,頻率范圍為4MHz~16MHz;
- LSI為低速內部時鍾、RC振盪器,頻率40kHz;
- LSE為低速外部時鍾,接32.768kHz晶振,作為RTC時鍾源;
- PLL為鎖相環倍頻輸出,其時鍾輸入源可選擇為HSI/2、HSE或者HSE/2。倍頻可選擇為2~16倍,但是其輸出頻率最大不得超過72MHz;
定時器TIM2~TIM7掛載在APB1分頻器上,TIM1和TIM8掛載在APB2分頻器上;APB1上面掛載的是低速外設,APB2上掛載高速外設。APB2可以工作在72MHz下,而APB1最大是36MHz。
定時器的產生路線:系統時鍾 -> AHB預分頻 -> APB2預分頻 -> TIM1倍頻器 -> 產生TIM1的時鍾系統
在system_stm32f10x.c文件下,有默認定義SYSCLK_FREQ_72MHz,同時在SystemInit()函數下調用了SetSysClock(),根據宏定義將時鍾設為72MHz。讀取SystemCoreClock變量即可獲得系統時鍾頻率。
在默認情況下,系統的各個時鍾頻率如下:
- SYSCLK:72M
- AHB:72M
- APB1(PCLK1):36M
- APB2(PCLK2):72M
- PLL:72M
計時器的類型
- TIM1和TIM8是高級定時器
- TIM2-TIM5是通用定時器
- TIM6和TIM7是基本的定時器
這8個定時器都是16位的,它們的計數器的類型除了基本定時器TIM6和TIM7其他都支持向上、向下、向上/向下這3種計數模式。
計數器的三種計數模式
- 向上計數模式:從0開始,計到arr預設值,產生溢出事件,返回重新計時
- 向下計數模式:從arr預設值開始,計到0,產生溢出事件,返回重新計時
- 中央對齊模式:從0開始向上計數,計到arr產生溢出事件,然后向下計數,計數到1以后,又產生溢出,然后再從0開始向上計數。(此種技術方法也可叫向上/向下計數)
各定時器的主要功能
基本定時器(TIM6、TIM7)的主要功能:
只有最基本的定時功能,基本定時器TIM6和TIM7各包含一個16位自動裝載計數器,由各自的可編程預分頻器驅動。主要用於產生DAC觸發信號。
通用定時器(TIM2~TIM5)的主要功能:
除了基本的定時器的功能外,還具有測量輸入信號的脈沖長度(輸入捕獲)或者產生輸出波形(輸出比較和PWM)
高級定時器(TIM1、TIM8)的主要功能:
高級定時器不但具有基本/通用定時器的所有的功能外,還具有控制交直流電動機所有的功能,比如它可以輸出6路互補帶死區的信號,剎車功能等等。
詳細的定時器設定如下:
- 首先要搞清楚定時器的計數時鍾頻率,在預分頻系數≠1的時候,TIM2~7的時鍾頻率為APB1的頻率的2倍,即72MHz,預分頻系數的默認值不是1。
- 定時器的設置主要包括定時器的初始化和中斷的初始化。
定時器的時鍾不是直接來自APB1或APB2,而是來自輸入為APB1或APB2的一個倍頻器,當APB1的預分頻系數為1時,這個倍頻器不起作用,定時器的時鍾頻率等於APB1的頻率;當APB1的預分頻系數為其它數值(即預分頻系數為2、4、8或16)時,這個倍頻器起作用,定時器的時鍾頻率等於APB1的頻率的兩倍。
假定AHB=36MHz,因為APB1允許的最大頻率為36MHz,所以APB1的預分頻系數可以取任意數值;
當預分頻系數=1時,APB1=36MHz,TIM2~7的時鍾頻率=36MHz(倍頻器不起作用);
當預分頻系數=2時,APB1=36MHz/2=18MHz,在倍頻器的作用下,TIM2~7的時鍾頻率=36MHz;
當預分頻系數=4時,APB1=36MHz/4=9MHz,在倍頻器的作用下,TIM2~7的時鍾頻率=18MHz;
當預分頻系數=8時,APB1=36MHz/8=4.5MHz,在倍頻器的作用下,TIM2~7的時鍾頻率=9MHz;
當預分頻系數=16時,APB1=36MHz/16=2.25MHz,在倍頻器的作用下,TIM2~7的時鍾頻率=4.5MHz;
既然需要TIM2~7的時鍾頻率=36MHz,為什么不直接取APB1的預分頻系數=1呢?這是因為APB1不但要為TIM2~7提供時鍾,而且還要為其它外設提供時鍾,設置這個倍頻器可以在保證其它外設使用較低時鍾頻率時,TIM2~7仍能得到較高的時鍾頻率。例如當AHB=72MHz時,APB1的預分頻系數必須大於2,因為APB1的最大頻率只能為36MHz。如果APB1的預分頻系數=2,則因為這個倍頻器,TIM2~7仍然能夠得到72MHz的時鍾頻率。能夠使用更高的時鍾頻率,無疑提高了定時器的分辨率,這也正是設計這個倍頻器的初衷。
定時器初始化:
首先定義TIM_TimeBaseInitTypeDef類型的結構體,它包含了如下的內容:
typedef struct { uint16_t TIM_Prescaler; uint16_t TIM_CounterMode; uint16_t TIM_Period; uint16_t TIM_ClockDivision; uint8_t TIM_RepetitionCounter; } TIM_TimeBaseInitTypeDef;
第一項 TIM_Prescaler 是定時器預分頻值,時鍾源經該預分頻器才是定時器時鍾,它設定TIMx_PSC 寄存器的值。可設置范圍為 0 至 65535,實現 1至 65536 分頻。
第二項 TIM_CounterMode 為定時器計數模式,它的內容如下:
#define TIM_CounterMode_Up ((uint16_t)0x0000) #define TIM_CounterMode_Down ((uint16_t)0x0010) #define TIM_CounterMode_CenterAligned1 ((uint16_t)0x0020) #define TIM_CounterMode_CenterAligned2 ((uint16_t)0x0040) #define TIM_CounterMode_CenterAligned3 ((uint16_t)0x0060)
它可以是向上計數、向下計數以及三種中心對齊模式。基本定時器只能是向上計數,即 TIMx_CNT只能從0開始遞增,並且無需初始化。
第三項 TIM_Period 為定時器周期,當計數寄存器的值遞增到等於該值時,將相關事件標志位置位。范圍為0 至 65535。
第四項 TIM_ClockDivision 為時鍾分頻,設置定時器時鍾 CK_INT 頻率與數字濾波器采樣時鍾頻率分頻比,基本定時器沒有此功能,不用設置。
第五項 TIM_RepetitionCounter 為重復計數器,屬於高級控制寄存器專用寄存器位,利用它可以非常容易控制輸出 PWM 的個數。一般的定時器不需要設置。
循環定時時間的計算:基本定時器只有內部時鍾72MHz,定時器的實際時鍾=內部時鍾 / ( 定時器預分頻值 + 1 ),那么如果 TIM_Prescaler 設置為7200-1,則內部時鍾源經過定時器預分頻后即可得到 (72MHz / (7200-1)+1)=10kHz的頻率。然后 TIM_Period 設置為5000-1(因為計數是從0開始,所以要減1),即可得到定時時間為(5000 * (1 / 10kHz))=0.5s的定時器。
除此之外還要設置中斷的類型,一般的定時器為更新中斷,即由溢出事件產生的中斷,設置的方式為:TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE),其中第一項是定時器代號,第二項為類型,這里設定為更新方式,第三項為使能。
TIM3的初始化函數:
void TIM3_Init(u16 arr,u16 psc) { // 定時時間=(arr+1)*(psc+1)/72 單位為us TIM_TimeBaseInitTypeDef TIM_STR; NVIC_InitTypeDef NVIC_STR; // TIM3掛載在APB1上,由於預分頻系數默認不是1,所以TIM3的時鍾為2*APB1=72M RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //初始化定時器 TIM_STR.TIM_Period=arr; TIM_STR.TIM_Prescaler=psc; // (arr+1)*(psc+1)/TIM時鍾=定時器溢出中斷觸發周期 TIM_STR.TIM_ClockDivision=TIM_CKD_DIV1; TIM_STR.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3,&TIM_STR); TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); // 初始化中斷 // 設定為TIM3中斷 NVIC_STR.NVIC_IRQChannel=TIM3_IRQn; // 先占優先級0級 NVIC_STR.NVIC_IRQChannelPreemptionPriority=0; // 從優先級3級 NVIC_STR.NVIC_IRQChannelSubPriority=3; // IRQ通道時能 NVIC_STR.NVIC_IRQChannelCmd=ENABLE; // 中斷初始化 NVIC_Init(&NVIC_STR); // 使能定時器 TIM_Cmd(TIM3,ENABLE); }
中斷服務函數:
TIM3的中斷函數為 TIM3_IRQHandler
中斷服務函數內包含了:判斷是否發生中斷、中斷發生后執行的內容、清除標志位三部分。
void TIM3_IRQHandler(void) { // 判斷是否發生中斷 if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET) { // 清除標志位 TIM_ClearITPendingBit(TIM3,TIM_IT_Update); // 執行中斷內容 } }
完成調用
只要在main函數里調用 TIM3_Init() 函數,並填入適當的參數,即可實現精確的定時中斷,例如獲得1秒,即(arr+1)*(psc+1)/72000000 = 1,則可分解成arr=9999,psc=7199,配置如下:
TIM3_Init(9999,7199);