2.1 時鍾來源
計數器時鍾可以由下列時鍾源提供:
·內部時鍾(CK_INT)
·外部時鍾模式1:外部輸入腳(TIx)
·外部時鍾模式2:外部觸發輸入(ETR)
·內部觸發輸入(ITRx):使用一個定時器作為另一個定時器的預分頻器,如可以配置一個定時器Timer1而作為另一個定時器Timer2的預分頻器。
由於今天的學習是最基本的定時功能,所以采用內部時鍾。TIM2-TIM5的時鍾不是直接來自於APB1,而是來自於輸入為APB1的一個倍頻器。這個倍頻器的作用是:當APB1的預分頻系數為1時,這個倍頻器不起作用,定時器的時鍾頻率等於APB1的頻率(36MHZ);
當APB1的預分頻系數為其他數值時(即預分頻系數為2、4、8或16),這個倍頻器起作用,定時器的時鍾頻率等於APB1的頻率的2倍。
{
假如APB1預分頻為2(變成36MHZ),則定時器TIM2-5的時鍾倍頻器起作用,將變成2倍的APB1(2x36MHZ)將為72MHZ給定時器提供時鍾脈沖。 一般APB1和APB2的RCC時鍾配置放在初始化函數中例如下面的void RCC_Configuration(void)配置函數所示,將APB1進行2分頻,導致TIM2時鍾變為72MHZ輸入。
如果是1分頻則會是36MHZ輸入,如果4分頻:CKINT=72MHZ/4x2=36MHZ; 8分頻:CKINT=72MHZ/8x2=18MHZ;16分頻:CKINT=72MHZ/16x2=9MHZ
}
//系統時鍾初始化配置 void RCC_Configuration(void) { //定義錯誤狀態變量 ErrorStatus HSEStartUpStatus; //將RCC寄存器重新設置為默認值 RCC_DeInit(); //打開外部高速時鍾晶振 RCC_HSEConfig(RCC_HSE_ON); //等待外部高速時鍾晶振工作 HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) { //設置AHB時鍾(HCLK)為系統時鍾 RCC_HCLKConfig(RCC_SYSCLK_Div1); //設置高速AHB時鍾(APB2)為HCLK時鍾 RCC_PCLK2Config(RCC_HCLK_Div1); //設置低速AHB時鍾(APB1)為HCLK的2分頻(TIM2-TIM5輸入TIMxCLK頻率將為72MHZ/2x2=72MHZ輸入) RCC_PCLK1Config(RCC_HCLK_Div2); //設置FLASH代碼延時 FLASH_SetLatency(FLASH_Latency_2); //使能預取指緩存 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //設置PLL時鍾,為HSE的9倍頻 8MHz * 9 = 72MHz RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //使能PLL RCC_PLLCmd(ENABLE); //等待PLL准備就緒 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //設置PLL為系統時鍾源 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //判斷PLL是否是系統時鍾 while(RCC_GetSYSCLKSource() != 0x08); } //允許TIM2的時鍾 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //允許GPIO的時鍾 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); }
三、定時器代碼實例
中斷優先級就不貼出來了,自己可以配置下
Tout= ((arr+1)*(psc+1))/Tclk;
arr:計數重裝值,psc分頻數,Tclk系統時鍾頻率,Tout一個周期的時間。
Tout= ((arr+1)*(psc+1))/Tclk;
3.1、定時器1使用
這里假設APB2時鍾是1分頻即72MHZ(如果是4分頻則為36MHZ [=72MHZ/4x2=36MHZ] )配置,void RCC_Configuration(void)中配置如下代碼:
1 //設置高速AHB時鍾(APB2)為HCLK時鍾 2 RCC_PCLK2Config(RCC_HCLK_Div1);
則這里:APB2的時鍾為1分頻故出來的APB2時鍾還是72MHZ,TIM1對系統時鍾APB2(72MHZ)再進行7200分頻,然后計數重載初值設置為100,則一個定時周期Tout=(100-1+1)*(7200-1+1)/72,000,000=1/10=0.1s,即100ms為一個計數周期
1 //放到主函數的初始化中初始化 2 void Timer1CountInitial(void) 3 { 4 //定時=36000/72000x2=0.001s=1ms; 5 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 6 /////////////////////////////////////////////////////////////// 7 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); 8 9 TIM_TimeBaseStructure.TIM_Period = 100-1;//自動重裝值(此時改為100ms) 10 TIM_TimeBaseStructure.TIM_Prescaler = 7200-1;//時鍾預分頻 11 // TIM_TimeBaseStructure.TIM_Prescaler = 36000-1;//時鍾預分頻 12 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上計數 13 // TIM_TimeBaseStructure.TIM_Period = 2-1;//自動重裝值 14 // TIM_TimeBaseStructure.TIM_Period = 10-1;//自動重裝值(此時改為10ms) 15 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時鍾分頻1 16 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; 17 TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure); 18 19 TIM_ClearFlag(TIM1,TIM_FLAG_Update); 20 TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE); 21 TIM_Cmd(TIM1, ENABLE); 22 } 23 24 25 void TIM1_UP_IRQHandler(void) 26 { 27 //TIM_TimeBaseStructure.TIM_Period = 100-1;//自動重裝值(此時進中斷的周期為100ms) 28 if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) 29 { 30 //添加行程開關去抖程序 31 if(XingChengTickNum_QuFantan<1000)// 32 { 33 XingChengTickNum_QuFantan++; 34 } 54 } 55 TIM_ClearITPendingBit(TIM1,TIM_IT_Update);58 }
3.2、定時器2使用
Tout= ((arr+1)*(psc+1))/Tclk;
arr:計數重裝值,psc分頻數,Tclk系統時鍾頻率,Tout一個周期的時間。
假設APB1時鍾是2分頻即72MHZ(如果是1分頻則為36MHZ)配置,void RCC_Configuration(void)中配置如下代碼:
//設置低速AHB時鍾(APB1)為HCLK的2分頻(TIM2-TIM5輸入TIMxCLK頻率將為72MHZ/2x2=72MHZ輸入) RCC_PCLK1Config(RCC_HCLK_Div2);
這里:APB1的時鍾為分頻故出來的APB2時鍾還是72MHZ,TIM1是對系統時鍾APB2(72MHZ)進行7200分頻,
則:Tout=(4-1+1)*(36000-1+1)/72,000,000=4/2,000=2ms
void TIM2_Int_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_DeInit(TIM2); TIM_TimeBaseStructure.TIM_Period = 4 - 1;//2000 - 1; TIM_TimeBaseStructure.TIM_Prescaler = (36000 - 1); TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_ClearFlag(TIM2, TIM_FLAG_Update); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM_Cmd(TIM2, ENABLE); } void TIM2_IRQHandler(void) { if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { interrupt_rtc();//可以使你自己定義的執行函數 } TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update); }
3.3、定時器3使用
假設APB1時鍾是2分頻即72MHZ(如果是1分頻則為36MHZ)配置,void RCC_Configuration(void)中配置如下代碼:
1 //設置低速AHB時鍾(APB1)為HCLK的2分頻(TIM2-TIM5輸入TIMxCLK頻率將為72MHZ/2x2=72MHZ輸入) 2 RCC_PCLK1Config(RCC_HCLK_Div2);
TIM3_Int_Init(4-1,36000-1);
則:Tout=(4-1+1)*(36000-1+1)/72,000,000=4/2,000=2ms
//通用定時器3中斷初始化 //這里時鍾選擇為APB1的2倍,而APB1為36M //arr:自動重裝值。 //psc:時鍾預分頻數 //這里使用的是定時器3! void TIM3_Int_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //時鍾使能 TIM_TimeBaseStructure.TIM_Period = arr; //設置在下一個更新事件裝入活動的自動重裝載寄存器周期的值 計數到5000為500ms TIM_TimeBaseStructure.TIM_Prescaler =psc; //設置用來作為TIMx時鍾頻率除數的預分頻值 10Khz的計數頻率 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設置時鍾分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中斷,允許更新中斷 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占優先級0級 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //從優先級3級 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 NVIC_Init(&NVIC_InitStructure); //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器 TIM_Cmd(TIM3, ENABLE); //使能TIMx外設 } //定時器3中斷服務程序 void TIM3_IRQHandler(void) //TIM3中斷 { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //檢查指定的TIM中斷發生與否:TIM 中斷源 { TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx的中斷待處理位:TIM 中斷源 LED1=!LED1; } }
3.4、定時器4使用
假設APB1時鍾是4分頻即72/4=18MHZ(如果是4分頻則TIMxCLK=18MHZx2=36MHZ)配置,void RCC_Configuration(void)中配置如下代碼:
1 //在void RCC_Configuration(void)中配置APB1時鍾4分頻或1分頻都變為36MHZ 2 //設置低速AHB時鍾(APB1)為HCLK的4分頻(TIM2-TIM5輸入TIMxCLK頻率將為72MHZ/4x2=36MHZ輸入) 3 RCC_PCLK1Config(RCC_HCLK_Div4);//加入使用4分頻
TIM4_Int_Init(4-1,36000-1);
則:Tout=(4-1+1)*(36000-1+1)/36,000,000=4/1,000=4ms
void TIM4_Int_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //時鍾使能 //定時器TIM4初始化 TIM_TimeBaseStructure.TIM_Period = arr; //設置在下一個更新事件裝入活動的自動重裝載寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //設置用來作為TIMx時鍾頻率除數的預分頻值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設置時鍾分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根據指定的參數初始化TIMx的時間基數單位 TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM4中斷,允許更新中斷 //中斷優先級NVIC設置 NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM3中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占優先級0級 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //從優先級3級 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器 TIM_Cmd(TIM4, ENABLE); //使能TIMx } //定時器4中斷服務程序 void TIM4_IRQHandler(void) //TIM3中斷 { if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //檢查TIM4更新中斷發生與否 { TIM_ClearITPendingBit(TIM4, TIM_IT_Update ); //清除TIMx更新中斷標志 LED0=!LED0; // Get_Angle(); } }
3.5、定時器5使用
假設APB1時鍾是1分頻即36MHZ(如果是1分頻則TimexCLK=36MHZx1=36MHZ)配置,void RCC_Configuration(void)中配置如下代碼:
1 //在void RCC_Configuration(void)中配置APB1時鍾4分頻或1分頻都變為36MHZ 2 //設置低速AHB時鍾(APB1)為HCLK的4分頻(TIM2-TIM5輸入TIMxCLK頻率將為72MHZ/4x2=36MHZ輸入) 3 RCC_PCLK1Config(RCC_HCLK_Div1);//假如使用1分頻
TIM5_Int_Init(4-1,36000-1);
則:Tout=(4-1+1)*(36000-1+1)/36,000,000=4/1,000=4ms
void TIM5_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //時鍾使能 TIM_TimeBaseStructure.TIM_Period = arr; //設置在下一個更新事件裝入活動的自動重裝載寄存器周期的值 計數到5000為500ms TIM_TimeBaseStructure.TIM_Prescaler =psc; //設置用來作為TIMx時鍾頻率除數的預分頻值 10Khz的計數頻率 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設置時鍾分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式 TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位 TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE ); //使能指定的TIM3中斷,允許更新中斷 NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM3中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占優先級0級 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //從優先級3級 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 NVIC_Init(&NVIC_InitStructure); //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器 TIM_Cmd(TIM5, ENABLE); //使能TIMx外? } //定時器5中斷服務程序 void TIM5_IRQHandler(void) //TIM3中斷 { if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) //檢查指定的TIM中斷發生與否:TIM 中斷源 { TIM_ClearITPendingBit(TIM5, TIM_IT_Update ); //清除TIMx的中斷待處理位:TIM 中斷源 LED1=!LED1; } }