基于单片机的电子日历时钟
基于单片机的电子万年历

论文题目基于单片机的电子万年历(英文)Design of Electronic Calendar basedon single Chip Microcomputer摘要现今信息技术飞速发展,时间和每一个人都有非常密切的相互联系,时间对任何人都有着非常重要的影响。
随着科技的快速发展,流逝的时间,我们从根据太阳来判断时间,发展到了用钟摆看时间,到现在又有了各种电子表等。
当各类电子表在我们生活中广泛应用的时候,电子万年历的的出现又把我们引入到一个全新的时代。
电子万年历是一种使用非常广泛的日常计时工具,对现代社会越来越流行。
它可以对年、月、日、周日、时、分、秒进行计时,还具有闰年补偿等多种功能,还具有时间校准等功能。
本设计是基于51系列的单片机进行的电子万年历设计,主要由时钟芯片DS1302采集数据到单片机进行处理再通过LCD1602显示出来。
电子万年历的软件部分是使用c语言编写,主要用到的硬件电路有时钟芯片DS1302、液晶显示LCD1602,主控制芯片AT89C51,还有按键。
关键词:单片机, LCD602, AT89C51 ,DS302AbstractNowadays information technology develops rapidly, and time and everyone have very close interconnections, and time has a very important influence on anyone. With the rapid development of science and technology, the time elapsed, we judge the time according to the sun, develop to use the pendulum to watch the time, and now have all kinds of electronic watches and so on. When all kinds of electronic watches are widely used in our lives, the advent of electronic calendar brings us to a whole new era. Electronic calendar is a kind of widely used daily timing tool, which is becoming more and more popular in modern society. It can time the year, month, day, Sunday, hour, minute, second, also have leap year compensation and so on many functions, still have time calibration and so on function.This design is based on the electronic calendar design of 51 series of single-chip microcomputer, mainly by the clock chip DS1302 collecting data to the single chip microcomputer for processing and then through LCD1602. The software part of the electronic calendar is written in c language. The main hardware circuits used are clock chip DS1302, liquid crystal display LCD1602, master control chip AT89C51, and buttons.Key words:Microcontroller;LCD1602;AT89C51;DS1302目录目录 (3)第1章绪论 (4)1.1背景及目的 (4)1.1.1课题研究背景 (4)1.1.2选题的意义及目的 (4)1.2 国内外发展现状及水平 (4)第2章系统的方案选择及论证 (6)2.1 单片机芯片选择 (6)2.2 时钟芯片的选择与论证 (6)2.3 显示模块的选择与论证 (6)2.4 电路设计最终方案 (7)第3章系统的硬件设计与实现 (8)3.1 电路设计框图 (8)3.2系统硬件概述 (8)3.3 系统的电路设计 (8)3.3.1 系统总体电路设计图 (9)3.3.2单片机主控制模块 (9)3.3.3 时钟电路模块 (12)3.3.4 显示模块 (16)第4章系统的软件设计 (19)4.1 程序流程框图: (19)第5章Proteus软件仿真与测试 (22)5.1 仿真软件介绍 (22)5.2 Proteus 仿真效果 (22)第6章总结与体会 (24)参考文献 (25)附录1:程序 ..................................................... 错误!未定义书签。
基于单片机的电子万年历设计

基于单片机的电子万年历设计一、概述随着科技的快速发展和人们对生活品质的追求,电子设备在日常生活中扮演着越来越重要的角色。
电子万年历作为一种集日期、时间显示于一体的实用电子产品,已经深入到人们的日常生活和工作中。
传统的机械式日历已经无法满足现代人对时间精确性和功能多样性的需求,基于单片机的电子万年历设计应运而生,成为了当前研究的热点之一。
基于单片机的电子万年历设计,旨在利用单片机(如STC89CAT89C51等)的强大计算和控制能力,结合液晶显示屏(LCD)、按键输入等外设,实现时间的准确显示、日期的自动更新、闹钟提醒、温度显示等多样化功能。
该设计不仅具有高度的集成性和可靠性,而且能够通过编程实现各种定制化的功能,满足不同用户的需求。
本文将对基于单片机的电子万年历设计进行详细的介绍和分析,包括设计思路、硬件组成、软件编程等方面。
通过本文的阅读,读者可以了解电子万年历的基本原理和设计方法,掌握单片机在电子万年历设计中的应用技巧,为实际的开发工作提供有益的参考和借鉴。
1.1 研究背景与意义随着科技的不断进步,人们日常生活和工作中对于时间的精度和便捷性的要求日益提高。
传统的机械式日历和简单的电子时钟已经无法满足现代生活的需求。
电子万年历作为一种集时间显示、日历查询、定时提醒等多功能于一体的电子装置,在日常生活、工作乃至科研领域都具有广泛的应用价值。
基于单片机的电子万年历设计,不仅可以提供准确的时间显示,还能实现复杂的日期计算、农历显示、节假日提示等功能,极大地提高了时间管理的效率和便捷性。
单片机作为一种集成度高、功耗低、价格适中的微型计算机,非常适合用于小型化、智能化的电子产品设计,如电子万年历。
本研究的意义在于,通过对基于单片机的电子万年历的设计研究,可以推动微型计算机技术和电子时钟技术的融合发展,提升电子产品的智能化水平,满足人们日益增长的生活和工作需求。
同时,该研究还可以为相关领域的技术人员提供参考和借鉴,推动电子万年历产品的不断创新和优化。
单片机制作数字钟(含万年历、秒表功能)

