1 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 2 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 3 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能porta 4 //PA1-> TIM2_CH2外部時鐘輸入 5 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//PA1 6 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 7 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; //10M時鐘速度 8 GPIO_Init(GPIOA, &GPIO_InitStructure);
1 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 2 NVIC_InitTypeDef NVIC_InitStructure; 3 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //時鐘使能 4 //!!!!!定時器3,用於產生標準時長的對外部脈衝計數的窗口,從而計算外部脈衝的頻率!!!!!// 5 TIM_TimeBaseStructure.TIM_Period = arr-1; //設置在下一個更新事件裝入活動的自動重裝載寄存器週期的值 計數到5000 6 TIM_TimeBaseStructure.TIM_Prescaler =(psc-1); //設置用來做爲TIMx時鐘頻率除數的預分頻值 10Khz的計數頻率 7 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設置時鐘分割:TDTS = Tck_tim 8 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式 9 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位 10 TIM_ITConfig( //使能或者失能指定的TIM中斷 11 TIM3, //TIM3 12 TIM_IT_Update, //數值溢出更新中斷 13 ENABLE //使能 14 ); 15 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 16 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM2更新中斷 17 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先佔優先級0級 18 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //從優先級3級 19 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 20 NVIC_Init(&NVIC_InitStructure); //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器 21 TIM_SetCounter(TIM3,0); 22 TIM_Cmd(TIM3, ENABLE); //使能TIMx外設
3)配置用於對外部被測脈衝進行計數的TIM2的時基單元和中斷數組
1 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 2 NVIC_InitTypeDef NVIC_InitStructure; 3 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //時鐘使能 4 //!!!!!定時器3,用於產生標準時長的對外部脈衝計數的窗口,從而計算外部脈衝的頻率!!!!!// 5 TIM_TimeBaseStructure.TIM_Period = arr-1; //設置在下一個更新事件裝入活動的自動重裝載寄存器週期的值 計數到5000 6 TIM_TimeBaseStructure.TIM_Prescaler =(psc-1); //設置用來做爲TIMx時鐘頻率除數的預分頻值 10Khz的計數頻率 7 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設置時鐘分割:TDTS = Tck_tim 8 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式 9 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位 10 TIM_ITConfig( //使能或者失能指定的TIM中斷 11 TIM3, //TIM3 12 TIM_IT_Update, //數值溢出更新中斷 13 ENABLE //使能 14 ); 15 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 16 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM2更新中斷 17 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先佔優先級0級 18 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //從優先級3級 19 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 20 NVIC_Init(&NVIC_InitStructure); //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器 21 TIM_SetCounter(TIM3,0); 22 TIM_Cmd(TIM3, ENABLE); //使能TIMx外設
這裏使用了全局變量top_watch,對外部脈衝計數器溢出次數進行清零,防止在標準時間長Tc1內發生計數溢出。ide
1 unsigned char i=0; 2 unsigned int frq[10];//連續存取10次的測頻法獲得的頻率 3 unsigned int pul_num;//標準時間內的脈衝數量 4 unsigned int cnt;//讀取當前計數值 5 unsigned int last_cnt=0;//上一次的計數值 6 void TIM3_IRQHandler(void) //TIM3中斷,達到定時時間 7 { 8 if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //檢查指定的TIM中斷髮生與否:TIM 中斷源 9 { 10 TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除TIMx的中斷待處理位:TIM 中斷源 11 cnt = TIM_GetCounter(TIM2);//讀取定時器2對外部脈衝的計數結果 12 if(cnt >= last_cnt)//若是發生過溢出,當前計數結果就有可能比上次的計數結果還小 13 pul_num = (unsigned int)(top_watch<<16)+ (unsigned int)(cnt - last_cnt); 14 else 15 pul_num = (unsigned int)((top_watch-1)<<16) + (unsigned int)(65536 + cnt - last_cnt); 16 last_cnt = cnt;//將當前計數結果複製到上次的複製結果寄存,方便下次計算 17 frq[i] = pul_num * 100;//因爲定時器3是1/100秒溢出一次,因此頻率時脈衝個數的100倍 18 i++; 19 if(i == 10) 20 i=0; 21 top_watch=0; 22 } 23 }
TIM_TIxExternalClockConfig(TIM2,TIM_TIxExternalCLK1Source_TI2,TIM_ICPolarity_Rising,0);
TIM_SelectInputTrigger(TIM2,TIM_TS_ETRF);
根據圖2所示的測周法原理,須要在被測信號週期(Tx2)內對STM32內部的最高頻率72MHz(爲得到最高測量精度和分辨率)的時鐘進行計數。最簡單的方式將被測信號做爲外部中斷源,並在外部中斷服務程序中讀取定時器中的計數值,但這樣作會使中斷入口時間也計算在Tx2之內。所以實現測周法的最佳方案,是使用STM32通用定時器或高級定時器的捕獲功能(Input Capture)。STM32的輸入捕獲電路框圖如圖4所示,它能在定時器的某個通道TIMx_CHy發生指定脈衝邊沿的時刻及時地將此時的計數器計數值鎖存在「捕獲/比較寄存器」中,從而有效地避免了上面提到的方法中進入中斷時延形成的計時偏差。函數
1 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //使能通用定時器TIM5時鐘 2 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA時鐘
2)接下來還要將TIM5CH1的輸入管腳PA0配置成輸入模式,這裏再也不贅述。測試
1 TIM_TimeBaseStructure.TIM_Period = 65535; //設定計數器溢出值(自動重裝值) 2 TIM_TimeBaseStructure.TIM_Prescaler = 0; //預分頻器 3 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設置時鐘分割因子 4 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計數模式 5 TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); 6 //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基單元
這裏將自動重裝值設置爲16位計數器的最大值65535(0xFFFF),以增長計數器計數範圍,下降自動重裝次數。spa
3)配置輸入捕獲器 設計
1 TIM_ICInitTypeDef TIM5_ICInitStructure; //定義輸入捕獲器初始化結構體 2 對初始化結構體TIM5_ICInitStructure中的參數賦值,例如以下代碼: 3 TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //選擇輸入捕獲通道爲TIM5_CH1 4 TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕獲 5 TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上 6 TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置輸入捕獲脈衝分頻,不分頻 7 TIM5_ICInitStructure.TIM_ICFilter = 0x00;//配置輸入濾波器 不濾波 8 TIM_ICInit(TIM5, &TIM5_ICInitStructure);
1 TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//容許更新中斷 ,容許CC1IE捕獲中斷
1 NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM5中斷 2 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先佔優先級2級 3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //從優先級0級 4 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 5 NVIC_Init(&NVIC_InitStructure); //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器
1 TIM_Cmd(TIM5, ENABLE); //使能TIM5
1 unsigned short i=0; 2 unsigned int pul_width[10];//脈衝週期 3 unsigned int pul_frq[10];//對應的脈衝頻率 4 unsigned short ov_num;//定時器溢出的次數,用於記錄以前溢出的次數 5 unsigned short last_cap_val=0,cur_cap_val;//當前捕獲到的數值和上一次捕獲到的數值 6 //定時器5中斷服務程序(能夠能由捕獲或定時器溢出) 7 void TIM5_IRQHandler(void) 8 { 9 if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) 10 //爲了增長測量頻率的動態範圍,定時器溢出次數也要計算,至關於增長了定時器的位數 11 ov_num++ ;//溢出次數加一 12 if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕獲1發生捕獲事件 13 { 14 cur_cap_val = TIM_GetCapture1(TIM5);//讀取當前捕獲發生時的定時器數值 15 if(cur_cap_val >= last_cap_val)//若是發生過溢出,當前捕獲結果就有可能比上次的捕獲結果還小 16 pul_width[i] = (unsigned int)(ov_num<<16)+ (unsigned int)(cur_cap_val - last_cap_val); 17 else 18 pul_width[i] = (unsigned int)((ov_num-1)<<16) + (unsigned int)(65536 + cur_cap_val - last_cap_val); 19 pul_frq[i] = 72000000 /(float)pul_width[i] + 0.5; 20 //折算爲頻率,加0.5是爲了防止強制類型轉換帶來的捨棄偏差 21 last_cap_val = cur_cap_val;/將當前捕獲結果複製到上次的捕獲結果寄存,方便下次計算 22 ov_num = 0; 23 i++; 24 if(i == 10) 25 i = 0; 26 } 27 TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中斷標誌位 28 }