STM32F4 定時器TIM(1)定時器控制輸出【使用庫函數】


高級時鍾控制定時器TIM1&TIM8簡介

STM32F4的高級控制定時器包含一個自動重裝載計數器,計數器的輸入是一個被預分頻的系統時鍾。

這個定時器有多種用途,包括車輛輸入信號長度(輸入捕獲模式)或者產生波形輸出(輸出捕獲,PWM,帶死區插入的互補PWM輸出等)

脈沖長度和波形周期可在通過定時器的預分頻器或者RCC的預分頻器在幾個微秒時鍾內調整。

高級控制定時器和通用定時器完全獨立,不共享任何資源。

高級時鍾控制定時器TIM1&TIM8的主要特性:

1、16位向上、向下、雙向自動重裝載計數器2、16位預分頻器,分頻值從1打655353、4個獨立通道4、帶死去輸出的互補輸出5、控制外部信號的同步電路6、剎車輸入7、產生中斷和DMA強求8、可外部觸發

等等。。

TIM定時器確實很強大。至於怎么用,ST的手冊不出奇的難看,完全沒有條理可言。昨天看一天,都沒明白是在說什么。配套的固件庫也是,各種函數的介紹,函數名結構體定義完全沒有邏輯可言。於是只能參照網友的介紹,從最基礎的部分弄起。

參考資料見:STM32入門篇之通用定時器徹底研究

【實驗1、TIM1的計時功能】

【實驗描述】

利用TIM1的技術功能,產生2Hz的中斷每次中斷LED1反轉,LED1反轉頻率為1Hz。

根據時鍾配置,系統時鍾為168MHz,APB2時鍾為84MHz。TIM1掛接在APB2上,所以APB2 時鍾為84MHz。

因此預分頻系數設置成了10000即0x2710,自動重裝載計數器ARR(TIM_Period)設置成了4200即0x1068。每次計數滿產生中斷。

中斷頻率f= 84MHz /4200 / 10000 = 2Hz

【代碼實現】

1、首先開啟TIM1的時鍾

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);

2、時基單元的初始化

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 0x1068;
TIM_TimeBaseInitStructure.TIM_Prescaler = 0x2710;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;

TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure);

TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM1,TIM_FLAG_Update);   //必須先清除配置時候產生的更新標志
TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);   //使能中斷,中斷事件為定時器工薪事件
TIM_Cmd(TIM1,ENABLE);    //使能定時器

3、中斷處理函數

沒什么可說的,反轉LED燈而已。每次中斷反轉一次,2Hz的中斷產生1Hz的閃爍。

中斷名字是庫里邊定義的,跟TIM10全局中斷公用。

void TIM1_UP_TIM10_IRQHandler(void)
{
  TIM_ClearFlag(TIM1,TIM_FLAG_Update);//進入中斷先清除更新標志
  LEDTog(LED1);
}

之后我們就可以看到LED以大約1Hz的頻率在閃爍了。

【實驗2、強制輸出模式實驗】

百度來的強制輸出模式的定義:在程序編程中,IO口一般都可以作為輸入輸出的。而有些數據要在讓其執行時候必須執行,所以讓其強制性的輸出。這是IO口只能做一件事。

看完之后還是一頭霧水。

簡單 點說,就是不管當時IO輸出的是什么,都能強制將其設為0或者為1.

【實驗描述】

為了實驗方便,這個實驗使用TIM4的強制輸出功能,點亮與GPIOD Pin13引腳相連的LED3。對於強制輸出功能,高級定時器和通用定時器是完全一樣的。

TIM4的CH2被復用在GPIOD 的Pin13。所以可以將這個輸出強制為高,將LED點亮。

【代碼實現】

1、首先將GPIO初始化為AF復用功能。

CM4的引腳復用功能和CM3的實現方法不同,要特別注意。按照CM3的寫法將不會有輸出
void TIM4_GPIO_Config(void)
{
  GPIO_InitTypeDef GPIO_initStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
 
  GPIO_initStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_initStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_initStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIO_initStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_initStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_Init(GPIOD,&GPIO_initStructure);
 
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource12,GPIO_AF_TIM4);
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource13,GPIO_AF_TIM4);
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource14,GPIO_AF_TIM4);
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource15,GPIO_AF_TIM4);
}