数字钟、万年历制作(基于单片机)电路原理图:程序://********************20131206****数字钟程序#pragma SMALL#include <reg51.h>#include <absacc.h>#include <intrins.h>//********************************************************* *********编译预处理void display(unsigned char *p); //显示函数,P为显示数据首地址unsigned char keytest(); //按键检测函数unsigned char search(); //按键识别函数void alarm(); //闹钟判断启动函数void ftion0(); //始终修改函数void ftion1(); //闹钟修改函数void ftion3(); //日期修改函数void cum(); //加1修改函数void minus(); //减1修改函数void jinzhi(); //进制修改函数void riqi(); //日期void stopwatch(); //秒表函数//********************************************************* *******函数声明sbit P2_7=P2^7;//********************************************************* *******端口定义unsigned char clockbuf[3]={0,0,0};unsigned char bellbuf[3]={0,0,0};unsigned char date[3]={1,1,1}; //日期存放数组unsigned char stop[3]={0,0,0};unsigned char msec1,msec2;unsigned char timdata,rtimdata,dtimdata;unsigned char count;unsigned char *dis_p;unsigned char or; //12进制控制标志unsigned char ri; //日期显示控制标志位unsigned char mb; //秒表控制标志位bit arm,rtim,rhour,rmin,hour,min,sec,day,mon,year; //定义位变量//********************************************************* *****全局变量定义void main(){unsigned char a;or=0; //12进制修改标志清零ri=0;mb=0;P2_7=0;arm=0;msec1=0;msec2=0;timdata=0;rtimdata=0;count=0;TMOD=0x12;TL0=0x06;TH0=0x06;TH1=(65536-10000)/256;TL1=(65536-10000)%256;EA=1;ET0=1;ET1=1;TR0=1;TR1=0;dis_p=clockbuf;while(1){a=keytest();if(a==0x78) //判断是否有键按下{display(dis_p);if(arm==1) alarm();}else{display(dis_p);a=keytest();if(a!=0x78){a=search();switch(a){case 0x00:ftion0();break;case 0x01:ftion1();break;case 0x02:cum();break;case 0x06:jinzhi();break;case 0x03:riqi();break;case 0x04:ftion3();break;case 0x05:minus();break;case 0x07:stopwatch();break;case 0x09:TR1=1;break;case 0x0a:TR1=0;break;case 0x0b:stop[0]=0;stop[1]=0;stop[2]=0;break;default:break;}}}}}//********************************************主函数【完】void display(unsigned char *p){unsigned char buffer[]={0,0,0,0,0,0};unsigned char k,i,j,m,temp;unsigned char led[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};buffer[0]=p[0]/10;buffer[1]=p[0]%10;buffer[2]=p[1]/10;buffer[3]=p[1]%10;buffer[4]=p[2]/10;buffer[5]=p[2]%10;if((sec==0)&&(min==0)&&(hour==0)&&(rmin==0)&&(rhour==0)&&( day==0)&&(mon==0)&&(year==0)) //没有修改标志,正常显示{for(k=0;k<3;k++){temp=0x01;for(i=0;i<6;i++){P0=0x00; //段选端口j=buffer[i];P0=led[j];P1=~temp; //位选端口temp<<=1;for(m=0;m<200;m++);}}}else //若有修改标志,则按以下标志分别显示{if(sec==1||day==1){P1=0x1f;i=buffer[5];P0=led[i];for(m=0;m<200;m++);P1=0x2f;j=buffer[4];P0=led[j];for(m=0;m<200;m++);}if(min==1||rmin==1||mon==1){P1=0x3b;i=buffer[2];P0=led[i];for(m=0;m<200;m++);P1=0x37;j=buffer[3];P0=led[j];for(m=0;m<200;m++);}if(hour==1||rhour==1||year==1) {P1=0x3e;i=buffer[0];P0=led[i];for(m=0;m<200;m++);P1=0x3d;j=buffer[1];P0=led[j];for(m=0;m<200;m++);}}}//**********************************LED显示函数【完】unsigned char keytest(){unsigned char c;P2=0x78; //检测是否有键按下c=P2;c=c&0x78;return(c);}//******************************************键盘检测函数【完】unsigned char search(){unsigned char a,b,c,d,e;c=0x3f;a=0; //行号while(1){P2=c;d=P2;d=d&0x07;if(d==0x03){b=0;break;} //列号else if(d==0x05){b=1;break;}else if(d==0x06){b=2;break;}a++;c>>=1;if(a==5){a=0;c=0x3f;}}e=a*3+b;do{display(dis_p);}while((d=keytest())!=0x78);return(e);}//***********************************************查键值函数【完】void alarm(){if((clockbuf[0]==bellbuf[0])&&(clockbuf[1]==bellbuf[1])){P2_7=1;rtim=1;if(count==10){count=0;P2_7=0;arm=0;rtim=0;}}}//****************************************闹钟判断启动函数【完】void ftion0(){TR0=0;rhour=0;rmin=0;dis_p=clockbuf;rtimdata=0;timdata++;switch(timdata){case 0x01:sec=1;break;case 0x02:sec=0;min=1;break;case 0x03:min=0;hour=1;break;case 0x04:timdata=0;hour=0;TR0=1;break;default:break;}}//*********************************************时钟设置函数【完】void ftion1(){if(TR0==0) TR0=1;sec=0;min=0;hour=0;dis_p=bellbuf;timdata=0;rtimdata++;switch(rtimdata){case 0x01:rmin=1;break;case 0x02:rmin=0;rhour=1;break;case 0x03:rtimdata=0;rhour=0;arm=1;dis_p=clockbuf;break;default:break;}}//*********************************************闹钟设置函数【完】void ftion3(){if(TR0==0) TR0=1;day=0;mon=0;year=0;dis_p=date;timdata=0;rtimdata=0;dtimdata++;switch(dtimdata){case 0x01:day=1;break;case 0x02:day=0;mon=1;break;case 0x03:mon=0;year=1;break;case 0x04:dtimdata=0;year=0;dis_p=clockbuf;break;default:break;}}//*************************************************日期修改函数【完】void minus(){if(sec==1){if(0==clockbuf[2]) clockbuf[2]=59;else clockbuf[2]--;}else if(min==1){if(0==clockbuf[1]) clockbuf[1]=59;else clockbuf[1]--;}else if(hour==1){if(or==0) //判断进制{if(0==clockbuf[0]) clockbuf[0]=23;else clockbuf[0]--;}if(or==1){if(1==clockbuf[0]) clockbuf[0]=12;else clockbuf[0]--;}}else if(rmin==1){if(bellbuf[1]==0) bellbuf[1]=59;else bellbuf[1]--;}else if(rhour==1){if(or==0){if(bellbuf[0]==0) bellbuf[0]=23;else bellbuf[0]--;}if(or==1){if(bellbuf[0]==1) bellbuf[0]=12;else bellbuf[0]--;}}else if(day==1){if(date[2]==1) date[2]=31;else date[2]--;}else if(mon==1){if(date[1]==1) date[1]=12;else date[1]--;}else if(year==1){if(date[0]==1) date[0]=99;else date[0]--;}}//*************************************减1修改功能函数【完】void cum(){if(sec==1){if(59==clockbuf[2]) clockbuf[2]=0;else clockbuf[2]++;}else if(min==1){if(59==clockbuf[1]) clockbuf[1]=0;else clockbuf[1]++;}else if(hour==1){if(or==0) //判断进制{if(23==clockbuf[0]) clockbuf[0]=0;else clockbuf[0]++;}if(or==1){if(12==clockbuf[0]) clockbuf[0]=1;else clockbuf[0]++;}}else if(rmin==1){if(bellbuf[1]==59) bellbuf[1]=0;else bellbuf[1]++;}else if(rhour==1){if(or==0){if(bellbuf[0]==23) bellbuf[0]=0;else bellbuf[0]++;}if(or==1){if(bellbuf[0]==12) bellbuf[0]=1;else bellbuf[0]++;}}else if(day==1){if(date[2]==31) date[2]=1;else date[2]++;}else if(mon==1){if(date[1]==12) date[1]=1;else date[1]++;}else if(year==1){if(date[0]==99) date[0]=0;else date[0]++;}}//*************************************加1修改功能函数【完】void jinzhi(){if(or==0) or=1;else or=0;}//***********************************进制修改控制函数【完】void riqi(){if(ri==0){dis_p=date;}if(ri==1){dis_p=clockbuf;}ri++;if(ri==2) ri=0;}//********************************日期控显示函数【完】void stopwatch(){if(mb==0){dis_p=stop;mb=1;}else{mb=0;dis_p=clockbuf;}}//************秒表**********秒表**********秒表函数【完】void clock() interrupt 1{EA=0;if(msec1!=0x14) msec1++; //6MHz晶振定时10mselse{msec1=0;if(msec2!=100) msec2++; //定时1selse{if(rtim==1) count++; //闹钟启动标志计时10smsec2=0;if(clockbuf[2]!=59) clockbuf[2]++;else{clockbuf[2]=0;if(clockbuf[1]!=59) clockbuf[1]++;else{clockbuf[1]=0;if(or==0){if(clockbuf[0]!=23) clockbuf[0]++;else{clockbuf[0]=0;if((date[1]==1)||(date[1]==1)||(date[1]==1)||(date[1]==3)||(date[ 1]==5)||(date[1]==7)||(date[1]==8)||(date[1]==10)||(date[1]==12)){if(date[2]!=30) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}if((date[1]==4)||(date[1]==6)||(date[1]==9)||(date[1]==11)){if(date[2]!=29) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}if(date[1]==2){if((((date[0]%4==0)&&(date[0]%100!=0))||(date[0]%400==0))){if(date[2]!=28) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}else{if(date[2]!=27) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}}}}if(or==1){if(clockbuf[0]!=12) clockbuf[0]++;else{clockbuf[0]=0;if((date[1]==1)||(date[1]==1)||(date[1]==1)||(date[1]==3)||(date[ 1]==5)||(date[1]==7)||(date[1]==8)||(date[1]==10)||(date[1]==12)){if(date[2]!=30) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}if((date[1]==4)||(date[1]==6)||(date[1]==9)||(date[1]==11)){if(date[2]!=29) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}if(date[1]==2){if((((date[0]%4==0)&&(date[0]%100!=0))||(date[0]%400==0))){if(date[2]!=28) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}else{if(date[2]!=27) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}}}}}}}}EA=1;}//*******************************定时器0中断函数【完】void miaobiao() interrupt 3{TH1=(65536-10000)/256;TL1=(65536-10000)%256;if(stop[2]!=99) stop[2]++;else{stop[2]=0;if(stop[1]!=59) stop[1]++;else{stop[1]=0;if(stop[0]!=59) stop[0]++;else stop[0]=0;}}}//***********************************定时器1中断函数【完】。
基于单片机的多功能电子万年历设计

引言随着生活节奏的日益加快,人们的时间观也越来越重,同时对电子钟表、日历的需求也随之提高。
因此,研究实用电子时钟及其扩展应用,有着非常现实的意义,具有很大的实用价值。
本系统程序由主程序、中断服务函数和多个子函数构成。
主函数主要完成各子函数和中断函数的初始化。
定时中断函数主要完成时钟芯片的定时扫描及键盘扫描。
时钟芯片的读写函数主要是将时间、日历信息读出来,并把要修改具体值写入时钟芯片内部。
系统的硬件设计与电路原理电路设计框图系统硬件概述本电路是由AT89S52单片机为控制核心,具有在线编程功能、低功耗、能在3V的超低压工作。
时钟电路由DS1302提供,它是一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,工作电压为2.5V~5.5V。
采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。
DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。
可产生年、月、日、周日、时、分、秒,具有使用寿命长、精度高和低功耗等特点,同时具有掉电自动保存功能。
主控制模块单片机主控制模块的设计AT89S52单片机为40引脚双列直插芯片,有四个I/O口P0,P1,P2,P3,MCS-51单片机共有4个8位的I/O口(P0、P1、P2、P3),每一条I/O线都能独立地作输出或输入。
时钟电路模块时钟电路模块的设计DS1302的引脚排列如图3所示,其中Vcc1为后备电源,Vcc2为主电源。
在主电源关闭的情况下,也能保持时钟的连续运行。
DS1302由Vcc1或Vcc2两者中的较大者供电。
当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电;当Vcc2小于Vcc1时,DS1302由Vcc1供电。
X1和X2是振荡源,外接32.768KHz晶振。
RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。
RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。
基于单片机的电子时钟万年历设计

