可编程作息时间控制器设计Company number:【0089WT-8898YT-W8CCB-BUUT-202108】信息工程学院课程设计报告书题目: 可编程作息时间控制器设计专业:电子信息科学与技术班级:学号:学生姓名指导教师:2013 年 5 月 13日信息工程学院课程设计任务书年月日信息工程学院课程设计成绩评定表摘要本设计是可编程作息时间控制器设计,由单片机AT89C51芯片和LCD、LED显示器,辅以必要的电路,构成一个单片机四路可调闹钟。
电子钟可采用数字电路实现,也可以采用单片机来完成。
LCD 显示“时”,“分”,LED亮灯来表示闹钟的到来,定时时间到能发出警报声。
现在是自动化高度发达的时代,特别是电子类产品都是靠内部的控制电路来实现对产品的控制,达到自动运行的目的,这就需要我们这里要做的设计中的电器元件及电路的支持。
在这次设计中主要是用AT89S51来进行定时,也结合着其他辅助电路实施控制,在定时的时候,按一下控制小时的键对小时加一;按一下控制分钟的键对分钟加一;到达预设的时间,此电路就会发出报警声音提示已经到点。
关键字:四路可调闹钟 AT89C51 LCD目录1 任务提出与方案论证单片机型号的选择通过对多种单片机性能的分析,最终认为AT89C51是最理想的电子时钟开发芯片。
AT89C51是一种带4K字节闪烁可编程可擦除只读存储器的低电压,高性能CMOS8位微处理器,器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。
由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的AT89C51是一种高效微控制器,而且它与MCS-51兼容,且具有4K字节可编程序存储器和1000次擦写循环,数据保留时间为10年,是最好的选择。
按键的选择本次设计按照题目要求使用独立式按键。
由于按键较少,在修改时间或设置闹铃时间时就不能直接输入,只能通过加或减完成,稍为麻烦一些,但其程序简单。
显示器的选择选用1602LCD液晶显示器。
计时部分的选择如果使用时钟芯片,系统就不怕掉电且时间精确。
但这种芯片比较贵,况且,设计本系统主要是为了学习单片机程序的编写和调试以及设计硬件电路的一些方法,因此采用软件的方法来计时而没有采用价格较高的时钟芯片。
2 总体设计系统总框图原理及工作过程说明制作一个可编程作息时间控制器闹钟,当4路闹钟中的任一路到时,均会点亮灯、打铃。
如有需求,可对程序进行调整,增加闹钟的路数及到时后的处理方式。
定时闹钟的基本功能如下。
(1)显示时钟时间,格式为“时时:分分”,并可重新设置。
(2)显示闹铃时间,格式为“时时:分分”,且显示闪烁以便与时钟时间相区分。
闹铃时间可重新设置。
(3)程序执行后工作指示灯LED闪烁,表示时钟工作为时钟显示模式.LCD 显示的初始时间为“23:58”。
按下K2,闪烁显示的“00:00”为闹铃的时间,单击K3又返回时钟显示模式。
时钟从“23:58”开始计时,定时时间“00:00”到时,继电器开关接通,控制电器的开启,且可发出声响(可控)。
时钟与闹铃时问的设置可通过4个功能按键Kl~K4实现,具体说明如下。
(1)时钟时间的设置:首先单击Kl进入时钟设置模式。
此时每单击一下Kl,则小时增l,单击一下K2,则分钟增1,再单击K3则设置完成,返回时钟显示模式。
此时小时和分钟均已发生变化。
(2)闹铃的时间设置:首先单击,K3进入闹铃的设置模式。
此时每单击一下Kl,则小时增1,单击一下K2,则分钟增l,最后单击.K3则设置完成,返回闹铃显示模式。
此时闹铃的小时和分钟均已发生变化。
(3) K4的功能:闹钟更换。
(4) K2单独的功能:显示闹铃时间。
系统电路图3详细设计主程序部分的设计程序部分主要采用了程序结构的模块化设计,避免了一些函数的不必要的重复书写,使程序变得单间易懂。
程序在执行时,主程序要须通过调用子函数就可完成相应的功能。
主程序流程图如下图3-1。
图3-1主程序流程图独立式键盘的接口电路在单片机应用系统中,有时只需要几个简单的按键向系统输入信息。
这时,可将每个按键接在一根I/O接口线上,这种方式的连接称为独立式键盘。
每个独立式按键单独占有一根 I/O接口线,每根I/O接口线的工作状态不会影响到其他 I/O接口线。
这种按键接口电路配置灵活,硬件结构简单,但每个按键必须占用一根I/O接口线,I/O接口线浪费较大。
故只在按键数量不多时采用这种按键电路。
在此电路中,按键输入都采用低电平有效。
1602LCD液晶显示器1602LCD的基本参数及引脚功能1602LCD分为带背光和不带背光两种,基控制器大部分为HD44780,带背光的比不带背光的厚,是否带背光在应用中并无差别,两者尺寸差别如下图3-3-1所示:图3-3-11602LCD尺寸图1602LCD主要技术参数:显示容量:16×2个字符芯片工作电压:—工作电流:模块最佳工作电压:字符尺寸:×(W×H)mm引脚功能说明1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如表3-1所示:表3-1:引脚接口说明表第1脚:VSS为地电源。
第2脚:VDD接5V正电源。
第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。
第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。
当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:D0~D7为8位双向数据线。
第15脚:背光源正极。
第16脚:背光源负极。
10.8.2.3 1602LCD的指令说明及时序1602液晶模块内部的控制器共有11条控制指令,如表3-2所示:表3-2:控制命令表1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
(说明:1为高电平、0为低电平)指令1:清显示,指令码01H,光标复位到地址00H位置。
指令2:光标复位,光标返回到地址00H。
指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。
高电平表示有效,低电平则无效。
指令4:显示开关控制。
D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。
指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。
指令7:字符发生器RAM地址设置。
指令8:DDRAM地址设置。
指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:写数据。
指令11:读数据。
与HD44780相兼容的芯片时序表如下:表3-3:基本操作时序表读写操作时序如图3-3-2和3-3-3所示:图3-3-3 读操作时序图3-3-3写操作时序1602LCD的RAM地址映射及标准字库表液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。
要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,图3-3-4是1602的内部显示地址。
图3-3-4 1602LCD内部显示地址在对液晶模块的初始化中要先设置其显示模式,在液晶模块显示字符时光标是自动右移的,无需人工干预。
每次输入指令前都要判断液晶模块是否处于忙的状态。
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如图3-3-5所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”图3-3-5字符代码与图形对应图1602LCD的一般初始化(复位)过程延时15mS写指令38H(不检测忙信号)延时5mS写指令38H(不检测忙信号)延时5mS写指令38H(不检测忙信号)以后每次写指令、读/写数据操作均需要检测忙信号写指令38H:显示模式设置写指令08H:显示关闭写指令01H:显示清屏写指令06H:显示光标移动设置写指令0CH:显示开及光标设置闹钟子函数闹钟时间的判别主要是通过设定时间与实时时间对逐位对比确定是否进行闹铃。
其工作流程图如下图3-4。
4总结通过自己的不懈努力,我终于完成了设计的任务要求。
功能上基本达标:时钟的显示,日期显示,调时功能、校时功能、闹铃功能、闹钟设功能。
其精确可以满足日常生活显示时间的需要。
在本次设计的过程中,我发现很多的问题,虽然以前没有做过这样的设计但通过这次设计我学会了很多东西,单片机课程设计重点就在于软件算法的设计,需要有很巧妙的程序算法,虽然以前写过几次程序,但我觉的写好一个程序并不是一件简单的事,比如写一个程序看其功能很少认为编写程序简单,但到编程的时候才发现一些细微的知识或低级错误经常犯做不到最后常常失败,所以有些东西只有学精弄懂并且要细心才行,只学习理论有些东西是很难理解的,更谈不上掌握。
从这次的课程设计中,我们真真正正的意识到,在以后的学习中,要理论联系实际,把我们所学的理论知识用到实际当中,学习单机片机更是如此,程序只有在经常的练习的过程中才能提高,我想这就是我在这次课程设计中的最大收获。
参考文献[1]《单片机原理及应用(第二版)》张毅刚彭喜元彭宇北京高等教育出版社[2]刘和平. 单片机编程与入门.重庆大学出版社,,111-122[3]陈明荧. 89C51单片机课程设计实训教材.清华大学出版社,,102-118附录#include<>#define uint unsigned int#define uchar unsigned charsbit key1=P1^0;sbit key2=P1^1;sbit key3=P1^2;sbit key4=P1^3;sbit lcden=P3^4;sbit lcdrs=P3^5;sbit lcdrw=P3^6;sbit led=P2^2;sbit sound=P2^7;int a,b,i,min,hour,minge,minshi,hourge,hourshi,sec,secge,secshi,cnt,cnt1, nian=2013,yue=5,ri=5,amin1=1,ahour1,aminge1,aminshi1,ahourge1,ahourshi1,amin2=1,ahour2,aminge2,aminshi2,ahourge2,ahourshi2,amin3=1,ahour3,aminge3,aminshi3,ahourge3,ahourshi3,amin4=1,ahour4,aminge4,aminshi4,ahourge4,ahourshi4; uchar code table1[]={'0','1','2','3','4','5','6','7','8','9'};uchar code table2[]="Time:00:00 " ;uchar code Alarm_1[]="Alar1:00:00 ";uchar code Alarm_2[]="Alar2:00:00 ";uchar code Alarm_3[]="Alar3:00:00 ";uchar code Alarm_4[]="Alar4:00:00 ";uchar code riqi[]="2013-05-06 ";uchar num1,num2,alarm1,alarm2,alarm3,alarm4;bit flag=0;void delay(unsigned int z) //延时程序{uint i,j;for(i=z;i>0;i--)for(j=110;j>0;j--);}void write_com(uchar com) //LCD命令控制,写指令函数{delay(5) ;lcdrs=0;P0=com;delay(5);lcden=1;delay(5);lcden=0;}void write_data(uchar date) //LCD数据控制,写数据函数{delay(5);lcdrs=1;P0=date;delay(5);lcden=1;delay(5);lcden=0;}void write_nian(uchar add , uint date) //年显示函数{uchar qian,bai,shi,ge;qian=date/1000;bai=(date-1000*qian)/100;shi=(date-qian*1000-bai*100)/10;ge=date%10;write_com(0x80+0x40+add);write_data(table1[qian]);write_data(table1[bai]);write_data(table1[shi]);write_data(table1[ge]);}void write_yue(uchar add , uchar date) //月显示函数 {uchar shi,ge;shi=date/10;ge=date%10;write_com(0x80+0x40+add);write_data(0x30+shi);write_data(0x30+ge);}void write_ri(uchar add , uchar date) //日显示函数 {uchar shi,ge;shi=date/10;ge=date%10;write_com(0x80+0x40+add);write_data(0x30+shi);write_data(0x30+ge);}void qi(){write_nian(0,nian);write_yue(5,yue);write_ri(8,ri);write_com(0x80+0x40+7);write_data('-');write_com(0x80+0x40+4);write_data('-');}void time() //设置时间函数{while(1){if(key1==0){delay(10);if(key1==0){if(hour==23) //"时"设置hour=0;elsehour++;hourge=hour%10;hourshi=hour/10;write_com(0x0f);delay(2);write_com(0x80+6);write_data(table1[hourge]); //"时"个位写入LCD第1行第6位delay(5);write_com(0x80+5);delay(2);write_data(table1[hourshi]); //"时"十位写入LCD第1行第5位while(!key1);}}if(key2==0){delay(10);if(key2==0){if(min==59) //"分"设置min=0;elsemin++;minge=min%10;minshi=min/10;write_com(0x0f);write_com(0x80+9);write_data(table1[minge]); //"分"个位写入LCD第二行第9位delay(1);write_com(0x80+8);write_data(table1[minshi]); //"分"十位写入LCD第二行第8位delay(1);while(!key2);}}if(key3==0){delay(10);if(key3==0){write_com(0x0c); //整体显示,关光标,不闪烁TR1=1; //定时计数器1启动while(!key3);break; //key3松开时,显示时间"时""分"位均已设置完毕}}}}void display1() //设置闹钟1时间函数{while(1){if(key1==0){delay(10);if(key1==0){if(ahour1==23) //闹钟"时"设置ahour1=0;elseahour1++;ahourge1=ahour1%10;ahourshi1=ahour1/10;write_com(0x0f);write_com(0x80+0x40+8);write_data(':');write_com(0x80+0x40+7);write_data(table1[ahourge1]);delay(1);write_com(0x80+0x40+6);write_data(table1[ahourshi1]);delay(1);while(!key1);}}if(key2==0) //闹钟"分"设置{delay(10);if(key2==0){if(amin1==59)amin1=0;elseamin1++;aminge1=amin1%10;aminshi1=amin1/10;write_com(0x0f);write_com(0x80+0x40+10);write_data(table1[aminge1]);delay(1);write_com(0x80+0x40+9);write_data(table1[aminshi1]);delay(1);while(!key2);}}if(key3==0){alarm1=~alarm1;delay(10);if(key3==0){write_com(0x0c);write_com(0x80+0x40);for(i=0;i<11;i++)write_data(riqi[i]);while(!key3);break; //设置结束,此时LCD第二行无数据显示,只有第一行有时间显示}}}}void display2() //设置闹钟2时间函数{while(1){if(key1==0){delay(10);if(key1==0){if(ahour2==23) //闹钟"时"设置ahour2=0;elseahour2++;ahourge2=ahour2%10;ahourshi2=ahour2/10;write_com(0x0f);write_com(0x80+0x40+8);write_data(':');write_com(0x80+0x40+7);write_data(table1[ahourge2]);delay(1);write_com(0x80+0x40+6);write_data(table1[ahourshi2]);delay(1);while(!key1);}}if(key2==0) //闹钟"分"设置{delay(10);if(key2==0){if(amin2==59)amin2=0;elseamin2++;aminge2=amin2%10;aminshi2=amin2/10;write_com(0x0f);write_com(0x80+0x40+10);write_data(table1[aminge2]);delay(1);write_com(0x80+0x40+9);write_data(table1[aminshi2]);delay(1);while(!key2);}}if(key3==0){alarm2=~alarm2;delay(10);if(key3==0){write_com(0x0c);write_com(0x80+0x40);for(i=0;i<11;i++)write_data(riqi[i]);while(!key3);break; //设置结束,此时LCD第二行无数据显示,只有第一行有时间显示}}}}void display3() //设置闹钟3时间函数{while(1){if(key1==0){delay(10);if(key1==0){if(ahour3==23) //闹钟"时"设置ahour3=0;elseahour3++;ahourge3=ahour3%10;ahourshi3=ahour3/10;write_com(0x0f);write_com(0x80+0x40+8);write_data(':');write_com(0x80+0x40+7);write_data(table1[ahourge3]);delay(1);write_com(0x80+0x40+6);write_data(table1[ahourshi3]);delay(1);while(!key1);}}if(key2==0) //闹钟"分"设置{delay(10);if(key2==0){if(amin3==59)amin3=0;elseamin3++;aminge3=amin3%10;aminshi3=amin3/10;write_com(0x0f);write_com(0x80+0x40+10);write_data(table1[aminge3]);delay(1);write_com(0x80+0x40+9);write_data(table1[aminshi3]);delay(1);while(!key2);}}if(key3==0){alarm3=~alarm3;delay(10);if(key3==0){write_com(0x0c);write_com(0x80+0x40);for(i=0;i<11;i++)write_data(riqi[i]);while(!key3);break; //设置结束,此时LCD第二行无数据显示,只有第一行有时间显示}}}}void display4() //设置闹钟4时间函数{while(1){if(key1==0){delay(10);if(key1==0){if(ahour4==23) //闹钟"时"设置ahour4=0;elseahour4++;ahourge4=ahour4%10;ahourshi4=ahour4/10;write_com(0x0f);write_com(0x80+0x40+8);write_data(':');write_com(0x80+0x40+7);write_data(table1[ahourge4]);delay(1);write_com(0x80+0x40+6);write_data(table1[ahourshi4]);delay(1);while(!key1);}}if(key2==0) //闹钟"分"设置{delay(10);if(key2==0){if(amin4==59)amin4=0;elseamin4++;aminge4=amin4%10;aminshi4=amin4/10;write_com(0x0f);write_com(0x80+0x40+10);write_data(table1[aminge4]);delay(1);write_com(0x80+0x40+9);write_data(table1[aminshi4]);delay(1);while(!key2);}}if(key3==0){alarm4=~alarm4;delay(10);if(key3==0){write_com(0x0c);write_com(0x80+0x40);for(i=0;i<11;i++)write_data(riqi[i]);while(!key3);break; //设置结束,此时LCD第二行无数据显示,只有第一行有时间显示}}}}void keyscan() //键盘扫描{if(key1==0){delay(10);if(key1==0){while(!key1); //key1键松开后执行下一行程序time(); //调用time()函数,即时间设置}}else if(key2==0){ cnt1++;delay(10);if(cnt1==1){while(!key2){ahourge1=ahour1%10;ahourshi1=ahour1/10;write_com(0x80+0x40+7);write_data(table1[ahourge1]);delay(5);write_com(0x80+0x40+6);delay(2);write_data(table1[ahourshi1]);aminge1=amin1%10;aminshi1=amin1/10;write_com(0x80+0x40+10);write_data(table1[aminge1]);delay(5);write_com(0x80+0x40+9);delay(2);write_data(table1[aminshi1]);write_com(0x80+0x40);for(i=0;i<11;++i)write_data(Alarm_1[i]); //显示闹钟设置的时间}write_com(0x80+0x40);for(i=0;i<11;i++)write_data(riqi[i]); //key2松开后,LCD只有第一行显示时间,闹钟设置时间不显示}if(cnt1==2){while(!key2){ahourge2=ahour2%10;ahourshi2=ahour2/10;write_com(0x80+0x40+7);write_data(table1[ahourge2]);delay(5);write_com(0x80+0x40+6);delay(2);write_data(table1[ahourshi2]);aminge1=amin1%10;aminshi1=amin1/10;write_com(0x80+0x40+10);write_data(table1[aminge2]);delay(5);write_com(0x80+0x40+9);delay(2);write_data(table1[aminshi2]);write_com(0x80+0x40);for(i=0;i<11;++i)write_data(Alarm_2[i]); //显示闹钟设置的时间}write_com(0x80+0x40);for(i=0;i<11;i++)write_data(riqi[i]); //key2松开后,LCD只有第一行显示时间,闹钟设置时间不显示}if(cnt1==3){while(!key2){ahourge3=ahour3%10;ahourshi3=ahour3/10;write_com(0x80+0x40+7);write_data(table1[ahourge3]);delay(5);write_com(0x80+0x40+6);delay(2);write_data(table1[ahourshi3]);aminge1=amin1%10;aminshi1=amin1/10;write_com(0x80+0x40+10);write_data(table1[aminge3]);delay(5);write_com(0x80+0x40+9);delay(2);write_data(table1[aminshi3]);write_com(0x80+0x40);for(i=0;i<11;++i)write_data(Alarm_3[i]); //显示闹钟设置的时间}write_com(0x80+0x40);for(i=0;i<11;i++)write_data(riqi[i]); //key2松开后,LCD只有第一行显示时间,闹钟设置时间不显示}if(cnt1==4){while(!key2){ahourge4=ahour4%10;ahourshi4=ahour4/10;write_com(0x80+0x40+7);write_data(table1[ahourge4]);delay(5);write_com(0x80+0x40+6);delay(2);write_data(table1[ahourshi4]);aminge1=amin1%10;aminshi1=amin1/10;write_com(0x80+0x40+10);write_data(table1[aminge4]);delay(5);write_com(0x80+0x40+9);delay(2);write_data(table1[aminshi4]);write_com(0x80+0x40);for(i=0;i<11;++i)write_data(Alarm_4[i]); //显示闹钟设置的时间}write_com(0x80+0x40);for(i=0;i<11;i++)write_data(riqi[i]); //key2松开后,LCD只有第一行显示时间,闹钟设置时间不显示}if(cnt1>4)cnt1=0;}else if(key3==0){cnt++;delay(10);if(cnt==1){while(!key3); //表示闹钟时间设置退出ahourge1=ahour1%10;ahourshi1=ahour1/10;write_com(0x80+0x40+7);write_data(table1[ahourge1]);delay(5);write_com(0x80+0x40+6);delay(2);write_data(table1[ahourshi1]);aminge1=amin1%10;aminshi1=amin1/10;write_com(0x80+0x40+10);write_data(table1[aminge1]);delay(5);write_com(0x80+0x40+9);delay(2);write_data(table1[aminshi1]);write_com(0x80+0x40);for(i=0;i<11;++i)write_data(Alarm_1[i]);display1();}if(cnt==3){while(!key3); //表示闹钟时间设置退出ahourge2=ahour2%10;ahourshi2=ahour2/10;write_com(0x80+0x40+7);write_data(table1[ahourge2]);delay(5);write_com(0x80+0x40+6);delay(2);write_data(table1[ahourshi2]);aminge2=amin2%10;aminshi2=amin2/10;write_com(0x80+0x40+10);write_data(table1[aminge2]);delay(5);write_com(0x80+0x40+9);delay(2);write_data(table1[aminshi2]);write_com(0x80+0x40);for(i=0;i<11;++i)write_data(Alarm_2[i]);display2();}if(cnt==5){while(!key3); //表示闹钟时间设置退出ahourge3=ahour3%10;ahourshi3=ahour3/10;write_com(0x80+0x40+7);write_data(table1[ahourge3]);delay(5);write_com(0x80+0x40+6);delay(2);write_data(table1[ahourshi3]);aminge3=amin3%10;aminshi3=amin3/10;write_com(0x80+0x40+10);write_data(table1[aminge3]);delay(5);write_com(0x80+0x40+9);delay(2);write_data(table1[aminshi3]);write_com(0x80+0x40);for(i=0;i<11;++i)write_data(Alarm_3[i]);display3();}if(cnt==7){while(!key3); //表示闹钟时间设置退出ahourge4=ahour4%10;ahourshi4=ahour4/10;write_com(0x80+0x40+7);write_data(table1[ahourge4]);delay(5);write_com(0x80+0x40+6);delay(2);write_data(table1[ahourshi4]);aminge4=amin4%10;aminshi4=amin4/10;write_com(0x80+0x40+10);write_data(table1[aminge4]);delay(5);write_com(0x80+0x40+9);delay(2);write_data(table1[aminshi4]);write_com(0x80+0x40);for(i=0;i<11;++i)write_data(Alarm_4[i]);display4();}if(cnt>10){cnt=0;}}else if(key4==0)delay(5);if(key4==0){while(!key4);a++;if(a%2==0){for(b=0;b<6;b++){sound=~sound;delay(200);}sound=1;}else if(a%2==1){sound=0;delay(300);sound=1;delay(300);}sound=1;}}void lcd_init() //LCD初始化{lcden=0;lcdrw=0;write_com(0x38); //设置8位格式,2行,5×7write_com(0x0c); //整体显示,关光标,不闪烁write_com(0x06); //设定输入方式,增量不转移write_com(0x01); //清除屏幕显示delay(2);write_com(0x80);for(i=0;i<16;i++){write_data(table2[i]); //写入显示时间数据delay(1);}}void judge(){if(sec==60){min++;sec=0;}if(min==60){hour++;min=0;}if(hour==24){ri++;hour=0;}if(ri==30){yue++;ri=1;}if(yue==12){nian++;yue=1;}}void init() //C51初始化函数{key1=1;key2=1;key3=1;key4=1;sec=0;a=0;sound=1;TMOD=0x10; //定时计数器T1工作在方式1TL1=0xB0;TH1=0x3C; //计数初值为15536EA=1;ET1=1;TR1=1;}void speak()//music{if(amin1==min&&ahour1==hour||amin2==min&&ahour2==hour||amin3==mi n||amin4==min) //显示时间与闹钟设置时间完全一样且闹钟"on"{delay(5);sound=0;led=0;}delay(10);delay(10);delay(10);led=1;sound=1;}void led1() interrupt 3 //LED1中断函数{TL1=0xB0;TH1=0x3C;speak();//num1++;num2++;if(num2==20){sec++;num2=0;judge();}}void main() //主函数{lcd_init(); //LCD初始化函数init(); //51初始化函数while(1){keyscan(); //调用扫描函数minge=min%10;minshi=min/10;write_com(0x80+9);write_data(table1[minge]);delay(5);write_com(0x80+8);write_data(table1[minshi]);hourge=hour%10;hourshi=hour/10;write_com(0x80+6);write_data(table1[hourge]);delay(5);write_com(0x80+5);write_data(table1[hourshi]);write_com(0x80+7);write_data(':');delay(5);secge=sec%10; //扩展秒表功能secshi=sec/10;write_com(0x80+15);write_data(table1[secge]);delay(5);write_com(0x80+14);write_data(table1[secshi]);qi();}}。