打开电脑发现以前曾经做过一个测频仪的东西!是大3时的单片机课程设计吧!翻出来回顾一下吧!
总的来说这个东西主要难点是在于小信号的调理方面!在我认为在做一些系统项目中,其实小信号的系统前调理是一件非常麻烦的事。因为我们自己用的线性电源,或多或少是会给小信号带来干扰的,再经放大后,干扰是一件让人头疼的东西!!所以我现在个人觉得,自己做的电源是干扰的一大来源!在市场上买的一些廉价电源更是如此,自己用示波器测一下,纹波吓得死人了。还有一点就是元器件的选型。测频仪的测频范围当然是越广越好,所以放大器,一定要选比较高速的,而比较器也是如此,别用运放做比较器(工作在放大饱和区),它的速度(带宽)不如专门的比较器好。比较器一定要搭成迟滞比较电路,这样才能抗电源纹波干扰。至于测频的方法,可用低频侧周,高频测频的经典方法!
一下是具体的设计:
2.1 放大电路的设计 集成芯片选择:AD811
芯片特点:电流反馈型宽带运放,其单位增益带宽很宽,高达140MHZ。
注意要点:应注意电路中各电阻电容应紧密靠近AD811的相应引脚,去耦电容必不可少。特意加了两个隔直电容,以便滤除直流的影响。整个系统单电源供电,提高稳定性。
放大倍数计算公式:
Vin = Vout * R4 / (R13 + R4)
即 Vout / Vin = (R13 + R4) / R4 = (510 + 51) / 51 = 11。
2.2 整形电路的设计
单片机只能检测到方波信号,为了能测量方波以外的信号。我们设计了整形电路,通过比较器LM339对信号进行整形编程方波信号。整形电路的原理图如图5所示:
注意要点:加入正反馈电阻构成迟滞比较器。如果输入信号Uin在门限值附近有微小的干扰,则输出电压就会产生相应的抖动(起伏)。在电路中引入正反馈可以克服这一缺点。
2.3分频电路的设计
为了能达到扩展部分的要求被测频率要达到10MHZ,故要对其进行分频,SN74HC390是高速分频器件,最高分频频率为50MHz。每片SN74HC390可实现100分频,采用两片串联,可实现对信号的1000分频,经分频后的数字信号频率较低,约8kHz以下,可由单片机直接计数。分频电路如图6示
2.4分频控制电路设计
单片机不能检测高频信号,为了满足设计要求中的能测量10MHZ的信号,我们设计了分频电路。并且为了满足自动换挡的要求,我们选用模拟开关CD4051对信号进行分频的倍数的控制。CD4051真值表如左图示,分频控制电路如右图示。
软件设计
通常采用的方法有低频端测周高频端测频和多周期同步测量频率。采用低频端测周高频端测频时存在中界频率测量误差很大即测量死区问题,也就是说不论低端和高端测量准确度有多高,中界频率测量误差总是最大。因此从理论上讲频率的测量准确度很难提高到某个数量级;多周期同步测频法则不存在这样的问题,只要周期数足够大,测量的准确度总可以提高到一定程度。
本次设计测频采用多周期同步测频法。被测信号接外部中断口INT0,外部信号在下降沿触发中断。此时计数器开始计时。如下图所示,若在中断中计得被测脉冲的个数为N。而定时器0计得的标准脉冲数为M。显然如下等式成立:
M/fx=N/f0
得:fx=(M*f0)/N
这样便算出了被测信号的频率值。
系统软件流程
void main(void)
{
unsigned char key_value;
CD4051_slect(0);//CDCO51初始化
Clr_Scr();
init_lcd();//液晶初始化
welcome();//欢迎界面
while(1)
{
key_value=scan_key();//键盘扫描
if(key_value==0x03)//等待开始键
break;
}
Clr_Scr();
Msg();
while(1)//数据实时采集
{}
}
附件:源代码
#include <reg52.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include<intrins.h>
#include"Port_Config.h"
#include"data.h"
/******************************lcd引脚定义*****************/
/* Define the register command code */
#define Disp_On 0x3f
#define Disp_Off 0x3e
#define Col_Add 0x40
#define Page_Add 0xb8
#define Start_Line 0xc0
unsigned char col,row; //全局变量,在输出字符窜是有用
int Num="0";
double const const_num=1000000;
unsigned flg_int0=0;
int flag_div=0,flag_div100=0,flag_khz=0,flag_mhz=0,flag_kkhz=0,flag_mmhz=0;
double fre_value ; //测的频率值
unsigned char code str_hz[]="( HZ)";
unsigned char code str_khz[]="(KHZ)";
unsigned char code str_mhz[]="(MHZ)";
unsigned char dis[8];
/*------------------CD4051选择通道------------------------------*/
void CD4051_slect(int v)
{
switch(v)
{
case 0:CD4015_0=0;CD4015_1=0;CD4015_2=0;break;//通道0
case 1:CD4015_0=1;CD4015_1=0;CD4015_2=0;break;//通道1
case 2:CD4015_0=0;CD4015_1=1;CD4015_2=0;break;//通道2
}
}
/********************************lcd部分***************************************************/
/*------------------延时子程序-----------------------------*/
void delay(unsigned int t)
{
unsigned int i,j;
for(i=0;i<t;i++)
for(j=0;j<10;j++)
;
}
/*------------------写命令到LCD------------------------------*/
void write_com(unsigned char cmdcode)
{
Di=0;
RW=0;
Lcd_Bus=cmdcode;
delay(0);
Enable=1;
delay(0);
Enable=0;
}
/*-------------------写数据到LCD----------------------------*/
void write_data(unsigned char Dispdata)
{
Di=1;
RW=0;
Lcd_Bus=Dispdata;
delay(0);
Enable=1;
delay(0);
Enable=0;
}
/*-------------------读LCD数据----------------------------*/
unsigned char read_data()
{
unsigned char tmpin;
Di=1;
RW=1;
delay(0);
Enable=1;
delay(0);
Enable=0;
tmpin=Lcd_Bus;
return tmpin;
}
/*------------------清除内存---------------*/
void Clr_Scr()
{
unsigned char j,k;
Mcs=1;Scs=1;
write_com(Page_Add+0);
write_com(Col_Add+0);
for(k=0;k<8;k++){
write_com(Page_Add+k);
for(j=0;j<64;j++)write_data(0x00);
}
}
/*---------------------指定位置显示汉字8*16-----------------------*/
void hz_disp8(unsigned char pag,unsigned char col, unsigned char code *hzk)
{
unsigned char j="0",i=0;
for(j=0;j<2;j++){
write_com(Page_Add+pag+j);
write_com(Col_Add+col);
for(i=0;i<8;i++) write_data(hzk[8*j+i]);
}
}
/*---------------------指定位置显示汉字16*16-----------------------*/
void hz_disp16(unsigned char pag,unsigned char col, unsigned char code *hzk)
{
unsigned char j="0",i=0;
for(j=0;j<2;j++){
write_com(Page_Add+pag+j);
write_com(Col_Add+col);
for(i=0;i<16;i++) write_data(hzk[16*j+i]);
}
}
/*---------------------指定位置显示汉字32*16-----------------------*/
void hz_disp32(unsigned char pag,unsigned char col, unsigned char code *hzk)
{
unsigned char j="0",i=0;
for(j=0;j<2;j++){
write_com(Page_Add+pag+j);
write_com(Col_Add+col);
for(i=0;i<32;i++) write_data(hzk[32*j+i]);
}
}
/*------------------初始化LCD屏--------------------------*/
void init_lcd()
{
Lcd_Rst=0;
delay(100);
Lcd_Rst=1;
delay(100);
Mcs=1;
Scs=1;
delay(100);
write_com(Disp_Off);
write_com(Page_Add+0);
write_com(Start_Line+0);
write_com(Col_Add+0);
write_com(Disp_On);
}
/*-------------------------半角字符点阵码数据输出-----------------------------------*/
void Putedot(unsigned char Order)
{
unsigned char cbyte, j="0",i=0;
int x;
x=Order * 0x10;
for(j=0;j<2;j++)
{
write_com(Page_Add+row+j);
write_com(Col_Add+col);
for(i=0;i<8;i++)
{
cbyte = Ezk[x];
write_data(cbyte); //写输出一字节
x++;
}
}
}
/*---------------------------一个字串的输出-------------------------------------*/
void Putstr( unsigned char *str , unsigned char i , unsigned char lie, unsigned char hang)
{
unsigned char j,X;
for (j=0;j<i;j++)
{
col="lie"+8*j; //换列。。。。。肖注释
row="hang";
X = str[j];
Putedot(X-0x20); /*ascii码表从0x20开始*/
}
}
/**********************************键盘扫描部分***********************************************************/
/*-------------------------delay---------------------------------*/
void mdelay(unsigned int N)
{
int i;
for(i=0;i<N;i++);
}
/*-----------------------------------1列3行的键盘扫描----------------*/
unsigned char scan_key()
{
P2=P2|0x07;
P2_4=0;
if((P2&0x07)!=0x07)
{
mdelay(100);
if((P2&0x07)!=0x07)
return (P2&0x07);
}
}
/*--------------------外部中断0服务程序-------------------------------*/
void int0() interrupt 0
{
unsigned char T0H,T0L;
//unsigned temp="0";
if(flg_int0==0)
{
TH0=0;
TL0=0;
TR0=1; //定时器0开始计时
}
if(flag_div==1)
{
CD4051_slect(1);
flag_div=0;
}
if(flag_div100==1)
{
CD4051_slect(2);
flag_div100=0;
}
if(Num>10)
{
EA="0"; //关中断
TR0=0;
T0H=TH0;
T0L=TL0;
//temp= (Num*65535+T0H*256+T0L);
fre_value=(const_num*flg_int0)/(Num*65535+T0H*256+T0L);
if(fre_value>=1000)
flag_khz=1;
else
flag_khz=0;
if(fre_value>5000) //超出11khz则分频
{
if(flag_kkhz)
{
flag_div100=1; //100分频标志
flag_mmhz=1; // 100fenpin单位标志
}
else
{
flag_div=1; //分频标志
flag_kkhz=1; //10分频后单位标志
}
TH0=0;
TL0=0;
T0H=0;
T0L=0;
Num="0";
flg_int0=0;
EA="1";
}
else{
if(flag_div==0&&flag_div100==0) //显示部分
{
Mcs=0;Scs=1;
if(flag_mmhz)
{
fre_value=fre_value/10.0;
Putstr(str_khz,5,0,4);
// flag_mhz=0;
}
else if(flag_kkhz)
{
fre_value=fre_value/100.0 ;
Putstr(str_khz,5,0,4);
}
else if(flag_khz)
{
fre_value=fre_value/1000.0 ;
Putstr(str_khz,5,0,4);
}
else
Putstr(str_hz,5,0,4);
sprintf(dis,"%f",fre_value);
Putstr(dis,8,0,2); //测周法显示
}
CD4051_slect(0) ;
TH0=0;
TL0=0;
T0H=0;
T0L=0;
Num="0";
flg_int0=0;
flag_div=0; //分频标志
flag_div100=0;
flag_kkhz=0;
flag_mmhz=0;
EA="1";
}
}
else
flg_int0++;
}
void Timer0() interrupt 1//定时器0的中断服务程序
{
TH0=0;
TL0=0;
Num++;
}
void welcome(void)
{
unsigned char str1[]="www.hnrk";
unsigned char str2[]="u.net.cn";
unsigned char str3[]="Welcome";
unsigned char str4[]="To";
Mcs=1;Scs=0;
Putstr(str3,7,1,0);
hz_disp32(2,32,cp);
Putstr(str1,8,0,6);
Mcs=0;Scs=1;
Putstr(str4,2,0,0);
Putstr(str2,8,0,6);
hz_disp32(2,0,xt);
}
void Msg( void)
{
Mcs="1";Scs=0;
hz_disp16(0,0,p);
hz_disp16(0,16,l);
hz_disp32(0,32,dx);
Mcs="0";Scs=1;
hz_disp16(0,0,wei);
hz_disp8(0,16,mh);
Putstr(str_hz,5,0,4);
TMOD="0x01"; //定时器0工作为定时方式
IP="0X06";//int1 最高 T0优先级高于INT0
IT0=1; //外部中断为下降沿触发方式
EX0=1; //允许外部中断0,接待测方波
ET0=1; //允许t0中断
EA="1";
}
//////////////////////////////////////main()
#include<reg52.h>
#include <stdio.h>
#include "Fren_Test.h"
#include"Port_Config.h"
#include"data.h"
unsigned char key;
extern double fre_value ;
void main(void)
{
unsigned char key_value;
CD4051_slect(0) ;
Clr_Scr();
init_lcd();
welcome();
while(1)
{
key_value=scan_key();
if(key_value==0x03)
break;
}
Clr_Scr();
Msg();
while(1)
{}
}
用户1588142 2011-6-20 21:28
用户158894 2009-4-19 16:51
用户1144279 2008-11-27 15:54