找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 11383|回复: 5
打印 上一主题 下一主题
收起左侧

单片机频率计数器(程序)

[复制链接]
跳转到指定楼层
楼主
ID:71259 发表于 2014-12-30 15:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 daming 于 2014-12-30 15:47 编辑

该程序能实现测量10至3MHZ的TTL信号频率,液晶显示4为有效数字,同时能够测量脉冲占空比,精度在0.5%左右...
需要硬件支持:C8051F360单片机,键盘,液晶显示器
main()
{
    int xdata flag1=0;
       float  sum1=0,sum2=0;
       float xdata sum3[10];
       int i;
       Init_device();
       LCD_REST();
       LCD_INIT();
       f=0;
       f1=0;
  while(1)
{
    if(flag)
   {
        if(f>=10&&f<=99)   额,不得不说,取11个数求平均值确实不好,读数不能稳定的说....
{
             sum2=(jishu[0]+jishu[1]+jishu[2]+jishu[3]+jishu[4]+jishu[5]+jishu[6]+jishu[7]+jishu[8]+jishu[9]+jishu[10])/11;
             get_flow(sum2);
             LCD_HZ(0x80,TAB_WORD);
             LCD_HZ(0x90,F_DISPLOW);
          flag=0;
            }
          else if(f>=100&&f<= 999)
       {
               get_flowhigh();
               LCD_HZ(0x80,TAB_WORD);
               LCD_HZ(0x90,F_DISPLOWHIGH);
               flag=0;
       }
          else if (f>=1000&&f<=9999)
          {
             get_high();
                LCD_HZ(0x80,TAB_WORD);
                LCD_HZ(0x90,F_DISPHIGH);
                flag=0;
          }
          else if(f>=10000&&f<=99999)
          {
             get_highone();
                LCD_HZ(0x80,TAB_WORD);
                LCD_HZ(0x90,F_DISPHIGHONE);
                flag=0;
          }
          else if(f>=100000&&f<=999999)
       {
           get_highone();
           LCD_HZ(0x80,TAB_WORD);
           LCD_HZ(0x90,F_DISPHIGHONE);         内部数据存储器只有128位,为节约空间与上个数组存在同一空间
                                                                                   (内部数据存储器空间用完的说...)
           flag=0;
              }
              else
              {
              get_highthree();
              LCD_HZ(0x80,TAB_WORD);
              LCD_HZ(0x90,F_DISPHIGHTHREE);
              flag=0;
              }
     }
       if((key_num&0xf0)==0)
        {   
               TR0=0;
                ET1=1;
                TMOD=0x10;
                TCON=0x40;
                for(i=0;i<10;i++)
                {
                 while(CHUFA==0);
                 TH1=0;
            TL1=0;
                  f1=0;
                     TR0=0;
                 while(CHUFA==1);
               while(CHUFA==0);
                 TR1=1;
                while(CHUFA==1);
              TR1=0;
                m=f1*65536+256*TH1+TL1;
                while(CHUFA==0);
                  TH1=0;
                TL1=0;
                f1=0;
                TR1=0;
                while(CHUFA==1);
                TR1=1;
                while(CHUFA==0);
                TR1=0;
                f=f1*65536+256*TH1+TL1;
          key_num=0xf0;
          sum1=m;
          sum2=m+f;
          sum1=sum1/sum2;
          sum3[ i]=sum1;
          }
          sum2=0;
          for(i=0;i<10;i++)
          {
            sum2=sum2+sum3[ i];
          }
          sum2=sum2/10;
             if(sum2>=0.1&&sum2<=0.40)
              {
                sum2=sum2-0.07;
                }
               else if(sum2>0.40&&sum2<=0.44)
                {
                sum2=sum2-0.04;
                }                                                                    占空比程序设计,本想用个中断来着,试验不成功简单的算了
                                                                                      由于每次运行指令要耗费时间,精度不高,故加个实测校准程序
                                                                                      O(∩_∩)O哈哈~测评时能达到0.5%的精度,踩狗屎运了...
                else if(sum2>0.44&&sum2<=0.55)
                {
                 sum2=sum2-0.02;
                }                                                            
                else if(sum2>0.55&&sum2<=0.63)
                {
                sum2=sum2+0.03;
                }
                else sum2=sum2+0.07;
          get_f(sum2);
          LCD_HZ(0x88,TAB_WORD1);
          LCD_HZ(0x98,F_DISP);
          flag1=1;
        }
        if(flag1==1)                                        让程序能范围继续测量频率
        {
            TMOD=0x51;                          
           CKCON=0;         
           TCON=0x50;
              flag1=0;
       }
}
}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:71259 发表于 2014-12-30 15:47 | 只看该作者
频率计数器就(3.ASCII液晶输出函数):
void get_f(float s1)

