1. 程式人生 > >STM32採用普通的IO口來測量PWM的頻率

STM32採用普通的IO口來測量PWM的頻率

STM32測量外部輸入訊號的頻率的方法有很多:

  • 採用內部定時器輸入捕獲功能。
  • 採用普通的IO口設定外部中斷+定時器的當時測量PWM訊號的頻率。

    這兩種方式比較推薦使用第一種,比較使用內部的資源可以節省CPU資源的利用,
    當然當內部資源不夠使用的時候,或者是說,硬體電路設計的時候沒有連線相應的應引腳只能使用第二種方式了。

    本次由於硬體電路設計的不足,導致需要測量PWM輸入訊號的引腳沒有接到相應的通道上,對此使用了第二種方式:
    注意:這裡定時器中斷的優先順序要高於外部中斷的優先順序

思路如下:

  • 設定PWM輸入訊號的引腳為外部中斷的方式,並且觸發方式為GPIO_MODE_IT_RISING_FALLING 上升,下降沿均可觸發。
  • 其次使能一個定時器TIM4,定時中斷時間看自己需要測量頻率來設定。(本次設定為2us –> 最大可測量的頻率為50KHz)
  • 外部中斷中,上升沿到來,清空計數器TIM4->CNT=0,置一個上升沿的標誌位為1,代表計算PWM時間的開始tim4_PWM_cnt++。
  • 下降沿到來,置一個下降沿的標誌為1.
  • 下一次上升沿到來,判斷上一次是否為下降沿的標誌,如果是,則代表PWM一個週期的時間已經到達。讀取時間。PWM_Cycle = timer4_PWM_cnt*2. 並且把計數變數清零tim4_PWM_cnt = 0
  • 接著下一次下降沿到來,判斷上一次是否為上升沿的標誌,如果是,則代表一個週期高電平結束,讀取時間,即為脈寬 PWM_Duty = timer4_PWM_cnt*2。

    具體c語言實現程式碼如下:
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_11) != RESET)
{                           
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);//呼叫中斷處理公用函式  
    if(PWM_EN()==1)     //上升沿觸發
    {
        TIM4->CNT=0;//這裡清空TIM4計數。重新開始計數
        if((PWM_FLAG_DOWM==1)&&(PWM_FLAG_UP==2))//判斷上一次是否為下降沿
        {
            PWM_Cycle = timer4_PWM_cnt*2
; timer4_PWM_cnt=0; } PWM_FLAG_CNT = 1; PWM_FLAG_UP = 1;//上升沿標誌 PWM_FLAG_DOWM = 2;//上升沿標誌 } else//下降沿觸發 { if((PWM_FLAG_DOWM==2)&&(PWM_FLAG_UP == 1))//下降沿判斷上一個狀態是否為上升沿 { PWM_Duty = timer4_PWM_cnt*2; } PWM_FLAG_DOWM=1;//下降沿標誌 PWM_FLAG_UP=2;//下降沿標誌 }
void TIM4_Init(u16 arr,u16 psc)
{  
    TIM4_Handler.Instance=TIM4;                                 //通用定時器4
    TIM4_Handler.Init.Prescaler=psc;                            //分頻係數
    TIM4_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;           //向上計數器
    TIM4_Handler.Init.Period=arr;                               //自動裝載值
    TIM4_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; //時鐘分頻因子
    HAL_TIM_Base_Init(&TIM4_Handler);
    HAL_TIM_Base_Start_IT(&TIM4_Handler);//使能定時器4和定時器4更新中斷:TIM_IT_UPDATE   
}

void TIM4_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&TIM4_Handler);
    if(PWM_FLAG_CNT == 1)//PWM上升沿到來標誌
    {
        timer4_PWM_cnt++;
    }
}