独立按键数字电子钟DOC.docx
《独立按键数字电子钟DOC.docx》由会员分享,可在线阅读,更多相关《独立按键数字电子钟DOC.docx(25页珍藏版)》请在冰点文库上搜索。
独立按键数字电子钟DOC
方案一
独
立
键
盘
数
字
电
子
钟
电科0902班
组长:
祁俐俐
组员:
吉才韩江蔡杨
苏欣李程付磊
2012年7月12日
独立键盘数字电子钟
一、电子钟设计目的
1、学习数字电子钟的原理和实现方法。
2、掌握键盘的控制原理和编程方法。
3、掌握51单片机定时器与中断的使用。
4、掌握LED数码管显示的原理及编程方法。
二电子钟设计要求
设计一个数字电子钟,要求可进行时、分、秒显示,最大显示时间为23:
59:
59,,并且具有时间调整、闹铃、启动、暂停和清零(复位)等功能。
可以完成以下几点功能:
1)六个LED上实现正常的时间显示,24小时制
2)实现时间的正确调节
3)闹钟的定时及到时间之后的音乐响铃
4)独立键盘,设有暂停键,启动键,清零键,时调整键,分调整键,秒调整键,闹钟键。
三设计方案规划与选定
根据要求采用AT89C51单片机进行设计,AT89C51单片机是一款低功耗,高性能CMOS8位单片机,片内含4KB在线可编程(ISP)的可反复擦写1000次的Flash只读程序存储器,器件采用高密度、非易失性存储技术制造,兼容标准MCS-51指令系统及80C51引脚结构。
这样,既能做到经济合理又能实现预期的功能。
在程序方面,采用分块设计的方法,这样既减小了编程难度、使程序易于理解,又能便于添加各项功能。
程序可分为闹钟的音乐程序、时间显示程序、闹钟显示程序、调时显示、定时程序,走时程序,复位的模块化的程序。
硬件接线图如图所示:
原理分析如下:
主程序:
执行主程序,按照得到的的1到7键值转到相应的子程序去执行相应的功能。
模块一:
时间显示模块:
用51单片机的6个LED七段数码管,依次分别显示时,分,秒,中间用小数点分开。
正常走时时秒数满60进位,分钟加1,分钟满60小时加1,小时满24清0
模块二:
显示时间调整模块:
当按下键值为1,2,3的开关后,进入时间调整程序,对六个数码管相应位的的控制按照我们生活中的正常逻辑进行控制。
进行调整时间
模块三:
闹钟音乐模块:
当按下键值为6的开关后,进入闹钟时间设置状态,设定相应的时间,当到了设定的时间之后,进入产生中断,进入闹钟音乐程序
模块四:
键盘扫描得到按键值函数,根据键值转到相应的模块执行相应的功能。
各个模块程序设计好之后,要进行最后的整合,函数的调用参数设置要正确,使程序能够正常的运行,在keil上调试通过之后,检查proteus中硬件连接有没有错误,确定无误后,在proteus中进行模拟实验,最后可以到实验室进行真实元器件的连接。
四.硬件设计
1.总体设计方案
2.硬件电路
(1)AT89C51
1、电源引脚
Vcc电源端,GND接地端,工作电压为5V,
2、外接晶体引脚
晶振连接的内部、外部方式图
XTAL1是片内振荡器的反相放大器输入端,XTAL2则是输出端,使用外部振荡器时,外部振荡信号应直接加到XTAL1,而XTAL2悬空。
内部方式时,时钟发生器对振荡脉冲二分频,如晶振为12MHz,时钟频率就为6MHz。
晶振的频率可以在1MHz-24MHz内选择。
电容取30PF左右。
系统的时钟电路设计是采用的内部方式,即利用芯片内部的振荡电路。
AT89单片机内部有一个用于构成振荡器的高增益反相放大器。
引脚XTAL1和XTAL2分别是此放大器的输入端和输出端。
这个放大器与作为反馈元件的片外晶体谐振器一起构成一个自激振荡器。
外接晶体谐振器以及电容C1和C2构成并联谐振电路,接在放大器的反馈回路中。
对外接电容的值虽然没有严格的要求,但电容的大小会影响震荡器频率的高低、震荡器的稳定性、起振的快速性和温度的稳定性。
因此,此系统电路的晶体振荡器的值为12MHz,电容应尽可能的选择陶瓷电容,电容值约为22μF。
在焊接刷电路板时,晶体振荡器和电容应尽可能安装得与单片机芯片靠近,以减少寄生电容,更好地保证震荡器稳定和可靠地工作。
3、复位RST
在振荡器运行时,有两个机器周期(24个振荡周期)以上的高电平出现在此引腿时,将使单片机复位,只要这个脚保持高电平,51芯片便循环复位。
复位后P0-P3口均置1引脚表现为高电平,程序计数器和特殊功能寄存器SFR全部清零。
当复位脚由高电平变为低电平时,芯片为ROM的00H处开始运行程序。
复位是由外部的复位电路来实现的。
片内复位电路是复位引脚RST通过一个斯密特触发器与复位电路相连,斯密特触发器用来抑制噪声,它的输出在每个机器周期的S5P2,由复位电路采样一次。
复位电路通常采用上电自动复位和按钮复位两种方式,此电路系统采用的是按钮复位电路。
4、输入输出引脚
(1)P0端口[P0.0-P0.7]P0是一个8位漏极开路型双向I/O端口,端口置1(对端口写1)时作高阻抗输入端。
作为输出口时能驱动8个TTL。
对内部Flash程序存储器编程时,接收指令字节;校验程序时输出指令字节,要求外接上拉电阻。
在访问外部程序和外部数据存储器时,P0口是分时转换的地址(低8位)/数据总线,访问期间内部的上拉电阻起作用。
(2)P1端口[P1.0-P1.7]P1是一个带有内部上拉电阻的8位双向I/0端口。
输出时可驱动4个TTL。
端口置1时,内部上拉电阻将端口拉到高电平,作输入用。
(3)P2端口[P2.0-P2.7]P2是一个带有内部上拉电阻的8位双向I/0端口。
输出时可驱动4个TTL。
端口置1时,内部上拉电阻将端口拉到高电平,作输入用。
对内部Flash程序存储器编程时,接收高8位地址和控制信息。
(4)P3端口[P3.0-P3.7]P2是一个带有内部上拉电阻的8位双向I/0端口。
输出时可驱动4个TTL。
端口置1时,内部上拉电阻将端口拉到高电平,作输入用。
(2)键盘电路设计
该设计只用了一个键盘,但实现的功能却是比较完善,减少了硬件资源的损耗,该键盘可以实现小时和分钟的调节以及控制是否进入省电模式。
当按键按下又松开,可以实现屏蔽数码管显示的功能,达到省电的目的;直接按下不松开,则可以通过按键实现分钟的累加,每按一次分钟加一;而连续两次按下按键不放松,则可实现小时的调节,同样每按一次小时加一。
达到时间调节的目的。
选择的多功能按键如图所示。
(3)数码管:
LED数码管实际上是由七个发光管组成8字形构成的,加上小数点就是8个。
如图3-10。
这些段分别由字母a,b,c,d,e,f,g,dp来表示。
当数码管特定的段加上电压后,这些特定的段就会发亮,以形成我们眼睛看到的字样了。
如:
显示一个“2”字,那么应当是a亮b亮g亮e亮d亮f不亮c不亮dp不亮。
LED数码管有一般亮和超亮等不同之分,也有0.5寸、1寸等不同的尺寸。
小尺寸数码管的显示笔画常用一个发光二极管组成,而大尺寸的数码管由二个或多个发光二极管组成,一般情况下,单个发光二极管的管压降为1.8V左右,电流不超过30mA。
发光二极管的阳极连接到一起连接到电源正极的称为共阳数码管,发光二极管的阴极连接到一起连接到电源负极的称为共阴数码管。
常用LED数码管显示的数字和字符是0、1、2、3、4、5、6、7、8、9。
(4)74LS373
1D~8D为8个输入端1Q~8Q为8个输出端
LE是数据锁存控制端;当LE=1时,锁存器输出端同输入端;当LE由“1”变为“0”时,数据输入锁存器中。
OE为输出允许端;当OE=“0”时,三态门打开;当OE=“1”时,三态门关闭,输出呈高阻状态。
在MCS-51单片机系统中,常采用74LS373作为地址锁存器使用,其连接方法如电路硬件图所示。
其中输入端1D~8D接至单片机的P0口,输出端提供的是低8位地址,LE端接至单片机的地址锁存允许信号ALE。
输出允许端OE接地,表示输出三态门一直打开。
五.软件设计
主程序以及各子程序的流程图如下:
软件设计思路如下:
1.主程序设计:
主程序中完成对定时器设置的初始化,然后进入无限循环的查询模块,动态扫描LED显示模块,使显示走时正常。
同时在循环中完成对键盘的状态(是否有键按下,如有是哪一个)进行监控,如果有键按下根据其键值跳转到相应的子程序中进行执行,完成相应的功能后会自动跳转回来。
这样整个程序就实现了连续有效的运行。
2.按键扫描子程序:
首先根据端口状态判断是否有键按下,如果没有就跳过读键值这个阶段。
如果有键按下就通过扫描判断出所按下键的位置,并相应的形成键值,保存在一个全局变量中等待被查询。
然后跳出子程序。
3.显示子程序:
该子程序在LED扫描中被调用。
首先根据参数判别是显示时间还是显示闹钟,然后针对六个位形成相应的段码值。
通过参数值在相应位输出显示。
4.时间及闹钟设定子程序:
本程序完成时间的修改及闹钟的设置,对时间和闹钟的设置是通过修改时间值的全局变量或闹钟值的全局变量来完成的。
在修改过程中正在修改位用时间调整键来显示,当长按时间调整键时,显示闹钟调整页面,当六位全部修改完毕,或者按下确定/退出键后自动跳出子程序。
5.响铃子程序:
当设定的闹钟时间到时,转入本程序执行。
本程序通过读取频率表来设定T1定时中断的设定,以在响铃端口输出频率一定的脉冲波。
同时通过读取时间表控制每一频率所响的时间,这样就可以在扬声器输出音乐了。
同时在程序中添加了键盘扫描环节,一旦按下退出键,就关闭T1定时器,跳出程序,响铃就可以终止。
六.调试
本次仿真实验,在调试时遇到了不少的困难,比如说按键一直闪烁,通过查资料,最后注释掉了按建时的延时即可。
闹钟键一直没有设计好,进入闹钟设置页面后,调整闹钟的时候时间也在变化,造成了盲调,是本实验的一大缺陷。
但是本次实验采用的是“模块化”,所以调试过程中可以清楚的知道是那部分出了问题,征对性的进行修改,避免了不必要的麻烦,也加快了实验进程。
独立按键数字电子钟,只是我们组为做矩阵键盘数字钟做的准备工作,通过简单的独立按键掌握数字电子钟的原理以及某些子程序的编程,从而为我们后面仿真矩阵键盘电子钟做了很好的铺垫。
七.心得体会
通过这次课程设计,使我们更深刻地感受到课程设计的综合性之强大,完成对数字电子钟的设计与制作调试,使我们对单片机应用系统的设计过程进行了掌握。
当我们选择一个课程设计的时候,不是马上就动手做,而是先进行可行性论证。
首先提出几套方案,然后对各个方案进行对比,由易到难,先做出一个简单的仿真,然后根据要求一步步修改,直至达到最终要求。
从刚开始对软件的不熟悉,对编程的不熟悉,通过查找资料,请教同学老师,不断克服困哪。
这次的课程设计,我作为我们小组的组长,我主要是负责画仿真图,调试,以及其中一部分程序的编写,最终还要把几部分程序都结合在一起,任务艰巨,但是也具有挑战性,让我学会了很多东西,最终我们团结一致,成功调制除了电子钟。
调试成功的那一刻,大家都很兴奋,几天的辛苦终于得到了很大的收获。
源程序如下:
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
/*七段共阴管显示定义*/
ucharcodedispcode[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,};
//显示的0-9以及小数点的段码
/*定义并初始化变量*/
ucharsecond=11;
ucharminute=11;
ucharhour=11;
ucharmstcnt=0;
ucharm=800;
ucharshi=8;//闹铃功能
ucharfen=8;
ucharmiao=8;
ucharbjcs;//报警次数
ucharj;
uchari;
sbitP1_0=P1^0;//second调整定义 用符号P1_0来表示P1.0引脚
sbitP1_1=P1^1;//minite调整定义
sbitP1_2=P1^2;//hour调整定义
sbitP1_3=P1^3;//复位清零
sbitP1_4=P1^4;//暂停
sbitP1_5=P1^5;//闹钟
sbitP2_7=P2^7;//蜂鸣器
sbitP1_6=P1^6;//启动
/*函数声明*/
voiddelay(uchark);//延时子程序
voidtime_pro();//时间处理子程序
voiddisplay();//显示子程序
voidkeyscan();//键盘扫描子程序
voiddingshi();//定时
voidbaojingsheng();//闹钟
/*****************************/
/*按键去抖/
/****************************/
voiddelay20ms(void)
{
for(i=0;i<100;i++)
for(j=0;j<60;j++)
;
}
/*****************************/
/*延时子程序*/
/****************************/
voiddelay(uchark)
{
ucharj;
while((k--)!
=0)
{
for(j=0;j<125;j++)
{;}
}
}
/**************************/
/*时间处理子程序*/
/**************************/
voidtime_pro(void)
{
if(second==60)//秒钟设为60进制
{second=0;
minute++;
if(minute==60)//分钟设为60进制
{minute=0;
hour++;
if(hour==24)//时钟设为24进制
{hour=0;}
}
}
}
/*****************************/
/*显示子程序*/
/*****************************/
voiddisplay(void)
{
P2=0xfe;
P0=dispcode[hour/10];//显示小时的十位
delay(4);
P2=0xfd;
P0=(dispcode[(hour%10)])|0X80;
delay(4);
P2=0xfb;
P0=dispcode[minute/10];//显示分的十位
delay(4);
P2=0xf7;
P0=(dispcode[minute%10])|0X80;//显示分的个位
delay(4);
P2=0xef;
P0=dispcode[second/10];//显示秒的十位
delay(4);
P2=0xdf;
P0=dispcode[second%10];//显示秒的个位
delay(4);
}
/*******************************/
/*键盘扫描子程序*/
/*******************************/
voidkeyscan(void)
{
if(P1_0==0)//按键1秒的调整
{
display();
if(P1_0==0)
{
second++;
while(!
P1_0)
display();
if(second==60)
{second=0;
minute++;
}
}
}
if(P1_1==0)//按键2分的调整
{
display();
if(P1_1==0)
{
minute++;
while(!
P1_1)
display();
if(minute==60)
{minute=0;
hour+=1;
}
}
}
if(P1_2==0)//按键3小时的调整
{
display();
if(P1_2==0)
{
hour++;
while(!
P1_2)
display();
if(hour==24)
{hour=0;}
}
}
if(P1_3==0)//复位清零
{
display();
if(P1_3==0)
{
hour=0;
minute=0;
second=0;
}
}
if(P1_4==0)//暂停
{delay(100);
if(P1_4==0)
{while(P1_4==0)
TR0=0; //定时器0关闭
}
}
if(P1_6==0)//启动
{delay(100);
if(P1_6==0)
{while(P1_6==0)
TR0=1; //定时器0启动
}
}
if(P1_5==0)
//按住P1_5不松,显示闹铃设置界面,分别按P1_1、P1_2、P1_3设置闹铃时间。
{
P2=0xfe;
P0=dispcode[shi/10];//显示小时的十位
delay(4);
P2=0xfd;
P0=(dispcode[(shi%10)])|0X80;//显示小时的个位
delay(4);
P2=0xfb;
P0=dispcode[fen/10];//显示分的十位
delay(4);
P2=0xf7;
P0=(dispcode[fen%10])|0X80;//显示分的个位
delay(4);
P2=0xef;
P0=dispcode[miao/10];//显示秒的十位
delay(4);
P2=0xdf;
P0=dispcode[miao%10];//显示秒的个位
delay(4);
}
if(P1_1==0)//设秒
{
delay(300);
if(P1_3==0)
{
miao++;
delay(1000);
if(miao==60)
{
miao=0;
}
}
delay(250);
}
if(P1_2==0)//设定分
{
delay(30);
if(P1_2==0)
{
fen++;
delay(1000);
if(fen==60)
{
fen=0;
}
}
delay(250);
}
if(P1_3==0)//设定时
{
delay(30);
if(P1_3==0)
{
shi++;
if(shi==24)
{
shi=0;
}
}
delay(250);
}
if((hour==shi)&(minute==fen)&(second==miao))
//闹铃时间到,报警十次。
{
for(bjcs=0;bjcs<10;bjcs++){
P1_5=0;
delay(500);
P1_5=1;
delay(500);
}
}
}
voidtimer0(void)interrupt1using0//定时器0方式1,50ms中断一次
{
TH0=0x3c;//手动加载计数脉冲次数
TL0=0xb0;
mstcnt++;//用于计算时间,每50ms加1
if(mstcnt==20)//mstcnt满20即为1秒
{
second++;
time_pro();//时间处理
mstcnt=0;//对计数单元的清零,重新开始计数
}
}
voidbaojingsheng(void)//闹钟音产生函数
{
while(m>300)
{P2_7=~P2_7;
time_pro();
display();
m--;
}
while(m>0)
{P2_7=~P2_7;
time_pro();
display();
delay(15);
m--;
}
}
/**************************/
/*主函数*/
/**************************/
voidmain(void)
{
P1=0xff;//初始化p1口,全设为1
TMOD=0x01;//time0为定时器0,方式1
TH0=0x3c;
TL0=0xb0;
EA=1;
ET0=1;//允许定时器0中断
//TR0=1;
while
(1)
{
keyscan();//按键扫描
time_pro();//时间处理
display();//显示时间
}
}