在做一个频率计,有个地方不知道怎么回事,想请问大家一下谢谢

2019-07-15 12:41发布

我想做一个51mcu  4位频率计,测1~9999hz方波,程序写好了,可以正常运行,显示正常。但是有个问题就是:当待测频率较小的时候,100hz左右时候没有误差,待测频率在1000hz左右时,测出来的相对误差大概1.6%,2000hz时候误差3.2%,3000hz时候5.3%,8000hz时候误差15%。频率越大,误差越大。但是误差是跟频率成正比的,所以我想给num乘以一个关于频率的函数,频率越高,此函数值越大,刚好就弥补了待测频率越高误差越大的缺陷。
但是void display()里面num一乘以double型变量就显示出错了,强制转换(uint)(num*x)类型也没用,还是显示不对。请问该怎么改?
//四位方波频率计                       
#include<reg52.h>
sbit dula=P2^6;
sbit wela=P2^7;         
#define uint unsigned int
#define uchar unsigned char
uint num,a,b,c,d,k;//num作为一个全局变量//a b c d是千位到个位
//double num;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};

/*函数声明*/
void delay(uint);
void display();
uint read1();         
/*主函数*/
void main()
{
        TMOD=0x15;         //0001 0101 定时器1,计数器0
        TH1=(65536-45872)/256;                        //11.0592MHZ下装入45872才是50ms
        TL1=(65536-45872)%256;
        TH0=0;
        TL0=0;                                                 //要用1个计数器,1个定时器
        ET1=1;
        EA=1;
        TR0=1;
        TR1=1;
        while(1);       
}

/*定时1s函数*/
void timer0() interrupt 3
{
        TR1=0;
        TH1=(65536-45872)/256;
        TL1=(65536-45872)%256;
        k++;
        if(k==20)
        {
                num=read1();                        //num是计数个数       
                display();
                k=0;
                TH0=0;
                TL0=0;
        }       
        TR1=1;
}



/*前4位数码管显示函数*/
void display()
{
        uint i;       
        for(i=100;i>0;i--)
        {       
                num=(num*1); //在此处num乘以修正系数,不修正时NUM乘1
                a=(num/1000);
                b=((num%1000)/100);
                c=(((num%1000)%100)/10);
                d=(((num%1000)%100)%10);

                dula=1;                                   //千位
                P0=table[a];                  
                dula=0;
                P0=0xff;
                wela=1;
                P0=0xfe;//1111 10
                wela=0;
                delay(5);
               
                dula=1;                                   //百位
                P0=table[b];                  
                dula=0;
                P0=0xff;
                wela=1;
                P0=0xfd;//1111 01
                wela=0;
                delay(5);

                dula=1;                                   //十位
                P0=table[c];                  
                dula=0;
                P0=0xff;
                wela=1;
                P0=0xfb;//1110 11
                wela=0;
                delay(5);

                dula=1;                                   //个位
                P0=table[d];                  
                dula=0;
                P0=0xff;
                wela=1;
                P0=0xf7;//1101 11
                wela=0;
                delay(5);

                wela=1;
                P0=0xff;//1101 11
                wela=0;
                delay(5);
           }
}

uint read1()                           //读计数器1的值
{
        uint t1_1,th1_1,th2_1;
        uint val_1;
        while(1)
        {
                th1_1=TH0;
                t1_1=TL0;
                th2_1=TH0;
                if(th1_1==th2_1)               
                break;
        }
    val_1=th1_1*256+t1_1;
        return val_1;
}



