51单片机项目开发实例_51单片机小项目分析5—频率计

本文介绍了51单片机如何实现频率计,重点讲解了利用信号高低电平时间测量周期和频率的方法。通过分析项目,详细阐述了频率计的构成部分,包括时基电路、输入电路、计数显示电路和控制电路,并提供了原理图和源代码。
摘要由CSDN通过智能技术生成

15.1 项目分析

       频率计又称为频率计数器,是一种专门对被测信号频率进行测量的电子测量仪器。频率计主要由四个部分构成:时基(T)电路、输入电路、计数显示电路以及控制电路。对于单片机来说无法直接测量正弦波,所以需要将正弦波变换成单片机可以测量的数字信号,频率计测量信号常用的方法是通过检测信号的单位时间内峰值次数来计算频率和周期,通常利用运放或者是三极管等电子元件采集信号的过零点信息,然后可以采用两种方法进行测量。

方法1:检测1秒之内脉冲的个数,这个次数就是信号的频率,但是这种方式检测过程太长,并且对单片机的计数频率要求很高,且无法测量信号的占空比,只适用于占空比为50%的方波;

方法2:检测一个信号的高低电平时间,然后将高低电平时间累加,最后计算出周期,利用周期计算频率,这种方式对单片机计数频率要求不高,并且可以完整的测量出一个信号的周期,占空比和频率,测量速度较快,一般普遍使用这种方法。

下面我们来利用方法2来实现测量一个方波信号的占空比,周期和频率。

15.2 原理图

2522c6fdbd28ec99d9edf518437d06e6.png

15.3 源代码

