RT1052的PIT定時器

開發平臺

  • Board:野火RT1052-MINI
  • IDE:Keil 5.28

關於PIT

PIT定時器(Periodic Interrupt Timer),也叫做週期性中斷定時器(反正我是這麼翻譯的),是一個32位遞減計數器,每個時鐘週期減1。與普通的定時器相比,它只能遞減計數,而不能向上計數,普通的定時器,相對高級一點的能向上或者向下計數,甚至再高級一點的可以產生pwm等等。而它就只能週期計數。但是不要小看它,它最大的作用就是爲其它外設提供週期信號。這聽起來像廢話,普通定時器不行嗎?當然行,但是普通定時器需要重啓計數器才能改變計數週期,而PIT定時器可以不需要重新啓動(其實就是重新初始化)就可以改變計數週期。典型的應用就是PIT+ADC,ADC週期性採集255(或者更大)的信號數據,通過FFT(快速傅里葉變換)處理,得到一段新的信號,這是很常見的,特別是做混合信號處理的時候。
描述一下特性吧:

  • 支持生成中斷並且可以獨立設置啓用或屏蔽。
  • 共享一箇中斷號(IRQ,別的Kinetis系列貌似沒有,在1052上共用)。
  • 具有相同的計數時鐘。
  • 可以獨立設置計數器的計數值、啓動和停止。
  • 32 位遞減計數,除定時器 0(四個定時器是 0 到 3),其他定時器可以設置爲定
    時器連接模式,組成一個 64 位定時器。
  • 無需重新啓動計時器即可更改計數器週期

在這裏插入圖片描述
由圖可知,PIT定時器的時鐘來源於外部,至於外部選擇哪個時鐘源,這個得看自己配置需求了。而我選擇的是osc_clk提供的時鐘源。

PIT的SDK配置

步入正題,用SDK配置PIT:

首先初始化pit,記得添加對應的.c和.h文件,代碼如下:

void Pit_init(uint8_t PIT_CHn,uint32_t reload)
{
    pit_config_t config;
    pit_chnl_t channel;
    
    if(PIT_CHn==0)      channel = kPIT_Chnl_0;
    else if(PIT_CHn==1) channel = kPIT_Chnl_1;
    else if(PIT_CHn==2) channel = kPIT_Chnl_2;
    else if(PIT_CHn==3) channel = kPIT_Chnl_3;

    /* PIT時鐘配置 */
    CLOCK_SetMux(kCLOCK_PerclkMux,1U);
    CLOCK_SetDiv(kCLOCK_PerclkDiv,0U);
    
    PIT_GetDefaultConfig(&config);
    
    config.enableRunInDebug = true;
    
    PIT_Init(PIT, &config);
    
    /* 設置PIT定時器通道0自動重裝載值 */
    PIT_SetTimerPeriod(PIT,channel,USEC_TO_COUNT(reload, PIT_SOURCE_CLOCK));
    
    /* 清除通道0的中斷標誌位 */
    PIT_ClearStatusFlags(PIT,channel,kPIT_TimerFlag);
    
    /* 使能通道0的計時完成中斷 */
    PIT_EnableInterrupts(PIT, channel, kPIT_TimerInterruptEnable);
    
    //Set_NVIC_PriorityGroup(Group_4);
    //Set_IRQn_Priority(PIT_IRQn,Group4_PreemptPriority_6, Group4_SubPriority_0);
	PIT_NVIC_Config();
    /* 使能中斷 */
    EnableIRQ(PIT_IRQn);

    if(PIT_CHn==0)      PIT_StartTimer(PIT,kPIT_Chnl_0);
    else if(PIT_CHn==1) PIT_StartTimer(PIT,kPIT_Chnl_1);
    else if(PIT_CHn==2) PIT_StartTimer(PIT,kPIT_Chnl_2);
    else if(PIT_CHn==3) PIT_StartTimer(PIT,kPIT_Chnl_3);
}

爲了方便,寫成通用型的了。

初始化之前,需要寫好中斷配置:

static void PIT_NVIC_Config(void)
{
    uint32_t Priority_Encode = 0;
    NVIC_SetPriorityGrouping(0x04);
    Priority_Encode = NVIC_EncodePriority (0x04, 0x06, 0x00);//得到中斷優先級編碼
    NVIC_SetPriority(PIT_IRQn,Priority_Encode);
}

然後編寫對應的中斷服務函數:

void PIT_IRQHandler(void)
{
    if(PIT_GetStatusFlags(PIT, kPIT_Chnl_0))
    {
        /* 清除中斷標誌位 */
        PIT_ClearStatusFlags(PIT, kPIT_Chnl_0, kPIT_TimerFlag); 
        PRINTF("進入PIT_CH0\n");
    }
    else if(PIT_GetStatusFlags(PIT, kPIT_Chnl_1))
    {
        /* 清除中斷標誌位 */
        PIT_ClearStatusFlags(PIT, kPIT_Chnl_1, kPIT_TimerFlag); 
        PRINTF("進入PIT_CH1\n");
    }
}

我這裏只用了兩個通道的PIT定時器,所以在中斷中只做了兩次判斷。
在這裏插入圖片描述
最後得到的效果是這樣的,沒做啥,就驗證是否進入了中斷。

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