STM32學習筆記(一)時鐘和定時器

   由於近期在準備海洋航行器比賽,正好趁此機會學習一下ARM,看到周圍很多同學都在使用32,所以我也買了一塊STM32F103ZET6,準備好好地學習一下。

   STM32的時鐘系統相當的複雜,包含了5個時鐘源,分別是HSI HSE LSI LSE PLL,HSI是高速內部時鐘、RC振盪器,頻率爲8M,HSE是高速外部時鐘,即晶振,我的核心板上晶振爲8M。LSI爲低速內部時鐘、RC振盪器,頻率40k,LSE爲低速外部時鐘,接32.768kHz晶振,作爲RTC時鐘源。PLL爲鎖相環倍頻輸出,最大不超過72M。

   我在學習定時器時先看的是TIM3,它掛載在APB1分頻器上,APB1上面掛載的是低速外設,APB2上掛載高速外設。

   在system_stm32f10x.c文件下,有默認定義SYSCLK_FREQ_72MHz,同時在SystemInit()函數下調用了SetSysClock(),根據宏定義將時鐘設爲72M。

   讀取SystemCoreClock變量即可獲得系統時鐘頻率。

   在默認情況下,系統的各個時鐘頻率如下:

   SYSCLK:72M

   AHB:72M

   APB1(PCLK1):36M

   APB2(PCLK2):72M

   PLL:72M

   

   詳細的定時器設定如下:

   ①首先要搞清楚定時器的計數時鐘頻率,在預分頻係數≠1的時候,TIM2~7的時鐘頻率爲APB1的2倍,即72MHz,預分頻係數的默認值不是1,但我並未查到該如何設置該值。

   ②定時器的設置主要包括定時器的初始化和中斷的初始化。

   2.1 定時器初始化:

   首先定義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是預分頻值,它與TIM_Period(重載週期值)的乘積即爲計數的總值。

   第二項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)

   

 後面三項爲中心對齊模式,指的是計數到一定的值,產生溢出事件,再向下計數到0。常用的爲向上計數模式,即TIM_CounterMode_Up

   第四項TIM_ClockDivision爲時鐘分割,對於時鐘分割沒有查到太多的描述,一般設定爲TIM_CKD_DIV1,或者直接填入0x0000。

   第五項TIM_RepetitionCounter爲PWM模式的一些設定,一般的定時器不用設置。


   除此之外還要設置中斷的類型,一般的定時器爲更新中斷,即由溢出事件產生的中斷,設置的方式爲:TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE),其中第一項是定時器代號,第二項爲類型,這裏設定爲更新方式,第三項爲使能。

   

   根據上述內容我們知道,初始化的過程如下:

   3

TIM_TimeBaseInitTypeDef TIM_STR;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//TIM3掛載在APB1上
//由於預分頻係數默認不是1,所以TIM3的時鐘爲2*APB1=72M
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);

   

 2.2 中斷初始化:

   中斷初始化爲操作NVIC(嵌套向量中斷控制器)函數。 設置方式如下:

   

NVIC_STR.NVIC_IRQChannel=TIM3_IRQn;//設定爲TIM3中斷
NVIC_STR.NVIC_IRQChannelPreemptionPriority=0;//先佔優先級0級
NVIC_STR.NVIC_IRQChannelSubPriority=3;//從優先級3級
NVIC_STR.NVIC_IRQChannelCmd=ENABLE;//IRQ通道時能
NVIC_Init(&NVIC_STR);//中斷初始化
TIM_Cmd(TIM3,ENABLE);//TIM3定時器使能


   2.3 把這些都封裝成一個函數,既可作爲TIM3的初始化函數。如下:

   

void TIM3_Init(u16 arr,u16 psc)
{
        //定時時間=(arr+1)*(psc+1)/72 單位爲us
    TIM_TimeBaseInitTypeDef TIM_STR;
    NVIC_InitTypeDef NVIC_STR;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    //初始化定時器
    TIM_STR.TIM_Period=arr;
    TIM_STR.TIM_Prescaler=psc;
    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);
    //初始化中斷
    NVIC_STR.NVIC_IRQChannel=TIM3_IRQn;
    NVIC_STR.NVIC_IRQChannelPreemptionPriority=0;
    NVIC_STR.NVIC_IRQChannelSubPriority=3;
    NVIC_STR.NVIC_IRQChannelCmd=ENABLE;
    NVIC_Init(&NVIC_STR);
        //使能定時器
    TIM_Cmd(TIM3,ENABLE);
}


③中斷服務函數:

   中斷函數的名字,TIM3的爲TIM3_IRQHandler

   中斷服務函數內包含了:判斷是否發生中斷、中斷髮生後執行的內容、清除標誌位三部分。

   首先是判斷是否發生了更新中斷,利用庫函數TIM_GetITStatus(P1,P2),它的參數P1爲代號,這裏是TIM3,P2爲中斷類型,這裏爲更新中斷TIM_IT_Update,當它爲1時即發生了更新中斷,這裏爲了增強可讀性,採用一個RESET代表0,當函數返回值不是RESET的時候,即發生了置位(中斷)。

   清除標誌位採用的是庫函數TIM_ClearITPendingBit(P1,P2),參數與判斷的函數一樣。

   具體函數如下:

   

void TIM3_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET)
    {
        TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
    //在這裏執行中斷內容
    }
}

   

   ④完成調用

   只要在main函數裏調用TIM3_Init()函數,並填入適當的參數,即可實現精確的定時中斷,例如獲得一秒,即72M個數字中斷一次,可分解爲10000*7200,配置如下:

   

TIM3_Init(9999,7199);


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章