前提工作:
PA6、PA0通過跳線相連,PA6測試PA0的輸出頻率
本來只有下列函數,改變占空比 但是我們需要測試頻率,需要動態改變頻率。
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2, Compare); //設置CCR1的值
}
?改變頻率的函數
/*** 函 數:PWM設置PSC* 參 數:Prescaler 要寫入的PSC的值,范圍:0~65535* 返 回 值:無* 注意事項:PSC和ARR共同決定頻率,此函數僅設置PSC的值,并不直接是頻率* 頻率Freq = CK_PSC / (PSC + 1) / (ARR + 1)*/
void PWM_SetPrescaler(uint16_t Prescaler)
{TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate); //設置PSC的值
}
?輸入捕獲模式測頻率的基本思路
用TIM3_CH1捕獲輸入頻率
輸入捕獲初始化函數
第一步:開始TIM3和GPIO的時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
第二步:初始化GPIO和時鐘源
/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //將PA6引腳初始化為上拉輸入/*配置時鐘源*/TIM_InternalClockConfig(TIM3); //選擇TIM3為內部時鐘,若不調用此函數,TIM默認也為內部時鐘
第三步:時基單元初始化
注意:為了防止計數溢出,ARR值要設置大一點。CNT的取值范圍0~ARR
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定義結構體變量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時鐘分頻,選擇不分頻,此參數用于配置濾波器時鐘,不影響時基單元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //計數器模式,選擇向上計數TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //計數周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //預分頻器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重復計數器,高級定時器才會用到TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //將結構體變量交給TIM_TimeBaseInit,配置TIM3的時基單元
第四步:輸入捕獲模塊初始化
注意:濾波器不會改變信號的原有頻率,分頻器就是對信號本身進行計次,會改變頻率
TIM_ICPSC_DIV1:1分頻——每次觸發(上升沿/下降沿)都有效
TIM_ICPSC_DIV2:2分頻——每2次觸發(上升沿/下降沿)有效
TIM_ICInitTypeDef TIM_ICInitStructure; //定義結構體變量TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //選擇配置定時器通道1TIM_ICInitStructure.TIM_ICFilter = 0xF; //輸入濾波器參數,可以過濾信號抖動TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //極性,選擇為上升沿觸發捕獲TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕獲預分頻,選擇不分頻,每次信號都觸發捕獲TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //輸入信號交叉,選擇直通,不交叉TIM_ICInit(TIM3, &TIM_ICInitStructure); //將結構體變量交給TIM_ICInit,配置TIM3的輸入捕獲通道
第五步:選擇觸發源及從模式
/*選擇觸發源及從模式*/TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); //觸發源選擇TI1FP1TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); //從模式選擇復位//即TI1產生上升沿時,會觸發CNT歸零
第六步:TIM使能
/*TIM使能*/TIM_Cmd(TIM3, ENABLE); //使能TIM3,定時器開始運行
獲取輸入捕獲的頻率的函數
上面tim3的psc配置為72,所以標準頻率fc為72000000/72=1Mhz
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);@retval Capture Compare 1 Register value.
uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);@retval Capture Compare 2 Register value.
uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);
/*** 函 數:獲取輸入捕獲的頻率* 參 數:無* 返 回 值:捕獲得到的頻率*/
uint32_t IC_GetFreq(void)
{return 1000000 / (TIM_GetCapture1(TIM3) + 1); //測周法得到頻率fx = fc / N,這里不執行+1的操作也可
}
Ic.c完整代碼
#include "stm32f10x.h" // Device header/*** 函 數:輸入捕獲初始化* 參 數:無* 返 回 值:無*/
void IC_Init(void)
{/*開啟時鐘*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //開啟TIM3的時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟GPIOA的時鐘/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //將PA6引腳初始化為上拉輸入/*配置時鐘源*/TIM_InternalClockConfig(TIM3); //選擇TIM3為內部時鐘,若不調用此函數,TIM默認也為內部時鐘/*時基單元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定義結構體變量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時鐘分頻,選擇不分頻,此參數用于配置濾波器時鐘,不影響時基單元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //計數器模式,選擇向上計數TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //計數周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //預分頻器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重復計數器,高級定時器才會用到TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //將結構體變量交給TIM_TimeBaseInit,配置TIM3的時基單元/*輸入捕獲初始化*/TIM_ICInitTypeDef TIM_ICInitStructure; //定義結構體變量TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //選擇配置定時器通道1TIM_ICInitStructure.TIM_ICFilter = 0xF; //輸入濾波器參數,可以過濾信號抖動TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //極性,選擇為上升沿觸發捕獲TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕獲預分頻,選擇不分頻,每次信號都觸發捕獲TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //輸入信號交叉,選擇直通,不交叉TIM_ICInit(TIM3, &TIM_ICInitStructure); //將結構體變量交給TIM_ICInit,配置TIM3的輸入捕獲通道/*選擇觸發源及從模式*/TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); //觸發源選擇TI1FP1TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); //從模式選擇復位//即TI1產生上升沿時,會觸發CNT歸零/*TIM使能*/TIM_Cmd(TIM3, ENABLE); //使能TIM3,定時器開始運行
}/*** 函 數:獲取輸入捕獲的頻率* 參 數:無* 返 回 值:捕獲得到的頻率*/
uint32_t IC_GetFreq(void)
{return 1000000 / (TIM_GetCapture1(TIM3) + 1); //測周法得到頻率fx = fc / N,這里不執行+1的操作也可
}
?mian.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"int main(void)
{/*模塊初始化*/OLED_Init(); //OLED初始化PWM_Init(); //PWM初始化IC_Init(); //輸入捕獲初始化/*顯示靜態字符串*/OLED_ShowString(1, 1, "Freq:00000Hz"); //1行1列顯示字符串Freq:00000Hz/*使用PWM模塊提供輸入捕獲的測試信號*/PWM_SetPrescaler(720 - 1); //PWM頻率Freq = 72M / (PSC + 1) / 100PWM_SetCompare1(50); //PWM占空比Duty = CCR / 100while (1){OLED_ShowNum(1, 6, IC_GetFreq(), 5); //不斷刷新顯示輸入捕獲測得的頻率}
}