stm32測量信號頻率及占空比


版權聲明:本文為CSDN博主「Mr Justin」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_43368814/java/article/details/103439564

基於stm32f103單片機對信號頻率、占空比的測量。
最近開始儀器儀表方面的學習了,計划后期做一個示波器。所以這周就在stm32f103上面做了一個測量頻率、占空比的小設計。總體上精度還是比較高的,測量頻率量程在35Hz—190KHz。頻率可以精確到小數點后四位,占空比測量的精度也比較高,可以到小數點后兩位。
說到用stm32測頻率,都會想到用定時器的輸入捕獲模式,只需要一個定時器和一個IO口即可,前幾天在論壇上看到還有一種是用兩個定時器測頻率,一個定時器用來檢測信號跳變沿,另外一個用來精准定時,比如說用TIM1檢測跳變沿(假設為上升沿),TIM2開一個1s的定時器中斷,這個1s就比較准確,在1s內TM1檢測到了多少個上升沿改信號的頻率就是多少。這種方法我本周二試過,精度比輸入捕獲模式下的高,而且還比較穩定,缺點是用到了兩個定時器,占用的cpu資源較多。考慮到我后面任務需要,定時器可能會不夠用,故還是用的輸入捕獲模式。

實驗平台:stm32f103zet6
定時器及通道:TIM2的通道2
IO口:PA1

定時器及輸入捕獲模式的配置:

u8 Edge_Flag;  //高低電平的標志位
u16 Rising,Falling,Rising_Last;   

//定時器2輸入捕獲中斷初始化
void TIM2_Cap_Init()
{
    GPIO_InitTypeDef GPIO_InitStruct;   
    TIM_TimeBaseInitTypeDef TIM_InitStruct;
    TIM_ICInitTypeDef TIM_ICInitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;   //浮空
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStruct);
    
    TIM_InitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_InitStruct.TIM_CounterMode=TIM_CounterMode_Up;  //向上計數
    TIM_InitStruct.TIM_Period=0xffff;
    TIM_InitStruct.TIM_Prescaler=0;                //分頻系數 當分頻系數越大時,可測量頻率最小值越小
    TIM_TimeBaseInit(TIM2,&TIM_InitStruct);
    
    TIM_ICInitStruct.TIM_Channel=TIM_Channel_2;
    TIM_ICInitStruct.TIM_ICFilter=0x00;         //不濾波
    TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;     //第一次是檢測上升沿進入中斷
    TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
    TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI; //直接映射
    TIM_ICInit(TIM2,&TIM_ICInitStruct);
    TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE);
    
    NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0x00;    //搶占優先級
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=0x01;          //響應優先級
    NVIC_Init(&NVIC_InitStruct);
    
    TIM_Cmd(TIM2,ENABLE);     //使能
}

定時器2的中斷服務函數:

void TIM2_IRQHandler(void)
{ 
    if(TIM_GetITStatus(TIM2,TIM_IT_CC2)!=RESET)    //捕獲到上升沿
    {
        if(Edge_Flag==1)
        {
            Rising=TIM2->CCR2;    //第一次檢測到下降沿
            TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising);  //再次改為上升沿觸發
            Edge_Flag++; 
        }
        else if(Edge_Flag==2)
        {
            Rising_Last=TIM2->CCR2;
            TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising);
            Edge_Flag=0;     //標志位清0
            TIM_SetCounter(TIM2,0); //定時器清0
        }
        else
        {
            Falling=TIM2->CCR2;     //第一次檢測到上升沿
            TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Falling);    //將上升沿觸發改為下降沿觸發
            Edge_Flag++;
        }
    }
    TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);    //清除標志位
}

輸入捕獲模式下,中斷服務函數里面處理的內容要盡量少,所以在記錄定時器捕獲到值時,直接將TIM2的CCR2寄存器里面的值賦值給相應變量。

主函數:

int main(void)
{    
    delay_init();    //延時函數初始化      
    
    OLED_Init();  //oled屏幕初始化
    OLED_On();
    OLED_Clear();
    
    TIM2_Cap_Init();   //定時器初始化

    while(1)
    {            
        OLED_ShowString(0,0,"Freq:",16);
        OLED_ShowString(100,0,"Hz",16);
        OLED_ShowNum(50,0,72000000/(Rising_Last-Falling),6,16);
        OLED_ShowString(0,2,"Duty:",16);
        OLED_ShowString(95,2,"%",16);
        OLED_Showdecimal(50,2,(float)(Rising-Falling)/(float)(Rising_Last-Falling)*100,2,3,16);
        delay_ms(100);
    }        
}

變量Rising_Last為第二次檢測到上升沿捕獲到的值,Falling為第一次捕獲到的值,兩者之差為定時器計數的數值差,根據TIM_Prescaler=0(即不分頻),主頻為72M,頻率f=72M/(Rising_Last-Falling)。而Rising-Falling為高電平的時間,除以一個周期就是占空比了。

實驗現象
頻率10K,占空比60%

 

 

可見效果還是挺不錯的,但是這種辦法包括上面講到的雙定時器法都有一個缺點,那就是當信號幅度小於2v時,單片機就檢測不到跳變沿。外部還需要硬件對信號進行適當放大。也是前幾天,在論壇上看到有人提出一個測頻率的叫過零檢測法,用ADC讀信號電壓值,ADC值為0時進行記錄,再次為0就相當於經過了半個周期。計算兩次ADC為0的時間差,就可以計算出信號的頻率,這種方法不會受限於信號幅度大小。原理也比較簡單,相關程序我也正在寫,等測試沒問題后我再發出來和大家分享!
————————————————
版權聲明:本文為CSDN博主「Mr Justin」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_43368814/java/article/details/103439564


免責聲明!

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



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