基于89C52单片机的数字频率计的设计(DOC)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
单片机课程设计报告
题目:基于89C52单片机的数字频率计
院(系):信息与通信学院
专业:电子信息工程
学生姓名: ------ 学号: ---------- 指导教师: -----
2012 年 11 月 15 日
摘要
该系统以STC89S51单片机为核心, 应用单片机的运算和控制功能并采用LCD 显示器实时地将所测频率显示出来, 通过测量结果对比,分析了测量误差的来源,提出了减小误差应采取的措施。
频率计具有电路结构简单、成本低、测量方便、精度较高等特点,适合测量低频信号。
关键词:单片机,频率测量
Abstract
The paper introduces one cymometer system Based on singlechip which applys the singlechip`s function of operation and control and displays the result by LCD. By comparing results, the source of measurement error is analysed, the measures are proposed for reducing errors. T he frequency meter has characteristics of simple circuit, low cost, easy measurement and high precision, it fits for measuring low frequency signals.
Key words : Singlechip,frequency- measure
引言 (1)
1 课程设计概述 (1)
1.1 课程设计任务及要求 (1)
1.2 主要仪器 (1)
1.3 数字频率计概述 (1)
1.4 测频基本设计原理 (2)
2 方案论证 (2)
2.1 总体方案 (2)
2.2 测频方案选择 (3)
3硬件设计 (3)
3.1系统功能描述 (3)
3.2硬件电路设计框架 (3)
3.3单片机部分 (4)
3.4 放大整形部分 (4)
3.5分频部分 (5)
3.6 LCD显示和键盘部分 (6)
4 软件设计 (6)
4.1 主程序流程图设计 (6)
4.2 子程序流程图设计 (7)
4.2.1 显示程序 (7)
4.2.2频率测量程序框图 (8)
4.2.3 中断服务流程图 (8)
5 系统调试 (9)
5.1显示调试 (9)
5.2键盘调试 (9)
5.3前置放大整形调试 (9)
5.4软件调试 (9)
6结果分析与结论 (10)
7总结 (10)
参考文献 (11)
附录 (12)
引言:
在工业生产、仪器仪表行业及实验教学中,经常会遇到频率的测量,我们经常使用的及目前市场上所售的频率测量装置,大多数是采用小规模集成电路及分离元件组成。
在现代电子学的各个领域,要求频率计精度高且能够直接读出频率值。
频率计由89S52单片机控制电路、信号处理电路、键盘电路以及测量数据的显示电路还有系统软件所构成的,在信号处理电路当中包含了待测信号放大、限幅、波形变换、波形整形以及分频电路。
信号的予处理电路当中的放大器所实现的是对待测信号的一个放大的功能,能够降低对待测信号的幅度的一个要求,波形的变换和整形电路实现将正弦波样的一个正负交替的号波形转换成为能够被单片机所接受的一个信号,分频电路所用于扩展的单片机的频率测量范围以及提高测量精度,并且通过实现单片机频率测量以及周期测量使用统一的一个输入的信号。
系统的软件包括有测量初始化的模块、显示的模块以及信号频率测量的模块等等。
1 课程设计概述
1.1 课程设计任务及要求
题目:数字频率计
要求:LCD显示,测量范围0~100KHZ,带前置放大、整形电路,可测周期信号的频率。
1.2 主要仪器设备
函数信号发生器1台
示波器1台
直流稳压电源(0~30V)1台
数字万用表1块
PC机1台
1.3数字频率计概述
数字频率计是计算机、通讯设备、音频视频等科研生产领域不可缺少的测量仪器。
它是一种用十进制数字显示被测信号频率的数字测量仪器。
它的基本功能是测量正弦信号,方波信号及其他各种单位时间内变化的物理量。
在进行模拟、数字电路的设计、安装、调试过程中,由于其使用十进制数显示,测量迅速,精确度高,显示直观,经常要用到频率计。
1.4 测频基本设计原理
所谓“频率”,就是周期性信号在单位时间(1s )内变化的次数。
若在一定时间间隔T 内测得这个周期性信号的重复变化次数N ,则其频率可表示为f=N/T (右图1-1所示)。
其中脉冲形成电路的作用是将被测信号变成脉冲信号,其重复频率等于被测频率f x 。
时间基准信号发生器
提供标准的时间脉冲信号,若其周期为1s ,则门控电路的 图1-1
输出信号持续时间亦准确地等于1s 。
闸门电路由标准秒信号进行控制,当秒信号来到时,闸门开通,被测脉冲信号通过闸门送到计数译码显示电路。
秒信号结束时闸门关闭,计数器停止计数。
由于计数器计得的脉冲数N 是在1秒时间内的累计数,所以被测频率fx=NHz 。
2 方案论证
2.1 总体方案
本次设计包含硬件设计与软件设计两部分,根据设计任务要求,采用AT89S52单片机,配置时钟电路,复位电路构成单片机最小系统,配置前置放大电路,人机对话通道中的键盘,L CD 显示,从而构成设计要求的单片机应用测频系统,其结构框图如下图2-1所示:
图2-1结构框图
单片机
前置放大整
形
复位电
时钟电路
键盘电路
LCD 显示电路
2.2 测频方案选择
方案一:直接测频法。
直接测频法是把被测频率信号经脉冲形成电路后加到闸门的一个输入端, 只有在闸门开通时间T ( 以秒计) 内, 被计数的脉冲被送到十进制计数器进行计数。
设计数器的值为N , 由频率定义式可以计算得到被测信号频率为: f = N / T 。
方案二:高精度恒误差测频法。
通过对传统测量方法的研究, 结合高精度恒误差测量原理, 设计一种测量精度与被测频率无关的硬件测频电路。
本方法立足于快速的宽位数高精度浮点数字运算。
方案三:倍频法。
直接测频法在高频段有着很高的精度。
可以把频率测量范围分成多个频段, 使用倍频技术, 根据频段设置倍频系数将经整形的低频信号进行倍频后再进行测量, 高频段则进行直接测量。
从编程难易及单片机资源利用情况和测量误差角度考虑,选择方案一,尽管在测量低频段时的相对测量误差较大。
但是可以通过增大 T 来提高测量精度。
3 硬件设计
3.1系统功能描述
本次课程设计主要完成功能有:
(1)长按设置键可选择测量频率或者周期。
(2)短按则是选择设置闸门时间(0.05s—10s)。
(3)测量频率范围:0.1Hz—4MHz。
3.2硬件电路设计框架
根据设计要求,数字频率计整个系统硬件框架图如下3-1
本系统实用LM318对待测信号进行放大,在用稳压二极管1N4733对信号进行限幅,然后经74LS14反向器整形得到TTL信号,送74LS161分频,最后送单片机P3^5内部计数器进行计数,单片机处理数据后送LCD显示。
3.3单片机部分
P0口经上拉后做LCD数据接口
P2.1~P2.3作为LCD控制端口
P2.4-P2.5作为分频选择端口
P1.6-P1.7作为键盘设置端口
P3.5作为被测信号输入端口
图3-2
3.4 放大整形部分
待测信号经过第一级放大后,进入第二级放大限幅电路,再由7414组成的施密特触发器整形,得到标准方波信号。
LM318是高数运放,工作电压±5--±20V,输入带宽15MHZ,足够处理高频信号。
放大倍数:n=RL2/RL1(RL2用50K,RL1用10K)。
限幅原理:限幅电路的稳压管跨接在集成运放的输出端和反相输入端之间。
假设稳压管截止,则集成运放必然工作在开环状态,输出电压不是+U OM,就是-U OM。
这样,必将导致稳压管击穿而工作在稳压状态,D Z构成负反馈通路,使反相输入端为“虚地”,限流电阻上的电流i R等于稳压管的电流i Z,输出电压u O=±U Z。
图3-3
3.5分频部分
74HC161与74ls161功能兼容,是常用的四位二进制可预置的同步加法计数器,他可以灵活的运用在各种数字电路,以及单片机系统中实现分频器等很多重要的功能.
其管脚图如图3-4所示:
图3-4 74HC161 图3-5 74HC153管脚图
74HC153是一个双4选1数据选择器,其管脚图如图3-5所示:
74LS161对整形后的防波信号进行分频,Q1为四分频输出,Q3为16分频输出。
未经分频、经过四分频和经过16分频的三路信号作为74LS153的一个4选1数据选择器低三位输入,由单片机控制选择分频数,然后再送单片机内部计数器T1(如图3-6).
图3-6
3.6 LCD显示和键盘部分
LCD显示,通过调节变阻器调节LCD背光亮度,八位数据口接单片机P0口,读写控制端接P2.0-P2.2口。
三个按键中,设置键接P3.2单片机按外部中断0接口,当按键按下后,置P3.2口低电平,单片机中断。
S1、S2为频率/周期、闸门时间加/减选择按键(如图3-7)。
图3-7
4 软件设计
4.1 主程序流程图设计
本次程序设计采用的是C语言程序设计,其设计流程图4-1所示:
图4-1主程序流程图4.2 子程序流程图设计
4.2.1 显示程序
LCD显示程序设计流程如图4-2
图4-2显示程序流程图
4.2.2频率测量程序框图
频率测量程序的整体架构如图4-3所示:
图4-3频率测量框架图
4.2.3 中断服务流程图
图4-4INT0中断流程图
5 系统调试
5.1显示调试
调节变阻器改变LCD背光亮度,直到亮度合适且显示正常。
去掉前置放大整形部分,送数据LCD显示看是否正常显示,能够正常显示,说明显示电路正常工作。
5.2键盘调试
在显示正常情况下调试键盘,按设置键,看是否能正常进入中断,若能,进入中断后,按下频率/周期、闸门时间设置键,看是否能正常设置。
在调试过程中遇到能够进入中断,但是不能进行设置,经检查电路、程序后发现两个选择按键之间短路,当其中一个按键按下,相当于两个同时按下,只是单片机CPU不能正常识别。
消除短路后电路正常工作了。
5.3前置放大整形调试
去掉LCD、单片机调试放大器是否正常工作。
给定输入信号,用示波器分别测量各级输入输出信号,看是否和放大相应倍数,限幅在指定范围。
调试结果:第一级放大五倍与符合预想要求。
第二级限幅在±6.2V,与理论值±5.1伏有所出入,但仍然满足后面电路要求。
5.4软件调试
单片机软件调试主要是调试本次课程设计的主程序。
其调试过程如下:
(1)新建一个工程。
单击Project菜单,在弹出的下拉菜单中选New Project。
(2)然后选择你要保存的路径,输入工程文件的名字,保存。
(3)新建一个工程后弹出一个对话框,根据你的需要选择你使用的单片机型号。
然后点击确定。
(4)单击“File”,选择“New”,新建文件并在其中输入程序代码,然后保存为c
语言文件。
(5)回到编辑界面后,单击“Target 1”前面的“+”号,然后在“Source Group 1”单击右键选择“Add File To Group ‘Source Group 1’”,选中Test.c文件。
(6)单击“Project”菜单,选中“Built Target”,完成程序的编译,在工程文件夹中找到*.hex文件即可
6 结果分析与结论
测量结果对比分析:
结论:整个系统完成测试后,性能稳定,由于所用函数发生器输出最大频率为10KHz,没有测试更高频率;从测量结果对比分析可知本次设计的频率计基本满足课程设计要,并且功能有所扩展。
7 总结
在整个课程设计的过程中每一步都是自己亲自做过的,遇到的问题也非常多,在经过遇到问题,思索问题到解决问题的过程中,收获是最多的。
以往没有注意到的问题,都在这一次的课程设计中得以体现,这培养了我的细心,耐心和专心。
我觉得能够在这次的课程设计中学到很多的东西,以往不注意的细节,在这一次中是必须让自己去注意的。
对实际经验的不足在设计过程中出现了不少的问题,得到了老师的耐心指导,在此表示感谢。
参考文献
[1] 张义和 . 例说51单片机 .人民邮电出版社
[2] 马淑华. 王凤文等著 .单片机原理与接口技术. 北京邮电大学出版社
[3] 华成英 .童诗白著. 模拟电子技术基础 . 高等教育出版社
[4] 阎石著.数字电子技术技术基础 . 高等教育出版社
[5] 谭浩强. C语言程序设计 . 清华大学出版社
[6] 陈尚松等.电子测量与仪器(第二版).电子工业出版社
附录:
PCB图:
程序清单:
#include <AT89x52.h>
#include <stdio.h>
#include <math.h>
#include <intrins.h>
float f; //频率
float p; //周期
float sj; //闸门时间
char idata buff[20];
char flag=0; //频率\周期选择标志位
char xs=0; //设置闸门时间结束后是否显示结果的标志位
unsigned char m=0,n=0,yichu=0,fenpin; //m定时中断次数 n计数中断次数 yichu判断是定时器还是计数器溢出
#define Key_Set P1
#define K1 0xbf //1011_1111 P16
#define K2 0x7f //0111_1111 P17
#define NO_Set 0xff
#define Freq 0
#define Peri 1
sbit B153=P2^4;
sbit A153=P2^3;
sbit P17=P1^7;
sbit P16=P1^6;
sbit P35=P3^5;
sbit Set=P3^2;
unsigned char LCD_Wait(void);
void LCD_Write(bit style, unsigned char input);
void LCD_SetDisplay(unsigned char DisplayMode);
void LCD_SetInput(unsigned char InputMode);
void LCD_Initial();
void GotoXY(unsigned char x, unsigned char y);
void Print(unsigned char *str);
void C52_Initial();
void Delay(unsigned int t);
void display(float f);
void cepin();
void panduan();
void timedisplay(float sj);
void Time_Set1();
void Time_Set2();
void t0();
void t1();
/****************************************
* 模块名称:LCD1602显示程序 *
*****************************************/
/***********************Port Definitions*********************/
sbit LcdRs= P2^0;
sbit LcdRw= P2^1;
sbit LcdEn= P2^2;
sfr DBPort= 0x80; //P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口
/************************内部等待函数************************/
unsigned char LCD_Wait(void)
{
LcdRs=0; //寄存器选择输入端 1:数据 0:指令
LcdRw=1; _nop_(); //RW:为0:写状态;为1:读状态;
LcdEn=1; _nop_(); //使能输入端,读状态,高电平有效;写状态,下降沿有效LcdEn=0;
return DBPort;
}
/***********************向LCD写入命令或数据*******************/
#define LCD_COMMAND 0 // Command
#define LCD_DATA 1 // Data
#define LCD_CLEAR_SCREEN 0x01 // 清屏
#define LCD_HOMING 0x02 // 光标返回原点
void LCD_Write(bit style, unsigned char input)
{
LcdEn=0;
LcdRs=style;
LcdRw=0; _nop_();
DBPort=input; _nop_();//注意顺序
LcdEn=1; _nop_();//注意顺序
LcdEn=0; _nop_();
LCD_Wait();
}
/********************设置显示模式****************************/
#define LCD_SHOW 0x04 //显示开
#define LCD_HIDE 0x00 //显示关
#define LCD_CURSOR 0x02 //显示光标
#define LCD_NO_CURSOR 0x00 //无光标
#define LCD_FLASH 0x01 //光标闪动
#define LCD_NO_FLASH 0x00 //光标不闪动
void LCD_SetDisplay(unsigned char DisplayMode)
{
LCD_Write(LCD_COMMAND, 0x08|DisplayMode);
}
/*********************设置输入模式****************************/
#define LCD_AC_UP 0x02
#define LCD_AC_DOWN 0x00 // default
#define LCD_MOVE 0x01 // 画面可平移
#define LCD_NO_MOVE 0x00 //default
void LCD_SetInput(unsigned char InputMode)
{
LCD_Write(LCD_COMMAND, 0x04|InputMode);
}
/******************初始化LCD*********************************/ void LCD_Initial()
{
LcdEn=0;
LCD_Write(LCD_COMMAND,0x38); //8位数据端口,2行显示,5*7点阵LCD_Write(LCD_COMMAND,0x38);
LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR); //开启显示, 无光标LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏
LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE); //AC递增, 画面不动}
/*************************************************************/ void GotoXY(unsigned char x, unsigned char y)
{
if(y==0)
LCD_Write(LCD_COMMAND,0x80|x);
if(y==1)
LCD_Write(LCD_COMMAND,0x80|(x-0x40));
}
void Print(unsigned char *str)
while(*str!='\0')
{
LCD_Write(LCD_DATA,*str);
str++;
}
}
/******************************************************** /
* *
* 模块名称:频率测量程序 *
* 主要技术指标:测量范围:0.1Hz~4M *
* 闸门时间:0.05s~10s可调。
*
* *
**********************************************************/
/************************89c52初始化**********************/ void C52_Initial()
{
sj=1000000.00;
Key_Set=0xff;
TMOD=0x51; // 01010001 T1为计数器,T0为定时器 EA=1;
ET0=1;
ET1=1;
EX0=1;
PX0=1; //外部中断0设置为高优先级
IT0=0; //电平触发方式
}
/**************************ms延时子程序********************/ void Delay(unsigned int t) //t随着数值越大,误差趋于平衡. {
unsigned char i;
while(t--)
{
for(i=0;i<123;i++){;}
}
}
/*************************计数中断*************************/ void t1(void) interrupt 3 //计数器1溢出,yichu=1
{n++;
yichu=1;
TH1=0;
TL1=0;
/*************************定时中断************************/ void t0(void) interrupt 1
{m++;
yichu=2; //定时器0溢出,yichu=2
TH0=0x3c; //定时50ms
TL0=0xb0;
}
/*************************频率显示*************************/ void Fdisplay(float f)
{
if(f>999400.00)
{
if(f<4000400.00)
{sprintf(buff," Freq:%2.4fmHz ",(f/1000000.00));}
}
else
{
if(f>1040.00)
{sprintf(buff," Freq:%4.2fkHz ",(f/1000.00));} else
{
if(f>0.06)
{sprintf(buff," Freq:%3.2fHz ",f);}
}
}
GotoXY(0,1);
Print(buff);
}
/*************************周期显示************************/ void Pdisplay(float p)
{
if(p>999400.00)
{
if(p<10004000.00)
{sprintf(buff," Cycle:%2.4fs ",(p/1000000.00));} else
{sprintf(buff,"error(Time or F)",p);}
}
else
{
if(p>9950.00)
{sprintf(buff," Cycle:%4.2fms ",(p/1000.00));}
else
{
if(p>0.248)
{sprintf(buff," Cycle:%3.3fus ",p);}
else
{sprintf(buff,"error(Time or F)",p);}
}
}
GotoXY(0,1);
Print(buff);
}
/*************************测试频率*****************/
void cepin()
{
unsigned char a;
unsigned long js;
m=0;
n=0;
TMOD=0x51;
TH0=0x3c; //定时50ms
TL0=0xb0;
TH1=0;
TL1=0;
a=sj/50000.00;
TCON=0x50; //启动定时器和计数器
while(m!=a);
TCON=0;
js=TH1*256+n*65536+TL1;
f=(js/(sj/1000000.00))*fenpin;
p=sj/(js*fenpin);
if(xs==0) //设置结束后第一次不显示结果
{
if(flag==Freq) Fdisplay(f);
else Pdisplay(p);
}
}
/************************判断频率******************************/ void panduan()
{
xs=0; //设置结束后第二次循环显示结果
B153=1; //选择16分频
A153=0;
yichu=0;
TMOD=0x51;
TH0=0xff; //定时器0 200us
TL0=0x38;
TH1=0xff; //计数器1 100脉冲
TL1=0x9c;
TR0=1; //启动定时器0和计数器1
TR1=1;
while(yichu==0); //如果没有溢出一直循环
TR0=0; //已经溢出关闭定时器0和计数器1
TR1=0;
if(yichu==1) //计数器先溢出:在200ms内测得的脉冲过多,说明频率较高(f>500khz)
{fenpin=16; //转为测16分频后的频率 16
cepin();}
else //定时器先溢出:100个脉冲的时间比较短,即频率较低,可以减少分频数
{
yichu=0;
B153=0;
A153=1;
TH0=0xfc; //定时器0 1ms
TL0=0x18;
TH1=0xff; //计数器1 100个脉冲
TL1=0x9c;
TR0=1; //启动定时器0和计数器1
TR1=1;
while(yichu==0); //如果没溢出一直循环
TR0=0; //已经溢出关闭定时器0和计数器1
TR1=0;
if(yichu==1) //计数器先溢出:在1ms内测得的脉冲过多,说明频率较高(1khz<f<500khz)
{fenpin=4; //转为测4分频后的频率 4
cepin();}
else //定时器先溢出:100个脉冲的时间比较短,即频率较低 { fenpin=1;
B153=0;
A153=0;
cepin();}
}
}
/**************显示闸门时间*************************/
void timedisplay(float GTime)
{
sprintf(buff,"GTime=%7.0fus ",GTime);
GotoXY(0,1);
Print(buff);
Delay(50);
}
/**********************减按键********************/ void Time_Set2()
{
Delay(1000);
if(P17==1)
{ sj=sj-50000.00;
if(sj>50000.00) timedisplay(sj);
else
{sj=50000.00;
timedisplay(sj); }
}
else
{while(P17==0)
{ Delay(500);
sj=sj-500000.00;
if(sj>50000.00) timedisplay(sj);
else
{sj=50000.00;
timedisplay(sj); }
}
}
}
/****************加按键******************/ void Time_Set1()
{
Delay(1000);
if(P16==1)
{
sj=sj+50000.00;
if(sj<10000000.00) timedisplay(sj);
else
{sj=10000000.00;
timedisplay(sj);}
}
else
{while(P16==0)
{ Delay(500);
sj=sj+500000.00;
if(sj<10000000.00) timedisplay(sj);
else
{sj=10000000.00;
timedisplay(sj);} //按住1s快加0.5s }
}
}
/*****************闸门时间设置********************/ void Time_Set() interrupt 0
{
EA=0; //防止无限中断
Delay(100);
if(Set==0)
{
Delay(1000); //判断处于哪种设置状态 if(Set==1)
{
GotoXY(0,1);
Print(" Press Button...");
GotoXY(0,0);
Print(" T Settings ");
while(Set==1)
{
switch(Key_Set)
{
case K1: Time_Set1();break;
case K2: Time_Set2();break;
default: break;
}
}
}
else //选择测试频率或周期 {
GotoXY(0,1);
Print(" 1.Freq 2.Cycle");
GotoXY(0,0);
Print(" Slecting... ");
while(Set==0); //等待设置按键松开
while(Set==1)
{
switch(Key_Set)
{
case K1: flag=Freq; GotoXY(0,1); Print(" ---Freq--- "); break;
case K2: flag=Peri; GotoXY(0,1); Print(" ---Cycle--- "); break;
default: break;
}
}
}
}
GotoXY(0,0);
Print(" ---Cymometer---");
GotoXY(0,1);
Print(" Waiting... ");
while(Set==0); //防止再次进入中断
EA=1;
xs=1; //不显示此次结果.
}
/***************主程序**************/
void main()
{
LCD_Initial(); //LCD初始化
GotoXY(0,0);
Print(" ---Cymometer---");
GotoXY(0,1);
Print(" designed by LZA");
Delay(1000);
GotoXY(0,1);
Print(" Waiting... ");
C52_Initial(); //89c52初始化
while(1)
{
panduan();
}
}。