(2)31 8 位暂存数据存储RAM(3)串行 I/O 口方式使得管脚数量最少(4)宽范围工作电压2.0 5.5V(5)工作电流 2.0V 时,小于300nA(6)读/写时钟或RAM 数据时有两种传送方式单字节传送和多字节传送字符组方式(7)8 脚DIP 封装或可选的8 脚SOIC 封装根据表面装配(8)简单 3 线接口(9)与 TTL 兼容Vcc=5V(10)可选工业级温度范围-40~+85优点:串行接口的日历时钟芯片,使用简单,接口容易,与微型计算机连线较少等特点,在单片机系统尤其是手持式信息设备中己得到了广泛的应用。
所以,最终选择串行时钟芯片DS1302,DS1302的管脚图如图2所示。
图2 DS1302管脚图1.2显示模块选择方案一:LED数码管显示数码管显示比较常用的是采用CD4511和74LS138实现数码转换,数码显示分动态显示和静态显示,静态显示具有锁存功能,可以使数据显示得很清楚,但浪费了一些资源。
目前单片机数码管普通采用动态显示。
编程简单,但只能显示数字,不能显示中文。
方案二:LCD1602能够显示英文和数字。
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。
所以最终选择LCD1602。
2.项目功能模块2.1 89C51模块Mcs-51单片机管脚图图如图3所示:单片机管脚图2.2 1602液晶显示模块1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。
基于单片机控制的电子万年历设计

基于单片机控制的电子万年历设计1设计要求功能:电子万年历能显示阳历、时间、室温,并能表明是否是闰年,通过按键实现切换。
本课题以单片机为核心,设计并制作出智能LCD电子钟,具有以下基本功能:计时、秒、分、时、天、周、月、年;能进行时间、年份、日期、星期显示;能区分是否闰年;能检测室温并显示。
扩展功能部分可以通过控制按键使时间暂停、可以调整校正时间并通过按键切换轮流显示时间、年份、日期、星期。
2方案论证与对比2.1液晶显示器控制方式选择采用LCD液晶显示,具有超精致影像画质、十足平面显示、节省空间、节省能源等优点,但按控制方式不同,LCD可分为被动矩阵式LCD及主动矩阵式LCD两种。
可根据不同需要采用不同的方式。
方案一被动矩阵式LCD被动矩阵式LCD在亮度及可视角方面受到较大的限制,反应速度也较慢。
由于画面质量方面的问题,使得这种显示设备不利于发展为桌面型显示器,但成本低廉。
方案二主动矩阵式LCD目前应用比较广泛的主动矩阵式LCD,也称TFT-LCD(Thin Film Transistor-LCD,薄膜晶体管LCD)。
TFT液晶显示器是在画面中的每个像素内建晶体管,可使亮度更明亮、色彩更丰富及更宽广的可视面积。
与CRT显示器相比,LCD显示器的平面显示技术体现为较少的零件、占据较少的桌面及耗电量较小,但CRT技术较为稳定成熟。
相比之下,本设计当中选用方案二主动矩阵式LCD方式。
2.2 并行接口动态显示电路选择可以采取串行接口动态显示电路或者并行接口动态显示电路,比较如下:方案一串行接口动态显示电路利用8051系列单片机内部的串行接口,也可以实现动态显示及键盘处理。
这样不但可以节省8051的并行I/O接口,而且在大多数不用单行口的情况下,可免于扩展接口。
在这种方法中,串行口工作在方式0状态,相当于一个移位寄存器,其输入/输出通过RXD引脚,移位脉冲则由TXD输出。
每次输入或输出8位数据(一个字节)。
基于单片机控制的电子万年历.

基于单片机控制的电子万年历摘要本设计是一个带温度显示的万年历电路系统,该电路具有年、月、日、星期、时、分、秒、闹钟显示和调整功能,并且还包含显示温度功能。
其中显示部分采用LCD1602显示,时钟部分采用DS1302时钟芯片,温度部分采用DS18B20单线温度传感器。
软件方面我们采用C语言编程,利用Keil uVision3软件编写C语言程序并且生成HEX文件。
先将程序在Proteus 仿真,通过之后再烧录到单片机中。
该设计的优点是充分利用了LCD1602的显示功能完成了万年历应该具有的功能并且还扩展了温度;不足之处是收到LCD1602显示功能的限制没能显示农历日期。
电子万年历是一种非常广泛日常计时工具,对现代社会越来越流行。
它可以对年、月、日、周日、时、分、秒进行计时,还具有闰年补偿等多种功能,而且DS1302的使用寿命长,误差小。
对于数字电子万年历采用直观的数字显示,可以同时显示年、月、日、周日、时、分、秒和温度等信息,还具有时间校准等功能。
该电路采用AT89S51单片机作为核心,功耗小,能在3V的低压工作,电压可选用3~5V电压供电。
关键词:万年历;AT89C51;液晶显示(LCD1602);温度传感器(DS18B20);时钟芯片(DS1302);proteus仿真;目录摘要 (1)目录 (1)1引言: (2)2设计方案 (3)2.2模块选择 (4)2.3方案框图 (4)3 软件实现 (5)3.1流程图 (5)3.2程序编写 (6)3.3运行程序生成hex文件 (12)4 proteus仿真 (13)4.1软件简介 (13)4.2 Proteus电路仿真与调试 (14)5 PCB制版 (21)5.1 绘制电路原理图并仿真调试 (21)5.2加载网络表及元件封装 (21)5.3规划电路板并设置相关参数 (23)5.4元件布局及调整 (24)5.5布线并调整 (25)5.6输出及制作PCB (26)总结 (27)参考文献 (28)致谢 (29)1引言:随着微电子技术的高速发展,单片机在国民经济的个人领域得到了广泛的运用。
基于单片机的电子日历时钟设计

