上一章介绍了利用STM32的TIM的捕获功能实现频率测量的方法,但测量误差受被测信号频率的影响,不适合测量频率变化较大的 。本章将介绍等精度测频的方法以及STM32的实现。
STM32硬件电路板及仿真器(以STM32F072C8单片机为例) Keil v5以上版本(MDK-ARM)
基本原理
首先看一张图:
50j043olh5c64048945230.png
传统的测频方式,闸门放时间是固定的,闸门时间内被测信号的计数个数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。[/ol]
STM32CubeMX的TIM配置如下:
gfkcpzrrpdu64048945330.jpg
TIM1作为产生闸门时间的定时器,其计数周期设置为47999,时钟为系统时钟,1000分频。则溢出周期即闸门时间为1秒,打开溢出中断:
sbcb1is1eyj64048945430.png
TIM3作为捕获被测信号的定时器,其配置如下,通道1设置为捕获模式,捕获上升沿,定时周期设置为最大65535,时钟为系统时钟,不分频。打开中断(TIM3捕获和溢出为同一个中断)。
iasacpombgt64048945530.png
hguccb04syy64048945630.jpg
程序实现:
按照之前介绍的步骤设置其它外设,并生成代码。初始化后,启动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_Cnt16) + 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串口的使用方法,敬请期待。 |