上一章介绍了利用STM32的TIM的捕获功能实现频率测量的方法,但测量误差受被测信号频率的影响,不适合测量频率变化较大的 。本章将介绍等精度测频的方法以及STM32的实现。
STM32硬件电路板及仿真器(以STM32F072C8单片机为例)
Keil v5以上版本(MDK-ARM)
基本原理
首先看一张图:
传统的测频方式,闸门放时间是固定的,闸门时间内被测信号的计数个数Nx不一定是整数个,因此会有一定的误差,且误差与被测信号频率有关。而等精度测频的方法,闸门时间不是固定的,而是被测信号的整数倍。 因此消除了对被测信号计数的±1误差,其误差只与标准信号的计数个数Ns的±1误差有关。可以看出,闸门时间越长,标准频率Fs越大,Ns的计数值越大,±1误差的影响就小。在相同的闸门时间内,被测信号的频率Fx=Nx*Fs/Ns。
STM32的实现
实现等精度测频用到两个定时器,其中一个定时器用于产生闸门时间,另外一个用于捕获被测信号和标准信号计数。
实现步骤:
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);
编写中断回调函数。
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;//标志清零,可以开始下一次测量
}
}
以上即为利用STM32定时器实现等精度测频的全部内容,STM32定时器的功能还有很多,如触发ADC采样、编码器模式等。不再一一做介绍,下一章开始介绍STM32串口的使用方法,敬请期待。
往期回顾
01 | |
02 | |
03 | |
04 | |