2、TIM4的初始化

這里的時鍾我沒有計算,因為這個實驗不太關注這個。

void TIM4_Config1(void)
{
  TIM4_GPIO_Config();
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
 
  TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInitStructure.TIM_Period =0x1068;
  TIM_TimeBaseInitStructure.TIM_Prescaler = 0x2710;
  TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;
  TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);
  TIM_ARRPreloadConfig(TIM4,ENABLE);
 
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Active;;  //設置成什么模式都行。
  TIM_OCInitStructure.TIM_Pulse= 1000;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OC2Init(TIM4,&TIM_OCInitStructure);

  TIM_Cmd(TIM4,ENABLE);
}

3、在主函數中強制輸出。

初始化完成之后,在任何時候都能強制引腳電平,只需要一個函數即可:

TIM_ForcedOC2Config(TIM4,TIM_ForcedAction_Active);
這個函數設置TIM的CCMR1的OCxM位為101或者100實現輸出的拉高或拉低

【實驗三、比較輸出】
一直不理解這里的比較是哪兩個東西在進行比較。今天翻ST參考手冊 reference manual發現這么句話:

當OCxM位為000時:The comparison between the output compare register  TIMx_CCR1 and the counter TIMx_CNT has no effect on the outputs.

即這里的“比較”是TIMx_CCR1和TIMx_CNT的比較。兩個相等時,觸發事件。這個事件發生時,TIm根據CCMRx寄存器的OCxM位進行輸出。

OCxM不同設置的不同功能如下表所示:

OCxM[2..0]值 功能
000 對輸出不影響
001 相等時輸出強制為1
010 相等時輸出強制為0
011 輸出反轉
100 不管是否相等,強制為0
101 不管是否相等,強制為1
110 PWM模式1(先正后負)
111 PWM模式2(先負后正)

結合庫中的定義,可以很方便地改變輸出方式:

#define TIM_OCMode_Timing                  ((uint16_t)0x0000)
#define TIM_OCMode_Active                  ((uint16_t)0x0010)
#define TIM_OCMode_Inactive                ((uint16_t)0x0020)
#define TIM_OCMode_Toggle                  ((uint16_t)0x0030)
#define TIM_OCMode_PWM1                    ((uint16_t)0x0060)
#define TIM_OCMode_PWM2                    ((uint16_t)0x0070)

【實驗現象】

LED周期閃爍

【代碼實現】

只需要將上邊的代碼中的TIM_OCMode改成PWM即可。

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;

參數TIM_Pulse對這種模式沒影響,TIM_OCPolarity只影響先輸出的是低電平還是高電平。

【實驗4、PWM輸出】

這是輸出部分的傳統了。所有的開發板的TIM例子都是一個PWM輸出。

時基單元好了,設置一下輸出模式,反轉時機(TIM_Pulse)。然后開啟哥哥通道的OC即可。對於每個Tim的所有通道,由於時基配置是一樣的所以只能改變各個通道的占空比。

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM2也行
TIM_OCInitStructure.TIM_Pulse= 2000;//CCR,設置占空比。反轉模式時候無效
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_ClearFlag(TIM4,TIM_FLAG_CC2);
TIM_OC2Init(TIM4,&TIM_OCInitStructure);
當然,引腳初始化不能少的。

【實驗5、單脈沖方式】

只需要在上邊的代碼之后加一句:

TIM_SelectOnePulseMode(TIM4,TIM_OPMode_Single);

這樣講產生一個負脈沖,效果是LED滅一下之后保持常亮。如果要要讓LED亮一下,輸出正脈沖還需要改下輸出的極性:

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

到這里,TIM控制輸出的實驗基本就做完了。馬上開始TIM控制輸入部分,包括輸入捕獲、PWM輸入等。

 


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM