基于传统测频原理的频率计的测量精度将随被测信号频率的变化而变化。传统的直接测频法其测量精度将随被测信号频率的降低而降低,测周法的测量精度将随被测信号频率的升高而降低,在实用中有较大的局限性,而等精度频率计不但具有较高的测量精度,而且在整个频率区域能保持恒定的测试精度。
等精度频率的测量频率为fx的被测信号经通道滤波、放大、整形后输入到同步门控制电路和主门1(闸门),晶体振荡器的输出信号作为标准信号(时基信号)输入到主门2。被测信号在同步控制门的作用下,产生一个与被测信号同步的闸门信号,被测信号与标准信号(时基信号)在同步门控制信号的控制下。在同步门打开时通过同步门分别输入到事件计数器和时间计数器的信号输入端,计数器开始计数。同步门关闭时信号不能通过主门,计数器停止计数,单片机发出命令读入计数器的数值,并进行数据处理,将处理后的结果送显示。
等精度频率测量方法是采用多周期同步测量。由单片机发出预置门控信号GATE,GATE的时间宽度对测频精度影响较少,可以在较大的范围内选择,即在高频段时,闸门时间较短;低频时闸门时间较长。实现了全范围等精度测量,减少了低频测量的误差。
在同步门的控制下,一方面保证了被测信号和时基信号的同步测量;另一方面在同步门打开后计数器并不是马上计数,而是在被测信号的下一个上升沿开始计数,同步门关闭后计数器也不是马上停止计数,而是在被测信号的下一个上升沿停止计数。即在实际闸门时间计数,从而提高了测量精度。
由于采用D触发器实现的同步门的同步作用,事件计数器所记录的Nx值已不存在误差的影响,但由于时钟信号与闸门的开和关无确定的相位关系,时间计数器所记录的N0的值仍存在±1误差的影响,只是由于时钟频率很高,误差的影响很小。所以在全频段的测量精度是均衡的,从而实现等精度频率测量。
单片机等精度数字频率计C程序
//-----------------------函数声明,变量定义-----------------------------
#include
sbitGATE=P3^0;//预制门限
sbitCLR=P3^1;//请零
sbitRGATE=P3^2;//实际门限
sbitSEL0=P3^4;//数据选择位0
sbitSEL1=P3^5;//数据选择位1
sbitSEL2=P3^6;//数据选择位2
#definedata_inP1
unsignedcharNx[4];//待测频率计数值
unsignedcharNs[4];//标准频率计数值
unsignedcharGATE_time=1;//门限时间,预定义为1S
unsignedchartime_count;
bitPRE_judge=1;
//-----------------------变量声明---------------------------------------
voidsystem_init(void);//初始化,设置定时器0的工作方式,供主程序调用
voidTIMER0_SCANkey();//定时器0中断处理函数
//-----------------------------------------------------------------------
//函数名称:system_init()
//函数功能:初始化设置
//设定INT0的工作方式
//-----------------------------------------------------------------------
voidsystem_init(void)
{
TMOD=0x01;//定时器0工作在方式1
ET0=1;//定时器0中断允许
TH0=-5000/256;//12M时钟时,定时0.01秒
TL0=-5000%256;
TR0=1;//定时器0开始计数
EA=1;//系统中断允许
}
//---------------------------------------------------------------------
//函数名称:read_result
//函数功能:将计数值读出到Nx、Ns
//--------------------------------------------------------------------
voidread_result()
{
GATE=0;
while(RGATE);//等待实际门限的结束
SEL0=0;
SEL1=0;
SEL2=0;
Nx[0]=data_in;//SEL=000
SEL0=1;
Nx[1]=data_in;//001
SEL1=1;
Nx[3]=data_in;//011
SEL0=0;
Nx[2]=data_in;//010
SEL0=0;
SEL1=0;
SEL2=1;
Ns[0]=data_in;//100
SEL0=1;
Ns[1]=data_in;//101
SEL1=1;
Ns[3]=data_in;//111
SEL0=0;
Ns[2]=data_in;//110
}
//-----------------------------------------------------------------------
//函数名称:judge_Prage
//函数功能:判断频率范围,
//大于1M即Nx>0x000F4240,GATE=1
//小于1M大于1k即0x000003E8<Nx//小于1k即Nx//-----------------------------------------------------------------------
voidjudge_Prage()
{
if((Nx[3]==0)&&(Nx[2]==0))
if((Nx[1]<3)||((Nx[1]==3)&&(Nx[0]<0xE8)))
GATE_time=10;
elseGATE_time=5;
elseif((Nx[3]==0)&&(Nx[2]<0x0f))
GATE_time=5;
elseif((Nx[3]==0)&&(Nx[2]==0x0f))
if(Nx[1]<0x42)
GATE_time=5;
elseif((Nx[1]==0x42)&&(Nx[0]<0x40))
GATE_time=5;
else
GATE_time=1;
elseGATE_time=1;
}
//---------------------------------------------------------------------
//函数名称:calcu_Fx
//函数功能:计算频率,根据Fx=(Nx/Ns)Fs计算结果
//-----------------------------------------------------------------------
voidcalcu_Fx()
{
}
//-------------------------------------------------------------------
//函数名称:TIMER0_intrupt
//函数功能:定时器0中断处理程序
//-----------------------------------------------------------------------
voidTIMER0_intrupt()interrupt1using1
{
EA=0;//系统中断禁止
GATE=1;
TH0=-5000/256;//12M时钟时,定时0.01秒
TL0=-5000%256;
time_count++;
if(++time_count==100)GATE_time--;
while(GATE_time==0)
{
GATE=0;
read_result();
if(PRE_judge)//预测,判断频率范围
{
judge_Prage();
PRE_judge=0;
if(GATE_time)//如果频率大于1M,直接计算,无须再测
calcu_Fx();
}
else
calcu_Fx();//不是预测,直接计算结果
}
EA=1;
}
//-----------------------------------------------------------------------
//函数名称:main
//函数功能:主函数
//-----------------------------------------------------------------------
voidmain()
{
CLR=0;
GATE=1;
system_init();
}