51单片机频率计,可以测量0-500Khz的频率 ,采用计数器的方式采集,里边附有论文资料。采用Proteus仿真,程序在下边压缩包里,自取按键支持保存频率和回看历史记录数据
1.单片机+最小系统+LCD1602液晶显示模块+NE555模块+电位器调节模块+按键模块
2.采用LCD1602液晶显示频率值,测量范围0~500KHZ(理论上500KHZ,实际480KHZ左右)。
3.配有鳄鱼夹,可以随意测量外部的频率。拨动开关,也可以测NE555产生的频率,通过电位器调节频率值的大小。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
元件清单:
1 104 直插瓷片电容 2
2 10uf 直插电解电容 1
3 30p 直插瓷片电容 2
4 LCD1602 液晶显示器 1
5 CON2 排针2-Pin 1
6 12MHZ 晶振 1
7 SW-PB 按键6X6X5MM 1
8 POWER DC电源插座 1
9 S9013 NPN三极管 1
10 10K 色环电阻 1
11 1k 色环电阻 2
12 2.2k 色环电阻 1
13 10K 电位计可调电阻 1
14 SW-SPST 波动开关 1
15 SW8*8 自锁开关 1
16 MCU 单片机 1
17 555 555芯片 1
配套器材
1 导线 XXcm 1
2 焊锡 XXcm 1
3 USB转DC3.5mm电源线 系统供电 1
4 7*9万用板 1
5 单片机插座 40脚IC座 1
6 IC插座 8脚IC座 1
7 2P杜邦线 公对母 1
8 16P排针 1
9 16P排母 1
单片机源程序如下:
- //包含头文件
- #include <reg52.h>
- #include <math.h>
- #define uc unsigned char
- #define ui unsigned int
- #define u8 unsigned char
- #define u16 unsigned int
- #define uchar unsigned char
- #define uint unsigned int
- unsigned char dispbuf[6]={0,0,0,0,0,0}; //显示数据暂存数组
- unsigned char temp[6]; //频率值暂存数组
- unsigned char T0count; //计数器计满次数,计满一次对应的脉冲数为65536个
- unsigned int timecount; //定时器定时1秒的变量,每次对应为50ms,计20次对应就是1秒,然后计算一秒内的计数器脉冲个数
- bit flag; //计时到1秒时该标志位置1,进行脉冲数的运算,得出结果送显示,然后该位清零,重新开始脉冲计数
- unsigned long x; //计算脉冲的数据范围一般比较大,所以用无符号长整形变量定义该变量
- /***********************************************************************************************************
- LCD1602相关函数
- ***********************************************************************************************************/
- //LCD管脚声明 (RW引脚实物直接接地,因为本设计只用到液晶的写操作,RW引脚一直是低电平)
- sbit LCDRS = P2^7;
- sbit LCDEN = P2^6;
- sbit D0 = P0^0;
- sbit D1 = P0^1;
- sbit D2 = P0^2;
- sbit D3 = P0^3;
- sbit D4 = P0^4;
- sbit D5 = P0^5;
- sbit D6 = P0^6;
- sbit D7 = P0^7;
- //LCD延时
- void LCDdelay(uint z) //该延时大约100us(不精确,液晶操作的延时不要求很精确)
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=10;y>0;y--);
- }
- //LCD写数据
- void LCD_WriteData(u8 dat)
- {
- if(dat&0x01)D0=1;else D0=0;
- if(dat&0x02)D1=1;else D1=0;
- if(dat&0x04)D2=1;else D2=0;
- if(dat&0x08)D3=1;else D3=0;
- if(dat&0x10)D4=1;else D4=0;
- if(dat&0x20)D5=1;else D5=0;
- if(dat&0x40)D6=1;else D6=0;
- if(dat&0x80)D7=1;else D7=0;
- }
- //写命令
- void write_com(uchar com)
- {
- LCDRS=0;
- LCD_WriteData(com);
- LCDdelay(5);
- LCDEN=1;
- LCDdelay(5);
- LCDEN=0;
- }
- //写数据
- void write_data(uchar date)
- {
- LCDRS=1;
- LCD_WriteData(date);
- LCDdelay(5);
- LCDEN=1;
- LCDdelay(5);
- LCDEN=0;
- }
- /*------------------------------------------------
- 选择写入位置
- ------------------------------------------------*/
- void SelectPosition(unsigned char x,unsigned char y)
- {
- if (x == 0)
- {
- write_com(0x80 + y); //表示第一行
- }
- else
- {
- write_com(0xC0 + y); //表示第二行
- }
- }
- /*------------------------------------------------
- 写入字符串函数
- ------------------------------------------------*/
- void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
- {
- SelectPosition(x,y) ;
- while (*s)
- {
- write_data( *s);
- s ++;
- }
- }
- //========================================================================
- // 函数: void LCD_Write_Char(u8 x,u8 y,u16 s,u8 l)
- // 应用: LCD_Write_Char(0,1,366,4) ;
- // 描述: 在第0行第一个字节位置显示366的后4位,显示结果为 0366
- // 参数: x:行,y:列,s:要显示的字,l:显示的位数
- // 返回: none.
- // 版本: VER1.0
- // 日期: 2013-4-1
- // 备注: 最大显示65535
- //========================================================================
- void LCD_Write_Char(u8 x,u8 y,u16 s,u8 l)
- {
- SelectPosition(x,y) ;
- if(l>=5)
- write_data(0x30+s/10000%10); //万位
- if(l>=4)
- write_data(0x30+s/1000%10); //千位
- if(l>=3)
- write_data(0x30+s/100%10); //百位
- if(l>=2)
- write_data(0x30+s/10%10); //十位
- if(l>=1)
- write_data(0x30+s%10); //个位
- }
- //1602初始化
- void Init1602()
- {
- uchar i=0;
- write_com(0x38);//屏幕初始化
- write_com(0x0c);//打开显示 无光标 无光标闪烁
- write_com(0x06);//当读或写一个字符是指针后一一位
- write_com(0x01);//清屏
-
- }
- void display() //显示函数
- {
- unsigned int j; //定义变量用于显示延时
- if(dispbuf[5]!=0) //如果十万位不为0
- {
- LCD_Write_Char(1,6,dispbuf[5],1) ;
- for(j=50;j>0;j--);
- }
- else
- {
- SelectPosition(1,6) ;
- write_data(' '); //万位
- }
- if(dispbuf[8]!=0||dispbuf[4]!=0) //如果十万位和万位都不等于零
- {
- LCD_Write_Char(1,7,dispbuf[4],1) ;
- for(j=50;j>0;j--);
- }
- else
- {
- SelectPosition(1,7) ;
- write_data(' '); //万位
- }
- LCD_Write_Char(1,8,dispbuf[3],1) ;
- for(j=50;j>0;j--);
- LCD_Write_Char(1,10,dispbuf[2],1) ;
- for(j=50;j>0;j--);
- LCD_Write_Char(1,11,dispbuf[1],1) ;
- for(j=50;j>0;j--);
- LCD_Write_Char(1,12,dispbuf[0],1) ;
- for(j=50;j>0;j--);
- }
- void main(void) //主函数
- {
- unsigned char i;
- TMOD=0x15; //定义T1为定时模式,T0位计数模式
- TH0=0;
- TL0=0; //计数器清零
- TH1=0x3c;
- TL1=0xb0; //定时器赋值(定时50ms)
- TR1=1; //打开定时器T1
- TR0=1; //打开计数器T0
- ET0=1; //打开中断允许
- ET1=1; //打开中断允许
- EA=1; //打开中断总开关
- Init1602(); //调用初始化显示函数
- //**********************0123456789ABCDEF***************
- LCD_Write_String(0,0,"The Frequency:"); //开机界面
- LCD_Write_String(1,0," 3.570kHz"); //
- while(1) //进入循环,因为括号内为常数1,不会变化,所以该表达式一直成立,又称死循环
- {
- display(); //调用显示函数
- if(flag) //判断1秒时间是否到
- {
- flag=0; //标志位清零,计算完脉冲数后重新开始计时计数
- x=T0count*65536+TH0*256+TL0; //读取1秒时间内的计数个数(T0count为每次计数超过65536时进入计数中断加1)
- for(i=0;i<6;i++) //for循环将暂存数组内数据清零
- {
- temp[i]=0;
- }
- i=0; //i清零
- while(x/10) //将x拆分为6个一位数
- {
- temp[i]=x%10; //如果x/10不为0,将x除以10的余数赋值temp【i】
- x=x/10; //然后将x/10的商赋值给x
- i++; //i++
- }
- temp[i]=x; //最高位直接赋值给temp【i】
- for(i=0;i<6;i++) //for循环用于将数据送入显示暂存数组
- {
- dispbuf[i]=temp[i]; //赋值语句
- }
- T0count=0; //计数器中断次数清零
- TH0=0;
- TL0=0; //计数器清零
- TR0=1;
- TR1=1; //重新打开定时计数器
- }
- }
- }
- void t0() interrupt 1 //计数器中断函数
- {
- T0count++; //计数超过65536,就产生一次中断
- }
- void t1() interrupt 3 //定时器中断函数
- {
- TH1=0x3c;
- TL1=0xb0; //50ms进入一次中断,进入中断后要重新赋初值
- timecount++; //每进一次中断就是50ms,该变量加一
- if(timecount==20) //该变量加到20次时,代表1秒到了
- {
- TR0=0; //关闭计数器
- TR1=0; //关闭定时器
- timecount=0; //计时变量清零,准备下次定时
- flag=1; //一秒时间到,该标志位置1,主函数中执行脉冲数运算与显示函数
复制代码
全部资料51hei下载地址:
频率计 - LCD1602.7z
(1.6 MB, 下载次数: 166)
|