课程设计-智能电子钟
发布时间:2012-06-01 17:06:04
发布时间:2012-06-01 17:06:04
摘要
单片机经过几十年的发展,已经广泛应用于生活中的各个领域。单片机以其体积小、功能全、性价比高等诸多优点,在许多行业都得到了广泛应用。在工业控制、家用电器、通信设备、信息处理、尖端武器等各种测控领域的应用中独占鳌头,单片机开发技术已成为电子信息、电气、通信、自动化、机电一体化等专业技术人员必须掌握的技术。
基于单片机的智能电子钟作为设计的课题,因为它有很好的开放性和可发挥性,对作者的要求比较高,不仅考察了对单片机的掌握能力而且强调了对单片机扩展的应用。另外LCD的智能电子钟已经越来越流行,它具有显示清晰直观、走时准确、可以进行夜视等功能,并且还可以扩展出其它多种功能。所以,智能电子钟作为设计课题很有价值。
随着科技的发展,单片机的应用正在不断深入,涉及到日常生活的方方面面。本设计是基于单片机AT89S51为控制核心,以液晶为显示的数字时钟。本数字时钟设计的原理相对简单,所以硬件电路也相对简单,难点和重点主要放在C语言的编程上,使用到定时器的子程序、延时程序、时分秒的控制程序、液晶模块和单片机模块的初始化程序、液晶显示的程序等,各个函数交叉调用,配合主程序的运行。
关键字:LCD1602 AT89S51 定时器
第一章 设计要求
1.1 LCD电子钟的功能要求
(1)能显示年、月、日、时、分、秒(通常显示时、分、秒);
(2)能对年、月、日、时、分、秒进行预置;
(3)具有定时功能,定时时间到声光报告。
1.2 智能电子钟的设计要求
(1)主控部分:选择单片机为核心元件构成系统。
(2)1602LCD主要技术参数:
显示容量:16×2个字符;芯片工作电压:4.5—5.5V;工作电流:2.0mA(5.0V);模块最佳工作电压:5.0V;字符尺寸:2.95×4.35(W×H)mm。
(3) 功能设计:采用了AT89S52型单片机,1602LCD液晶显示屏,蜂鸣器、发光二极管。为了实现时钟,定时,闹钟,秒表的功能,用到了单片机的外部中断,计时器中断,及I/O端口。
(4)S0显示日期(按下显示日期,弹起后回到显示时间状态);
S1显示闹钟(按下显示闹钟,弹起后回到显示时间状态);
S2设置日期(按键1次设置年,2次设置月,3次设置日);
S3设置时间(按键1次设置星期,2次设置时,3次设置分,4次设置秒);
S4设置闹钟(按键1次设置时,2次设置分,3次设置秒);
S5增加一(设置中对所选择变量加一);
S6减少一(设置中对所选择变量减一)。
(5) 主程序循环显示当前的时间并扫描按键S0对应P3.0(显示日期)和按键S1对应P3.1(显示闹钟时刻)是否有按下,并比较判断定时时刻是否到达;按键S2对应INT0中断用来设置日期,每按下一次可分别对年、月、日进行设置,P3.6和P3.7用来对所要设置的属性进行加一和减一操作,S7对应的P2.4统一的返回键,当处在中断设置状态时按此键可以返回至正常显示时间状态;按键S3对应INT1中断用来设置时间,操作同上面的日期设置;按键S4对应定时器T0,让T0工作在计数模式,通过设置计数初值为最大,当P3.3管脚来一个低电平时,加一后计数器产生溢出中断,以此用作外部中断来设置闹钟时刻。
第二章 方案选择与系统框图及工作原理
2.1 方案选择
本次实验采用了AT89S52型单片机,1602LCD液晶显示屏,蜂鸣器、发光二极管。为了实现时钟,定时,闹钟,秒表的功能,用到了单片机的外部中断,计时器中断,及I/O端口.
2.2 系统框图
图2.1 系统框图
2.3 工作原理
程序循环显示当前的时间并扫描按键S0对应P3.0(显示日期)和按键S1对应P3.1(显示闹钟时刻)是否有按下,并比较判断定时时刻是否到达;按键S2对应INT0中断用来设置日期,每按下一次可分别对年、月、日进行设置,P3.6和P3.7用来对所要设置的属性进行加一和减一操作,S7对应的P2.4统一的返回键,当处在中断设置状态时按此键可以返回至正常显示时间状态;按键S3对应INT1中断用来设置时间,操作同上面的日期设置;按键S4对应定时器T0,让T0工作在计数模式,通过设置计数初值为最大,当P3.3管脚来一个低电平时,加一后计数器产生溢出中断,以此用作外部中断来设置闹钟时刻。
第三章 硬件电路设计与分析
3.1 控制模块
1. AT89S52
图3.1.1 AT89S52模块
2. 晶振电路
图3.1.2 晶振电路
3. 复位电路
图3.1.3 复位电路
以上三部分构成了单片机最小系统,其中P0和P2口的部分管脚接显示模块,P3口接控制模块,P2口的部分管脚接报警模块。
3.2 显示模块
图3.2.1 显示模块
1602LCD主要技术参数:
显示容量:16×2个字符
芯片工作电压:4.5—5.5V
工作电流:2.0mA(5.0V)
模块最佳工作电压:5.0V
字符尺寸:2.95×4.35(W×H)mm
引脚功能说明:
1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如下表3.2.1所示:
表3.2.1 引脚接口说明表
编号 | 符号 | 引脚说明 | 编号 | 符号 | 引脚说明 |
1 | VSS | 电源地 | 9 | D2 | 数据 |
2 | VDD | 电源正极 | 10 | D3 | 数据 |
3 | VL | 液晶显示偏压 | 11 | D4 | 数据 |
4 | RS | 数据/命令选择 | 12 | D5 | 数据 |
5 | R/W | 读/写选择 | 13 | D6 | 数据 |
6 | E | 使能信号 | 14 | D7 | 数据 |
7 | D0 | 数据 | 15 | BLA | 背光源正极 |
8 | D1 | 数据 | 16 | BLK | 背光源负极 |
第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脚:背光源负极。
硬件连接原理图如下:
图3.2.2 硬件连接原理图
3.3 按键电路
图3.3.1 按键电路图
S0显示日期(按下显示日期,弹起后回到显示时间状态);
S1显示闹钟(按下显示闹钟,弹起后回到显示时间状态);
S2设置日期(按键1次设置年,2次设置月,3次设置日);
S3设置时间(按键1次设置星期,2次设置时,3次设置分,4次设置秒);
S4设置闹钟(按键1次设置时,2次设置分,3次设置秒);
S5增加一(设置中对所选择变量加一);
S6减少一(设置中对所选择变量减一);
3.4 报警部分模块
图3.4.1 报警部分模块
第四章 软件设计与分析
4.1 基本资源的使用
本次实验采用了AT89S52型单片机,1602LCD液晶显示屏,蜂鸣器、发光二极管。为了实现时钟,定时,闹钟,秒表的功能,用到了单片机的外部中断,计时器中断,及I/O端口.
表4.2.1 资源功能表
资源 | 功能 | |
外部中断 | 外部中断INT1 | 设置时分秒(每按一次改变设置类型) |
外部中断INT0 | 设置年月日(每按一次改变设置类型) | |
定时器 | 定时器T0 | 用溢出中断设置闹钟(每按一次改变设置类型) |
定时器T1 | 定时器中断(每隔1S调整一次时间) | |
I/O端口 | P0,P2,P3 | LCD接口,蜂鸣器、发光二极管、按键 |
4.2 程序设计的基本思路
主程序循环显示当前的时间并扫描按键S0对应P3.0(显示日期)和按键S1对应P3.1(显示闹钟时刻)是否有按下,并比较判断定时时刻是否到达;按键S2对应INT0中断用来设置日期,每按下一次可分别对年、月、日进行设置,P3.6和P3.7用来对所要设置的属性进行加一和减一操作,S7对应的P2.4统一的返回键,当处在中断设置状态时按此键可以返回至正常显示时间状态;按键S3对应INT1中断用来设置时间,操作同上面的日期设置;按键S4对应定时器T0,让T0工作在计数模式,通过设置计数初值为最大,当P3.3管脚来一个低电平时,加一后计数器产生溢出中断,以此用作外部中断来设置闹钟时刻。
4.3 程序的主要流程图
图4.3.1 按键程序流程图
图4.3.2 年、月、日程序框图
第五章 Protues仿真与调试
本实验采用Keil 4和Protues 7.7SP2联合仿真调试
图5.1 Protues仿真图
显示时间:
图5.2 时间显示图
设置日期:
图5.3 日期显示图
设置闹钟:
图5.4 闹铃显示图
仿真结果:
经过多次的反复测试与分析,掌握了硬件的设计与分析的能力,对所学的知识得到很大的提高与巩固。
最终实现功能:
(1)能显示阳历年、月、日、星期、小时、分、秒
(2)显示模块采用LCD液晶显示,要求能用按键调整日期、时间和闹钟。
(3)能进行定时,并进行声光报警。
第六章 PCB板的设计
图6.1 PCB板设计图
在PCB设计中,布线是完成产品设计的重要步骤,可以说前面的准备工作都是为它而做的, 在整个PCB中,以布线的设计过程限定最高,技巧最细、工作量最大。PCB布线有单面布线、 双面布线及多层布线。布线的方式也有两种:自动布线及交互式布线,在自动布线之前, 可以用交互式预先对要求比较严格的线进行布线,输入端与输出端的边线应避免相邻平行, 以免产生反射干扰。必要时应加地线隔离,两相邻层的布线要互相垂直,平行容易产生寄生耦合。一般先进行探索式布经线,快速地把短线连通, 然后进行迷宫式布线,先把要布的连线进行全局的布线路径优化,它可以根据需要断开已布的线。 并试着重新再布线,以改进总体效果。对目前高密度的PCB设计已感觉到贯通孔不太适应了, 它浪费了许多宝贵的布线通道,为解决这一矛盾,出现了盲孔和埋孔技术,它不仅完成了导通孔的作用, 还省出许多布线通道使布线过程完成得更加方便,更加流畅,更为完善,PCB 板的设计过程是一个复杂而又简单的过程,要想很好地掌握它,自已体会, 才能得到其中的真谛。
第七章 原件明细清单
表7.1 原件明细清单表
名称 | 数量 | 参数 |
电阻 | 1个 | 1K |
排阻 | 1个 | 10K |
电阻 | 1个 | 220 |
蜂鸣器 | 1个 | 5v |
按键 | 9个 | |
三极管 | 1个 | PNP |
发光二级管 | 1个 | 10-20mA |
LCD显示器 | 1个 | 1602LCD |
极性电容 | 1个 | 10uF |
晶振及其插座 | 一套 | 12MHz |
电阻 | 2个 | 2k,10k |
电容 | 2个 | 30pF |
芯片 | 1块 | AT89S51 |
第八章 课程设计总结
本次智能电子时钟的实验课程设计,学习将理论和实践相结合,对数字器件及集成电路有较深入的认识,初步掌握综合运用所学知识分析和设计一般数字系统的基本方法,增强动手解决实际问题的能力。认识到了自身的许多缺点和不足,初步接触到了如何将硬件和软件相连接来实现一定的自动化。在试验板的焊接过程中,更深地意识到焊接技术的重要性。使我明白现实生活中电子钟的工作原理,锻炼了查找资料的能力。通过这次课程设计,我深深体会到这句千古名言的真正含义.我今天认真的进行课程设计,学会脚踏实地迈开这一步,就是为明天能稳健地在社会大潮中奔跑打下坚实的基础。通过这次智能电子时钟设计,本人在多方面都有所提高。通过这次智能电子时钟设计,综合运用本专业所学课程的理论和生产实际知识进行智能电子时钟设计工作的实际训练从而培养和提高学生独立工作能力,巩固与扩充了课程所学的内容,掌握智能电子时钟设计的方法和步骤,掌握智能电子时钟设计的工艺方案,了解了智能电子时钟的基本结构,熟悉了规范和标准,同时各科相关的课程都有了全面的复习,独立思考的能力也有了提高。
致谢
本设计是在叶天凤老师及南光群老师的悉心指导下完成的,老师渊博的知识,严谨的治学态度,一丝不苟的工作作风,平易近人的性格都是我学习的楷模。在实物制作期间,老师给我们细心讲解制作过程和有关的注意事项,我在遇到困难的时候总是能得到及时的得到老师的帮助。在论文的研究及整理期间,老师给了我很大的支持和鼓励,才使得报告得以顺利的完成,在此谨向老师表示忠心的感谢和崇高的敬意。同时感谢实验室的等老师,他们给我们提供了必要的实验器材,提供了很大的方便感谢同实验室的同学,在实验期间,他们不仅在学习上对我有很大的帮助,还在生活上提供方便。这两个星期,我和他们合作的是非常愉快的。同时还要感谢各位同学,他们也给了我很大的支持和帮助。最后,由于本人知识有限,不足之处在所难免,还请老师指点纠正。
参考文献
[1]电气与电子信息工程学院.单片机实验指导书
[2]高峰编著.单片微型计算机原理与接口技术.北京:科学出版社,2003
[3]陈粤初等.单片机应用系统设计与实践.北京:北京航空航天大学出版社,1991
[4]邹逢兴主编.计算机硬件技术及应用基础.长沙:国防科技大学出版社,2001
[5]黄冰等编著.微机原理及应用. 重庆:重庆大学出版社,2003
[6]曾峰等.印制电路板(PCB)设计与制作.北京:电子工业出版社,2005
[7] 周润景,张丽娜,刘印群. PROTEUS入门实用教程[M].北京:机械工业出版社,2007,314-325
[8] 戴佳,戴卫恒. 51单片机C语言应用程序设计实例精讲[M].北京:电子工业出版社,2006,231-246
[9] 徐爱钧,彭秀华. Keil Cx51 V7.0 单片机高级语言编程与uVision2应用实践 [M].(第二版)北京:电子工业出版社,2008,156-171
[10] 肖炎根,舒望.基于实时钟芯片的电子万年历设计[J].电子技术,2007,卷号(36):91-94
[11] 王怀平,王仁波,胡开明.Proteus仿真设计基于单片机AT89C51的电子万年历[J].科技广场,2008,卷号(10):197-198
[12] 鲁刚强. 基于液晶显示器的单片机系统设计[J].科技资讯,2008,卷号(35):22-23
[13] 余威明. MCU语音型电子万年历的开发[J]. 浙江工贸职业技术学院学报,2004,卷号(4):20-25
[14] 邱关源. 电路 [M].(第四版)北京: 高等教育出版社, 2006, 241-268.
[15] 陈凯. 液晶显示万年历、时间、星期及温度[D].湖南:湖南理工学院,2009.
[16] 张海兵, 李 敏. Protel电路设计实例与分析[M]. 北京:人民邮电出版社, 2005,119-205
[17] 黄劼, 徐晓秋. 单片机原理及接口技术[M]. 北京:国防工业出版社,2008,102-112
[18] 刘迎春. MCS-51单片机原理及应用教程 [M]. 北京:清华大学出版社,2005,145-157
[19] 张齐, 朱宁西.单片机应用系统设计技术:基于C51的Proteus仿真[M].(第二版) 北京:电子工业出版社,2009,245-264
附录
附录1 硬件电路原理图
附录2 程序清单
/***********************************************************
DISPLAY.H
***********************************************************/
#include
#define uchar unsigned char
#include
#define __REG52_H__
/************************定义端口**********************************/
sbit rs = P2^0;
sbit rw = P2^1;
sbit en = P2^2;
struct dateType //定义日期数据类型
{
unsigned int year;
unsigned char month;
unsigned char day;
};
struct timeType //定义时间数据类型
{
unsigned char week;
unsigned char hour;
unsigned char min;
unsigned char sec;
};
//定义全局变量,日期、时间、闹钟和计数器
struct dateType dateNow={2000,2,29}; //设置默认日期 2000年2月29日
struct timeType timeNow={07,23,58,30}; //设置默认时间周日23:58:30
struct timeType setClock={0,0,05,20}; //设置默认的闹铃 00:05:20
unsigned char count=0;
void lcd_wdat(uchar date);
void lcd_wcmd(uchar com);
/**************************延时函数*********************************/
void delay2us(uchar k)
{
while(--k);
}
void delay1ms(uchar k)
{
int i,j;
for(i=k;i>0;i--)
for(j=110;j>0;j--);
}
void delay(unsigned int count)
{
unsigned int j;
while(count--!=0)
{
for(j=0;j<72;j++);
}
}
/*********************判定是否是闰年*********************/
unsigned char leap_year(unsigned int n)
{
if((n%4==0&&n%100!=0)||n%400==0)
return 1;
else
return 0;
}
/**********************判定是否是30天***********************/
unsigned char is_30day(unsigned char n)
{
switch(n)
{
case 1:
return 0;
case 2:
return 0;
case 3:
return 0;
case 4:
return 1;
case 5:
return 0;
case 6:
return 1;
case 7:
return 0;
case 8:
return 0;
case 9:
return 1;
case 10:
return 0;
case 11:
return 1;
case 12:
return 0;
default:return 0;
} }
/***********************1602初始化************************/
void lcd_init(void)
{
delay1ms(5);
lcd_wcmd(0x38);
lcd_wcmd(0x0c);
lcd_wcmd(0x06);
lcd_wcmd(0x01);
lcd_wcmd(0x80);
delay2us(200);
}
/******************设置显示位置*****************************/
void lcd_pos(unsigned char pos)
{
lcd_wcmd(pos | 0x80);
}
/***********************1602写指令***********************/
void lcd_wcmd(uchar com)
{
rs=0;
rw=0;
P0=com;
en=0;
delay2us(200);
en=1;
delay2us(200);
en=0;
}
/***********************1602写数据***********************/
void lcd_wdat(uchar date)
{
rs=1;
rw=0;
P0=date;
en=0;
delay2us(200);
en=1;
delay2us(200);
en=0;
}
/********************显示日期***************************************/
void display_date()
{
unsigned char array[16];
unsigned char i=0;
unsigned char j=0;
unsigned int temp=0;
array[i++]='D';
array[i++]=':';
array[i++]=dateNow.year/1000+0x30;
temp=dateNow.year%1000;
array[i++]=temp/100+0x30;
temp=temp%100;
array[i++]=temp/10+0x30;
array[i++]=temp%10+0x30;
array[i++]='-';
array[i++]=dateNow.month/10+0x30;
array[i++]=dateNow.month%10+0x30;
array[i++]='-';
array[i++]=dateNow.day/10+0x30;
array[i++]=dateNow.day%10+0x30;
array[i++]='\a';
delay1ms(10);
lcd_pos(0x00);//设置显示位置
while(array[j] != '\a')
{
lcd_wdat(array[j]);//显示字符
j++;
}
lcd_wcmd(0x02); //光标复位
}
/*****************中断内显示日期*****************************/
void idisplay_date()
{
unsigned char array[16];
unsigned char i=0;
unsigned char j=0;
unsigned int temp=0;
array[i++]='S';
array[i++]=':';
array[i++]=dateNow.year/1000+0x30;
temp=dateNow.year%1000;
array[i++]=temp/100+0x30;
temp=temp%100;
array[i++]=temp/10+0x30;
array[i++]=temp%10+0x30;
array[i++]='-';
array[i++]=dateNow.month/10+0x30;
array[i++]=dateNow.month%10+0x30;
array[i++]='-';
array[i++]=dateNow.day/10+0x30;
array[i++]=dateNow.day%10+0x30;
array[i++]='\a';
delay1ms(10);
lcd_pos(0x00);//设置显示位置
while(array[j] != '\a')
{
lcd_wdat(array[j]);//显示字符
j++;
}
lcd_wcmd(0x02); //光标复位
}
/*********************显示时间*********************************/
void display_time()
{
unsigned char array[16];
unsigned char i=0;
unsigned char j=0;
array[i++]='T';
array[i++]=':';
array[i++]=0+0x30;
array[i++]=timeNow.week+0x30;
array[i++]='-';
array[i++]=timeNow.hour/10+0x30;
array[i++]=timeNow.hour%10+0x30;
array[i++]=':';
array[i++]=timeNow.min/10+0x30;
array[i++]=timeNow.min%10+0x30;
array[i++]=':';
array[i++]=timeNow.sec/10+0x30;
array[i++]=timeNow.sec%10+0x30;
array[i++]='\a';
delay1ms(10);
lcd_pos(0x00);//设置显示位置
while(array[j] != '\a')
{
lcd_wdat(array[j]);//显示字符
j++;
}
lcd_wcmd(0x02); //光标复位
}
/*********************中断内显示时间*********************************/
void idisplay_time()
{
unsigned char array[16];
unsigned char i=0;
unsigned char j=0;
array[i++]='S';
array[i++]=':';
array[i++]=0+0x30;
array[i++]=timeNow.week+0x30;
array[i++]='-';
array[i++]=timeNow.hour/10+0x30;
array[i++]=timeNow.hour%10+0x30;
array[i++]=':';
array[i++]=timeNow.min/10+0x30;
array[i++]=timeNow.min%10+0x30;
array[i++]=':';
array[i++]=timeNow.sec/10+0x30;
array[i++]=timeNow.sec%10+0x30;
array[i++]='\a';
delay1ms(10);
lcd_pos(0x00);//设置显示位置
while(array[j] != '\a')
{
lcd_wdat(array[j]);//显示字符
j++;
}
lcd_wcmd(0x02); //光标复位
}
/*********************显示闹钟时刻*******************************/
void display_clock()
{
unsigned char array[16];
unsigned char i=0;
unsigned char j=0;
array[i++]='C';
array[i++]=':';
array[i++]=setClock.hour/10+0x30;
array[i++]=setClock.hour%10+0x30;
array[i++]=':';
array[i++]=setClock.min/10+0x30;
array[i++]=setClock.min%10+0x30;
array[i++]=':';
array[i++]=setClock.sec/10+0x30;
array[i++]=setClock.sec%10+0x30;
array[i++]='\a';
delay1ms(10);
lcd_pos(0x00);//设置显示位置
while(array[j] != '\a')
{
lcd_wdat(array[j]);//显示字符
j++;
}
lcd_wcmd(0x02); //光标复位
}
/*****************中断内显示闹钟时刻****************************/
void idisplay_clock()
{
unsigned char array[16];
unsigned char i=0;
unsigned char j=0;
array[i++]='S';
array[i++]=':';
array[i++]=setClock.hour/10+0x30;
array[i++]=setClock.hour%10+0x30;
array[i++]=':';
array[i++]=setClock.min/10+0x30;
array[i++]=setClock.min%10+0x30;
array[i++]=':';
array[i++]=setClock.sec/10+0x30;
array[i++]=setClock.sec%10+0x30;
array[i++]='\a';
delay1ms(10);
lcd_pos(0x00);//设置显示位置
while(array[j] != '\a')
{
lcd_wdat(array[j]);//显示字符
j++;
}
lcd_wcmd(0x02); //光标复位
}
//**********************************************
// INTERRUPT.H
//***********************************************
sbit P3_0=P3^0;
sbit P3_1=P3^1;
sbit P3_2=P3^2;
sbit P3_3=P3^3;
sbit P3_4=P3^4;
sbit P3_6=P3^6;
sbit P3_7=P3^7;
sbit P2_4=P2^4;
sbit P2_5=P2^5;
sbit P2_7=P2^7;
void set_date() interrupt 0 //外部中断0,设置日期
{
unsigned char flag=2;
lcd_wcmd(0x01); //清屏
idisplay_date();
while(1)
{
switch(flag)
{
case 0: //设置年
for(; ;)
{
if(P3_2==0)
{
flag++;
if(flag>=3)
flag=0;
here1:idisplay_date();
if(P3_2==0)
goto here1;
break;
}
idisplay_date();
if(P3_6==0)
{
dateNow.year++;
dis1:idisplay_date();
delay(10);
if(P3_6==0)
goto dis1;
}
if(P3_7==0)
{
dateNow.year--;
dis2:idisplay_date();
if(P3_7==0)
goto dis2;
}
if(P2_4==0)
{
delay(10);
if(P2_4==0)
return;
}
}
case 1: //设置月
for(; ;)
{
if(P3_2==0)
{
flag++;
if(flag>=3)
flag=0;
here2:idisplay_date();
if(P3_2==0)
goto here2;
break;
}
idisplay_date();
if(P3_6==0)
{
if(dateNow.month<12)
dateNow.month++;
else
dateNow.month=1;
dis3:idisplay_date();
if(P3_6==0)
goto dis3;
}
if(P3_7==0)
{
if(dateNow.month>1)
dateNow.month--;
else
dateNow.month=12;
dis4:idisplay_date();
if(P3_7==0)
goto dis4;
}
if(P2_4==0)
{
delay(10);
if(P2_4==0)
return;
}
}
case 2://设置日
for(; ;)
{
if(P3_2==0)
{
flag++;
if(flag>=3)
flag=0;
here3:idisplay_date();
if(P3_2==0)
goto here3;
break;
}
idisplay_date();
if(P3_6==0)
{
if(dateNow.day<31)
dateNow.day++;
else
dateNow.day=1;
dis5:idisplay_date();
if(P3_6==0)
goto dis5;
}
if(P3_7==0)
{
if(dateNow.day>1)
dateNow.day--;
else
dateNow.day=31;
dis6:idisplay_date();
if(P3_7==0)
goto dis6;
}
if(P2_4==0)
{
delay(10);
if(P2_4==0)
return;
}
}
}
}
}
//**************************************************
void set_clock() interrupt 1 //计数器T0扩展为外部中断,设置闹钟
{
unsigned char flag=2;
lcd_wcmd(0x01); //清屏
idisplay_clock();
while(1)
{
switch(flag)
{
case 0://设置时
for(; ;)
{
if(P3_4==0)
{
flag++;
if(flag>=3)
flag=0;
here1:idisplay_clock();
if(P3_4==0)
goto here1;
break;
}
idisplay_clock();
if(P3_6==0)
{
if(setClock.hour<23)
setClock.hour++;
else
setClock.hour=0;
dis1:idisplay_clock();
if(P3_6==0)
goto dis1;
}
if(P3_7==0)
{
if(setClock.hour>0)
setClock.hour--;
else
setClock.hour=23;
dis2:idisplay_clock();
if(P3_7==0)
goto dis2;
}
if(P2_4==0)
{
delay(10);
if(P2_4==0)
return;
}
}
case 1://设置分
for(; ;)
{
if(P3_4==0)
{
flag++;
if(flag>=3)
flag=0;
here2:idisplay_clock();
if(P3_4==0)
goto here2;
break;
}
idisplay_clock();
if(P3_6==0)
{
if(setClock.min<59)
setClock.min++;
else
setClock.min=0;
dis3:idisplay_clock();
if(P3_6==0)
goto dis3;
}
if(P3_7==0)
{
if(setClock.min>0)
setClock.min--;
else
setClock.min=59;
dis4:idisplay_clock();
if(P3_7==0)
goto dis4;
}
if(P2_4==0)
{
delay(10);
if(P2_4==0)
return;
}
}
case 2://设置秒
for(; ;)
{
if(P3_4==0)
{
flag++;
if(flag>=3)
flag=0;
here3:idisplay_clock();
if(P3_4==0)
goto here3;
break;
}
idisplay_clock();
if(P3_6==0)
{
if(setClock.sec<59)
setClock.sec++;
else
setClock.sec=0;
dis5:idisplay_clock();
if(P3_6==0)
goto dis5;
}
if(P3_7==0)
{
if(setClock.sec>0)
setClock.sec--;
else
setClock.sec=59;
dis6:idisplay_clock();
if(P3_7==0)
goto dis6;
}
if(P2_4==0)
{
delay(10);
if(P2_4==0)
return;
}
}
}
}
}
//*********************************************************
void set_time() interrupt 2 //外部中断1,设置时间
{
unsigned char flag=3;
lcd_wcmd(0x01); //清屏
idisplay_time();
while(1)
{
switch(flag)
{
case 0: //设置星期
for(; ;)
{
if(P3_3==0)
{
flag++;
if(flag>=4)
flag=0;
here1:idisplay_time();
if(P3_3==0) goto here1;
break;
}
idisplay_time();
if(P3_6==0)
{
if(timeNow.week<7)
timeNow.week++;
else
timeNow.week=0;
dis1:idisplay_time();
if(P3_6==0) goto dis1;
}
if(P3_7==0)
{
if(timeNow.week>0)
timeNow.week--;
else
timeNow.week=7;
dis2:idisplay_time();
if(P3_7==0) goto dis2;
}
if(P2_4==0)
{
delay(10);
if(P2_4==0)
return;
}
}
case 1: //设置时
for(; ;)
{
if(P3_3==0)
{
flag++;
if(flag>=4)
flag=0;
here2:idisplay_time();
if(P3_3==0) goto here2;
break;
}
idisplay_time();
if(P3_6==0)
{
if(timeNow.hour<23)
timeNow.hour++;
else
timeNow.hour=0;
dis3:idisplay_time();
if(P3_6==0) goto dis3;
}
if(P3_7==0)
{
if(timeNow.hour>0)
timeNow.hour--;
else
timeNow.hour=23;
dis4:idisplay_time();
if(P3_7==0) goto dis4;
}
if(P2_4==0)
{
delay(10);
if(P2_4==0)
return;
}
}
case 2: //设置分
for(; ;)
{
if(P3_3==0)
{
flag++;
if(flag>=4)
flag=0;
here3:idisplay_time();
if(P3_3==0) goto here3;
break;
}
idisplay_time();
if(P3_6==0)
{
if(timeNow.min<59)
timeNow.min++;
else
timeNow.min=0;
dis5:idisplay_time();
if(P3_6==0) goto dis5;
}
if(P3_7==0)
{
if(timeNow.min>0)
timeNow.min--;
else
timeNow.min=59;
dis6:idisplay_time();
if(P3_7==0) goto dis6;
}
if(P2_4==0)
{
delay(10);
if(P2_4==0)
return;
}
}
case 3: //设置秒
for(; ;)
{
if(P3_3==0)
{
flag++;
if(flag>=4)
flag=0;
here4:idisplay_time();
if(P3_3==0) goto here4;
break;
}
idisplay_time();
if(P3_6==0)
{
if(timeNow.sec<59)
timeNow.sec++;
else
timeNow.sec=0;
dis7:idisplay_time();
if(P3_6==0) goto dis7;
}
if(P3_7==0)
{
if(timeNow.sec>0)
timeNow.sec--;
else
timeNow.sec=59;
dis8:idisplay_time();
if(P3_7==0) goto dis8;
}
if(P2_4==0)
{
delay(10);
if(P2_4==0)
return;
}
}
}
}
}
//***********************************************************
void adjust_time()
{
timeNow.sec++;
if(timeNow.sec==60)//是否满60秒
{
timeNow.min++;
timeNow.sec=0;
if(timeNow.min==60) //是否满60分
{
timeNow.hour++;
timeNow.min=0;
if(timeNow.hour==24) //是否满24小时
{
dateNow.day++;
timeNow.week++;
timeNow.hour=0;
if(timeNow.week==8)
timeNow.week=1;
if(dateNow.day==29&&dateNow.month==2&&!leap_year(dateNow.year)) //平年二月28天
{
dateNow.month++;
dateNow.day=1;
}
else if(dateNow.day==30&&dateNow.month==2&&leap_year(dateNow.year)) //闰年二月29天
{
dateNow.month++;
dateNow.day=1;
}
else if(dateNow.day==31&&is_30day(dateNow.month)) //有30天的月份
{
dateNow.month++;
dateNow.day=1;
}
else if(dateNow.day==32) //有31天的月份
{
dateNow.month++;
dateNow.day=1;
}
if(dateNow.month==13) //是否满一年
{
dateNow.year++;
dateNow.month=1;
}
}
}
}
}
void timer_T1() interrupt 3 //定时器T1,时时时间调整
{
count++;
if(count==20)
{
adjust_time();
count=0;
}
}
#include
/****************初始化计数器和定时器函数****************************/
void init_timer()
{
EA=1; //开中断
EX0=1; //允许外部中断0
EX1=1; // 允许外部中断1
PT1=1; //设置 定时器T1为高优先级
TMOD =0x16; // T0工作为计数器,T1工作为定时器
TH0=-(50000/256); //计数器T1装入初值
TL0=-(50000%256);
TR1=1; // 启动定时器T1
ET1=1; // 允许定时器T1中断
TH0=0xff; //计数器T0装入初值
TL0=0xff;
TR0=1; // 启动计数器T0
ET0=1; // 允许计数器T0中断
}
/*******************闹钟时刻到达报警函数*****************************/