{

   int term;

   term=(int)(s1*10000);

F_DISP[0]=term/1000%10+0x30;

F_DISP[1]=term/100%10+0x30;

F_DISP[2]=0x2E;

F_DISP[3]=term/10%10+0x30;

F_DISP[4]=term%10+0x30;             占空比(原值一般为0.****)

}

//*******************************************

void  get_flow(float s1)

{  int term;

   term=(int)(s1*100);



F_DISPLOW[0]=term/1000%10+0x30;

F_DISPLOW[1]=term/100%10+0x30;

F_DISPLOW[2]=0x2E;

F_DISPLOW[3]=term/10%10+0x30;

F_DISPLOW[4]=term%10+0x30;              频率读数输出显示(10——99HZ)

}

//********************************************

void  get_flowhigh(void)

{

  

  

   F_DISPLOWHIGH[0]=f/100%10+0x30;

   F_DISPLOWHIGH[1]=f/10%10+0x30;

   F_DISPLOWHIGH[2]=f%10+0x30;

   F_DISPLOWHIGH[3]=0x2E;

   F_DISPLOWHIGH[4]=0x30;                     频率读书输出显示(100——999HZ)以下类推...

}

//********************************************

void  get_high(void)

{

  

   F_DISPHIGH[0]=f/1000%10+0x30;

   F_DISPHIGH[1]=f/100%10+0x30;

   F_DISPHIGH[2]=f/10%10+0x30;

   F_DISPHIGH[3]=f%10+0x30;

   }

  //*******************************************

  void get_highone(void)

  {

    if(f>=10000&&f<=99999)

       {

   F_DISPHIGHONE[0]=f/10000%10+0x30;

   F_DISPHIGHONE[1]=f/1000%10+0x30;

   F_DISPHIGHONE[2]=0x2E;

   F_DISPHIGHONE[3]=f/100%10+0x30;

   F_DISPHIGHONE[4]=f/10%10+0x30;

   }

   else

    {   F_DISPHIGHONE[0]=f/100000%10+0x30;

       F_DISPHIGHONE[1]=f/10000%10+0x30;

       F_DISPHIGHONE[2]=f/1000%10+0x30;

       F_DISPHIGHONE[3]=0x2E;

       F_DISPHIGHONE[4]=f/100%10+0x30;

       }

   }

   //******************************************





       void get_highthree(void)

   {

       F_DISPHIGHTHREE[0]=f/1000000%10+0x30;

       F_DISPHIGHTHREE[1]=0x2E;

       F_DISPHIGHTHREE[2]=f/100000%10+0x30;

       F_DISPHIGHTHREE[3]=f/10000%10+0x30;

       F_DISPHIGHTHREE[4]=f/1000%10+0x30;

       }
回复

使用道具 举报

板凳
ID:71259 发表于 2014-12-30 15:48 | 只看该作者
频率计数器(2.初始化及中断):
void PCA_INIT(void)

{

       PCA0CN=0X40;                         //允许PCA计数器、定时器

       PCA0MD=0;                               //禁止看门狗定时器

}

//***********************************************

void INT_INIT(void)

