⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 频率计.c

📁 低频频率计 实例目的:学习定时器、计数器、中断应用 说明:选用24MHz的晶体
💻 C
字号:
//  低频频率计
//实例目的:学时定时器、计数器、中断应用
//说明:选用24MHz的晶体,主频可达2MHz。用T1产生100us的时标,T0作信号脉冲计数器。假设晶体频率没有误差,而且稳定不变(实际上可达万分之一);被测信号是周期性矩形波(正负脉冲宽度都不能小于0.5us),频率小于1MHz,大于1Hz。要求测量时标1S,测量精度为0.1%。
//解:从测量精度要求来看,当频率超过1KHz时,可采用1S时标内计数信号脉冲个数来测量信号频,而信号频率低于1KHz时,可以通过测量信号的周期来求出信号频率。两种方法自动转换。
//对于低于1KHz的信号,信号周期最小为1ms,也就是说超过1000us,而我们用的定时器计时脉冲周期为0.5us,如果定时多计或少计一个脉冲,误差为1us,所以相对误差为1us/1000us=0.1%。信号周期越大,即信号频率越低,相对误差就越小。
//从上面描述来看,当信号频率超过1KHz后,信号周期就少于1000us,显然采用上面的测量方法,不能达到测量精度要求,这时我们采用1S单位时间计数信号的脉冲个数,最少能计到1000个脉冲,由于信号频率不超过1MHz,而我们定时脉冲为2MHz,最差多计或少计一个信号脉冲,这样相对误差为1/1000,可见信号频率越高,相对误差越小。
//信号除输入到T1(P3.5)外,还输入到INT1(P3.3)。
#include<reg52.h>
unsigned int us100;        //对100us时间间隔单位计数,即有多少个100us。
unsigned char Second;
unsigned int K64;          //对64K单位计数,即有多少个64K
unsigned char oldT0;
unsigned int oldus, oldK64, oldT1;
unsigned long fcy;         //存放频率值,单位为Hz
bit HighLow=1;             //1:表示信号超过1KHz;0:表示信号低于1KHz。
unsigned char table(unsigned char x)//软件查表输出
{unsigned char code n[10]={0xee,0x82,0xdc,0xd6,0xb2,0x76,0x7e,0xc2,0xfe,0xf6};
return(n[x]);
}

//频率显示//
display(float f)             
{
    unsigned long x;
    unsigned char a[5]={0,0,0,0,0},i=0,j;
    if(f!=0)
    {
        while(f<10000)
        {
            f=f*10;
            i++;
        }  
        x=f;
        a[1]=x%10;
        a[2]=(x/10)%10;
        a[3]=(x/100)%10;
        a[4]=(x/1000)%10;
        for(j=0;j<5;j++)
        {
            a[j]=table(a[j]);
	    }
        a[i+1]++;
        a[0]=0;
    }
    for(j=0;j<5;j++)//串行输出//
    {
        SBUF=a[j];
        while(TI==0);
    }

}
void InitialHigh( void )
{
    IE=0; IP=0; HighLow=1;
    TMOD = (TMOD & 0xf0) | 0x02; TH0=-200; TL0=TH0; PX0=1; T0=1; 
    TMOD = (TMOD & 0x0f) | 0x50; TH1=0; TL1=0; T1=1; ET1=1;
    us100=0; Second=0; K64=0;
    oldK64=0; oldT1=0;
    TCON |= 0x50;          //同时置 TR0=1; TR1=1;
    EA = 1;
}
void InitialLow( void )
{
    IE=0; IP=0; HighLow=0;
    TMOD = (TMOD & 0xf0) | 0x02; TH0=-200; TL0=TH0; ET0=1; TR0=1;
    INT1 = 1; IT1=1; EX1=1;
    us100=0; Second=0; K64=0;
    oldK64=0; oldT1=0;
    EA = 1;
}
void T0intr( void ) interrupt 1
    {
        if( HighLow==0 ) ++us100;
        else
        if( ++us100 >= 10000 )
        { 
            unsigned int tmp1, tmp2;
            TR1=0; tmp1=(TH1<<8) + (TL1); tmp2=K64; TR1=1;
            fcy=((tmp2-oldK64)<<16) + (tmp1-oldT1);
            oldK64=tmp1; oldT1=tmp2;
            Second++;
            us100=0;
        }
    }
void T1intr( void ) interrupt 3{++K64;}
void X1intr( void ) interrupt 2
{
    static unsigned char sts=0;
    switch( sts )
    {
        case 0: sts = 1; break;
        case 1: oldT0=TL0; oldus=us100; sts=2; break;
        case 2: 
        {
            unsigned char tmp1, tmp2;
            TR0=0; tmp1=TL0; tmp2=us100; TR0=1;
            fcy = 1000000L/( (tmp2-oldus)*100L + (256-tmp1)/2 );
            Second ++;
        }
        sts = 0;
        break;
    }
}
void main( void )
{
    IE=0x8a;
    TMOD=0x51;	    
    TH0=0xce;        //定时器0=12.8ms
    TL0=0;
    TH1=0xff;        //计数器1=100个脉冲
    TL1=0x9c;
    TCON=0x50;
    TH0=0;
    TL0=0;
    TMOD=0x09;
    TR0=1;
    GATE=1;
    while(P33==0);
    GATE=0;
    while(P33==1);
    TR0=0;
    if( HighLow==1) InitialHigh(); 
    else InitialLow();
    while(1)
    {unsigned char i;
        if( Second != 0 )
        {
            Second = 0;
//display fcy  引用前面的数码管驱动程序,注意下面对T0中断服务程序的修改
            
                
                for( i=0; i<8; i++ )
                {
//                    display(i, fcy%10); 
                    fcy /= 10;
                }
            
            if( HighLow==1 );
            if( fcy<1000L ) InitialLow();  
            else
            if( fcy>1000L ) InitialHigh();
        }
    }
}
//修改T0的中断服务程序,让它在完成时标的功能时,同时完成数码管显示刷新
/*void T0intr( void ) interrupt 1
{
    static unsigned char ms = 0;
    if( HighLow==0 ) ++us100;
    else
    if( ++us100 >= 10000 )
    {
        unsigned int tmp1, tmp2;
        TR1=0; tmp1=(TH1<<8) + (TL1); tmp2=K64; TR1=1;
        fcy=((tmp2-oldK64)<<16) + (tmp1-oldT1);
        oldK64=tmp1; oldT1=tmp2;
        Second++;
        us100=0;
    }
    if( ++ms >= 10 )ms=0, display;//Brush();//1ms数码管刷新 
}*/    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -