于51单片机的数字频率计
设计的频率计范围能够达到1HZ-1MHZ(实际上51单片机达不到这个范围,不要在实验环境下进行),这个是课设来着,用Proteus仿真实现的,给有需要的同学参考一下
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载).
本文提出设计数字频率计的方案,重点介绍以单片机AT89C51为控制核心,实现频率测量的数字频率设计。测频的基本原理是采用在低频段直接测频法,在低频段直接测频法的设计思路,硬件部分由单片机和数计显示电路组成;软件部分由信号频率测量模块和数据显示模块等模块实现。应用单片机的控制功能和数学运算能力,实现计数功能和频率的换算。设计的频率计范围能够达到1HZ~1MHZ,满足所要求的频率范围,测量精度较高。
目录
前 言
第一章 总体设计方案
1.1 总设计框图
1.2 硬件设计分析
1.2.1 电源的设计
(4):LCD1602的指令说明及时序
(5): LCD1602的RAM地址映射及标准字库表
第二章 软件设计与分析
2.1 软件设计的组成
2.2 各部分软件分析
2.2.1 定时器0中断子函数
2.2.2 定时器1中断子函数
2.2.3 主函数
2.3 总源程序
第三章 软件介绍
3.1 PROTEUS简介
3.2 PROTEL 99 SE简介
3.2.1 电路工程设计部分
3.2.2 电路仿真与PLD部分
3.3 Protel 99 SE的功能特性
3.4 Protel99SE快捷键大全
3.6仿真图
3.7原理图
第四章 减小误差措施及扩展方面
4.1减小误差措施
4.2扩展方面
(1)预处理电路部分
(2)增加电源部分
4.3 功能上的完善
4.3.1 增加键盘控制
4.3.2 实现自动量程转换
4.3.3 液晶显示器(LCD)进行数据的显示
总结
致谢词
参考文献
前 言
频率是电子技术领域的一个基本参数,同时也是一个非常重要的参数,因此,频率测量已成为电子测量领域最基本最重要的测量之一。 随着科学技术的不断发展提高,人们对科技产品的要求也相应的提高,数字化的电子产品越来越受到欢迎。频率计作为比较常用和实用的电子测量仪器,广泛应用于科研机构、学校、家庭等场合,因此它的重要性和普遍性勿庸质疑。数字频率计具有体积小、携带方便;功能完善、测量精度高等优点,因此在以后的时间里,必将有着更加广阔的发展空间和应用价值。比如:将数字频率计稍作改进,就可制成既可测频率,又能测周期、占空比、脉宽等功能的多用途数字测量仪器。将数字频率计和其他电子测量仪器结合起来,制成各种智能仪器仪表,应用于航空航天等科研场所,对各种频率参数进行计量;应用在高端电子产品上,对其中的频率参数进行测量;应用在机械器件上,对机器振动产生的噪声频率进行监控;等等。研究数字频率计的设计和开发,有助于频率计功能的不断改进、性价比的提高和实用性的加强。以前的频率计大多采用TTL数字电路设计而成,其电路复杂、耗电多、体积大、成本高。随后大规模专用IC(集成电路)出现,如ICM7216,ICM7226频率计专用IC,使得频率计开发设计变得简单,但由于价格较高,因此利用IC设计数字频率计的较少。现在,单片机技术发展非常迅速,采用单片机来实现数字频率计的开发设计,实现频率的测量,不但测量准确,精度高,而且误差也很小。我们将介绍一种简单、实用的基于单片机的数字频率计的设计和制作。
第一章 总体设计方案
以AT89C51单片机为核心,起着控制作用。系统包括LCD1602液晶显示电路、复位电路、时钟电路。设计思路分为四个模块:复位电路、晶振电路模块、AT89C51、LCD1602液晶显示电路。
1.1 总设计框图
图1-1-1 总设计框图
1.2 硬件设计分析1.2.1 电源的设计
(1):系统电源使用直流5伏。
(2):单片机最小系统
单片机选用型号为AT89C51。
AT89C51是一个低电压,高性能CMOS 8位单片机,片内含4k bytes的可反复擦写的Flash只读程序存储器和128bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,内置功能强大的微型计算机的AT89C51提供了高性价比的解决方案。
如图1-2-3所示为AT89C51单片机基本构造,其基本性能介绍如下:
图1-2-3 AT89C51单片机
AT89C51本身内含40个引脚,32个外部双向输入/输出(I/O)端口,同时内含2个外中端口,3个16位可编程定时计数器,2个全双工串行通信口,AT89C51可以按照常规方法进行编程,但不可以在线编程。其将通用的微处理器和Flash存储器结合在一起,特别是可反复擦写的Flash存储器可有效地降低开发成本。
AT89C51的主要特性如下表所示:
兼容MCS—51指令系统
32个可编程I/O线
4k字节可编程闪烁存储器
可编程UARL通道
三个16位可编程定时/计数器中断
时钟频率0-24MHz
2个外部中断源,共8个中断源
256×8bit内部RAM
2个读写中断口线
可直接驱动LED
软件设置睡眠和唤醒功能
低功耗空闲和掉电模式
表1-2-1 AT89C51主要功能描述
AT89C51为40脚双列直插封装的8位通用微处理器,采用工业标准的C51内核,在内部功能及管脚排布上与通用的8xc51相同,其主要用于会聚调整时的功能控制。功能包括对会聚主IC内部寄存器、数据RAM及外部接口等功能部件的初始化,会聚调整控制,会聚测试图控制,红外遥控信号IR的接收解码及与主板CPU通信等。主要管脚有:XTAL1(19脚)和XTAL2(18脚)为振荡器输入输出端口,外接12MHz 晶振。RST/Vpd(9脚)为复位输入端口,外接电阻电容组成的复位电路。VCC(40脚)和VSS(20脚)为供电端口,分别接+5V电源的正负端。P0~P3 为可编程通用I/O脚,其功能用途由软件定义,在本设计中,P0端口(32~39脚)被定义为N1功能控制端口,分别与N1的相应功能管脚相连接,13脚定义为IR输入端,10脚和11脚定义为I2C总线控制端口,分别连接N1的SDAS(18脚)和SCLS(19脚)端口,12脚、27脚及28脚定义为握手信号功能端口,连接主板CPU的相应功能端,用于当前制式的检测及会聚调整状态进入的控制功能。
P0口:P0口是一组8位漏极开路型双向I/O 口,也即地址/数据总线复用口。作为输出口用时,每位能吸收电流的方式驱动8个TTL逻辑门电路,对端口P0写“1”时,可作为高阻抗输入端用。在访问外部数据存储器或程序存储器时,这组口线分时转换地址(低8位)和数据总线复用,在访问期间激活内部上拉电阻。在Flash 编程时,P0口接收指令字节,而在程序校验时,输出指令字节,校验时,要求外接上拉电阻。
P1口:P1是一个带内部上拉电阻的8位双向I/O口,P1的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(IIL)。与AT89C51不同之处是,P1.0和P1.1还可分别作为定时/计数器2 的外部计数输入(P1.0/T2)和输入(P1.1/T2EX)。Flash编程和程序校验期间,P1接收低8位地址。
P2口:P2是一个带有内部上拉电阻的8 位双向I/O口,P2的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对端口P2写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口,作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(IIL)。在访问外部程序存储器或16位地址的外部数据存储器(例如执行MOVX @DPTR指令)时,P2口送出高8位地址数据。在访问8位地址的外部数据存储器(如执行MOVX @RI指令)时,P2口输出P2锁存器的内容。Flash编程或校验时,P2亦接收高位地址和一些控制信号。
P3口:P3口是一组带有内部上拉电阻的8位双向I/O口。P3口输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对P3口写入“1”时,它们被内部上拉电阻拉高并可作为输入端口。此时,被外部拉低的P3口将用上拉电阻输出电流(IIL)。P3口除了作为一般的I/O口线外,更重要的用途是它的第二功能P3口还接收一些用于Flash 闪速存储器编程和程序校验的控制信号。
RST:复位输入。当振荡器工作时,RST引脚出现两个机器周期以上高电平将使单片机复位。
ALE/PROG:当访问外部程序存储器或数据存储器时,ALE(地址锁存允许)输出脉冲用于锁存地址的低8位字节。一般情况下,ALE仍以时钟振荡频率的1/6输出固定的脉冲信号,因此它可对外输出时钟或用于定时目的。要注意的是:每当访问外部数据存储器时将跳过一个AL脉冲。对Flash存储器编程期间,该引脚还用于输入编程脉冲(PROG)。如有必要,可通过对特殊功能寄存器(SFR)区中的8EH单元的D0位置位,可禁止ALE操作。该位置位后,只有一条 MOVX 和MOVC指令才能将ALE激活。此外,该引脚会被微弱拉高,单片机执行外部程序时,应设置ALE禁止位无效。
PSEN:程序储存允许(PSEN)输出是外部程序存储器的读选通信号,当AT89C51由外部程序存储器取指令(或数据)时,每个机器周期两次PSEN有效,即输出两个脉冲。在此期间,当访问外部数据存储器,将跳过两次PSEN信号。
EA/VPP:外部访问允许。欲使CPU仅访问外部程序存储器(地址为0000H—FFFFH),EA端必须保持低电平(接地)。需注意的是:如果加密位LB1被编程,复位时内部会锁存EA端状态。如EA端为高电平(接Vcc端),CPU则执行内部程序存储器中的指令。Flash存储器编程时,该引脚加上+12V的编程允许电源Vpp,当然这必须是该器件是使用12V编程电压Vpp。
XTAL1:振荡器反相放大器的及内部时钟发生器的输入端。
XTAL2:振荡器反相放大器的输出端。
单片机最小原理图如图1-2-4所示。
图1-2-4 单片机最小系统
单片机最小系统说明:
时钟信号的产生:在MCS-51芯片内部有一个高增益反相放大器,其输入端为芯片引脚XTAL1,其输出端为引脚XTAL2。而在芯片的外部,XTAL1和XTAL2之间跨接晶体振荡器和微调电容,从而构成一个稳定的自激振荡器,这就是单片机的时钟振荡电路。
时钟电路产生的振荡脉冲经过触发器进行二分频之后,才成为单片机的时钟脉冲信号。
一般地,电容C1和C2取30pF左右,晶体的振荡频率范围是1.2-12MHz。如果晶体振荡频率高,则系统的时钟频率也高,单片机的运行速度也就快。
单片机复位使CPU和系统中的其他功能部件都处在一个确定的初始状态下,并从这个状态开始工作。单片机复位条件:必须使9脚加上持续两个机器周期(即24个振荡周期)的高电平。
(3):显示系统
LCD1602分为带背光和不带背光两种,基控制器大部分为HD44780,带背光的比不带背光的厚,是否带背光在应用中并无差别,两者尺寸差别如下图1-2-5所示:
LCD1602的主要技术参数:
1、显示容量:16×2个字符
2、芯片工作电压:4.5—5.5V
3、工作电流:2.0mA(5.0V)
4、模块最佳工作电压:5.0V
5、字符尺寸:2.95×4.35(W×H)mm
引脚功能说明
LCD1602采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如图1-2-6所示:
编号
符号
引脚说明
编号
符号
引脚说明
1
VSS
电源地
9
D2
数据
2
VDD
电源正极
10
D3
数据
3
VL
液晶显示偏压
11
D4
数据
4
RS
数据/命令选择
12
D5
数据
5
R/W
读/写选择
13
D6
数据
6
E
使能信号
14
D7
数据
7
D0
数据
15
BLA
背光源正极
8
D1
数据
16
BLK
背光源负极
图1-2-1:引脚接口说明表
第1脚:VSS为地电源。
第2脚:VDD接5V正电源。
第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。
第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:D0~D7为8位双向数据线。
第15脚:背光源正极。
第16脚:背光源负极。
(4):LCD1602的指令说明及时序
1602液晶模块内部的控制器共有11条控制指令,如图1-2-7所示:
序号
指令
RS
R/W
D7
D6
D5
D4
D3
D2
D1
D0
1
清显示
0
0
0
0
0
0
0
0
0
1
2
光标返回
0
0
0
0
0
0
0
0
1
*
3
置输入模式
0
0
0
0
0
0
0
1
I/D
S
4
显示开/关控制
0
0
0
0
0
0
1
D
C
B
5
光标或字符移位
0
0
0
0
0
1
S/C
R/L
*
*
6
置功能
0
0
0
0
1
DL
N
F
*
*
7
置字符发生存贮器地址
0
0
0
1
字符发生存贮器地址
8
置数据存贮器地址
0
0
1
显示数据存贮器地址
9
读忙标志或地址
0
1
BF
计数器地址
10
写数到CGRAM或DDRAM)
1
0
要写的数据内容
11
从CGRAM或DDRAM读数
1
1
读出的数据内容
1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平)
指令1:清显示,指令码01H,光标复位到地址00H位置。
指令2:光标复位,光标返回到地址00H。
指令3:光标和显示模式设置I/D:光标移动方向,高电平右移,低电平左移S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。
指令4:显示开关控制。D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示C:控制光标的开与关,高电平表示有光标,低电平表示无光标B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:光标或显示移位S/C:高电平时移动显示的文字,低电平时移动光标。
指令6:功能设置命令DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。
指令7:字符发生器RAM地址设置。
指令8:DDRAM地址设置。
指令9:读忙信号和光标地址BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:写数据。
指令11:读数据。
(5): LCD1602的RAM地址映射及标准字库表
液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,图2-2-6是1602的内部显示地址。
例如第二行第一个字符的地址是40H,那么是否直接写入40H就可以将光标定位在第二行第一个字符的位置呢?这样不行,因为写入显示地址时要求最高位D7恒定为高电平1所以实际写入的数据应该是01000000B(40H)+10000000B(80H)=11000000B(C0H)。
在对液晶模块的初始化中要先设置其显示模式,在液晶模块显示字符时光标是自动右移的,无需人工干预。每次输入指令前都要判断液晶模块是否处于忙的状态。
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。
图1-2-9 液晶显示电路
3.6仿真图
3.7原理图
3.8元件清单
第四章 减小误差措施及扩展方面4.1减小误差措施
(1)选用频率较高和稳定性好晶振。如选24KHZ的晶振可使测量范围扩大,稳定性好的晶振可以减小误差。
(2)测量频率低的信号时,可适当调整程序,延长门限时间,减少原理上±1的相对误差。
(3)测量频率高的信号时,可先对信号进行分频,在进行测量。
4.2扩展方面
(1)预处理电路部分
在实际工作中,如若两级NPN放大管仍不能使放大作用明显,则可以再级联一个NPN放大管;或者采用放大能力更强的三极管或CMOS管代替。后一种思路虽然在价格上有所增加,但却减少了电路的复杂程度,并且在电路板一旦出现问题时,能尽最大可能的减少元器件的更换和连接线路的修改,非常方便和实用。
(2)增加电源部分
在上面数字频率计的设计工程中,使用的是外部干电池电源对单片机和其他电路供电,操作起来很方便,但有一个缺点是外部提供的电源准确度不是很高。比如,单片机需要提供5V的标准电压,我们使用的干电池,由于使用时间过久或型号不同而使得提供的电压达不到5V或高于5V,这样使得电路不能在正常的状态下工作或损坏元器件。因此在原理图中,我们可以加入电源部分,采用元件7805或7809和整流电路对外来电压进行整流、限压,提供标准的5V电压给电路,这样就增加了硬件电路的稳定性和测试的准确性。
4.3 功能上的完善4.3.1 增加键盘控制
通过按键实现数字频率计的测频率,周期,占空比,脉宽等各项功能。按不同的键起到不同的作用,也就是完成不同的功能。还可以根据按键数的多少来选择不同的键盘。所以我们可以从实际操作中知道键盘的扩展是非常方便的。
4.3.2 实现自动量程转换
在测量频率时,软件编程也可以实现频率测量量程的自动转换。频率计每个工作循环开始时使用计数方法实现频率测量,测量完后判断测量结果是否具有2位有效数字,如果成立,将结果送去显示,本工作循环结束;否则将计数闸门宽度依次扩大10倍,继续进行测量判断,直到计数闸门宽度达到1s,这时对应的频率测量范围为100Hz~999Hz。如果测量结果仍不具有2位有效数字,频率计则使用定时方法实现频率测量。
4.3.3 液晶显示器(LCD)进行数据的显示
LED显示管只能显示0~9和一些简单的英文字母,频率计的功能就受到极大的限制,而LCD显示管能够解决LED的不足,增强显示功能。LCD具有体积小、低耗电量、无辐射危险,平面直角显示以及影像稳定不闪烁等优势,因此广泛应用于各种仪表设备中去。LCD显示器主要有字符型和点阵型两种。
总结
系统的分析与设计过程也是对学习的总结过程,更是进一步学习和探索的过程。在这过程中,我对利用可编程控制器进行控制系统的设计与开发有了深刻的的认识,对机械手的工作原理有了进一步的掌握,对控制系统的分析与设计有了切身的认识和体会,并在学习和实践过程中增长了知识,丰富了经验。控制系统的开发设计是一项复杂的系统工程,必须严格按照系统分析、系统设计、系统实施、系统运行与调试的过程来进行。系统的分析与设计是一项很辛苦的工作,同时也是一个充满乐趣的过程。在设计过程中,要边学习,边实践,遇到新的问题就不断探索和努力,即可使问题得到解决。
同时,在本次设计中,也深刻体会到理论和实践相集合的重要性。虽然之前收集了大量的资料但在实际应用中却有很大差异,出现了许多意想不到的问题。但经过长时间的摸索最终还是设计出达到要求的系统。由于时间紧迫,有些设计工作还有待完善,在以后的工作中我会继续努力,不断提高自己的技术水平,以适应未来的激烈竞争形势。
致谢词
毕业,意味着一个人一个阶段学习生涯的结束。在大学里,毕业论文是宣告这一事实的标准。从大一到现在三年的学习三年的磨练,在此刻沉淀成一篇毕业论文。
通过这次毕业设计,使我得到了一次用专业知识、专业技能分析和解决问题的全面系统的锻炼。我学到了很多书本上学不到的实践知识,尤其对电子硬件、电路设计有了更深刻的理解,了解了设计一个产品从方案的选择到最终产品的一系列的设计阶段,了解了产品的调试技术。使我真正体会到理论和实践相结合的重要性。
在此有无数感谢。
首先,感谢我的父母。是他们教会我做人做事的道理,他们的谆谆教导是.我前进的强大动力和坚实后盾。
感谢大学三年里教育过我的老师, 那些曾经的岁月,曾经的年华,我们一起走过的路。
感谢我的同学。无论是教室里的如切如磋,餐桌旁的高谈阔论。还是寝室里的欢声笑语,都留下了我们最美好的回忆。这是我最宝贵的财富之一。
当然,这里更要感谢的是xxx老师,他是我这次毕业设计的指导老师。衷心的感谢他在这段时间对我的帮助和对我的教导。任老师的言传身教我将谨记遵循,他渊博的学识和严谨的治学态度将是我收益终生。
最后感谢各位评委和答辩老师在百忙之中抽出时间来亲自检阅我的毕业设计。
2.2 各部分软件分析
2.2.1 定时器0中断子函数
void t0() interrupt 1 using 1
{
}
2.2.2 定时器1中断子函数
void t1() interrupt 3 using 3//定时器T1中断服务程序
{
if(num==3999)
{
GATE=0;
TR0=0;
TR1=0;
aaa=TH0*256+TL0;
bbb=P1;
d=c/100.0;
c=0;
e=f;
f=1;
CLR=1;
CLR=0;
TH0=0x00;
TL0=0x00;
TH1=0x06;
TL1=0x06;
num=0;
GATE=1;
TR0=1;
TR1=1;
}
else
num++;
}
2.2.3 主函数
void main()//主函数
{
unsigned long a=0;
bit b=0;
uchar tab[10];
uint temp=0;
LCD_init();
init();
LCD_sfj1(0,0);
LCD_print("Welcome to use ");
LCD_sfj1(0,1);
LCD_print("Please Wating...");
delay3();
LCD_write(0,0x01);
while(1)
{
if(K1==0)
{
delay2(10);
if(K1==0)
{
while(K1==0);
b=~b;
LCD_write(0,0x01);
}
}
temp=fenjie(0);
if(temp>c)
c=temp;
if(temp>c>>3&&temp<c>>1)
f=0;
if(b==0)
{
a=(aaa*256)+bbb;
if(a==0)
{
LCD_sfj1(0,0);
LCD_print("F= 0000000000 Hz");
LCD_sfj1(0,1);
LCD_print("F= 0000000000 Hz");
}
else
{
LCD_sfj1(0,0);
LCD_print("F= Hz");
sprintf(tab,"%ld",a);
LCD_sfj1(2,0);LCD_print(tab);
LCD_sfj1(0,1);
LCD_print("P= ms");
sprintf(tab,"%0.6f",1000.0/a);
LCD_sfj1(2,1);
LCD_print(tab);
}
}
else
{
sprintf(tab,"%bd",e);
LCD_sfj1(0,0);
LCD_print(tab);
sprintf(tab,"Upp=%0.3fV",d);
LCD_sfj1(0,1);
LCD_print(tab);
}
}
}
2.3 总源程序
#include<reg51.h>
#include<stdio.h>
#include<intrins.h>
typedef unsigned char uchar;
typedef unsigned int uint;
sbit RS=P2^5;
sbit RW=P2^6;
sbit E=P2^7;
sbit CLK=P2^0;
sbit DO=P2^1;
sbit DI=P2^1;
sbit CS=P2^2;
sbit CLR=P3^0;
sbit GATE=P3^1;
sbit K1=P3^7;
uint num=0;
uint c=0;
float d=0;
uchar e=1,f=1;
unsigned long int aaa=0,bbb=0;
uchar LCD_wait()//LCD1602内部等待函数
{
RS=0;
RW=1;
_nop_();
E=1;
_nop_();
E=0;
return P0;
}
void LCD_write(bit aa,uchar bb)//向LCD写入命令或数据
{
E=0;
RS=aa;
RW=0;
_nop_();
P0=bb;
_nop_();//注意顺序
E=1;
_nop_();//注意顺序
E=0;
_nop_();
LCD_wait();//LCD1602内部等待函数
}
void LCD_display(uchar temp)
{
LCD_write(0,0x08|temp);
}
void LCD_input(uchar cc)
{
LCD_write(0,0x04|cc);
}
void LCD_init()//初始化LCD
{
E=0;
LCD_write(0,0x38);//8位数据端口,2行显示,5*7点阵
LCD_write(0,0x38);
LCD_display(0x04|0x00);//开启显示, 无光标
LCD_write(0,0x01);//清屏
LCD_input(0x02|0x00);//AC递增,画面不动
}
void LCD_sfj1(uchar x,uchar y)
{
if(y==0)
LCD_write(0,0x80|x);
if(y==1)
LCD_write(0,0x80|(x-0x40));
}
void LCD_print(uchar *p)
{
while(*p!='\0')
{
LCD_write(1,*p);
p++;
}
}
void delay1(uchar x)//ms延时子函数
{
uchar i;
for(i=0;i<x;i++); //延时,脉冲一位持续的时间
}
uchar start(bit temp) //把模拟电压值转换成8位二进制数并返回,dat为通道选择。
{
uchar i,aa=0;
CS=0;
DO=0;//片选,DO为高阻态
delay1(10);
CLK=0;
delay1(2);
DI=1;
CLK=1;
delay1(2);//第一个脉冲,起始位
CLK=0;
delay1(2);
DI=1;
CLK=1;
delay1(2);//第二个脉冲,DI=1表示双通道单极性输入
CLK=0;
delay1(2);
DI=temp; /*******************************/
CLK=1;
delay1(2);//第三个脉冲,DI=1表示选择通道1(CH2)
DI=0;
DO=1;//DI转为高阻态,DO脱离高阻态为输出数据作准备
CLK=1;
delay1(2);
CLK=0;
delay1(2);//经实验,这里加一个脉冲AD便能正确读出数据,
//不加的话读出的数据少一位(最低位d0读不出)
for(i=0;i<8;i++)
{
CLK=1;
delay1(2);
CLK=0;
delay1(2);
aa=(aa<<1)|DO;//在每个脉冲的下降沿DO输出一位数据,最终ch为8位二进制数
}
CS=1;//取消片选,一个转换周期结束
return(aa);//把转换结果返回
}
uint fenjie(bit cc)
{
uchar dd;
uint ee;
dd=start(cc);
ee=(uint)dd*100/51; //51是由5/255的倒数得来的,5是5V,255是8位AD。
return(ee);
}
void delay2(uint z)//按键消抖
{
uint x;
uchar y;
for(x=0;x<z;x++)
for(y=0;y<110;y++);
}
void delay3()//1s延时子函数
{
uchar h,i,j,k;
for(h=5;h>0;h--)
for(i=4;i>0;i--)
for(j=116;j>0;j--)
for(k=214;k>0;k--);
}
//定时计数初始化
void init()
{
TMOD=0x25; // T0计数,T1定时
TH0=0x00;
TL0=0x00;
TH1=0x06;
TL1=0x06;
CLR=1;
CLR=0;
GATE=0;
GATE=1;
ET0=1;
ET1=1;
EA=1;
TR0=1;
TR1=1;
}
void main()//主函数
{
unsigned long a=0;
bit b=0;
uchar tab[10];
uint temp=0;
LCD_init();
init();
LCD_sfj1(0,0);
LCD_print("Welcome to use ");
LCD_sfj1(0,1);
LCD_print("Please Wating...");
delay3();
LCD_write(0,0x01);
while(1)
{
if(K1==0)
{
delay2(10);
if(K1==0)
{
while(K1==0);
b=~b;
LCD_write(0,0x01);
}
}
temp=fenjie(0);
if(temp>c)
c=temp;
if(temp>c>>3&&temp<c>>1)
f=0;
if(b==0)
{
a=(aaa*256)+bbb;
if(a==0)
{
LCD_sfj1(0,0);
LCD_print("F= 0000000000 Hz");
LCD_sfj1(0,1);
LCD_print("F= 0000000000 Hz");
}
else
{
LCD_sfj1(0,0);
LCD_print("F= Hz");
sprintf(tab,"%ld",a);
LCD_sfj1(2,0);LCD_print(tab);
LCD_sfj1(0,1);
LCD_print("P= ms");
sprintf(tab,"%0.6f",1000.0/a);
LCD_sfj1(2,1);
LCD_print(tab);
}
}
else
{
sprintf(tab,"%bd",e);
LCD_sfj1(0,0);
LCD_print(tab);
sprintf(tab,"Upp=%0.3fV",d);
LCD_sfj1(0,1);
LCD_print(tab);
}
}
}
void t0() interrupt 1 using 1
{
}
void t1() interrupt 3 using 3//定时器T1中断服务程序
{
if(num==3999)
{
GATE=0;
TR0=0;
TR1=0;
aaa=TH0*256+TL0;
bbb=P1;
d=c/100.0;
c=0;
e=f;
f=1;
CLR=1;
CLR=0;
TH0=0x00;
TL0=0x00;
TH1=0x06;
TL1=0x06;
num=0;
GATE=1;
TR0=1;
TR1=1;
}
else
num++;
}