{

       EX0=1;                                      //INIT0,键盘

       PX0=0;                                      //INT0为低优先级

       ET0=1;                                      //T0

       ET1=1;                                    //T1

       ET2=0;                                      //T2

       EIE1=0X0;                                 //0X08,允许ADC中断

       ES0=0;                                       //uart

       EA=1;

}

//**************************************************



void Init_device(void)

{

       OSC_INIT();

       IO_INIT();

       XRAM_INIT();

       SMB_INIT();

       UART_INIT();

       DAC_INIT();

       ADC_INIT();

       INT0_INIT();

       TIMER_INIT();

       PCA_INIT();

       INT_INIT();

}

//**************************************************

void LCD_REST(void)

{

       int i;

       LCD_RST=0;

       for(i=0;i<255;i++);

       LCD_RST=1;

}

//********************************************************

void LCD_WC(unsigned char command)                          //LCD写命令

{

       while(RCOMADDR&0X80);

       WCOMADDR=command;

}

//********************************************************

void LCD_INIT(void)                                                 //LCD初始化

{

       LCD_WC(0X30);                                                    //设为基本命令集

       LCD_WC(0X01);

       LCD_WC(0X02);                                                    //将DDRAM填满20H,并设定DDRAM地址计数器为0

       LCD_WC(0X0C);                                                   //开整体显示

}

//***********************************************************



void LCD_WD(unsigned char d)                               //LCD写数据

{

       while(RCOMADDR&0X80);

       WDATADDR=d;

}

//**********************************************************

void LCD_HZ(unsigned char x,unsigned char temp[])                      //显示一行字符

{

   int i=0;

   LCD_WC(x);                                                                                    //x代表位置,=0x80对应左上角

   while(temp[i]!=0)

        {

              LCD_WD(temp[i]);

              i++;

       }

}

//********************************************************

void LCD_BYTE(unsigned char x,unsigned char temp)                           //显示一行字符

{

   LCD_WC(x);                                                                                    //x代表位置,=0x80对应左上角

   LCD_WD(temp);

}

//*********************************************************

void LCD_CLR(void)                                                     //LCD清屏

{

        LCD_WC(0X01);

}

//********************************************************

void KEY_INIT0(void) interrupt 0

{

  key_num=KEYCS&0x0f;

}

//*****T0中断服务***************************************

void  TT0_INT0(void) interrupt 1

{

    int j=0;

       TL0=0x66;                                        //0Xb0;

       TH0=0x3d;                                        //0X3c;每单位0.5微秒*50000*40

擦,难道上次精度不够是因为参数还没改正确?

      fp--;

        if(fp) return;

        TR1=0;

              fp=T_C;                      //1s

        f=65536*f1+256*TH1+TL1;

              if(n==0)

              {

              jishu[n%11]=f;

              }

              else

              {

              if(abs(jishu[n%11-1]-f)>=10)

              {

                for(j=0;j<=10;j++)

                {

                  jishu[j]=f;

                }

           }

                else

                     {

                          jishu[n%11]=f;

                         }

              }



              n++;

        flag=1;

  TH1=0;

        TL1=0;

        f1=0;

              TR1=1;

     }

//******************************************

void TT1_INT1(void ) interrupt 3

{

f1++;      定时器中断3,当计数器有溢出时会引发中断

}
回复

使用道具 举报

地板
ID:71259 发表于 2014-12-30 15:49 | 只看该作者
频率计数器(1.液晶初始及键盘等):
#define WDATADDR XBYTE[0XC009]                            //LCD写数据地址

#define RDATADDR XBYTE[0XC00B]                            //LCD读数据地址

#define WCOMADDR XBYTE[0XC008]                          //LCD写命令地址

#define RCOMADDR XBYTE[0XC00A]                           //LCD读命令地址

#define KEYCS      XBYTE[0XC00C]                      //键盘片选地址

#define T_C    40

sbit LCD_RST=P3^0;

sbit CHUFA=P0^6;

unsigned char code TAB_WORD[]={"Frequency="};

