高精度单片机频率计的设计.docx
- 文档编号:26695684
- 上传时间:2023-06-21
- 格式:DOCX
- 页数:24
- 大小:262.71KB
高精度单片机频率计的设计.docx
《高精度单片机频率计的设计.docx》由会员分享,可在线阅读,更多相关《高精度单片机频率计的设计.docx(24页珍藏版)》请在冰豆网上搜索。
高精度单片机频率计的设计
《综合课程设计》
一.数字频率计的设计
姓名:
万咬春学号2005142135
一、课程设计的目的
通过本课程设计使学生进一步巩固光纤通信、单片机原理与技术的基本概念、基本理论、分析问题的基本方法;增强学生的软件编程实现能力和解决实际问题的能力,使学生能有效地将理论和实际紧密结合,拓展学生在工程实践方面的专业知识和相关技能。
二、课程设计的内容和要求
1.课程设计内容
(硬件类)频率测量仪的设计
2.课程设计要求
频率测量仪的设计
要求学生能够熟练地用单片机中定时/计数、中断等技术,针对周期性信号的特点,采用不同的算法,编程实现对信号频率的测量,将测量的结果显示在LCD1602上,并运用Proteus软件绘制电路原理图,进行仿真验证。
三.实验原理
可用两种方法测待测信号的频率
方法一:
(定时1s测信号脉冲次数)
用一个定时计数器做定时中断,定时1s,另一定时计数器仅做计数器使用,初始化完毕后同时开启两个定时计数器,直到产生1s中断,产生1s中断后立即关闭T0和T1(起保护程序和数据的作用)取出计数器寄存器内的值就是1s内待测信号的下跳沿次数即待测信号的频率。
用相关函数显示完毕后再开启T0和T1这样即可进入下一轮测量。
原理示意图如下:
实验原理分析:
1.根据该实验原理待测信号的频率不应该大于计数器的最大值65535,也就是说待测信号应小于65535Hz。
2.实验的误差应当是均与的与待测信号的频率无关。
方法二(测信号正半周期)
对于1:
1占空比的方波,仅用一个定时计数器做计数器,外部中断引脚作待测信号输入口,置计数器为外部中断引脚控制(外部中断引脚为“1”切TRx=1计数器开始计数)。
单片机初始化完毕后程序等待半个正半周期(以便准确打开TRx)打开TRx,这时只要INTx(外部中断引脚)为高电平计数器即不断计数,低电平则不计数,待信号从高电平后计数器终止计数,关闭TRx保护计数器寄存器的值,该值即为待测信号一个正半周期的单片机机器周期数,即可求出待测信号的周期:
待测信号周期T=2*cnt/(12/fsoc)cnt为测得待测信号的一个正半周期机器周期数;fsoc为单片机的晶振。
所以待测信号的频率f=1/T。
原理示意图如下:
实验原理分析:
1.根据该实验原理该方法只适用于1:
1占空比的方波信号,要测非1:
1占空比的方波信号
2.由于有执行f=1/(2*cnt/(12/fsoc))的浮点运算,而数据类型转换时未用LCD浮点显示,故测得的频率将会被取整,如1234.893Hz理论显示为1234Hz,测得结果会有一定程度的偏小。
也就是说测量结果与信号频率的奇偶有一定关系。
3.由于计数器的寄存器取值在1~65535之间,用该原理时,待测信号的频率小于单片机周期的1/12时,单片机方可较标准的测得待测信号的正半周期。
故用该原理测得信号的最高频率理论应为fsoc/12如12MHZ的单片机为1MHz。
而最小频率为f=1/(2*65535/(12/fsoc))如12MHZ的单片机为8Hz。
四.实验内容及步骤
1.仿真模型的构建
数字方波频率计的设计总体可分为两个模块。
一是信号频率测量,二是将测得的频率数据显示在1602液晶显示模块上。
因此可搭建单片机最小系统构建构建频率计的仿真模型。
原理图,仿真模型的总原理图如下:
2.液晶显示部分功能与原理分析
由于此部分并非课程的主要部分,故仅作简要原理分析
A.1602硬件接口及功能接口
//硬件接口部分**********************************************************
sbitLcdRs=P2^0;
sbitLcdRw=P2^1;
sbitLcdEn=P2^2;
sfrDBPort=0x80;//P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口
//向LCD写入命令或数据
************************************************************
#defineLCD_COMMAND0//Command
#defineLCD_DATA1//Data
#defineLCD_CLEAR_SCREEN0x01//清屏
#defineLCD_HOMING0x02//光标返回原点
//设置显示模式************************************************************
#defineLCD_SHOW0x04//显示开
#defineLCD_HIDE0x00//显示关
#defineLCD_CURSOR0x02//显示光标
#defineLCD_NO_CURSOR0x00//无光标
#defineLCD_FLASH0x01//光标闪动
#defineLCD_NO_FLASH0x00//光标不闪动
//设置输入模式************************************************************
#defineLCD_AC_UP0x02//将光标返回0x00
#defineLCD_AC_DOWN0x00//default
#defineLCD_MOVE0x01//画面可平移
#defineLCD_NO_MOVE0x00//default
B.1602初始化流程和原理框图
voidLCD_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递增,画面不动
}
C.写DDRAM地址(原理框图如上)
voidGotoXY(unsignedcharx,bity)
{if(y==0)
LCD_Write(LCD_COMMAND,0x80|x);
if(y==1)
LCD_Write(LCD_COMMAND,0x80|(x-0x40));
}
D.写字符串(原理框图如上)
voidPrint(unsignedchar*str)
{while(*str!
='\0')
{LCD_Write(LCD_DATA,*str);
str++;
}
}
3.程序机原理框图(关于显示函数部分不列出,只分析算法函数)
方法一:
用定时计数器T0做脉冲计数器(下跳沿有效),开始与暂停由T1控制定时计数器T1做定时中断,定时1s,定时开启置T0开始计数,定时完毕,置T0为暂停,关闭T1,读取计数数据并清空计数器,将计数数据装换为有效规范的字符串显示后再开启T0和T1,进入下一轮测量。
以下是程序的核心部分:
(定时1s,取计数数,并将其转换显示出来)原理框图如下
voidtimer1()interrupt3//定时50ms
{TH1=THCLK;
TL1=TLCLK;
if(--Cnt==0)//Cnt初值为20
{
TR0=0;TR1=0;
Cnt=CntNum;
tmp=TH0*256+TL0;
TH0=TL0=0;
Dynamic_LCD_Print();
TR0=1;
TR1=1;
}
}
方法二:
用一个定时计数器做计数器,外部中断引脚作待测信号输入口,置计数器为外部中断引脚控制(外部中断引脚为“1”切TRx=1计数器开始计数)。
单片机初始化完毕后程序等待半个正半周期(以便准确打开TRx)打开TRx,这时只要INTx(外部中断引脚)为高电平计数器即不断计数,低电平则不计数,待信号从高电平后计数器终止计数,关闭TRx保护计数器寄存器的值,该值即为待测信号一个正半周期的单片机机器周期数,即可求出待测信号的周期:
待测信号周期T=2*cnt/(12/fsoc)cnt为测得待测信号的一个正半周期机器周期数;fsoc为单片机的晶振。
所以待测信号的频率f=1/T。
以下是程序的核心部分:
(原理框图如下)
voidchkfreq()//
{while(FreqIN==0);
while(FreqIN==1);
TR0=1;
while(FreqIN==0);
while(FreqIN==1);
TR0=0;
cnttime=500000/(TH0*256+TL0);
TH0=TL0=0;
tmp=(int)cnttime;
Dynamic_LCD_Print();
}
4.原理框图如下
五.课程设计结果及结论
1.通过程序调试,用Protues用两种方法均可测得小于6Mhz的频率,以下是用方法一测量1000Hz频率的仿真图:
2.实验结果及误差分析
对于用原理一
A.待测信号的频率小于65535Hz。
B.实验的误差2000Hz时为0.05%;10000Hz时为0.07%;50000~60000Hz时为0.073%。
对于用原理二
C.在频率8-10000Hz时测得的值相当精确,频率为奇数时有1-2的误差。
D.超过频率8-10000Hz测得值完全错误
由此可见实验结果符合之前的原理分析,验证成功。
3。
实验优化及改进建议
a)方法一可将计数器0更改为中断扩展数据位数并延长定时时间,数据处理后和测量大于65535Hz的频率,但由T0中断不确定性,加大了测量范围会加大测量误差
b)方法二可将硬件待测信号取反接入剩余的外部中断接口,用于测量待测信号的负半周期,将正半周期和负半周期数相加即为待测信号的周期。
这样即可测量非均衡占空比的方波信号。
c)方法二还可计多次正半周期取平均值,可大大提高精度,但这样会提高实验的最低量程
4.两算法的对比
a)方法一误差均衡,切易于扩大量程,且可测量任意占空比的方波信号,但由于单片机的限制频率越高误差将表现更明显。
b)方法二在量程内误差比方法一稍小,占用CPU资源较小,但量程比方法一小,切不能测量非均衡占空比的频率信号,超过量程测量结果完全错误。
c)由此可见方法一较方法二有明显的优势
六.课程设计的心得体会
通过这次综合实验,不仅加深了我对单片接的认识而却还学会了设计,开发以及实际测试,锻炼了我们的实际动手能力。
在课程设计中通过两种原理与算法是我更清晰的认识了单片机对数据的处理,
进行程序调试。
在此期间我们遇到很多麻烦,但通过仔细分析,我一次又一次品尝到了解决问题的喜悦,最终完成了实验,在测试中我们发现了自己知识的不足,通过几天的奋斗,我们学到了很多东西,最重要的是我们学会了一种精神————永不放弃。
在以后的时间里面我们会用这种精神去学习,更上一层楼。
七、课程设计参考资料
教材:
1)张毅刚编.《单片机原理及应用》[M].北京:
高等教育出版社,2003.
参考书:
1)Optisystem实验指导书(自编讲义)。
2)周景润编著.基于Proteus的单片机设计与仿真[M].北京:
北京航空航天出版社,2007.
附录(完整的源程序)
一.1602_Drive.h完整的库函数
/**************************************************************************
THE1602CHARLCDLIB
COPYRIGHT(c)2008BYwanxun
FileName:
1602_Drive.h
Author:
wanxun
Created:
2008/12/1
***************************************************************************/
#ifndefLCD_CHAR_1602
#defineLCD_CHAR_1602
#include
//硬件接口部分**********************************************************
sbitLcdRs=P2^0;
sbitLcdRw=P2^1;
sbitLcdEn=P2^2;
sfrDBPort=0x80;//P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口
//内部等待函数**********************************************************
unsignedcharLCD_Wait(void)
{
LcdRs=0;
LcdRw=1;_nop_();
LcdEn=1;_nop_();
//while(DBPort&0x80);//在用Proteus仿真时,注意用屏蔽此语句,在调用GotoXY()时,会进入死循环,
//可能在写该控制字时,该模块没有返回写入完备命令,即DBPort&0x80==0x80
//实际硬件时打开此语句
LcdEn=0;
returnDBPort;
}
//向LCD写入命令或数据
************************************************************
#defineLCD_COMMAND0//Command
#defineLCD_DATA1//Data
#defineLCD_CLEAR_SCREEN0x01//清屏
#defineLCD_HOMING0x02//光标返回原点
voidLCD_Write(bitstyle,unsignedcharinput)
{
LcdEn=0;
LcdRs=style;
LcdRw=0;_nop_();
DBPort=input;_nop_();//注意顺序
LcdEn=1;_nop_();//注意顺序
LcdEn=0;_nop_();
LCD_Wait();
}
//设置显示模式************************************************************
#defineLCD_SHOW0x04//显示开
#defineLCD_HIDE0x00//显示关
#defineLCD_CURSOR0x02//显示光标
#defineLCD_NO_CURSOR0x00//无光标
#defineLCD_FLASH0x01//光标闪动
#defineLCD_NO_FLASH0x00//光标不闪动
voidLCD_SetDisplay(unsignedcharDisplayMode)
{
LCD_Write(LCD_COMMAND,0x08|DisplayMode);
}
//设置输入模式************************************************************
#defineLCD_AC_UP0x02
#defineLCD_AC_DOWN0x00//default
#defineLCD_MOVE0x01//画面可平移
#defineLCD_NO_MOVE0x00//default
voidLCD_SetInput(unsignedcharInputMode)
{
LCD_Write(LCD_COMMAND,0x04|InputMode);
}
//移动光标或屏幕************************************************************
/*
#defineLCD_CURSOR0x02
#defineLCD_SCREEN0x08
#defineLCD_LEFT0x00
#defineLCD_RIGHT0x04
voidLCD_Move(unsignedcharobject,unsignedchardirection)
{
if(object==LCD_CURSOR)
LCD_Write(LCD_COMMAND,0x10|direction);
if(object==LCD_SCREEN)
LCD_Write(LCD_COMMAND,0x18|direction);
}
*/
//初始化LCD************************************************************
voidLCD_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递增,画面不动
}
//************************************************************************
voidGotoXY(unsignedcharx,bity)
{
if(y==0)
LCD_Write(LCD_COMMAND,0x80|x);
if(y==1)
LCD_Write(LCD_COMMAND,0x80|(x-0x40));
}
voidPrint(unsignedchar*str)
{
while(*str!
='\0')
{
LCD_Write(LCD_DATA,*str);
str++;
}
}
/*
voidLCD_LoadChar(unsignedcharuser[8],unsignedcharplace)
{
unsignedchari;
LCD_Write(LCD_COMMAND,0x40|(place*8));
for(i=0;i<8;i++)
LCD_Write(LCD_DATA,user[i]);
}
*/
//************************************************************************
#endif
二.方法一的源程序
#include
#include<1602_Drive.h>
/******************************************************************
*定义接口:
*
*液晶显示器的接口“1602_Drive.h”库函数中已经定义*
*定义待测方波频率的接口:
*
*P3^5(T0口)做时钟输入接口;*
******************************************************************/
//==================================================================
//用测量脉冲次数的方法时定义的定时1s的参数
#defineTHCLK0x3c
#defineTLCLK0xb0
#defineCntNum20
//==================================================================
//定义中间变量
unsignedintCnt;
unsignedinttmp;
unsignedcharoutcnt[8];
//==================================================================
//将测量的整数装换为标准有效的字符串
voidNumToChar(void)
{unsignedchari;
outcnt[0]=tmp/10000+48;tmp%=10000;
outcnt[1]=tmp/1000+48;tmp%=1000;
outcnt[2]=tmp/100+48;tmp%=100;
outcnt[3]=tmp/10+48;tmp%=10;
outcnt[4]=tmp+48;
outcnt[5]='H';
outcnt[6]='z';
outcnt[7]='\0';
for(i=0;i<4;i++)//将字符中数字的最高有效位之前的'0'清空为‘’。
{if(outcnt[i]=='0')outcnt[i]='';
elsebreak;
}
}
//==================================================================
//静态显示文本
voidStatic_LCD_Print()
{GotoXY(0,0);
Print("Freqis:
");
GotoXY(1,1);
Print("Madebywanxun");
}
//==================================================================
//动态显示数据
voidDynamic_LCD_Print()
{NumToChar();
GotoXY(9,0);
Print(outcnt);
}
//==================================================================
/******************************************************************
*用定时计数器T0做脉冲计数器(下跳沿有效),开始与暂停由T1控制*
*定时计数器T1做定时中断,定时1s,定时开启置T0开始计数,定时完毕置*
*T0为暂停,关闭T1,读取计数数据并清空计数器,将计数数据装换为有效*
*规范的字符串显示后再开启T0和T1,进
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 高精度 单片机 频率计 设计