/*********************************************************************************************************                头    文    件    引    用*********************************************************************************************************/#include                                             //导入51单片机头文件/*********************************************************************************************************              数    据    类    型    定    义*********************************************************************************************************/#define u8 unsigned char                                        //定义无符号字符型数据(0~255)#define u16 unsigned int                                        //定义无符号整型数据(0~65535)#define u32 unsigned long/*********************************************************************************************************              硬    件    端    口    定    义*********************************************************************************************************///LCD1602控制端口#define LCD_DB  P0                                            //LCD数据口sbit LCD_RS = P2^0 ;                                          //数据命令选择sbit LCD_RW = P2^1 ;                                          //读写控制sbit LCD_EN  = P2^2 ;                                          //使能控制//DS1302控制端口sbit Check  = P1^0 ;                                          //检测端口/*********************************************************************************************************              数    据    结    构    定    义*********************************************************************************************************/typedef struct{  u8 Count ;                      //溢出次数  u8 Duty ;                      //占空比  u32 Time_H ;                    //高电平时间  u32 Time_L ;                    //低电平时间  u16 Fosc ;                      //频率  u32 Cycle ;                      //周期  u8 Fosc_State;                    //频率单位  u8 Time_H_State ;                  //时间单位  u8 Time_L_State ;                  //时间单位  u8 Cycle_State ;                  //周期单位}PWMData;PWMData PWM_Data;u8 UI_Page ;                                              //翻页/********************************************************Name    :delay_msFunction  :毫秒延时函数Paramater  :      ms:延时的时间Return    :None********************************************************/void delay_ms( u16 ms ){  u8 i ;  while( --ms )    for( i=0; i<110; i++ ) ;}/*********************************************************************************************************                LCD1602    显    示    程    序*********************************************************************************************************//********************************************************Name    :LCD_Write_CommandFunction  :LCD写入命令Paramater  :      Command:命令代码Return    :None********************************************************/void LCD_Write_Command( u8 Command ){  LCD_RS = 0 ;                                            //命令模式  LCD_RW = 0 ;                                            //写模式  LCD_EN = 0 ;                                            //使能复位  LCD_DB = Command ;                                          //发送数据到P0总线  delay_ms( 5 ) ;  LCD_EN = 1 ;                                            //使能拉高  delay_ms( 1 ) ;  LCD_EN = 0 ;                                            //下降沿数据写入  delay_ms( 1 ) ;}/********************************************************Name    :LCD_Write_DataFunction  :LCD写入数据Paramater  :      Data:数据Return    :None********************************************************/void LCD_Write_Data( u8 Data ){  LCD_RS = 1 ;                                            //数据模式  LCD_RW = 0 ;                                            //写模式  LCD_EN = 0 ;                                            //使能复位  LCD_DB = Data ;                                            //发送数据到P0总线  delay_ms( 5 ) ;  LCD_EN = 1 ;                                            //使能拉高  delay_ms( 1 ) ;  LCD_EN = 0 ;                                            //下降沿数据写入  delay_ms( 1 ) ;}/********************************************************Name    :LCD_InitFunction  :LCD初始化Paramater  :NoneReturn    :None********************************************************/void LCD_Init(){  LCD_Write_Command( 0x38 ) ;                                      //8位总线宽度+显示2行+每个字符占用5×10的点阵  LCD_Write_Command( 0x0C ) ;                                      //开启显示+关闭光标+关闭光标显示  LCD_Write_Command( 0x06 ) ;                                      //光标右移+写入数据后显示屏不移动  LCD_Write_Command( 0x01 ) ;                                      //清屏}/********************************************************Name    :LCD_Show_StringFunction  :LCD显示字符串Paramater  :NoneReturn    :None********************************************************/void LCD_Show_String( u8 x, u8 y, u8 *str ){  u8 Address ;  //计算坐标  switch( y )  {    case 0:      Address=0x80+x ;                                      //第一行数据地址      break;    case 1:      Address=0xC0+x ;                                      //第二行数据地址      break;    default:      break;  }  //写入数据  LCD_Write_Command( Address ) ;                                    //设置写入地址  while( *str!='\0' )  {    LCD_Write_Data( *str ) ;                                    //写入数据    str ++ ;                                            //指针地址累加  }}/*********************************************************************************************************                频    率    测    量    程    序*********************************************************************************************************/void TIM0_IRQHandler() interrupt 1{  TH0 = 0 ;  TL0 = 0 ;  PWM_Data.Count ++ ;}void EXIT0_IRQHandler() interrupt 0{  delay_ms( 10 ) ;  UI_Page ++ ;  if( UI_Page==1 )  {    LCD_Show_String( 0, 0, "Time_H:000.000 s" ) ;    LCD_Show_String( 0, 1, "Time_L:000.000 s" ) ;  }  if( UI_Page==2 )  {    LCD_Show_String( 0, 0, "Cycle: 000.000 s" ) ;    LCD_Show_String( 0, 1, "                " ) ;  }  if( UI_Page==3 )  {    LCD_Show_String( 0, 0, "Fosc:000.000 Hz " ) ;    LCD_Show_String( 0, 1, "Duty:000%       " ) ;    UI_Page = 0 ;  }}/********************************************************Name    :Interrupt_InitFunction  :初始化TIM0+EXTI0Paramater  :NoneReturn    :None********************************************************/void Interrupt_Init(){  IE = 0x83 ;  IT0 = 1 ;  TMOD = 0x01 ;  TH0 = 0 ;  TL0 = 0 ;  PWM_Data.Count = 1 ;  UI_Page = 0 ;}/********************************************************Name    :DispFunction  :计算参数Paramater  :NoneReturn    :None********************************************************/void Disp(){  PWM_Data.Cycle = 0 ;  //采集高电平时间  while( Check==0 ) ;                                          //等待端口产生高电平  TR0 = 1 ;  TH0 = 0 ;  TL0 = 0 ;  PWM_Data.Count = 1 ;  while( Check ) ;                                          //等待高电平结束  PWM_Data.Time_H = PWM_Data.Count*( TH0*256+TL0 );                          //获取高电平时间  PWM_Data.Cycle += PWM_Data.Time_H ;  //采集低电平时间  TH0 = 0 ;  TL0 = 0 ;  PWM_Data.Count = 1 ;  while( Check==0 ) ;                                          //等待端口产生高电平  TR0 = 0 ;  PWM_Data.Time_L = PWM_Data.Count*( TH0*256+TL0 );                          //获取低电平时间  PWM_Data.Cycle += PWM_Data.Time_L ;  //计算数据  PWM_Data.Fosc = 1000000/PWM_Data.Cycle ;  PWM_Data.Duty = ( ( float )PWM_Data.Time_H/PWM_Data.Cycle )*100 ;  if( PWM_Data.Fosc<999 )  {    PWM_Data.Fosc_State = 2 ;    PWM_Data.Fosc *= 1000 ;  }  else if( PWM_Data.Cycle>=1000 )    PWM_Data.Fosc_State = 1 ;    if( PWM_Data.Cycle<999 )    PWM_Data.Cycle_State = 2 ;  else if( ( PWM_Data.Cycle>=1000 )&&( PWM_Data.Cycle<999999 ) )    PWM_Data.Cycle_State = 1 ;  else if( PWM_Data.Cycle>=1000000 )  {    PWM_Data.Cycle_State = 1 ;    PWM_Data.Cycle /= 1000 ;  }    if( PWM_Data.Time_L<999 )    PWM_Data.Time_L_State = 2 ;  else if( ( PWM_Data.Time_L>=1000 )&&( PWM_Data.Time_L<999999 ) )    PWM_Data.Time_L_State = 1 ;  else if( PWM_Data.Time_L>=1000000 )  {    PWM_Data.Time_L_State = 1 ;    PWM_Data.Time_L /= 1000 ;  }    if( PWM_Data.Time_H<999 )    PWM_Data.Time_H_State = 2 ;  else if( ( PWM_Data.Time_H>=1000 )&&( PWM_Data.Time_H<999999 ) )    PWM_Data.Time_H_State = 1 ;  else if( PWM_Data.Time_H>=1000000 )  {    PWM_Data.Time_H_State = 1 ;    PWM_Data.Time_H /= 1000 ;  }  delay_ms( 100 ) ;}/*********************************************************************************************************                    主    函    数*********************************************************************************************************/void main(){  Interrupt_Init() ;  LCD_Init() ;  LCD_Show_String( 0, 0, "Fosc:000.000 Hz " ) ;  LCD_Show_String( 0, 1, "Duty:000%       " ) ;  while( 1 )  {    Disp() ;    if( UI_Page==0 )    {      //显示频率      LCD_Write_Command( 0x80+5 ) ;      LCD_Write_Data( 0x30+PWM_Data.Fosc/100000 ) ;      LCD_Write_Data( 0x30+PWM_Data.Fosc%100000/10000 ) ;      LCD_Write_Data( 0x30+PWM_Data.Fosc%10000/1000 ) ;      LCD_Write_Data( '.' ) ;      LCD_Write_Data( 0x30+PWM_Data.Fosc%1000/100 ) ;      LCD_Write_Data( 0x30+PWM_Data.Fosc%100/10 ) ;      LCD_Write_Data( 0x30+PWM_Data.Fosc%10 ) ;      if( PWM_Data.Fosc_State==0 )        LCD_Write_Data( ' ' ) ;      else if( PWM_Data.Fosc_State==1 )        LCD_Write_Data( 'k' ) ;      //显示占空比      LCD_Write_Command( 0xC0+5 ) ;      LCD_Write_Data( 0x30+PWM_Data.Duty/100 ) ;      LCD_Write_Data( 0x30+PWM_Data.Duty%100/10 ) ;      LCD_Write_Data( 0x30+PWM_Data.Duty%10 ) ;    }    else if( UI_Page==1 )    {      //显示高电平时间      LCD_Write_Command( 0x80+7 ) ;      LCD_Write_Data( 0x30+PWM_Data.Time_H/100000 ) ;      LCD_Write_Data( 0x30+PWM_Data.Time_H%100000/10000 ) ;      LCD_Write_Data( 0x30+PWM_Data.Time_H%10000/1000 ) ;      LCD_Write_Data( '.' ) ;      LCD_Write_Data( 0x30+PWM_Data.Time_H%1000/100 ) ;      LCD_Write_Data( 0x30+PWM_Data.Time_H%100/10 ) ;      LCD_Write_Data( 0x30+PWM_Data.Time_H%10 ) ;      if( PWM_Data.Time_H_State==0 )        LCD_Write_Data( ' ' ) ;      else if( PWM_Data.Time_H_State==1 )        LCD_Write_Data( 'm' ) ;      else if( PWM_Data.Time_H_State==2 )        LCD_Write_Data( 'u' ) ;      //显示低电平时间      LCD_Write_Command( 0xC0+7 ) ;      LCD_Write_Data( 0x30+PWM_Data.Time_L/100000 ) ;      LCD_Write_Data( 0x30+PWM_Data.Time_L%100000/10000 ) ;      LCD_Write_Data( 0x30+PWM_Data.Time_L%10000/1000 ) ;      LCD_Write_Data( '.' ) ;      LCD_Write_Data( 0x30+PWM_Data.Time_L%1000/100 ) ;      LCD_Write_Data( 0x30+PWM_Data.Time_L%100/10 ) ;      LCD_Write_Data( 0x30+PWM_Data.Time_L%10 ) ;      if( PWM_Data.Time_L_State==0 )        LCD_Write_Data( ' ' ) ;      else if( PWM_Data.Time_L_State==1 )        LCD_Write_Data( 'm' ) ;      else if( PWM_Data.Time_L_State==2 )        LCD_Write_Data( 'u' ) ;    }    else if( UI_Page==2 )    {      LCD_Write_Command( 0x80+7 ) ;      LCD_Write_Data( 0x30+PWM_Data.Cycle/100000 ) ;      LCD_Write_Data( 0x30+PWM_Data.Cycle%100000/10000 ) ;      LCD_Write_Data( 0x30+PWM_Data.Cycle%10000/1000 ) ;      LCD_Write_Data( '.' ) ;      LCD_Write_Data( 0x30+PWM_Data.Cycle%1000/100 ) ;      LCD_Write_Data( 0x30+PWM_Data.Cycle%100/10 ) ;      LCD_Write_Data( 0x30+PWM_Data.Cycle%10 ) ;      if( PWM_Data.Cycle_State==0 )        LCD_Write_Data( ' ' ) ;      else if( PWM_Data.Cycle_State==1 )        LCD_Write_Data( 'm' ) ;      else if( PWM_Data.Cycle_State==2 )        LCD_Write_Data( 'u' ) ;    }  }}

15.4 仿真截图

e6e159984ddcb2b787a3fcedf6da5736.png

ae2eb3ac3b9a8108faea1094619eafab.png

10d1923c803d1f246db30dc4ef946cc1.png

781378df85c7a42be1225d84caa24315.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值