摘 要
本文主要介绍了数字频率计的设计与实现,详细讲述了频率的测量原理。本作品以STC89C52单片机为核心实现
对三角波、锯齿波、矩形波等波形频率测量的目的。测量结果显示在LCD显示屏上。由于52单片机所能处理的频率范
围有限,所以先用74ls161芯片实现外部10分频,扩大测量范围。本设计所支持的测量范围为1HZ-1MHZ,能够满足日
常生活与学习的需要。
关键词:52单片机;数字频率计;LCD1602;
第1章 绪 论
1.1 课题背景及研究的目的和意义
频率是一个基本的电子技术参量,它与很多的电参量、方案的设计、测量结果等密切相关,是电子技术中一个
十分重要的参量。所以,在很多频率测量的情况下就需要用到频率计。[3]数字频率计是一种基础的测量仪器,具有
高精度测量、测量方便、使用简单等优点,被用来测量三角波、矩形波、锯齿波等信号的频率,测量结果以十进制
的方式显示。在国际上有很多种数字频率计,它们能实现的功能很多、应用范围很广。如果按照仪表的功能进行分
类,可以分为通用仪表和专用仪表。对于通用计数器来说:通用计数器具有许多测量功能,用途非常广泛,它相当
于一个通用测量仪。它不仅可以测量频率、周期和多周期平均值等参数,还可以进行累积计数、计时等功能;如果
加载上相应的辅助装置,可以完成测量电流、功率和信号电阻等电参数的功能;加载上适当的传感器,还可进行长
度、重量、压力、温度、速度等非电量参量的测量。对于专用计数器来说:“专用计数器 ”意味着该计数器只用于
测量一个特定的参数。例如,频率计数器只能用来测量信号的频率,时间计数器只能够用来测量时间,这种类型的
计数器具有很高的精度和测量分辨率,通常可以实现纳秒级的时间测量序列,专用计数器具有特殊的功能,如反转
计数器、阈值计数器、差分计数器。
[3]伴随着电子技术的快速发展和单片机技术的提高,很多大规模和超大规模的集成电路开始广泛的使用单片机,很
大程度地提高了设计的性价比与可靠性。本设计就是制作一款以52单片机为核心芯片的的数字频率计,来满足日常
生活与学习的需要。
1.2 发展动态
20世纪50年代初数字技术的出现标志着仪器领域的一次重大革命,导致了一系列数字仪器的产生和发展,并大大提
高了模拟工具的准确性、分辨率和速度,为自动化仪器的发展奠定了基础。
20世纪60年代中期,由于计算机与计算机技术的引进,使得测量技术有了新的发展。将个别参量的测量转变为对全
系统的待测参量的检测,由单纯的接收、显示转变为控制、分析、处理、计算和显示,由单一仪表的测量向向整个
系统的测量转变。
常规化的数字频率计能够由常见的一些硬件电路组合而成。它的设计和调试都十分繁琐。另外,因为电子元器
件彼此的干扰,使得频率计的准确度受到了影响,而且因为它的体积较大。无法适应电子产品开发的需要。所以,
当前的频率计通常都是以多种软件、硬件和 LCD为基础结合起来进行设计。在电子设备的设计、开发以及其制造、
检测等过程中,[15]经常要进行频率测量与计数的设计,而不需购置昂贵的专用的频率测量与计数设备。数字式频
率计的发展越来越精确,越来越方便。在设计、研发、生产、测试众多电子设备产品时,经常要自行设计、制作测
试频率元件。有时,不需要去购买一些专用的频率测量或者是计数仪器。
第2章 系统模块设计
2.1 整体设计
本设计采用STC89C52单片机作为主控芯片,运用其定时/计数功能对输入到单片机的信号进行测量。采用
74ls161芯片组成的分频电路对信号进行分频来扩大测量量程。能够实现1HZ-1MHZ内信号频率的测量,把测量结果展
现在LCD显示屏上。具体流程见图 1。
图 1系统框图
2.2设计思路
本设计所要实现的功能是对信号的频率进行测量,所谓频率就是信号在单位时间内能够完成周期性变化的次
数。频率的测量通常有两种方法,它们分别是测频法与测周法。[2]测频法的依据是频率的定义式,即F=N/T,用计
数器对信号在门限时间T内进行计数,能够获得一数值N,根据上述定义式进行计算就能得出频率值。此方法适合于
比较高频率的信号的测量。[7]测周法就是测量被测信号的周期,再利用公式F=1/T计算所求频率。这个方法的缺点
在于如果被测信号的周期比较短,就会使测量精度大大下降。由于测周法具有这个缺点,所以本设计选择测频法。
运用单片机的定时/计数功能,对信号定时1s,计数器所测数值即为信号的频率。见图 2测频原理。
图 2测频原理
2.3系统模块
在本设计中,整个系统一共分为五个模块,它们分别是电源模块、放大整形模块、分频模块、主控模块与显示
模块。
放大整形模块:对待测信号进行放大,减小了微弱信号对测量结果的影响,运用整形模块将待测的三角波、锯
齿波等整形为方波,方便频率的测量。
分频模块: [8]由于单片机外接的晶振为12M,单片机的时钟周期为1/12us,确认一次跳变需要花两个机器周
期,即24个振荡周期,因此允许输入的外部脉冲的最高频率为振荡器频率的1/24,即最高频率为500KHz,所以如果
想扩大量程必须进行分频,我所采用的是74ls161芯片与一个与非门相连实现十分频的方法。
主控模块:采用STC89C52单片机为主控核心,外接12MHZ晶振提供时钟基准信号,运用单片机的定时/计数功
能,对信号定时1s,计数器所测数值即为信号的频率。
显示模块:显示模块是用来显示测得的频率的值,所使用的器件为LCD1602,LCD中LC是液晶的英文名称缩写,
而D是显示器的英文名称缩写,它是一种被动的显示器,液晶本身不发光。显示还可以选用数码管来进行显示,不过
它的缺点是实现比较困难,需要加一个驱动电路。使用LCD的优点是实现简单、数据清晰。
电源模块:运用DC电源连接器与开关组成电源模块,在实物中外加5v电压对整个电路进行供电,开关决定电路
的开断。
图 3系统模块图
图 3为系统模块图。
第三章 硬件设计
3.1放大整形模块
[15]为了增强频率计的适应范围、减小由信号特征带来的影响,设计了放大电路,放大电路是由电阻、耦合电容和
NPN型三极管组成的共射极放大电路。共射极放大电路是电子技术中一种常见的放大电路,它不仅可以放大电压也可
以放大电流,输入信号与输出信号反相,属于反相放大电路,常用作低频电压放大单元电路。
考虑到所测量的波形为三角波、锯齿波,设计了由74ls14组成的整形电路,把输入信号整形为方波。74ls14是
一种具有双列直插式封装的施密特触发器,且它具有六反相器,其中A端是输入端、Y端为输出端,一块芯片有六
路,输入信号与输出信号反相。其原理是,当输入信号的电压由低往高变化时,如果电压超过正向电压阈值,则输
出是低电平。当输入信号的电压由高往低变化时,如果输入电压要低于另一个阈值电压,则输出是高电平。高低电
压阈值之间的信号系统判定为无效信号,所以这就使输出信号变为了方波。74ls14与三极管组成的放大整形电路能
够有效的对信号进行放大整形,并且有稳定的输出与较强的驱动能力,满足设计的要求。
由图 5可知,信号由1A输入经由三个反相器由6Y输出,由于共射极放大电路为反相放大电路,输入信号是输出
信号反相信号,经由三次反相即可得到正相电路。通过proteus我们可以观察到信号分别经过三次反相的信号波形。
3.2分频模块
分频电路由74ls161与与非门构成。[6]74ls161是一个常用的四位可预置的二进制计数器,最大计数为16。所谓
同步计数器指的是被测量累计值,它的优点是很大程度地提高了计数器的工作频率,与之相对应的是异步计数器。
对于同步计数器来说,因为时钟脉冲会同时作用在各个触发器上,这就使异步触发器所具有的触发器逐级延迟问题
得到了解决。同时这也大大提高了计数器的工作频率、减小了各级触发器的输出相差值、解决了译码时的尖峰问
题。但是如果同步计数器的计数级数增加,就会加重计数脉冲的负载。所谓可预置是指74ls161可以与其他元器件组
合来实现十六进制以下任意进制的计数器,例如预置数为7,则芯片会从7开始计数,计数到16后清零,下一次计数
若没有新的预置则会从0开始计数,
由引脚图可知:
1、1脚为清零端,低电平有效,优先级最大,具有异步清零功能,即端口符合条件时马上清零,不需等下个上升沿
的到来。
2、2脚为时钟脉冲输入端,高电平有效。
3、3~6脚为输入(预置)端,可预置任意一个四位二进制数。
4、7、10脚为计数控制端,高电平有效,当两者同时处于高电平时,整个芯片计数,任一为低电平时计数器保持原
始数据。
5、9脚为并行启动控制端,低电平有效。
6、11~14脚为数据输出端。
7、15脚为进位输出端,高电平有效。
74ls161可以实现任意进制的计数器,本设计中应用74ls161与一与非门相连,实现十分频。具体原理为:因为芯片
是四位二进制,所以从0000开始计数,当计数到1010时,Q1与Q3引脚均输出高电平,则此时与非门输出一低电平,
传回清零端时,清零端作用计数器清零。从Q3端作为输出端的原因是:因为清零端具有异步清零功能,当Q3端为1
时,此时计数值为1000即已计够十个数。
并行启动控制端与计数控制端都处于高电平,芯片处于计数状态,信号由时钟信号输入端进入,当11与13脚都为高电平时,即计数到11时,与非门输出低电平,清零端清零,由于清零端具有异步清零功能,所以芯片实际实现的是十分频。
3.3主控模块
[1]STC89C52是一款8位的CMOS微控制器,它的优点是功耗比较低且有很高的性能,可以替代传统的STC51单片
机,与传统51单片机的引脚配置几乎相同。它比传统51单片机更优的一点是具有三个定时/计数器,[12]其中的定时
器2是一个16位的定时器,通过特殊功能寄存器(T2CON)中的选择控制位,可将其设置为定时器或计数器。它的输
入时钟源既能选择内部机器周期,也可以选择通过T2口输入的外部种种。通过控制特殊功能寄存器中的工作模式选
择位可将定时器2设置为三种工作模式,分别是捕获模式、自动重新装载(递增或递减计数)模式与波特率发生器模式
。所谓的自动重载就是在确定模式后自动计数,当计数计满时会在溢出位溢出,单片机自动重装预设好的初值,这
也就为软件编程带来了方便。这也是本设计中选择52单片机的原因。
3.3.1定时器2
在定时器2的16位自动重载模式中,其DCEN=0的流程如图 8所示。DCEN控制定时器的计数方式,当它等于0时,
定时器自动递增计数。此时TR2位控制定时器的运行,当TR=1时,定时器开始运行。EXEN2位控制位选择,当EXEN2=0
时,定时器开始递增计数,当计数计满时,溢出在TF2位,然后将RCAP2L与RCAP2H上的值重装在定时器2上;当
EXEN=1时,自动重载值受T2EX控制,通过跳变检测将信号传递到EXF2位,与TF2位共同控制定时器2的中断。其中
RCAP2L与RCAP2H的可以进行预置。
3.3.2计数器0与计数器1
图 9为计数器0的8位自动重装模式图,在本设计中T0与T1均作为计数器,且模式为自动重装模式。由图可知,
定时/计数器选择位控制单片机是选择内部机器周器还是外部引脚输入,GATE、外部中断0与TR0控制计数器0的中
断,因为已经选定T0为自动重装模式的计数器,且为内部中断,所以T0的中断只由TR0控制,当TR0=1时,中断开
始,开始进行计数,当计够时会溢出在TF0位上,而TH0自动填充初值。与之相同的是,T1的工作流程也是如此。
3.3.3最小系统
在本设计的单片机最小系统中含有单片机程序烧入部分、复位电路与时钟电路。时钟电路是维持单片机稳定、
有序工作的决定条件,所以要有稳定的时钟电路,在时钟电路中含有12MHZ
基准信号。复位电路是为了让单片机在开始工作前能够有一个初始状态,复位电路中含有开关按键,可通过它进行
复位。程序烧入采用串口烧入的方法,需与转换器相连,安装CH340驱动,然后进行程序的烧入。
图 10最小系统
如图 10可知:
P1端口:P1端口是一个8位的双向输入/输出口,其内带有上拉电阻。它的输出缓冲器可以带动4个TTL输入,此
外P1.0和P1.1口还是定时器的输入端口,P1.0口是定时器的外部输入,接收外部信号输入。P1.1是定时器的触发输
入口,可以控制定时器的输入。在此设计中,P1.0、P1.1、P1.2口分别与LCD显示屏的RS端、RW端、E端相连。
P0端口:P0口为8位漏极开路双向I/O口,每引脚可吸收8个TTL门电流。在本设计中与显示屏的数据输入端相
连。
RST:复位信号的输入端。若振荡器要进行复位,则需要保持RST口在2个机器周期内一直为高电平。
XTAL2:反向振荡器的输出端。
XTAL1:内部时钟电路的输入端、反向振荡器与放大器的输入端。
T0/1端:定时/计数器0/1的外部输入端。在本设计中采用两个计数器,即T0、T1均为计数器,T0与整形后的输
出端相连,T1与分频后的输出端相连。
RXD与TXD端分别为串行口的输入与输出端,用作程序烧入使用。
3.4显示模块
LCD1602是一种常见的字符型液晶显示屏,在工程与生活中被广泛应用。其中LC是指液晶、D是指显示屏,1602
是指显示器的显示容量是16*2个字符,即一共有两行,每行16个字符。它的工作电压为4.5v-5.5v。
图 11显示模块
如图 11可知:
1、VO端负责控制液晶显示器的对比度调整,当其接正向电源时对比度最低,当其接地线时对比度最高,为了避免
“鬼影效应”特加一电位器来调节对比度。
2、RS端负责控制显示器中寄存器的选择,当其处于高电平时显示器选择数据寄存器,而当其处于低电平时显示器则
选择指令寄存器。此外,在本设计中RS端与52单片机的P1.0口相连。
3、R/W端负责控制显示进行读/写信号,当其处于高电平时显示器进行读操作,而当其处于低电平时显示器进行写操
作。
4、E端控制信号的输入与输出,当使能端由高电平向低电平跳变时,液晶模块执行命令。
5、DB0~DB7端为双向8位数据线。在其与单片机的连线上加一排阻是为了保护液晶显示屏,避免电压突变对液晶显示
屏的影响。
其工作原理我们知道, LCD是由M×N个显示单元组成的。假设LCD屏幕有64行,每行128列,每8列对应1字节的8
位,即每行16字节,共16×8=128点。当在显示屏上按下一个字符时,就会出现与之相对应的图像信息和数据,这些
信息可以被存储到存储器中。而这些数据又可通过数据线或外接电路传送给其他设备。显示器上64×16显示单元对
应1024字节的显示RAM,每个字节的显示内容对应显示器上相应位置的亮暗。
3.4整体电路
图 12整体电路
整体过程如下:
1、信号由信号端输入。
2、经由共射极放大电路放大
3、输出信号传入74ls14,进行三次反相整形,输出为正相方波。
4、输入信号有时钟输入端输入,ET、EP端均为高电平,74ls161处于正常计数模式,与与非门相连构成了十分频
器。
5、T0与T1作为计数器,T0与整形信号ain端相连,T1与分频信号in端相连,给单片机设置一阈值,当信号频率未超
过阈时,显示ain端信号频率。反之,显示分频后信号频率。
6、测完的信号频率通过显示器的数据输入端输入显示器内,并显示在显示屏上。
第四章 软件设计
4.1定时/计数器初始化
本设计中共使用到三个定时/计数器,T0、T1作为计数器进行计数,T2作为定时器进行1秒钟的定时,因为单片机的
最大定时为65ms所以需要用通过编程来实现1秒钟的定时,本设计中采用中断50ms共中断20次的方法。欲对定时/计
数器进行设计,需要了解方式控制寄存器(TMOD)。如表 1
位 7 6 5 4 3 2 1 0
字节地址 GATE C/T M1 M0 GATE C/T M1 M0
表 1控制寄存器
GATE:控制计数/定时器的启动,当GATE=0时,由TRX位来控制定时计数器的启动或停止,当GATE=1时,定时/计
数器的启动或停止则由TRX位与外部输入共同控制。
C/T:控制定时/计数器的模式选择,当C/T=0,单片机选择定时模式,当C/T=1时,单片机选择计数模式。
M0与M1为定时计数器的工作位,本设计中两个计数器的工作模式均为自动重载,所以M1=1,M0=0。
代码中TMOD=0x66是指对定时/计数器进行设置,化为二进制可知TMOD=00100110,即T1与T0都为计数器,且工作
方式为8为自动重载模式,
部分代码如下:
void timer_init(void) //定时/计数器初始化函数
{
TMOD=0x66; // 计数器均为8位自动重载模式,所以TMOD=0110 0110
TH0=0; //计数器0设初值为0
TL0=0;
TR0=1; //TR0:计数器0运行控制位。开始计数
ET0=1; //ET0:计数器0溢出中断允许位。允许中断
TH1=0; //计数器1设置初值为0
TL1=0;
TR1=1; //开始计数
ET1=1; //开中断
RCAP2H=(65536-50000)/256; //给RCAP2H与RCP2L设置初值,
RCAP2L=(65536-50000)%256; //设置定时时间为50ms
TH2=RCAP2H; //给定时器2设置初始值
TL2=RCAP2L;
ET2=1; //使定时器2开始中断
TR2=1; //使定时器2开始计时
EA=1; //打开总中断
}
当定时器2选择16位的工作模式1时,由计算可知16位二进制的范围在0到2^16即65535内,此时定时器2开始向上
计数,一个数一个数的向上加。在给定时器2赋值前要先设置它的定时初始值,若它每计数50000次就溢出一次,产
生一次中断,那么定时器2的初始值就是65535-50000+1=15536,现在将计算得到的15536这个初始值定义到TH2和TL2
上就行了。又因为52单片机是8位的单片机,每次运算只能够处理8位数据,所以就要将初始值分成高8位与低8位,
然后分别赋值给TH2和TL2,代码中(65536-50000)/256就是将初始值的高八位取出,而(65536-50000)%256就是
将初始值的低八位取出。
4.2定时/计数器中断
本设计中采用定时器2进行定时,void timer2(void) interrupt 5为定时器2的中断函数,采用的是16为自动重
装模式。先设置中断时间为50ms,当中断够20次时即为定时1s,此时计时清零、关闭中断,然后开始计数。如果测
得频率超过2000HZ那么输出计数器0的值即为未分频信号的频率,如若测得频率超过2000HZ那么输出经过分频后的信
号的频率,此频率还需乘上分频数。最后对计数器清零,打开总中断,为进行下一轮计数做准备。
void timer2(void) interrupt 5 //定时器2的中断函数
{
time++; //
TF2=0; // TF为定时器2的中断标志位,不能清零,需要在软件部分实施
if (time20) //如果中断20次,即为定时1s
{
time=0; //
EA=0; // 关闭中断
fre=(long)count1256+TL1; //输出频率fre
FLAG = 0; //FLAG为分频标志判断位
if(fre<2000) //如果频率小于2000HZ那么输出未分频信号的频率
{ //分频标志位为1
fre = (long)count256+TL0;
FLAG = 1;
}
if(!FLAG) 如果FLAG不等于1,即信号频率大于2000HZ
{
fre = fre 10;// 输出频率等于分频后信号频率乘分频数
}
TL0=0; // 计数器0清零
TH0=0;
TL1=0; //计数器1清零
TH1=0;
count=0; //
count1=0;
EA=1; // 开启中断
}
}
值得一提的是count代表着 计数器在1S内 TL1重装初值的次数。而这个次数也是计数器1在1S内的中断次数。代
码中fre=(long)count1256+TL1代表着计数器在计时1S内捕获到输入脉冲的准确数量,但因为fre为长整形变量,所
以在计算前需要把count转换为长整形。
4.3显示函数
LCD1602的显示原理可以简单的理解为:在显示屏上有32个“空格”,每个“空格”可显示一个字符,这也就使
显示原理变为单片机如何使显示器在指定的位置显示指定的内容的问题。
液晶显示器的函数初始化是在显示函数编写之前完成的,初始化的内容有:“162显示格式”,“57矩阵”,“显示
器打开,光标关闭”,“增量不移位”,“清晰屏幕显示”等指令。具体代码如下:
Void LCD_init(void)
{
LCD_write_comd(0x38);
LCD_write_comd(0x0c);
LCD_write_comd(0x06);
LCD_write_comd(0x01);
delay_n40us(100);
}
对于显示位置问题需要用到void lcd1602_Write_Cmd(unsigned char Cmd),它为写入命令函数,需要注意的是
写入命令函数LCD_RS=0,而写入数据函数LCD_RS=1。写命令给显示器的字节由表 2可知
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
表 2液晶显示字节(1602)
上面每一格对应显示器上的空格,设置坐标的命令字节最高位为1,在哪个位置显示就写入哪个地址,例如第一
行第二列为0X80+0X01=0X81。代码如下
void LCD_disp_char(unsigned char x,unsigned char y,unsigned char dat)// 在屏幕某位置
{ 显示某个数
unsigned char address;
if(y1)
address=0x80+x; // 显示在第一行时的值
else
address=0xc0+x; //显示在第二行时的值
LCD_write_comd(address); // 输入地址
LCD_write_data(dat); // 输入数据
}
对于显示内容问题则需要用到void lcd1602_Write_Data(unsigned char Data),它是写入数据函数,当写入数
据时需使RS=1。写入数据需要参考液晶标准字符库,LCD1602内含有192个常见字符的编码,它们存储在中文字符库
中,其中就含有标准的ASCII码。另外LCD1602还提供给用户一个用来存储自定义的字符编码的空间,这个存储空间
命名为CGRAM,它的存储量为8个字节。液晶显示器的显示过程应该可以理解为:首先选择CGROM存储器或CGRAM存储
器用于选择字符编码,然后通过上述存储器的存储地址将待显示字符编码传送到动态随机存储器,从此找到存储单
元,并读取上述存储器内部存储的字模编码到动态随机存储器中。在这种情况下,DMOS管便开始工作并产生一个与该
字模式相关的电压值。如果把它作为输入信号,那么,由数据驱动电路输出相应的脉冲波形。最终实现DDRAM存储的
字模编码在屏幕相应位置的显示,字符库与代码如下
void LCD_disp_num(unsigned char x,unsigned char y,unsigned char dat)//显示字符
{
unsigned char address;
if(y==1)
address=0x80+x; //显示在第一行时的值
else
address=0xc0+x; //显示在第二行时的值
LCD_write_comd(address); //输入地址
LCD_write_data(dat+48); //输入数据
}
图 13液晶显示屏字符库
最后,需要用到void dis_num(void)函数,定义一个数组character[10] ,将中的8位数字分别赋值给数组
character[0]到character[7],character[8]与character[9]则固定用于显示“Hz”。我们所定义的数组
character_1[i]的作用是把想要显示的字符显示在显示屏上,character_1[0]到 character_1[3]用于在显示器的第
一行显示字符“fre=”,所以后面的i就大于3,当后续测量的信号频率出来时,就从i=4处开始显示。
4.4主函数
void main()
{
unsigned char i;//定义一个变量i
LCD_init();
timer_init(); // 定时/计数器初始化
for(i = 0;i<4;i++)
{
LCD_disp_char(i+0,1,character_1[i]);//在LCD上把fre显示出来
}
while(1)
{
dis_num(); //进行无限循环
delay_1s();
}
}
在主函数中先将之前定义的函数进行初始化,然后加入一个while循环,让程序持续的工作。代码中
LCD_disp_char(i+0,1,character_1[i])意味着要将输入信号的频率变化通过fre值的变化在液晶显示屏上显示出
来。若此时无信号输入,那么此时液晶显示屏上将会固定显示fre=HZ。
附录
#include <reg52.h>
unsigned long int fre;
unsigned char time;
unsigned int count;
unsigned int count1;
sbit LCD_RS=P1^0; //片选信号
sbit LCD_RW=P1^1; //读写信号
sbit LCD_E=P1^2; //使能信号
#define LCD_DB P0 //数据信号
unsigned char character[10]={0};//在屏幕上显示的字符串
unsigned char character_1[]={"fre= Hz"};
unsigned char FLAG = 0; //是否分频选择标志
void LCD_init(void);//初始化函数
void LCD_write_comd(unsigned char comd);//写指令函数
void LCD_write_data(unsigned char dat);//写数据函数
void LCD_disp_char(unsigned char x,unsigned char y,unsigned char dat);//在某个屏幕位置上显示一个字符,
X(0-15),y(1-2)
void delay_n40us(unsigned int n);//延时函数
19
void timer_init(); //中断初始化函数
//-----------------------------延时函数---------------------------
void delay_n40us(unsigned int n) //延时函数
{
unsigned int i;
unsigned char j;
for(i=n;i>0;i--)
for(j=0;j<2;j++);
}
void delay_1s()
{
unsigned int i,j;
for(i = 0;i<100;i++)
for(j = 0;j<1000;j++);
}
//---------------------lcd1602液晶显示函数--------------------
void LCD_init(void) //液晶初始化函数
{
LCD_write_comd(0x38);//设置8位格式,2行,5x7
LCD_write_comd(0x0c);//整体显示,关光标,不闪烁
LCD_write_comd(0x06);//设定输入方式,增量不移位
LCD_write_comd(0x01);//清除屏幕显示
delay_n40us(100);//清屏延时
}
void LCD_write_command(unsigned char dat) //写命令函数
{
LCD_DB=dat;
LCD_RS=0;//指令
LCD_RW=0;//写入
LCD_E=1; //使能
LCD_E=0;
delay_n40us(1);//写命令延时
}
void LCD_write_data(unsigned char dat) //写数据函数
{
LCD_DB=dat;
LCD_RS=1;//数据
LCD_RW=0;//写入
LCD_E=1;//使能
LCD_E=0;
delay_n40us(1); //写数据延时
}
void LCD_disp_char(unsigned char x,unsigned char y,unsigned char dat)//显示一个字符
{
unsigned char address;
if(y==1)
address=0x80+x; //显示在第一排的时候的x的地址
20
else
address=0xc0+x; //显示在第二排的时候的x的地址
LCD_write_comd(address); //输入地址
LCD_write_data(dat); //输入数据
}
void LCD_disp_num(unsigned char x,unsigned char y,unsigned char dat)//显示一个数字
{
unsigned char address;
if(y==1)
address=0x80+x; //显示在第一排的时候的x的地址
else
address=0xc0+x; //显示在第二排的时候的x的地址
LCD_write_comd(address); //输入地址
LCD_write_data(dat+48); //输入数据
}
void dis_num(void)
{
unsigned char i=0,j=0,k=0;
LCD_write_comd(0x01);//清除屏幕显示
character[0] = fre/10000000;
character[1] = fre/1000000%10;
character[2] = fre/100000%10;
character[3] = fre/10000%10;
character[4] = fre/1000%10;
character[5] = fre/100%10;
character[6] = fre/10%10;
character[7] = fre%10;
character[8] = 'H';
character[9] = 'z';
for(i = 0;i<4;i++) //显示“fre=”
{
LCD_disp_char(i+0,1,character_1[i]);
}
for(i = 0;i<10;i++) //判断第一个不为0的数
{
if(character[i]!=0)
break;
}
k = 8-i;
for(j = 0;j<k;j++) //显示所有的数字
{
LCD_disp_num(4+j,1,character[i++]);
}
for(i = 5;i<7;i++) //显示“Hz”
{
LCD_disp_char(j+4,1,character_1[i]);
j++;
21
}
}
//----------------主函数--------------------
void main()
{
unsigned char i;
LCD_init();
timer_init(); //定时/计数器初始化
for(i = 0;i<4;i++)
{
LCD_disp_char(i+0,1,character_1[i]);
}
while(1)
{
dis_num(); //显示
delay_1s();
}
}
//-------------------定时/计数器初始化--------------
void timer_init(void) //定时/计数器初始化
{
TMOD=0x66; //计数器0和计数器1工作工作方式2,自动重装初值
TH0=0; //计数器初值为0
TL0=0;
TR0=1; //计数器开始计数
ET0=1; //打开计数器0中断
TH1=0; //计数器初值为0
TL1=0;
TR1=1; //计数器开始计数
ET1=1; //打开计数器1中断
RCAP2H=(65536-50000)/256; //在程序初始化的时候给RCAP2L和RCAP2H赋值,
RCAP2L=(65536-50000)%256; //TH2和TL2将会在中断产生时自动使TH2=RCAP2H,TL2=RCAP2L。
TH2=RCAP2H; //12M晶振下每次中断50ms(1s=1000ms=50ms×20)
TL2=RCAP2L;
ET2=1; //打开定时器2中断
TR2=1; //定时器2开始计时
EA=1; //开总中断
}
//------------------中断函数----------------------
void timer2(void) interrupt 5 //定时器2中断(50ms)
{
time++;
TF2=0; //定时器2的中断标志位TF2不能够由硬件清零,所以要在中断服务程序中将其清零
if (time==20) //定时1s时间到
{
time=0; //计时清0
EA=0; //关中断
22
fre=(long)count1*256+TL1; //count*256强制转换成long型,否则将不产生进位~先判断分频后(计数器1)
FLAG = 0;
if(fre<2000)//如果不到20KHz则读取分频前(计数器0)频率(20K÷10=2000)
{
fre = (long)count*256+TL0;
FLAG = 1;
}
if(!FLAG)
{
fre = fre *10;//10分频
}
TL0=0; //清零计数器0计数
TH0=0;
TL1=0;
TH1=0;
count=0; //清零计数器0计数
count1=0;
EA=1; //开中断
}
}
//----------------------------------------------------------------
void timer0(void) interrupt 1 //计数器0中断(10分频前)
{
count++;
}
//----------------------------------------------------------------
void timer1(void) interrupt 3 //计数器1中断(10分频后)
{
count1++;
}
第5章 系统调试
5.1仿真调试
5.1.1软件概述
本设计中仿真设计所使用的软件为proteus与keil,它们分别用来搭建硬件电路与代码编写。
Proteus是一个在日常学习被广泛使用的电路设计与仿真测试软件,它操作简单,常用的电路元器件在元件库中
都可以找到,但是在本设计中由于proteus中并没有STC芯片,所以我们选择用AT89C52来代替本设计中的52单片机,
其引脚配置、具体功能与52单片机几乎相同。
Keil是美国Keil微软公司出品的一种C语言软件开发系统,它可以对51、52等单片机进行程序编写。该软件使用
了与传统C语言相近的语法,相对于汇编语言来说, C语言简单易用,工作效率和时间都得到了极大的提升,同时,
还可以将汇编嵌入到软件的各个重要部分,使得编程的工作效率更接近于汇编。此软件具有一个完整的开发方案,
其中包括链接器、C编译器、宏汇编、库管理与一个功能强大的仿真调试器等
电路仿真需要用到两款软件联合调试,所谓联合调试是将keil软件中编写的C语言程序输出为HEX文件然后输入
到proteus的单片机中。需要注意的是,与proteus相同,keil中有STC芯片,所以可以直接使用。
5.1.2硬件仿真
本设计的测量量程为1HZ-1MHZ频率的测量,下面将从测量量程内选择几个频率进行测量,测量结果如下图。
图 14为900kHZ三角波频率的测量,此时信号频率大于2000HZ,计数器1在工作。如图所示,测得结果为
900168HZ,误差为1.87%,在可接受范围内。
图 15为900HZ三角波频率的测量,此时信号频率小于2000HZ,计数器0在工作。
图 14仿真图1
图 15仿真图2
5.1.3误差分析
原始频率 1HZ 20HZ 300HZ 4KHZ 50KHZ 600KHZ
测得频率 1HZ 20HZ 300HZ 4KHZ 49.9KHZ 600.1KZ
表 3测量结果
根据表 3可以看出,软件仿真测得频率与信号的原始频率相差较小,所以可以知道此设计的误差较小。但是在
实物调试中,由于元器件本身的误差、手工焊接时产生的误差、由于环境等因素对电路造成的干扰等,可能会对测
量结果产生一定的影响,与仿真时的结果有一定的出入。总体而言,由本次实验仿真可知,此设计电路是符合要求
的。
5.2实物调试
制作实物所用的软件为立创EDA,此软件相对于AD18来说,操作更加容易,设计更加方便。
立创EDA是一国产板级EDA设计软件。EDA指的是通过计算机的辅助完成电路原理图、印刷电路板文件等的绘制、
制作、仿真设计。它分为标准版与专业版两个版本,立创EDA标准版基于浏览器运行,轻量级,高效率,无需下载,
打开网站就能开始设计。云端在线设计,文件云端存储,摆脱硬件储存束缚。Windows、Mac、Linux 多设备,跨平
台支持,设计进度自动同步。兼容常用PCB设计软件,支持文件导入导出。支持常用元件的在线仿真,一键将原理图
布局传递到PCB,一键导入图片LOGO到PCB。
在PCB设计中元器件的摆放位置与整体布局非常重要,其中PCB中元器件布局的基本原则为:
1、尽可能缩短高频元器件之间的连接,争取减少高频元件的分布参数及电磁干扰问题。
2、容易受到干扰问题的电子元器件放置位置不能太近,输入和输出端应尽量远离。
3、[11]部分电子元器件或导线有较高的电位差,应增大它们之间的距离,避免短路问题,高电压的电子元器件
应放在难以触及的地方。
4、热敏元器件应该尽量远离发热元件,避免对实验结果造成干扰。
5、常用到的开关,应放置在手边容易接触到的东西。
对于地线的处理方法是可以进行铺铜,需要注意的是,顶层与底层皆要铺铜,图 16与图 17分别为PCB图与实物
图。
图 16PCB图
对于实物的组装需要注意的是焊接的技巧,如下焊接的步骤:
1、焊接的准备阶段:把要焊接的元件摆放好位置,焊锡丝与洛铁头一同靠近要焊接的位置,做好焊接的准备,需要
注意保持烙铁头干净以便沾上焊锡。
2、对所要焊接的器件进行加热:我们用电洛铁对元器件加热的时候,要注意电洛铁的尖端应该接触耐热的焊件而不
要触碰到外围的电路板。
3、对焊锡丝进行熔化:当要对焊锡进行熔化时,先把焊锡丝送到洛铁头上,因为此时的洛铁头达到了焊锡的熔化温
度,所以熔化的焊锡会沿着洛铁头流到焊盘上,一直送锡,当熔化的焊锡包裹住焊盘与元器件的引脚时停止。
4、把焊锡丝与电洛铁拿开:此时,熔化的焊锡已经包裹住了焊盘与元器件引脚,整体形状像一个椎体,先后移开焊
锡丝和电洛铁。移开的方向均为沿着元器件引脚的方向向上,这是为了焊接的更加美观。
图 17实物图
图 17为信号输入时的显示界面。此时并无外部信号输入,所以只显示初始界面。
结 论
本次设计顺利实现了运用STC89C52单片机的定时/计数功能对三角波、矩形波、锯齿波等波形的频率的测量,并
将测量结果显示在了LCD显示屏上。本设计的两大亮点分别是在设计方面运用了52单片机定时器2的16位自动重装功
能、在实物制作方面运用了立创EDA这一软件。自动重装功能使得软件设计变得更加简单,而立创EDA则在简化设计
操作的同时让我学会了一个新软件的运用。
通过这次毕业设计让我获益良多。首先,学到一些关于单片机、LCD与PCB设计的知识,提高了我的C语言编程能
力。其次,学会了一些软件的应用,例如proteus、keil、立创EDA等。也让我学会了如何去查找资料、阅读文献,
在庞杂的信息中选择自己应用的部分,这对我以后的生活与学习很有帮助。在遇到问题时,学会了独立思考,有不
确定的地方,会及时向老师、同学等寻求帮助。