课程设计报告
题
目:
电子钟通信工程
专业名称:班学姓
级: 1班号: 710705135名:
周茂宁
2010年 6月10日
课程设计报告
1.基本内容
1.1课程设计的基本内容(包括设计目标):1.1.1实现可手动调整的时钟,闹钟功能1.1.2按键可长按,也可短按。1.1.3可指示工作模式
1.1.4可直观地区别,当前修改时分还是秒1.1.5具有整点提示功能1.1.6日误差<4S1.2基本的环境条件:
硬件:WAVE单片机仿真器、单片机实验板
软件:KEIL C51单片机仿真调试软件,伟福V系列仿真调试软件,PROTEUS单片机系统仿真软件
2.方案论证
2.1方案比较:采用外部时钟信号较麻烦,需要外部时钟,因此采用内部时钟方式
图2-1内部时钟方式图2-2外部时钟方式
本设计是定时闹钟的设计,由单片机AT89C51芯片和LED数码管为核心,辅以必要的电路,构成的一个单片机电子定时闹钟。电子钟设计可采用数字电路实现,也可以采用单片机来完成。数字电子钟是用数字集成电路构成的,用数码管显示“时”,“分”,“秒”的现代计时装置。若用数字电路完成,所设计的电路相当复杂,大概需要十几片数字集成块,其功
能也主要依赖于数字电路的各功能模块的组合来实现,焊接的过程比较复杂,成本也非常高。若用单片机来设计制作完成,由于其功能的实现主要通过软件编程来完成,那么就降低了硬件电路的复杂性,而且其成本也有所降低,所以在该设计中采用单片机利用AT89C51,它是低功耗、高性能的CMOS型8位单片机。片内带有4KB的Flash存储器,且允许在系统内改写或用编程器编程。另外, AT89C51的指令系统和引脚与8051完全兼容,片内有128B的RAM、32条I/O口线、2个16位定时计数器、5个中断源、一个全双工串行口等。AT89C51单片机结合七段显示器设计的简易定时闹铃时钟,可以设置现在的时间及显示闹铃设置时间,若时间到则发出一阵声响,进—步可以扩充控制电器的启停。2.2设计原理
P0口输出显示码,P2口为位选端口,数码管用最简单的三极管驱动。用来显示时间。P1口作按键输入口,用二极管作为指示灯,蜂鸣器也采用三极管驱动。
利用中断进行计时,每次计时50ms,计20次达到1S,60秒为一分,60分为一小时,24小时为第二天0时。按键S13用来设定工作模式(设置闹钟、正常计时、修改时间)为了避免按键按下时数码管闪烁过于强烈,采用中断显示,这样就可以很稳定亮度的输出。为了利用P1口的二极管指示工作模式,将键盘的反转法改进。这样可以有三个二极管可以用来指示模式。当设置闹钟和修改时间时,当前正在修改的两个数码管较亮,其它4个较暗(如改小时,分和秒的显示较暗),更直观。当闹钟响的时候,若不取消响声,默认响30秒,要取中止响声,可按S15按键停止。当整点时,以“嘀”声提示。2.3硬件模块2.3.1各模块电路图
图2-3-1扬声器模块图2-3-2数码显示模块
按键模块(如图2-3-3,2-3-4)
图2-3-5按键模块图2-3-6按键指示灯模块
2.3.2总电路图
图2-3-7电子钟总电路图
图2-3-8正常计时模式(第5个二极管亮)
图2-3-9正常计时模式截图
3.软件流程图
初始化,清零显示是否有键按下N是否是key13Keycode1++Keycode1=1Keycode1=2Keycode1=3Keycode1=4Keycode1=5设置闹钟正常计时第6灯亮还原计时闹钟开启第5灯亮修改时间第7灯亮正常计时闹钟开启第5灯亮Keycode1=1显示图3-1主程序流程图
4.设计过程
先明确要做的电子钟具有哪些功能,这些功能用单片机中的哪些资源来实现,画个大体流程图,先从简单的功能入手。首先编调试出计时的程序,即保证可以输出正常显示。刚开始是在主程序中用动态显示。
接着增加按键功能,让按键控制电子钟的停与计时。此时发现数码管的显示不稳定,当按键按下后显示明显闪烁强烈,考虑用中断来显示,即把显示程序,交给中断处理程序了。这时考虑到二极管指示模式,因此,将键盘反转法改进为只用5根线,即1行4个按键。于是二极管就剩下3个可以做为三种不同模式的指示灯。
再下来是增加修改时间程序模块,增加设置闹钟程序,这两个比较相似。为了能够比较直观地看出正在修改的是时还是分或秒。即不使数值变化可直接看出正在修改的位。修改过程中发现,需要修改的数离当前值相差较多时,修改很麻烦,因此设置了按键的长按功能。
最后添加整点报时,以及闹钟提示音。以及闹钟响时,切断响声设置。
实现可手动调整的时钟,包括闹钟功能(当时间超过10S左右还原到计时模式,以避免长时间未操作),时间可调,按键可长按,也可短按,4个按键(其中一个为功能键,一个为确定要修改的是小时,还是分钟,还是秒,另外两个按键1个加,1个减)8个二极管从左到右,第5个为计时模式指示灯,第6个为设置闹钟的模式指示灯,第7个为修改时间指示灯。不管是在闹钟设置模式还是修改时间模式,当修改小时数值时,分和秒的数码管较暗,以示区别,修改分钟或秒时,类似的。当闹钟响时,若无取消则响30s,按第15键可取消响声。
5.心得体会
这次课程设计真正地让我们走出了课堂里,只有我们听,老师讲课的情况。完完全全由自已组建起一个电子钟。课程设计根据设计要求,查找资料,然后按要求根据已学过的时钟程序编写定时闹钟的程序,依据程序利用proteus软件进行了仿真试验,对出现的问题进行分析和反复修改源程序,最终用硬件实验板进行调试修改,得到正确并符合要求的结果。这个设计将所学的知识很好地联系在一起。虽然本设计经过规划,但是还有不足的地方,如没有秒表功能,倒计时功能。可把T1中断显示放到T0中,再进行相应的修改,就可以空出T1用来倒计时或秒表功能使用,这时就不会与正常计时相干扰了。签于时间关系,以及所用的知识是和上面的工作相同,因此就不做出具体实际程序了。
附录程序:
/*说明:按键从左至右
按KEY 13 1次设定闹钏钟:
按KEY 14 1次设SECOND
单击15加1长按10倍单位时间加单击16减1长按10倍单位时间减
2次设MINUTE
单击15加1长按10倍单位时间加单击16减1长按10倍单位时间减
3次设HOUR
单击15加1长按10倍单位时间加单击16减1长按10倍单位时间减
按KEY 13 2次还原计时
按KEY 13 3次修改时间:可进入修改时间状态,否则10s后还原初始状态,
按KEY 14 1次设SECOND
单击15加1长按10倍单位时间加单击16减1长按10倍单位时间减
2次设MINUTE
单击15加1长按10倍单位时间加单击16减1长按10倍单位时间减
3次设HOUR
单击15加1长按10倍单位时间加单击16减1长按10倍单位时间减
按KEY 13 4次开始计时状态说明:改时间第 7个二极管亮改闹钟第 6个二极管亮正常计时第 5个二极管亮
可整点报时,闹钟(可手动设置)30s闹钟响时,可通过按第4排第3个键停即key15在设定闹钟状成态和修改时间状态,数码管相对较亮的两个表示现在可以调这两个位的数值*/
#include #define uchar unsigned char#define uint unsigned intsbit P1_4=P1^4;sbit P1_5=P1^5;sbit P1_6=P1^6;sbit P1_7=P1^7;sbit P2_0=P2^0;sbit P2_1=P2^1;sbit P2_2=P2^2;sbit P2_3=P2^3;sbit P2_4=P2^4;sbit P2_5=P2^5;uchar table1[]={0x20,0x10,0x08,0x04,0x02,0x01};uchar table2[]={0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f}; //显示码 uchar table3[]={0,0,0,0,0,0};//用来显示的数 组 uchar setalarm[]={0,0,0,0,0,0};//用来存储闹钟时间的 uchartcount,tcount02s,tcount03;//tcount为正常计时中断次数,tcount02为30S闹钟响的时间变量,tcount03为当在改闹钟状态超过10s没有操作则自动返回到计时状态uchar keycode1,keycode2,keycode3,keycode4,keytcount;//keycode1用来计键13按下的次数(在不同模式下切换),keycode2用来计键14的次数(在改时,改闹钟状态用来确定改变的是时或分或秒),keycode3用来加,keycode4用来减char second,minute,hour,alarm_second,alarm_minute,alarm_hour;void delay(){uint i; //延时 for(i=400;i>0;i--){}} void delay10ms(void){ unsigned char i,u; for(i=20;i>0;i--) for(u=200;u>0;u--);} void keycode(){ uchar key,i=0;int a=0;P1=0xff;P1_7=0;key=P1&0x0f;if(key!=0x0f){ delay10ms();key=P1&0x0f;if(key!=0x0f){ switch(key){ case 0x0e: keycode1++; break;//当为key13按下时,改变模式 case 0x0d: keycode2++; break;//当key14按下时,改变时或分或秒,由这个键来选择 case 0x0b: keycode3=1;break;//当为key15按下时,短按加1长按以10倍单位时间加 case 0x07: keycode4=1;break;//当为key16按下时,短按减1长按以10倍时间减} key=key&0x0f;while(key!=0x0f){key=P1;key=key&0x0f;i++;if(i==250){i=0;a++;if(a==150) {a=0; keytcount++;if(keytcount==6){ keytcount=0;}}}}}}} void set_alarm(){ if(keycode2==0){ P2_2=0;//用来区别是否在改的状态,让时分暗一些P2_3=0;P2_4=0;P2_5=0; if(keycode3==1){ if(keytcount==0){ alarm_second++;} alarm_second=alarm_second+keytcount*10; //长按以10倍加keytcount=0; if(alarm_second==60){ alarm_second=0;} if(alarm_second>60)返回从个位开始{ alarm_second=alarm_second-60;} keycode3=0;} if(keycode4==1){ //减秒 //超过60 //单击以1倍加//加秒 //改秒 if(keytcount==0){ alarm_second--; //单击以1倍减} alarm_second=alarm_second-keytcount*10; //长按以10倍减keytcount=0; if(alarm_second==-1)回从59开始{ alarm_second=59;} if(alarm_second<-1){ alarm_second=alarm_second+60;} keycode4=0;}} if(keycode2==1){P2_0=0;一些P2_1=0;P2_4=0;P2_5=0; if(keycode3==1){ if(keytcount==0){ alarm_minute++;} alarm_minute=alarm_minute+keytcount*10;keytcount=0; if(alarm_minute==60){ alarm_minute=0;} if(alarm_minute>60){ alarm_minute=alarm_minute-60;} keycode3=0;} //加分 //用来区别是否在改的状态,让时秒暗 //改分 //小于0返 if(keycode4==1){ if(keytcount==0){ alarm_minute--;} //减分 alarm_minute=alarm_minute-keytcount*10;keytcount=0; if(alarm_minute==-1){ alarm_minute=59;} if(alarm_minute<-1){ alarm_minute=alarm_minute+60;} keycode4=0;}} if(keycode2==2){ P2_0=0;//用来区别是否在改的状态,让分秒暗一些P2_1=0;P2_2=0;P2_3=0; if(keycode3==1){ if(keytcount==0){ alarm_hour++;} alarm_hour=alarm_hour+keytcount*10;keytcount=0;if(alarm_hour==24){ alarm_hour=0;} if(alarm_hour>24&&alarm_hour<44){ alarm_hour=alarm_hour-20;} if(alarm_hour>=44){ //加时 //改时 alarm_hour=alarm_hour-40;} keycode3=0;} if(keycode4==1)//减时 { if(keytcount==0){ alarm_hour--;} alarm_hour=alarm_hour-keytcount*10;keytcount=0;if(alarm_hour==-1){ alarm_hour=23;} if(alarm_hour<-1&&alarm_hour>-24){ alarm_hour=alarm_hour+20;} if(alarm_hour<=-24){ alarm_hour=alarm_hour+40;} keycode4=0;}} if(keycode2==3){ keycode2=0;} table3[0]=table2[alarm_hour/10]; //把对应时分秒显示码赋给数组3table3[1]=table2[alarm_hour%10];table3[2]=table2[alarm_minute/10];table3[3]=table2[alarm_minute%10];table3[4]=table2[alarm_second/10];table3[5]=table2[alarm_second%10];} void set_clock(){uchar i;TR0=0; if(keycode2==0) //改秒{ P2_2=0;//用来区别是否在改的状态,让时分暗一些P2_3=0;P2_4=0;P2_5=0; if(keycode3==1)//加秒 { if(keytcount==0)//单击以1倍加{ second++;} second=second+keytcount*10;//长按以10 倍加 keytcount=0;if(second==60){ alarm_second=0;} if(second>60)//超过60返回从个位 开始{ second=second-60;} keycode3=0;} if(keycode4==1)//减秒 { if(keytcount==0){ second--; //单击以1倍减} second=second-keytcount*10;//长按以10 倍减 keytcount=0;if(second==-1){ second=59;} if(second<-1){ second=second+60;//小于0返回从 59开始} keycode4=0;}} if(keycode2==1){ P2_0=0;//用来区别是否在改的状态,让时秒暗一//改分 keycode4=0;}} if(keycode2==2){ P2_0=0;//用来区别是否在改的状态,让分秒暗一//改时 些P2_1=0;P2_4=0;P2_5=0; if(keycode3==1)//加分 { if(keytcount==0){ minute++;} minute=minute+keytcount*10;keytcount=0;if(minute==60){ minute=0;} if(minute>60){ minute=minute-60;} keycode3=0;} if(keycode4==1)//减分{ if(keytcount==0){ minute--;} minute=minute-keytcount*10;keytcount=0;if(minute==-1){ minute=59;} if(minute<-1){ minute=minute+60;} 些P2_1=0;P2_2=0;P2_3=0; for(i=6;i>0;i--){} if(keycode3==1)//加时 { if(keytcount==0){hour++;} hour=hour+keytcount*10;keytcount=0;if(hour==24){hour=0;} if(hour>24&&hour<44){ hour=hour-20;} if(hour>=44){ hour=hour-40;} keycode3=0;} if(keycode4==1)//减时{ if(keytcount==0){hour--;} hour=hour-keytcount*10;keytcount=0;if(hour==-1) {hour=23;} if(hour<-1&&hour>-24){ hour=hour+20;} if(hour<=-24){ hour=hour+40;} keycode4=0;}} if(keycode2==3){ keycode2=0;}} void time(){ if(tcount>=20){ second++;tcount=0;} if(second>=60){ minute++;second=0;} if(minute>=60){hour++;minute=0;} if(hour>=24){hour=0;}} void alarm(void){ static unsigned int flag,tcountn,fh; //30s闹钟 {fh++;if(fh==1){RD=0; //正常计时 停 //30s闹钟,可通过按第4排第3个键 if(second==alarm_second&&minute==alarm_minute&&hour==alarm_hour){flag=1;} if(keycode3==1){flag=0;RD=1;} if(flag==1){ if(tcount02s>=4){RD=~RD;tcount02s=0;tcountn++;} if(tcountn>=150){RD=1;}} if(second==0&&minute==0) //整点报时 delay();delay();delay();delay();delay();delay();delay();delay();delay();RD=1;}} if(second!=0)fh=0;}//主程数void main(){ TMOD=0X21; //T0方式1 EA=1;ET0=1;ET1=1;TR1=1; TH0=-46312/256;TL0=-46312%256;TH1=6;TL1=6;while(1){ keycode(); if(keycode1==1) //改闹钟时间{ P1_5=0;//第6个二极管作些状态指示灯P1_6=1;P1_4=1;TR0=1;set_alarm();time();}else{ if(keycode1==2){ P1_5=1;//第5个二极管作些状态指示灯P1_6=1;P1_4=0;TR0=1;time();alarm(); if(tcount03==200)改闹钟设置状态{ keycode1=4;}} if(keycode1==3) //改时间{ P1_5=1;//第7个二极管作些状态指示灯P1_6=0;P1_4=1;set_clock();} if(keycode1==4) //还原计时//约10秒后,可以跳过 //还原计时 { P1_5=1;//第5个二极管作些状态指示灯P1_6=1;P1_4=0;TR0=1;time();alarm();} if(keycode1==5){ keycode1=1;} table3[0]=table2[hour/10];应时分秒显示码赋给数组3table3[1]=table2[hour%10];table3[2]=table2[minute/10];table3[3]=table2[minute%10];table3[4]=table2[second/10];table3[5]=table2[second%10];}};} void t0() interrupt 1{ tcount++;tcount02s++;tcount03++;间变量 TH0=-46312/256;TL0=-46312%256;} void t1() interrupt 3{ static unsigned char tcount1,j;tcount1++;if(tcount1==15){ tcount1=0;j++;} if(j==6)j=0;P0=table3[j];P2=table1[j];} //时间累加并显示 //中断显示 //正常计时的时间变量//30闹钟响的时间变量 //跳过改时间状态的时 //50MS时间中断 //把对 //返回闹钟 因篇幅问题不能全部显示,请点此查看更多更全内容