#include<STC12C5A.h>#define uchar unsigned char#define uint unsigned int//----端口定义---sbit ACC_7=ACC^7;sbit RST1=P2^5;sbit IO=P2^6;sbit SCLK=P2^7;sbit k1=P3^2;sbit k2=P3^3;sbit k3=P2^2;sbit k4=P2^3;//uchar wei[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; // 数码的位选,左到右uchar tab_1302[7]={45,50,11,19,1,1,15};uchar tab_time[8]={0,0,10,0,0,10,0,0}; //时间uchar tab_day[8]={0,0,10,0,0,10,0,0,}; //年月日uchar tab_num[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};//0 1 2 3 4 5 6 7 8 9 - {"0123456789-"}////////////=============函数声明============////////////////void display_time();void delayms(uint);void display_day();void ds1302(); //获取DS1302的时间void ds1302_init(); //DS1302的初始化void write1302(uchar,uchar); //指定地址向DS1302写数据uchar read1302(uchar); //指定地址向DS1302读数据void ds1302();void int0_init();/////////=======中断初始化=======///////////void int0_init(){EX0=1;IT0=1;EX1=1;IT1=1;EA=1;}///////////========时间显示======///////////// void display_time(){P1=0x7f;P0=tab_num[tab_time[7]];delayms(10);P1=0xbf;P0=tab_num[tab_time[6]];delayms(10);P1=0xdf;P0=tab_num[tab_time[5]];delayms(10);P1=0xef;P0=tab_num[tab_time[4]];delayms(10);P1=0xf7;P0=tab_num[tab_time[3]];delayms(10);P1=0xfb;P0=tab_num[tab_time[2]];delayms(10);P1=0xfd;P0=tab_num[tab_time[1]];delayms(10);P1=0xfe;P0=tab_num[tab_time[0]];delayms(10);}//////////=========延时函数========//////////////// void delayms(uint x){int i,j;for(i=x;i>=0;i--)for(j=0;j<=110;j++);}//////////=======日期显示======///////////void display_day(){P1=0x7f;P0=tab_num[tab_day[7]];delayms(10);P1=0xbf;P0=tab_num[tab_day[6]];delayms(10);P1=0xdf;P0=tab_num[tab_day[5]];delayms(10);P1=0xef;P0=tab_num[tab_day[4]];delayms(10);P1=0xf7;P0=tab_num[tab_day[3]];delayms(10);P1=0xfb;P0=tab_num[tab_day[2]];delayms(10);P1=0xfd;P0=tab_num[tab_day[1]];delayms(10);P1=0xfe;P0=tab_num[tab_day[0]];delayms(10);}////////////=========DS1302初始化======//////////// void ds1302_init() //DS1302初始化,设置初始时间{uchar i,add;add=0x80;write1302(0x8e,0x00);for(i=0;i<7;i++){write1302(add,tab_1302[i]);add+=2;}/* write1302(0x80,0x50); // 秒...write1302(0x82,0x59); // 分write1302(0x84,0x23); // 时write1302(0x86,0x19); // 日write1302(0x88,0x01); // 月write1302(0x8a,0x01); // 周write1302(0x8c,0x15); // 年*/write1302(0x8e,0x80);}//////////============从DS1302获取数据============///////////// uchar read1302(uchar add){uchar i,temp,dat1,dat2;RST1=0;SCLK=0;RST1=1;for(i=8;i>0;i--) //发送地址{SCLK=0;temp=add;IO=(bit)(temp&0x01);add>>=1;SCLK=1;}for(i=8;i>0;i--) //读取数据{ACC_7=IO;SCLK=1;ACC>>=1;SCLK=0;}RST1=0;dat1=ACC;dat2=dat1/16;dat1=dat1%16;dat1=dat1+dat2*10;return(dat1);}/////////============向DS1302写入数据程序================//////////// void write1302(uchar add,uchar dat){uchar i,temp;RST1=0;SCLK=0;RST1=1;for(i=0;i<8;i++) //发送地址{SCLK=0;temp=add;IO=(bit)(temp&0x01);add>>=1;SCLK=1;}temp=(dat/10<<4)|(dat%10);for(i=0;i<8;i++) //发送数据{SCLK=0;IO=(bit)(temp&0x01);temp>>=1;SCLK=1;}RST1=0;}/////////-------------获取DS1302的时间-----------////////void ds1302(){uchar i,add=0x81;write1302(0x8e,0x00); //允许向DS1302写入数据for(i=0;i<7;i++){tab_1302[i]=read1302(add); //获得的数据已转换为十进制add+=2;}write1302(0x8e,0x80); //获取完一次时间,禁止向DS1302写入数据,提高可靠}///////////============转换函数============///////////void change(){tab_time[0]=tab_1302[2]/10; //小时十位tab_time[1]=tab_1302[2]%10; //小时个位tab_time[3]=tab_1302[1]/10; //分十位tab_time[4]=tab_1302[1]%10; //分个位tab_time[6]=tab_1302[0]/10; //秒十位tab_time[7]=tab_1302[0]%10; //秒个位tab_day[0]=tab_1302[6]/10; //年十位tab_day[1]=tab_1302[6]%10; //年个位tab_day[3]=tab_1302[4]/10; //月十位tab_day[4]=tab_1302[4]%10; //月个位tab_day[6]=tab_1302[3]/10; //日十位tab_day[7]=tab_1302[3]%10; //日个位}////////////========主函数=======///////////// void main(){P2M0=0xff;P2M1=0;ds1302_init();int0_init();while(1){ds1302();change();display_time();while(!k4){ds1302();change();display_day();}}}/////========time=========////////////void int0() interrupt 0{uchar ky=0,n1,n2,n3=1,flag=1;while(flag!=0){write1302(0x8e,0x00);write1302(0x80,0x80|tab_1302[0]);P1=0xdf;P0=tab_num[tab_time[5]];delayms(10);P1=0xfb;P0=tab_num[tab_time[2]];delayms(10);if(k3==0){delayms(50);if(k3==0){ky++;while(!k3);if(ky==5){ky=0;}}}//////////=======1========////////if(ky==1){n1=tab_1302[0];if(k4==0){delayms(30);if(k4==0){n1++;while(!k4);if(n1>=60)n1=0;}}tab_1302[0]=n1;change();P1=0x7f;P0=tab_num[tab_time[7]];delayms(10);P1=0xbf;P0=tab_num[tab_time[6]];delayms(10);}////////=======2======////////if(ky==2){n2=tab_1302[1];if(k4==0){delayms(30);if(k4==0){n2++;while(!k4);if(n2>=60)n2=0;}}tab_1302[1]=n2;change();P1=0xef;P0=tab_num[tab_time[4]];delayms(10);P1=0xf7;P0=tab_num[tab_time[3]];delayms(10);P1=0x7f;P0=tab_num[tab_time[7]];delayms(10);P1=0xbf;P0=tab_num[tab_time[6]];delayms(10);}/////==3==///if(ky==3){n3=tab_1302[2];if(k4==0){delayms(10);if(k4==0){n3++;while(!k4);if(n3==24)n3=1;}}tab_1302[2]=n3;change();P1=0xfd;P0=tab_num[tab_time[1]];delayms(10);P1=0xfe;P0=tab_num[tab_time[0]];delayms(10);P1=0xef;P0=tab_num[tab_time[4]];delayms(10);P1=0xf7;P0=tab_num[tab_time[3]];delayms(10);P1=0x7f;P0=tab_num[tab_time[7]];delayms(10);P1=0xbf;P0=tab_num[tab_time[6]];delayms(10);}//////===4====////if(ky==4){flag=0;ds1302_init();}}}/////////////=============day================///////////// void int1() interrupt 2{uchar ky=0,n1,n2=1,n3=1,flag=1;while(flag!=0){write1302(0x8e,0x00);write1302(0x80,0x80|tab_1302[0]);P1=0xdf;P0=tab_num[tab_day[5]];delayms(10);P1=0xfb;P0=tab_num[tab_day[2]];delayms(10);if(k3==0){delayms(50);if(k3==0){ky++;while(!k3);if(ky==5){ky=0;}}}//////////=======1========////////if(ky==1){n1=tab_1302[6];if(k4==0){delayms(30);if(k4==0){n1++;while(!k4);if(n1==50)n1=0;}}tab_1302[6]=n1;change();P1=0xfd;P0=tab_num[tab_day[1]];delayms(10);P1=0xfe;P0=tab_num[tab_day[0]];delayms(10);}////////=======2======////////if(ky==2){n2=tab_1302[4];if(k4==0){delayms(30);if(k4==0){n2++;while(!k4);if(n2==13)n2=1;}}tab_1302[4]=n2;change();P1=0xfd;P0=tab_num[tab_day[1]];delayms(10);P1=0xfe;P0=tab_num[tab_day[0]];delayms(10);P1=0xef;P0=tab_num[tab_day[4]];delayms(10);P1=0xf7;P0=tab_num[tab_day[3]];delayms(10);}/////==3==///if(ky==3){n3=tab_1302[3];if(k4==0){delayms(10);if(k4==0){n3++;while(!k4);if(n3==31)n3=1;}}tab_1302[3]=n3;change();P1=0x7f;P0=tab_num[tab_day[7]];delayms(10);P1=0xbf;P0=tab_num[tab_day[6]];delayms(10);P1=0xef;P0=tab_num[tab_day[4]];delayms(10);P1=0xf7;P0=tab_num[tab_day[3]];delayms(10);P1=0xfd;P0=tab_num[tab_day[1]];delayms(10);P1=0xfe;P0=tab_num[tab_day[0]];delayms(10);}if(ky==4){flag=0;ds1302_init();}}}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
微机原理课程设计报告题目:电子日历时钟学院电子与信息学院专业08信息工程1班组员陈晓伟05 冯劲增06 指导教师林耀荣提交日期2010.6.21一课程设计题目:电子日历时钟二实现的功能:基本功能:(1)显示北京时间,并且能够校准时间;(2)程序使用汇编语言;(3)显示的时、分、秒之间以及年、月、日间以小数点分隔;(4)显示公历日期,并且能够校准日期;发挥功能:(5)运动秒表;(6)闹钟功能;(7)自动整点报时。
三课程设计的目的:课程标志性内容的设计理解和综合运用,对所学内容进行一次实操,学以致用。
四、设计方案说明1、硬件部分(1)采用6位LED数码管显示日期或者时间。
(2)显示器的驱动采用“动态扫描驱动”,且采用“一键多用”的设计方案,系统电路大为简化。
使用小数点表示闹钟设置状态;(3)电路连接使用PCB,使电路连接简洁美观2、软件部分(1)“时钟”基准时间由单片机内部的定时中断提供,考虑因素:定时时间是“秒”的整除数,且长短适宜。
最长不能超过16位定时器的最长定时时间;最短不能少于中断服务程序的执行时间。
基准时间越短,越有利于提高时钟的运行精确度。
基准时间定为0.05秒。
(2)用一个计数器对定时中断的次数进行计数,由基准时间为0.05秒知计数值为20即可实现实现“秒”定时,同理进行“分”﹑“时”定时,以及“日”﹑“月”﹑“年”定时。
(3)LED 数码管显示器采用“动态扫描驱动”考虑问题:驱动信号的维持时间必须大于“起辉时间”(电流大起辉时间短),而驱动信号的间歇时间必须小于“余辉时间”(电流大余辉时间长),但驱动电流大小受硬件电路能力和LED数码管极限功耗的制约。
(4)动态扫描显示方式在更新显示内容时,考虑到因LED数码管余辉的存在可能会造成显示字符的模糊,所以新内容写入显示器之前将所有的LED数码管熄灭。
(5)关于自动识别“月大﹑月小”和“平年﹑润年”问题的考虑a)月大和月小2月另外计算;4月﹑6月﹑9月﹑11 月为月小30天,其余为月大31天。
b)平年和润年(年号能被4整除的就是润年)平年的2月为28天;润年的2月为29天。
五、使用说明实物图请参照后面附带图片,从左至右为按键K2,K1,K0,以两个LED显示器为一组,左中右显示时分秒或者年月日,还有闹钟和秒表K2:复位 K1:设置闪烁 K0:切换时间/日期或者调整时间/日期初始状态:接上电源之后,日期默认为10年6月21日,时间为0时0分秒,闹钟2点整但默认关闭,秒表为0状态(1)显示状态切换:不断按K0键就会依次循环显示下面的状态初始状态时间日期闹钟时间闹钟状态秒表状态(2)调节时间,日期:按K0键切换到想要调节的显示状态,再按K1键选择要修改的位,不断按K1键会按左闪烁.中闪烁.右闪烁.确定.四个状态切换,闪烁的位可以修改,按K0键可以实现增加,不能递减,例如要调慢时间要按到循环到较慢时间。
(3)闹钟使用:闹钟默认响的时间为一分钟,闹钟的时间设置同时间日期的调节,只需把状态切换到闹钟时间的状态,闹钟的开关先按K0键切换到屏幕显示为OFF的状态,如下:再按K1可切换到开状态,如下图,再按K1可关闭,不断循环(4)秒表:K0键按4下就可切换到秒表状态,出示为0,此时按下K1键就可开始计时,再按一下K1键可停止,此时K1为秒表开关,按K0键可再切换显示其他。
六、硬件连接图1、原理图2、pcb图3、实物图七、程序流程图:1. 主程序八、性能测试与故障排查1、硬件部分问题:断路。
现象:程序下载完之后可以工作但是6个LED显示器有2个没亮。
分析:因为其他几个显示器完全正常,这两个则完全没亮,所以推断是位选的线路出故障。
检测:用万用表测试各点电压,着重测试两条位选线路的断路与短路情况,最终发现两处断路。
解决:焊锡接上,最终全亮2、软件部分偶数组实现基础功能的程序老师已经提供,该程序基本没有多大的问题,就是里面的几个参数需要修改,同时还有一个小bug。
修改一:由于提供的程序所默认采取的晶振计数频率是6MHz,但是所提供的现实原件则是12MHz,所以根据晶振的不同,定时器的定时时间变为0.05s。
按照该程序直接跑的话,计数时间为0.5s。
这就需要设置计数次数TICK_CNT为#14H,即0.05s*20=1s。
代码段:MOV TICK_CNT,#14H修改二:程序默认设置的外部中断延时过短,导致操作过于“灵敏”,也即按键K0、K1按下时,跳变过快。
这里所说的延时是中断子程序EX0_INT和EX1_INT 中的语句LCALL DIS_DELAY。
解决这个情况只需修改DELAY 次数,则DIS_DELAY:MOV D_CNT_DIS,#10H。
修改三:观察实物电路工作发现每一位:LED数码管的小数点都是亮的,没有起到用小数点区分时间/日期中的时分秒/年月日。
要解决这个问题,在显示子程序中TSA代码段的MOV Rx A前插入语句ADD A,#80H(x=1、2、4、6)。
以及加上发挥部分的拓展功能:秒表和闹钟。
九、原件清单十、心得体会与总结这个学期做了两个与汇编有关的课程设计(不过这次是大作业),一次是开学初的微机原理课程设计,还有就是这次单片机原理大作业。
上次基本上只与程序打交道,硬件部分实操不多。
而这次大作业则是硬件、软件两方面都有兼顾,且两者所花的时间也都不少。
虽然从老师那已经获取了原理图和程序,但这是我们第一次比较系统的从熟悉软件操作到软硬件设计了解整个流程。
硬件部分,由于先前我们都没有操作过protel之类的软件,所以一切从零开始,针对这次大作业需要,学习了protel软件的基本操作、原理图的绘制修改、原件的封装以及原件集成库的创建,当然还有PCB板的排线。
之后就是PCB 图打印,电路板热压制、腐蚀、钻孔,元器件的焊接。
流程很简洁,过程很纠结。
我们一步一个脚印地制作着,生怕哪个步骤出错而导致前功尽废。
不过在我们不懈努力下终于走完。
但是焊接的不仔细——两个电阻虚焊,使后来电路出现问题,也排查了好久,需要记住教训。
软件部分,虽然老师已经给了具备基本功能的程序,但是仍需看懂弄懂,后期才能更好地发现问题以及修改添加功能。
我发现这个过程也并非一件易事,清楚认识每一句的作用也需要经常查阅书籍。
另外在硬件焊接已经实现后我们把两者结合在一起,通过下载器把程序烧进52单片机中实现既定功能,发现上面故障排查中出现的问题,继而针对每个问题分别从软硬件寻找解决方法,这个过程我认为收获更大,能让我们更清楚熟悉软硬件两者的运作方法。
而且我俩分工是按硬件、软件而分的,自个儿认为分工尚算明确,各司其职。
十一、程序附录;wahaha.asm; (Electronic Calendar and Clock); Reference for Grade 2008, s.c.u.t.; Key0(for shift/adjust) connected to INT1; Key1(for un-flash/flash) connected to INT0; 学生姓名:陈晓伟、冯劲增; 学生学号:200830240144,200830240229; 分组编号:004;变量定义TICK_CNT EQU 20H ;T0倍乘;------------------SECOND_BCD EQU 21H ;时间记录MINUTE_BCD EQU 22HHOUR_BCD EQU 23HDAY_BCD EQU 24H ;日期记录MONTH_BCD EQU 25HYEAR_BCD EQU 26H;------------------FLASH_FLAG EQU 27H ;是否闪烁DIS_FLAG EQU R7 ;当前显示内容标志;DIS_FLAG: 0-时间;1-日期;2-闹钟;3-闹钟开关;4-秒表;------------------NSECOND_BCD EQU 2BH ;闹钟时间NMINUTE_BCD EQU 2CHNHOUR_BCD EQU 2DH;------------------TCC_BCD EQU 2EH ;秒表计时器TBB_BCD EQU 2FHTAA_BCD EQU 30H;------------------TIMER_FLAG EQU 31H ;秒表模式TIMER_START_FLAG EQU 32H ;秒表开始;------------------ALAM_STATE EQU 33H ;闹钟开启标志;------------------DI_40H EQU 34H ;提示音延时变量DI_41H EQU 35H ;延时;------------------ALAM_ON1 EQU 36H ;闹钟状态显示ALAM_ON2 EQU 37HALAM_ON3 EQU 38HALAM_OFF1 EQU 39HALAM_OFF2 EQU 3AHALAM_OFF3 EQU 3BH;------------------;中断向量表ORG 0000HLJMP MAINORG 0003HLJMP EX0_INT ; port INT0ORG 000BHLJMP T0_INT ; port T0ORG 0013HLJMP EX1_INT ; port INT1;主程序ORG 0030HMAIN: NOP ; main program;初始化堆栈MOV SP,#60H;初始化变量MOV SECOND_BCD,#00H ; BCD of "second"MOV MINUTE_BCD,#00H ; BCD of "minute"MOV HOUR_BCD,#00H ; BCD of "hour"MOV NSECOND_BCD,#00H ;闹钟BCD of "second"MOV NMINUTE_BCD,#00H ;闹钟BCD of "minute"MOV NHOUR_BCD,#06H ;闹钟BCD of "hour"MOV TCC_BCD,#00H ; 秒表BCD of "second"MOV TBB_BCD,#00H ; 秒表BCD of "minute"MOV TAA_BCD,#00H ; 秒表BCD of "hour"MOV TIMER_START_FLAG,#00H ;秒表工作标志MOV TIMER_FLAG,#00H ;秒表模式标志MOV DAY_BCD,#21H ; BCD of "day"MOV MONTH_BCD,#06H ; BCD of "month"MOV YEAR_BCD,#010H ; BCD of "year"MOV FLASH_FLAG,#00H ; flag for un-flash/flash MOV DIS_FLAG,#00H ; flag for shift(time/date)MOV ALAM_ON1,#55H ; BCD OFF 闹钟状态显示MOV ALAM_ON2,#01HMOV ALAM_ON3,#55HMOV ALAM_OFF1,#63HMOV ALAM_OFF2,#42HMOV ALAM_OFF3,#33HMOV ALAM_STA TE,#00H ;初始化闹钟状态为OFF;------------------MOV TL0,#0B0H ; constant for 0.05sMOV TH0,#3CH ; 65536-15536=50,000 for 12MHz MOV TICK_CNT,#14H ; times of overflow 0.05*20=1sMOV TMOD,#01H ; Mode 1 for T0, Timer ModeSETB ET0 ; open T0SETB EX0 ; open INT0, Key1SETB EX1 ; open INT1, Key0SETB EA ; total openSETB PT0 ; priority for T0,高优先级SETB TR0 ; start T0, RunSCAN_HOUR: ;闹钟扫描MOV A,SECOND_BCDCJNE A,#00H,SCANALARMMOV A,MINUTE_BCDCJNE A,#00H,SCANALARMHOUR:CLR P2.0NOP ;整点,滴SETB P2.0SCANALARM: ;闹钟扫描MOV A,ALAM_STA TEJZ SCAN_HOUR ;闹钟开关已打开?MOV A,NHOUR_BCDCJNE A,HOUR_BCD,W AITMOV A,NMINUTE_BCDCJNE A,MINUTE_BCD,W AITALARM:CLR P2.0 ;闹铃:滴滴滴滴``````SETB P2.0CLR P2.0SETB P2.0CLR P2.0SETB P2.0CLR P2.0SETB P2.0NOPNOPNOPWAIT:SETB P2.0SJMP SCAN_HOUR ; wait for interrupt ; -------------------------------------------------; sub: T0 interrupt; 定时器0中断T0_INT:PUSH ACCMOV TL0,#0B0H ; constant for 0.05s MOV TH0,#3CH ; Timer 0重装载MOV A,TIMER_START_FLAGCJNE A,#01H,TIMER_NEXT ;秒表模式?LJMP TIMER_INC ;秒表计时TIMER_NEXT:DJNZ TICK_CNT,NOT_1S ; is up to 1 second ?SJMP IS_1SNOT_1S:LJMP T0_RET; 1秒时间到IS_1S:MOV A,SECOND_BCD ; take BCD of "second"CJNE A,#59H,IN3 ; is up to 59 seconds ?SJMP IN4IN3:LJMP SECOND_INC ; 秒加1IN4:MOV SECOND_BCD,#00H ; 秒进位MOV A,MINUTE_BCD ; take BCD of "minute"CJNE A,#59H,IN5 ; is up to 59 minutes ?SJMP IN6IN5: LJMP MINUTE_INCIN6: MOV MINUTE_BCD,#00H ; 分进位MOV A,HOUR_BCD ; take BCD of "hour"CJNE A,#23H,HOUR_INC ; is up to 23 hours ?MOV HOUR_BCD,#00H ; "时"进位MOV A,MONTH_BCD ; take BCD of "month"CJNE A,#02H,NOT_FEB ; is February ?;2月处理;--------------------------FEB: NOPACALL BCD_DIV4 ; BCD of "year in 26H" divided by 4MOV A,R3 ; remainder in R3CJNE A,#00H,NOT_LEAP_Y ; "00" means leap year;闰年,29天LEAP_Y: M OV A,DAY_BCD ; take BCD of "day" in Feb.CJNE A,#29H,DAY_INC ; is up to 29 days (leap year)?MOV DAY_BCD,#01H ; keep the first dayMOV MONTH_BCD,#03H ; increase "month"SJMP RESET_CNT;非闰年NOT_LEAP_Y: MOV A,DAY_BCD ; take BCD of "day" in Feb.CJNE A,#28H,DAY_INC ; is up to 28 days (common year)?MOV DAY_BCD,#01H ; keep the first dayMOV MONTH_BCD,#03H ; increase "month"SJMP RESET_CNT;---------------------------;非2月处理;30/31天?NOT_FEB:NOP ; other "month" except Feb.CJNE A,#04H,Y01 ; is April ?AJMP MON_30DY01: CJNE A,#06H,Y02 ; is June ?AJMP MON_30DY02: CJNE A,#09H,Y03 ; is September ?AJMP MON_30DY03: CJNE A,#11H,T11 ; is November ?AJMP MON_30D;31天T11: MOV A,DAY_BCD ; take BCD of "day"CJNE A,#31H,DAY_INC ; is up to 31 days ?AJMP NEXT_MONTH;30天MON_30D:MOV A,DAY_BCD ; take BCD of "day"CJNE A,#30H,DAY_INC ; is up to 30 days ?;天进位NEXT_MONTH: MOV DAY_BCD,#01H ; keep the first day MOV A,MONTH_BCD ; take BCD of "month"CJNE A,#12H,MONTH_INC ; is December ?; 月进位MOV MONTH_BCD,#01H ; keep the first monthMOV A,YEAR_BCD ; take BCD of "year"CJNE A,#99H,YEAR_INC ; is up to 99 years ?MOV YEAR_BCD,#00H ; keep the first yearSJMP RESET_CNT;年加1YEAR_INC: MOV A,YEAR_BCD ; take BCD of "year"ADD A,#01H ; increase "year"DA A ; adjust BCDMOV YEAR_BCD,A ; keep "year"SJMP RESET_CNTMONTH_INC: MOV A,MONTH_BCD ; take BCD of "month"ADD A,#01H ; increase "month"DA A ; BCD码调整MOV MONTH_BCD,A ; keep "month"SJMP RESET_CNTDAY_INC: MOV A,DAY_BCD ; take BCD of "day"ADD A,#01H ; increase "day"DA A ; BCD码调整MOV DAY_BCD,A ; keep "day"SJMP RESET_CNTHOUR_INC: MOV A,HOUR_BCD ; take BCD of "hour"ADD A,#01H ; increase "hour"DA A ; BCD码调整MOV HOUR_BCD,A ; keep "hour"SJMP RESET_CNTMINUTE_INC: MOV A,MINUTE_BCD ; take BCD of "minute"ADD A,#01H ; increase "minute"DA A ; BCD码调整MOV MINUTE_BCD,A ; keep "minute"SJMP RESET_CNTSECOND_INC: MOV A,SECOND_BCD ; take BCD of "second"ADD A,#01H ; increase "second"DA A ; BCD码调整MOV SECOND_BCD,A ; save back "second"RESET_CNT: MOV TICK_CNT,#14H ; retrieve times of overflowT0_RET:POP ACCRETI;--------------------------------------------------------------------;秒表增TIMER_INC:TCC_INC:MOV A,TCC_BCD ; take BCD of "0.05S"CLR CSUBB A,#95HJZ TBB_INCMOV A,TCC_BCDADD A,#05H ; increase "0.05S"DA A ; BCD码调整MOV TCC_BCD,A ; keep "0.05S"AJMP TIMER_OUTTBB_INC:MOV TCC_BCD,#00HMOV A,TBB_BCD ; take BCD of "SECOND"CLR CSUBB A,#59HJZ TAA_INCMOV A,TBB_BCDADD A,#01H ; increase "SECOND"DA A ; BCD码调整MOV TBB_BCD,A ; keep "SECOND"AJMP TIMER_OUTTAA_INC:MOV TBB_BCD,#00HMOV A,TAA_BCD ; take BCD of "MINUTE"CLR CSUBB A,#59HJZ TDD_INCMOV A,TAA_BCDADD A,#01H ; increase "MINUTE"DA A ; BCD码调整MOV TAA_BCD,A ; save back "MINUTE"AJMP TIMER_OUTTDD_INC:MOV TAA_BCD,00HTIMER_OUT: LJMP TIMER_NEXT ;返回定时器中断;------------------------------------------------------------------; -------------------------------------------------------------------; sub: LED Display;显示子程序DISPLAY:MOV A,DIS_FLAGCJNE A,#03H,DISPLAY2 ;选择不同字模MOV DPTR,#TAB2SJMP DISPLAY3DISPLAY2:MOV DPTR,#TAB ; set address of code table DISPLAY3:MOV A,DIS_FLAG ; take flag for shiftCJNE A,#00H,DISP_DATE ; "00" 当前显示内容为时间;R0: point to display bufferDISP_TIME: MOV R0,#SECOND_BCD ; beginning from "second"SJMP TSADISP_DATE:CJNE A,#01H,DISP_ALAM ; "01" 当前显示内容为日期MOV R0,#DAY_BCD ; "FF" for showing dateSJMP TSA;显示时间或日期DISP_ALAM:CJNE A,#02H,DISP_ALAM_SET ; "02" 当前显示内容为闹钟MOV R0,#NSECOND_BCD ; beginning from "second"SJMP TSADISP_ALAM_SET:CJNE A,#03H,DISP_TIMER ; "03" 当前显示内容为闹钟设置MOV A,ALAM_STATE ; 闹钟状态显示JZ SHOWOFFMOV R0,#ALAM_ON1 ; 显示"ON"SJMP TSASHOWOFF:MOV R0,#ALAM_OFF1 ;显示"OFF"SJMP TSADISP_TIMER: ;"04"当前显示内容为秒表MOV R0,#TCC_BCD ; beginning from "second"TSA: MOV A,@R0 ; begin from "day"ANL A,#0FH ; get the "low half byte"MOVC A,@A+DPTR ; take character from code tableMOV R1,A ; keep in R1 for DS6 showingMOV A,@R0SWAP AANL A,#0FH ; get the "high half byte"MOVC A,@A+DPTR ; take character from code tableMOV R2,A ; keep in R2 for DS5 showing;---------------INC R0MOV A,@R0 ; next one from "month"ANL A,#0FH ; get the "low half byte"MOVC A,@A+DPTRMOV R3,A ; keep in R3 for DS4 showingMOV A,@R0SWAP AANL A,#0FH ; get the "high half byte"MOVC A,@A+DPTRMOV R4,A ; keep in R4 for DS3 showing;-------------INC R0MOV A,@R0 ; next one from "year"ANL A,#0FH ; get the "low half byte"MOVC A,@A+DPTRMOV R5,A ; keep in R5 for DS2 showingMOV A,@R0SWAP AANL A,#0FH ; get the "high half byte"MOVC A,@A+DPTRMOV R6,A ; keep in R6 for DS1 showing;---------------------;P1:位选线;P0:段选线NOPTDP: MOV P1,#0FFH ; close all showing///;Display DS6MOV A,ALAM_STA TE ;是否显示闹钟状态位?(最末位小数点)JZ DIS_NEXTMOV A,R1ANL A,#7FHMOV R1,ADIS_NEXT:MOV A,R1MOV P0,A ; send character to DS6MOV A,FLASH_FLAG ; get flag of un-flash/flashCJNE A,#03H,A02 ; "03" is flash on DS5&DS6SJMP A03A02: CJNE A,#03H,A04; ; "03" is flash on DS5&DS6A03: MOV A,TICK_CNT ; take Counter of overflowRRC AA04: MOV P1,#0dfH ; turn on DS6A05: LCALL DELAYMOV P1,#0FFH ; close all showing;Display DS5MOV P0,R2 ; send character to DS5MOV A,FLASH_FLAG ; get flag of un-flash/flashCJNE A,#03H,B02 ; "03" is flash on DS5&DS6SJMP B03B02: C JNE A,#03H,B04B03: M OV A,TICK_CNT ; take times of overflowRRC AJNC B05 ; check bit C ( 1 or 0 )B04: M OV P1,#0efH ; turn on DS5B05: L CALL DELAYMOV P1,#0FFH ; close all showing;Display DS4MOV A,R3ANL A,#7FH ;该位增加小数点显示MOV P0,A ; send character to DS4MOV A,FLASH_FLAG ; get flag of un-flash/flashCJNE A,#02H,C02 ; "02" is flash on DS3&DS4SJMP C03C02: C JNE A,#02H,C04C03: M OV A,TICK_CNT ; take times of overflowRRC AJNC C05 ; check bit C ( 1 or 0 )C04: M OV P1,#0f7H ; turn on DS4C05: L CALL DELAYMOV P1,#0FFH ; close all showing;Display DS3MOV P0,R4 ; send character to DS3MOV A,FLASH_FLAG ; get flag of un-flash/flashCJNE A,#02H,D02 ; "02" is flash on DS3&DS4SJMP D03D02: CJNE A,#02H,D04D03: MOV A,TICK_CNT ; take times of overflow RRC AD04: MOV P1,#0fbH ; turn on DS3D05: LCALL DELAYMOV P1,#0FFH ; close all showing;Display DS2MOV A,R5ANL A,#7FH ;该位增加小数点显示MOV P0,A ; send character to DS2MOV A,FLASH_FLAG ; get flag of un-flash/flashCJNE A,#01H,E02 ; "01" is flash on DS1&DS2SJMP E03E02: CJNE A,#01H,E04E03: MOV A,TICK_CNT ; take times of overflowRRC AJNC E05 ; check bit C ( 1 or 0 )E04: MOV P1,#0fdH ; turn on DS2E05: LCALL DELAYMOV P1,#0FFH ; close all showingMOV P0,R6 ; send character to DS1MOV A,FLASH_FLAG ; get flag of un-flash/flashCJNE A,#01H,F02 ; "01" is flash on DS1&DS2SJMP F03F02: CJNE A,#01H,F04F03: MOV A,TICK_CNT ; take times of overflowRRC AJNC F05 ; check bit C ( 1 or 0 )F04: MOV P1,#0feH ; turn on DS1F05: LCALL DELAYMOV P1,#0FFH ; close all showingRET; -------------------------------------------------------------------; ----------------------------------------; sub: delay (1.542ms for 12MHz, 3.084ms for 6MHz);延时子程序D_CNT_2 EQU 28HD_CNT_1 EQU 29HDELAY: MOV D_CNT_2,#03HD_LOOP2: MOV D_CNT_1,#0FFH ;[1]D_LOOP1: DJNZ D_CNT_1,D_LOOP1 ;[2]DJNZ D_CNT_2,D_LOOP2 ;[2]RET; ----------------------------------------; ---------------------------------------------------------;外部中断0; sub: INT0 interrupt; 处理按键K0,切换时间/日期/闹钟/闹钟设置/秒表显示或者调整EX0_INT: NOP ; switch or adjust with date/timePUSH ACCPUSH PSWLCALL DIS_DELAY ; re-bounce (with LED display)JNB P3.3,OUT ; check port INT1;K0按下NOP ; inhibit INT1 ( use k0);---------------------------------------------------MOV A,FLASH_FLAGCJNE A,#00H,JUDGE_MODE ;有闪烁进入调整模式SET_DIS: ;无闪烁进入设置显示或秒表模式CLR P2.0 ;按键滴一声MOV DI_41H,#19HDI_LPO:MOV DI_40H,#0FFHDI_LP:DJNZ DI_40H,DI_LPDJNZ DI_41H,DI_LPOSETB P2.0;---------------------------------------------------MOV A,DIS_FLAGINC AMOV DIS_FLAG,ACJNE A,#04H,CROSSTIMER ;进入秒表?;---------------------------------------------------TIMER:MOV TIMER_FLAG,#01H ;进入秒表,秒表模式设置为开LJMP EX0_RET ;退出;---------------------------------------------------CROSSTIMER: ;显示模式切换CJNE A,#05H,OUTMOV DIS_FLAG,#00H ;已到5需置零MOV TIMER_FLAG,#00HMOV A,TIMER_START_FLAGJNZ OUT ;秒表后台工作,暂停计数时退出则对秒表清零MOV TCC_BCD,#00H ; BCD of "second" 秒表清零MOV TBB_BCD,#00H ; BCD of "minute"MOV TAA_BCD,#00H ; BCD of "hour"OUT: LJMP EX0_RET ; 退出;---------------------------------------------------JUDGE_MODE: ;进入调整模式MOV A,DIS_FLAG ; 读取当前显示内容为?(时间/日期/秒表/闹钟)CJNE A,#00H,JDATE ;是否进入时间调整00;---------------------------------------------------JTIME: ;调整时间MOV A,FLASH_FLAG ; take flag of un-flash/flashADH: CJNE A,#01H,ADM ; "03" for adjusting "hour"MOV A,HOUR_BCD ; take BCD of "hour"CJNE A,#23H,JH0 ; is up to 23 hours ?MOV HOUR_BCD,#00H ; keep the first hourLJMP JHFJH0: ADD A,#01H ; increase "hour"DA A ; adjust BCDMOV HOUR_BCD,A ; keep "hour"JHF: L JMP EX0_RET;-----------------------------------------ADM: CJNE A,#02H,ADS ; "02" for adjusting "minute"MOV A,MINUTE_BCD ; take BCD of "minute"CJNE A,#59H,JM0 ; is up to 59 minutes ?MOV MINUTE_BCD,#00H ; keep the first minuteLJMP JMFJM0: ADD A,#01H ; increase "minute"DA A ; adjust BCDMOV MINUTE_BCD,A ; keep "minute"JMF: LJMP EX0_RETADS: MOV A,SECOND_BCD ; take BCD of "second"CJNE A,#59H,JS0 ; is up to 59 seconds ?MOV SECOND_BCD,#00H ; keep the first secondLJMP JSFJS0: ADD A,#01H ; increase "second"DA A ; adjust BCDMOV SECOND_BCD,A ; keep "second"JSF: NOPLJMP EX0_RET;---------------------------------------------------JALAM0: LJMP JALAMJDATE: CJNE A,#01H,JALAM0 ;是否进入日期调整01JYY: NOP ; "01 to 06" is in flashMOV A,FLASH_FLAGCJNE A,#01H,JMM ; "01" for adjusting "year";调节年MOV A,YEAR_BCD ; take BCD of "year"CJNE A,#99H,YY0 ; is up to 99 year ?MOV YEAR_BCD,#00H ; keep the first yearLJMP YYFYY0: ADD A,#01H ; increase "year"DA A ; adjust BCDMOV YEAR_BCD,A ; keep "year"YYF: LJMP EX0_RET;---------------------------------------JMM: CJNE A,#02H,JDD ; "02" for adjusting "month";调节月MOV A,MONTH_BCD ; take BCD of "month"CJNE A,#12H,MM0 ; is December ?MOV MONTH_BCD,#01H ; keep the first monthLJMP MMFMM0: ADD A,#01H ; increase "month"DA A ; adjust BCDMOV MONTH_BCD,A ; keep "month"MMF: LJMP EX0_RET;---------------------------------------JDD: CJNE A,#03H,AA1 ; "03" for adjusting "day"LJMP BB1AA1: LJMP ADH ;BB1: MOV A,MONTH_BCD ; first, should take "month"CJNE A,#02H,NFB ; is February ?IFB: NOPACALL BCD_DIV4 ; BCD of "year in YEAR_BCD" divided by 4MOV A,R3 ; remainder in R3CJNE A,#00H,ANG ; "00" means leap yearARN: MOV A,DAY_BCD ; take BCD of "day"CJNE A,#29H,D0A ; is up to 29 days in Feb.?LJMP D0BD0A: LJMP DDAD0B: LJMP DD1ANG: MOV A,DAY_BCD ; take BCD of "day"CJNE A,#28H,D0A ; is up to 28 days in Feb.?LJMP DD1NFB: NOP ; check "little/large" monthCJNE A,#04H,Y04 ; is April ?LJMP AD1Y04: CJNE A,#06H,Y05 ; is June ?LJMP AD1Y05: CJNE A,#09H,Y06 ; is September ?LJMP AD1Y06: CJNE A,#11H,Y07 ; is November ?LJMP AD1Y07: NOP ; for "large" monthMOV A,DAY_BCD ; take BCD of "day"CJNE A,#31H,D0A ; is up to 31 days ?LJMP DD1AD1: NOP ; for "little" monthMOV A,DAY_BCD ; take BCD of "day"CJNE A,#30H,D0A ; is up to 30 days ?DD1: MOV DAY_BCD,#01H ; keep the first dayLJMP DDFDDA: ADD A,#01H ; increase "day"DA A ; adjust BCDMOV DAY_BCD,A ; keep "day"DDF: LJMP EX0_RET;---------------------------------------------------JALAM: ;调整闹钟MOV A,FLASH_FLAG ; take flag of un-flash/flash NADH: CJNE A,#01H,NADM ; "03" for adjusting "hour"MOV A,NHOUR_BCD ; take BCD of "hour"CJNE A,#23H,NJH0 ; is up to 23 hours ?MOV NHOUR_BCD,#00H ; keep the first hourLJMP NJHFNJH0: ADD A,#01H ; increase "hour"DA A ; adjust BCDMOV NHOUR_BCD,A ; keep "hour"NJHF: LJMP EX0_RET;-----------------------------------------NADM: CJNE A,#02H,NADS ; "02" for adjusting "minute"MOV A,NMINUTE_BCD ; take BCD of "minute"CJNE A,#59H,NJM0 ; is up to 59 minutes ?MOV NMINUTE_BCD,#00H ; keep the first minuteLJMP NJMFNJM0: ADD A,#01H ; increase "minute"DA A ; adjust BCDMOV NMINUTE_BCD,A ; keep "minute"NJMF: LJMP EX0_RETNADS: MOV A,NSECOND_BCD ; take BCD of "second"CJNE A,#59H,NJS0 ; is up to 59 seconds ?MOV NSECOND_BCD,#00H ; keep the first secondLJMP NJSFNJS0: ADD A,#01H ; increase "second"DA A ; adjust BCDMOV NSECOND_BCD,A ; keep "second"NJSF: NOPLJMP EX0_RET;---------------------------------------------------EX0_RET:NOP ;中断退出POP PSWPOP ACCRETI;---------------------------------------------------;---------------------------------------------------; sub: INT1 interrupt; 处理按键K1,设置闪烁EX1_INT:NOP ; revise flag(00 to 06) in FLASH_FLAG PUSH ACCPUSH PSWJNB P3.2,EX1_RET ; check port INT0LCALL DIS_DELAY ; re-bounce (with LED display);;K1按键按下NOP ; inhibit INT0 (use k1)MOV A,DIS_FLAGCJNE A,#03H,TIMER_START0 ;非设置闹钟开关模式?MOV A,ALAM_STA TECPL A ;取非ANL A,#01H ;保留最后MOV ALAM_STA TE,A ;设置闹钟开关AJMP DI_START ;提示音后退出;---------------------------------------------------TIMER_START0:MOV A,TIMER_FLAGCJNE A,#01,FLASH_SHIFT ;非秒表模式?TIMER_START:MOV A,TIMER_START_FLAGCPL AANL A,#01H ;保留最低位MOV TIMER_START_FLAG,A ;设置秒表开关;---------------------------------------------------DI_START:CLR P2.0 ;按键滴一声MOV DI_41H,#19HDI_LOOPO:MOV DI_40H,#0FFHDI_LOOP:DJNZ DI_40H,DI_LOOPDJNZ DI_41H,DI_LOOPOSETB P2.0AJMP EX1_RET ;退出;---------------------------------------------------FLASH_SHIFT: ;进入切换闪烁MOV A,FLASH_FLAG ; take flag of un-flash/flashCJNE A,#00H,ED1 ; "00" 无闪烁MOV FLASH_FLAG,#01H ; 设置1,2号数码管闪烁SJMP EX1_RETED1: CJNE A,#01H,ED2 ; "01" 1,2号闪烁中MOV FLASH_FLAG,#02H ; 设置3,4号闪烁SJMP EX1_RETED2: CJNE A,#02H,ED3 ; "02" 3,4号闪烁MOV FLASH_FLAG,#03H ; 设置5,6号闪烁SJMP EX1_RETED3: MOV FLASH_FLAG,#00H ; 关闭所有闪烁EX1_RET:NOPPOP PSWPOP ACCRETI;------------------------------------; ---------------------------------------------; 带显示延迟D_CNT_DIS EQU 2AHDIS_DELAY: MOV D_CNT_DIS,#10H ; or(#0BH)DELAY_LOOP: LCALL DISPLAY ; with LED display DJNZ D_CNT_DIS,DELAY_LOOPRET; -----------------------------------------------; ----------------------------------------------------------; sub: BCD division; BCD除法:除4; 输出:; R3: 余数; R2: 商BCD_DIV4: MOV R0,YEAR_BCD ; dividend in BCD MOV R1,#04H ; divider in BCDMOV R2,#00H ; R2:输出商MOV A,R1CPL AADD A,#9BHMOV R1,A ; R1:BCD补码MOV A,R0ANL A,#0F0H ; BCD高位SWAP ALP0: M OV R3,A ; BCD码的余数ADD A,R1DA AJNC LP1INC R2SJMP LP0LP1: M OV A,R3SWAP AMOV R3,AMOV A,R2SWAP AMOV R2,A ; 商的高位MOV A,R0ANL A,#0FH ; 年BCD的低位ORL A,R3LP2: M OV R3,AADD A,R1DA AJNC LP3INC R2SJMP LP2LP3: N OP ; no roundingRET;----------------------------------------------; ------------------------------------------------------ TAB:DB 0c0H ; for "0"DB 0f9H ; for "1"DB 0a4H ; for "2"DB 0b0H ; for "3"DB 99H ; for "4"DB 92H ; for "5"DB 82H ; for "6"DB 0f8H ; for "7"DB 80H ; for "8"DB 90H ; for "9"TAB2:DB 0C0H ; "0"DB 11001000B ; "N"DB 10001110B ; "F"DB 0FFH ; " "DB 40H ; "0."DB 07FH ; "."DB 00001110B ; "F."END。