高級時鐘控制定時器TIM1&TIM8簡介:
STM32F4的高級控制定時器包含一個自動重裝載計數(shù)器,計數(shù)器的輸入是一個被預分頻的系統(tǒng)時鐘。
這個定時器有多種用途,包括車輛輸入信號長度(輸入捕獲模式)或者產(chǎn)生波形輸出(輸出捕獲,PWM,帶死區(qū)插入的互補PWM輸出等)
脈沖長度和波形周期可在通過定時器的預分頻器或者RCC的預分頻器在幾個微秒時鐘內(nèi)調(diào)整。
高級控制定時器和通用定時器完全獨立,不共享任何資源。
高級時鐘控制定時器TIM1&TIM8的主要特性:
1、16位向上、向下、雙向自動重裝載計數(shù)器2、16位預分頻器,分頻值從1打655353、4個獨立通道4、帶死去輸出的互補輸出5、控制外部信號的同步電路6、剎車輸入7、產(chǎn)生中斷和DMA強求8、可外部觸發(fā)
等等。。
TIM定時器確實很強大。至于怎么用,ST的手冊不出奇的難看,完全沒有條理可言。昨天看一天,都沒明白是在說什么。配套的固件庫也是,各種函數(shù)的介紹,函數(shù)名結(jié)構(gòu)體定義完全沒有邏輯可言。于是只能參照網(wǎng)友的介紹,從最基礎的部分弄起。
參考資料見:STM32入門篇之通用定時器徹底研究
【實驗1、TIM1的計時功能】
【實驗描述】
利用TIM1的技術(shù)功能,產(chǎn)生2Hz的中斷每次中斷LED1反轉(zhuǎn),LED1反轉(zhuǎn)頻率為1Hz。
根據(jù)時鐘配置,系統(tǒng)時鐘為168MHz,APB2時鐘為84MHz。TIM1掛接在APB2上,所以APB2 時鐘為84MHz。
因此預分頻系數(shù)設置成了10000即0x2710,自動重裝載計數(shù)器ARR(TIM_Period)設置成了4200即0x1068。每次計數(shù)滿產(chǎn)生中斷。
中斷頻率f= 84MHz /4200 / 10000 = 2Hz
【代碼實現(xiàn)】
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); //必須先清除配置時候產(chǎn)生的更新標志
TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE); //使能中斷,中斷事件為定時器工薪事件
TIM_Cmd(TIM1,ENABLE); //使能定時器
3、中斷處理函數(shù)
沒什么可說的,反轉(zhuǎn)LED燈而已。每次中斷反轉(zhuǎn)一次,2Hz的中斷產(chǎn)生1Hz的閃爍。
中斷名字是庫里邊定義的,跟TIM10全局中斷公用。
void TIM1_UP_TIM10_IRQHandler(void)
{
TIM_ClearFlag(TIM1,TIM_FLAG_Update);//進入中斷先清除更新標志
LEDTog(LED1);
}
之后我們就可以看到LED以大約1Hz的頻率在閃爍了。
【實驗2、強制輸出模式實驗】
百度來的強制輸出模式的定義:在程序編程中,IO口一般都可以作為輸入輸出的。而有些數(shù)據(jù)要在讓其執(zhí)行時候必須執(zhí)行,所以讓其強制性的輸出。這是IO口只能做一件事。
看完之后還是一頭霧水。
簡單 點說,就是不管當時IO輸出的是什么,都能強制將其設為0或者為1.
【實驗描述】
為了實驗方便,這個實驗使用TIM4的強制輸出功能,點亮與GPIOD Pin13引腳相連的LED3。對于強制輸出功能,高級定時器和通用定時器是完全一樣的。
TIM4的CH2被復用在GPIOD 的Pin13。所以可以將這個輸出強制為高,將LED點亮。
【代碼實現(xiàn)】
1、首先將GPIO初始化為AF復用功能。
CM4的引腳復用功能和CM3的實現(xiàn)方法不同,要特別注意。按照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、在主函數(shù)中強制輸出。
初始化完成之后,在任何時候都能強制引腳電平,只需要一個函數(shù)即可:
TIM_ForcedOC2Config(TIM4,TIM_ForcedAction_Active);
這個函數(shù)設置TIM的CCMR1的OCxM位為101或者100實現(xiàn)輸出的拉高或拉低
【實驗三、比較輸出】
一直不理解這里的比較是哪兩個東西在進行比較。今天翻ST參考手冊 reference manual發(fā)現(xiàn)這么句話:
當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的比較。兩個相等時,觸發(fā)事件。這個事件發(fā)生時,TIm根據(jù)CCMRx寄存器的OCxM位進行輸出。
OCxM不同設置的不同功能如下表所示:
OCxM[2..0]值功能000對輸出不影響001相等時輸出強制為1010相等時輸出強制為0011輸出反轉(zhuǎn)100不管是否相等,強制為0101不管是否相等,強制為1110PWM模式1(先正后負)111PWM模式2(先負后正)結(jié)合庫中的定義,可以很方便地改變輸出方式:
#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)
【實驗現(xiàn)象】
LED周期閃爍
【代碼實現(xiàn)】
只需要將上邊的代碼中的TIM_OCMode改成PWM即可。
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
參數(shù)TIM_Pulse對這種模式?jīng)]影響,TIM_OCPolarity只影響先輸出的是低電平還是高電平。
【實驗4、PWM輸出】
這是輸出部分的傳統(tǒng)了。所有的開發(fā)板的TIM例子都是一個PWM輸出。
時基單元好了,設置一下輸出模式,反轉(zhuǎn)時機(TIM_Pulse)。然后開啟哥哥通道的OC即可。對于每個Tim的所有通道,由于時基配置是一樣的所以只能改變各個通道的占空比。
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM2也行
TIM_OCInitStructure.TIM_Pulse= 2000;//CCR,設置占空比。反轉(zhuǎn)模式時候無效
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);
這樣講產(chǎn)生一個負脈沖,效果是LED滅一下之后保持常亮。如果要要讓LED亮一下,輸出正脈沖還需要改下輸出的極性:
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
到這里,TIM控制輸出的實驗基本就做完了。馬上開始TIM控制輸入部分,包括輸入捕獲、PWM輸入等。