/*延时函数*/
void delay(uint z)
{
        uint x,y;
        for(x=z;x>0;x--)
                for(y=110;y>0;y--);       
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
8条回答
STURCT
1楼-- · 2019-07-15 13:48
你算一个数的具体位数是多少没有算对,所以才显示不对 最佳答案
dgzgqg
2楼-- · 2019-07-15 15:47
 精彩回答 2  元偷偷看……
275849752
3楼-- · 2019-07-15 17:07
dgzgqg 发表于 2016-11-5 16:10
你这个程序好神奇,都没看到你从哪个IO口检测方波,寄存器比较一下就可以测出方波频率!
正常是使用定时器的外部中断,方波加到中断IO口,利用下降沿触发中断,记下触发时的定时器值;然后根据相邻2次的定时器值相减,得到方波的频率。
如果是较低频率的,定时器一个周期记不下的,还要添加定时器溢出中断的次数。 ...

我是用一个单片机发出方波,从P2.0口输入到频率计P3.4口,这个口是单片机内部已经定义好做计数器外部输入的,所以程序里面没有写出来,直接连一根杜邦线就可以了。我现在就想把num乘以一个浮点数后再拿去数码管显示,不然误差太大,但是一乘之后最后显示出来的数就不断地在变,不知道怎么改
275849752
4楼-- · 2019-07-15 18:09
dgzgqg 发表于 2016-11-5 16:10
你这个程序好神奇,都没看到你从哪个IO口检测方波,寄存器比较一下就可以测出方波频率!
正常是使用定时器的外部中断,方波加到中断IO口,利用下降沿触发中断,记下触发时的定时器值;然后根据相邻2次的定时器值相减,得到方波的频率。
如果是较低频率的,定时器一个周期记不下的,还要添加定时器溢出中断的次数。 ...

谢谢,现在这个错误已经改过来了
275849752
5楼-- · 2019-07-15 20:57
正在改进中,完全做好后会再把代码发在此贴
275849752
6楼-- · 2019-07-16 02:19
//四位方波频率计        ,初学者,做得比较粗糙,精确的应该用FPGA来做
//由于是拿郭天祥C51单片机做的,段选P2.6位选,P2.7,6位数码管,选前四位显示频率。外部方波输入是P3.4口       
//由于51单片机机器周期比较长,所以在测频率的时候会产生误差,而且待测频率越大,误差越大。测1000HZ以内时误差可稳定在1%100以内。测很高频率时候请自行乘以修正函数。我下面程序里面没有写,乘完之后显示的频率误差会小很多。       
#include<reg52.h>
sbit dula=P2^6;
sbit wela=P2^7;         
#define uint unsigned int
#define uchar unsigned char
double num,a,b,c,d,k;//num作为一个全局变量//a b c d是千位到个位

uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};

/*函数声明*/
void delay(uint);
void display();
uint read1();         
/*主函数*/
void main()
{
        TMOD=0x15;         //0001 0101 定时器1,计数器0
        TH1=(65536-45872)/256;                        //11.0592MHZ下装入45872才是50ms
        TL1=(65536-45872)%256;
        TH0=0;
        TL0=0;                                                 //要用1个计数器,1个定时器
        ET1=1;
        EA=1;
        TR0=1;
        TR1=1;
        while(1);       
}

/*定时1s函数*/
void timer0() interrupt 3
{
        TR1=0;
        TH1=(65536-45872)/256;
        TL1=(65536-45872)%256;
        k++;
        if(k==20)
        {
                num=read1();                        //num是计数个数       
                display();
                k=0;
                TH0=0;
                TL0=0;
        }       
        TR1=1;
}



/*前4位数码管显示函数*/
void display()
{
        uint i;       
        if(num<=200)                 num=num*1+num*(0.001);
        if(num>200&&num<=500)        num=num*1+num*(0.003);                                                  //在此处num乘以修正系数
        if(num>500&&num<=1000)       num=num*1+num*(0.008);                                  
        for(i=100;i>0;i--)
        {                         
                a=((uint)num/1000);
                b=((uint)((uint)((uint)num%1000))/100);
                c=((uint)((uint)((uint)num%1000)%100)/10);
                d=((uint)((uint)((uint)num%1000)%100)%10);

                dula=1;                                   //千位
                P0=table[(uint)a];                  
                dula=0;
                P0=0xff;
                wela=1;
                P0=0xfe;//1111 10
                wela=0;               
                delay(5);
                               
                dula=1;                                   //百位
                P0=table[(uint)b];                  
                dula=0;
                P0=0xff;
                wela=1;
                P0=0xfd;//1111 01
                wela=0;
                delay(5);

                dula=1;                                   //十位
                P0=table[(uint)c];                  
                dula=0;
                P0=0xff;
                wela=1;
                P0=0xfb;//1110 11
                wela=0;
            delay(5);
                               
                dula=1;                                   //个位
                P0=table[(uint)d];                  
                dula=0;
                P0=0xff;
                wela=1;
                P0=0xf7;//1101 11
                wela=0;
                  delay(5);       


                wela=1;
                P0=0xff;//1101 11
                wela=0;
                delay(5);
           }
}

uint read1()                           //读计数器1的值
{
        uint t1_1,th1_1,th2_1;
        uint val_1;
        while(1)
        {
                th1_1=TH0;
                t1_1=TL0;
                th2_1=TH0;
                if(th1_1==th2_1)               
                break;
        }
    val_1=th1_1*256+t1_1;
        return val_1;
}



/*延时函数*/
void delay(uint z)
{
        uint x,y;
        for(x=z;x>0;x--)
                for(y=110;y>0;y--);       
}

一周热门 更多>