unsigned char code TAB_WORD1[]={"DUTY="};

unsigned char    F_DISP[]={"00000%"};

unsigned char   F_DISPLOW[]={"00000HZ    "};

unsigned char   F_DISPLOWHIGH[]={"00000HZ   "}  ;

unsigned char  F_DISPHIGH[]={"0000HZ     "} ;

unsigned char  F_DISPHIGHONE[]={"00000*1kHZ"};

unsigned char  F_DISPHIGHTHREE[]={"00000*1MHZ"};  

unsigned char   jishu[11]={ 0,0,0,0,0,0,0,0,0,0,0};        低频采用堆栈求平均值方法,但貌似最终对数不能稳定,难道是因为取11个数不好?

unsigned long n=0;

unsigned long m=0;

unsigned char fp;

unsigned long f;

unsigned char f1;

bit flag=0;

unsigned char key_num=0xff;                                  //存键号

void OSC_INIT (void)

{

       SFRPAGE=0X0F;

       OSCICL=OSCICL+4;

       OSCICN=0XC3;

       CLKSEL=0X30;

       SFRPAGE=0;

}

//********************************************

void IO_INIT(void)

{

       SFRPAGE=0X0F;

       P0MDIN=0Xe7;

       P0MDOUT=0X83;

       P0SKIP=0XF9;

       P1MDIN=0XFF;

       P1MDOUT=0XFF;

       P1SKIP=0XFF;

       P2MDIN=0XFE;

       P2MDOUT=0XFF;

       P2SKIP=0XFF;

       P3MDIN=0XFF;

       P3MDOUT=0XFF;

       P3SKIP=0XF9;                   //0xfd,增加P3.2作T1输入

       P4MDOUT=0XFF;

       XBR0=0X09;

       XBR1=0Xe0;                       //0xc0,增加T1

       SFRPAGE=0X0;

}

//********************************************

void XRAM_INIT(void)

{

       SFRPAGE=0X0F;

       EMI0CF=0X07;

       SFRPAGE=0;

}

//********************************************

void SMB_INIT(void)

{

       SMB0CF=0XC1;

}

//********************************************

void UART_INIT(void)

{

             SCON0=0X0;

//********************************************

void DAC_INIT(void)

{

       IDA0CN=0XF2;

}

//********************************************

void ADC_INIT(void)

{

       REF0CN=0;                         //VDD为基准

       AMX0P=0X08;                           //正端接P20

       AMX0N=0X1F;                          //负端接GND

       ADC0CF=0X2C;                  //左对齐,转换时钟2MHZ

       ADC0CN=0X80;                  //写ADOBUSY启动AD

}

//********************************************

void INT0_INIT(void)

{

       IT01CF=0X05;                           //P0.5为INT0

       IT0=1;                                       //下降沿触发

}

//********************************************

void TIMER_INIT(void)

{

       TMOD=0x51;                             //T0、T1方式1,T1计数方式

       CKCON=0;                                //系统时钟12分频

       TL0=0x66;                                

       TH0=0x3e;                        

       TL1=0X0;

       TH1=0X0;                                  //计数器清0

       fp=T_C;

       TMR2CN=0X04;                        //16位自动重装

       TMR2RLL=0XF0;                       //10MS

       TMR2RLH=0XD8;

       TMR3CN=0X0C;                        //双8位自动重装入,系统时钟1/12

       TMR3RLL=0XE0;                       //定时100us

       TMR3RLH=0XFF;

       TR0=1;

       TR1=1;

}
回复

使用道具 举报

5#
ID:71326 发表于 2014-12-30 15:59 | 只看该作者
好 非常好
回复

使用道具 举报

6#
ID:890642 发表于 2023-12-13 22:17 来自手机 | 只看该作者
daming 发表于 2014-12-30 15:49
频率计数器(1.液晶初始及键盘等):
#define WDATADDR XBYTE[0XC009]                            //LCD写 ...

够详细,值得学习
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表