单片机技术网|技术阅读
登录|注册

您现在的位置是:单片机技术网 > 技术阅读 > STM32实现等精度测频

STM32实现等精度测频

上一章介绍了利用STM32的TIM的捕获功能实现频率测量的方法,但测量误差受被测信号频率的影响,不适合测量频率变化较大的 。本章将介绍等精度测频的方法以及STM32的实现。


  •     STM32硬件电路板及仿真器(以STM32F072C8单片机为例)

  •     Keil v5以上版本(MDK-ARM)


基本原理

首先看一张图:

传统的测频方式,闸门放时间是固定的,闸门时间内被测信号的计数个数Nx不一定是整数个,因此会有一定的误差,且误差与被测信号频率有关。而等精度测频的方法,闸门时间不是固定的,而是被测信号的整数倍。 因此消除了对被测信号计数的±1误差,其误差只与标准信号的计数个数Ns的±1误差有关。可以看出,闸门时间越长,标准频率Fs越大,Ns的计数值越大,±1误差的影响就小。在相同的闸门时间内,被测信号的频率Fx=Nx*Fs/Ns。


STM32的实现

实现等精度测频用到两个定时器,其中一个定时器用于产生闸门时间,另外一个用于捕获被测信号和标准信号计数。

实现步骤:

  • TIM1设置约1秒的闸门时间。
  • TIM3捕获到被测信号上升沿后,将TIM1计数器清零。
  • 闸门时间开始,TIM3开始捕获计数同时本身计数器也开始计数。
  • 闸门时间到后,标志置位。
  • TIM3检测到标志置位且捕获到上升沿后,记录当前捕获计数的值Nx和本身计数器的计数值Ns。
  • 计算被测信号频率Fx=Nx*Fs/Ns,其中Fs为定时器时钟频率48MHz。

  • STM32CubeMX的TIM配置如下:

    TIM1作为产生闸门时间的定时器,其计数周期设置为47999,时钟为系统时钟,1000分频。则溢出周期即闸门时间为1秒,打开溢出中断:

    TIM3作为捕获被测信号的定时器,其配置如下,通道1设置为捕获模式,捕获上升沿,定时周期设置为最大65535,时钟为系统时钟,不分频。打开中断(TIM3捕获和溢出为同一个中断)。


    程序实现:

    按照之前介绍的步骤设置其它外设,并生成代码。初始化后,启动TIM1和TIM3中断。

    HAL_TIM_Base_Start_IT(&htim1); HAL_TIM_Base_Start_IT(&htim3); HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);

    编写中断回调函数。

    #define Fs 48000000L //定时器时钟频率uint32_t TIM3_Cnt_Value[2];//定时器3捕获值uint32_t TIM3_Over_Cnt=0;//定时器3溢出次数uint32_t TIM1_Over_Flag=0;//定时器1溢出标志uint32_t Ns,Nx;//标志信号计数值 被测信号计数值double Fx;//被测频率
    //定时器溢出中断 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
    if(htim->Instance == TIM1) { TIM1_Over_Flag = 1; } if(htim->Instance == TIM3) { TIM3_Over_Cnt++; if(TIM3_Over_Cnt==0xffffffff)TIM3_Over_Cnt=0xfffffffe; }
    }
    //定时器捕获中断void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){ if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) { if(TIM1_Over_Flag == 0) { __HAL_TIM_SET_COUNTER(&htim1,0);//TIM1清零 开始闸门时间 TIM3_Cnt_Value[0] = __HAL_TIM_GET_COUNTER(&htim3); Nx++; } else if(TIM1_Over_Flag == 1)//闸门时间到 { Nx++; TIM3_Cnt_Value[1] = __HAL_TIM_GET_COUNTER(&htim3); Ns = (TIM3_Over_Cnt<<16) + TIM3_Cnt_Value[1] - TIM3_Cnt_Value[0];//计算标准信号的计数值 TIM1_Over_Flag = 2;//一次测量完成 标志置位 } }}//计算被测频率void CalcFx(void){ if(TIM1_Over_Flag == 2) { Fx = (double)Nx * Fs / Ns;//计算频率    Nx=0; //计数清零    TIM1_Over_Flag = 0;//标志清零,可以开始下一次测量 }}


    在主函数中调用CalcFx()函数即可获取被测信号的频率。
    以上即为利用STM32定时器实现等精度测频的全部内容,STM32定时器的功能还有很多,如触发ADC采样、编码器模式等。不再一一做介绍,下一章开始介绍STM32串口的使用方法,敬请期待。

    往期回顾



    01


    02


    03


    04