51单片机电子万年历设计电路图及程序
- 格式:doc
- 大小:298.50 KB
- 文档页数:38
作品名称:基于C51单片机的万年历设计目录一、绪论 (1)二、系统功能 (1)三、硬件电路 (1)3.1. 电路设计框图 (1)3.2. 系统硬件概述 (2)四、各模块功能及工作原理 (2)4.1. 单片机主控制模块的设计 (2)4.2. LCD1602显示模块 (3)4.3. 键盘模块 (6)五、实现结果 (9)六、系统的实用性及创新性 (9)七、调节中遇到的问题及心得体会 (10)八、程序设计 (11)8.1. 流程图 (11)8.2. 源代码 (12)九、总结及感谢 (24)一、绪论众所周知单片机是一种集成在电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU 随机存储器RAM 、只读存储器ROM 、多种I/O 口和中断系统、定时器/计时器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D 转换器等电路)集成到一块硅片上构成的一个小而完善的计算机系统。
本设计要制作的就是单片机于生活中最为常见的几种应用——万年历。
本设计以AT89S52单片机作为核心,可以显示当前的日历和时间,时间也可以人为设定,显示格式为年(四位),月(两位),日(两位),时(两位),分(两位),秒(两位)。
设置时间的位切换、设定数值、启动定时器、切换日历通过外部中断来实现。
万年历显示电路由LCD1602组成, 制作该装置的材料需要有软硬件的支持,硬件方面AT89C51单片机,晶振,电源,液晶屏LCD1602。
二、系统功能本次设计的是万年历,采用LCD1602显示,实现的功能如下: 1. 显示当前时间,显示格式为年(四位),月(两位),日(两位),时(两位),分(两位),秒(两位);2. 时钟计时,自动进行时间的位切换;3. 键盘设置,能通过键盘设定当前时间和计时,并通过键盘人为设定时间。
三、硬件电路3.1. 电路设计框图AT89S52主控制模块LCD1602显示模块计时模块键盘输入模块3.2.系统硬件概述本电路是由AT89S52单片机为控制核心,具有在线编程功能,低功耗,能在3V超低压工作,本系统选用12MHZ的晶振,使得单片机有合理的运行速度;利用液晶屏LCD1602显示时间信息,通过对AT89S52单片机的编程控制液晶屏LCD1602的显示。
1. 综述本课题要求设计一个常用的万年历。
该电路是用于反应年、月、日、时、分、秒、星期的实时状态,液晶显示屏上显示第一排显示“湖南工学院”第二排显示“年、月、日”第三排显示“时、分、秒”第四排显示“星期”。
当接通时液晶屏上一次显示,并且可以通过矩阵键盘调节年、月、日、时、分、秒、星期的实时状态。
假设液晶显示屏显示的是2008年8月1日,要求是:通过矩阵键盘的调节可以实时时间。
经过以上所述的设计内容及要求的分析,可以将电路分为以下几部分:首先,通过晶振电路产生频率为32.768KH z的脉冲信号,该脉冲信号用于提供给DS1302的时钟脉冲信号。
接通电源时,液晶屏上显示“湖南工学院”“电气与信息工程系”“电信0901”“蒋赞荣”。
当按下第一个按键时进入“欢迎进入万年历”界面。
按下第二个按键时进入显示经典万年历界面。
理论部分已用protues软件进行仿真,并且达到设计要求。
实际部分在电子实验室和同组的成员在老师的指导下一进行模拟,能够达到理论设计要求。
在设计的过程中应该本着元件通用化,成品化,程序的精简化,以满足大规模生产的要求,以便在日后产品的更新维护能够更好的方便的进行。
同时也要尽量减少设计过程中掉电现象和不稳定现象。
使产品在使用过程中能够稳定的运行,达到良好的无故障率。
二者必须达到一定的标准,才能在工厂进行量产。
2. 方案设计与分析方案通过DS1302时钟芯片产生时钟数据信息,通过读写该芯片内的时钟信号通过单片机的控制将其显示在液晶屏幕上。
该芯片的三总线SCLK、I/O、CE分别接在单片机的P3^2、P3^3、P3^4三端效果是最好的,因为P3^0、P3^1位接在液晶屏的RS、RW,P3^5接在液晶屏的E端,其它的三态数据线接在P0口,矩阵键盘可以通过跳线接P1口或P2口,在使程序设计起来比较简单,可以很好的利用者一点,设计的复杂程度适中,而且达到了预期的设计目的。
在此电路中由于P0口用于液晶电路的三态八根数据线了,而P3口也用作了特殊作用,所以矩阵键盘的跳线只能是在P1口或者是P2口作为键盘的输入信号。
51单片机实现万年历利用AT89S52单片机的P0口来和另外几个口来控制1602液晶的显示和P1口还有其它口来控制ds12887时钟芯片。
设置四个按键,1个定义为时间设置功能键,一个定义为闹钟设置功能键,另外两个用来调节时间的增减。
原理图:pcb图:源程序:#include<reg52.h>#define uint unsigned int#define uchar unsigned charsbit beep=P2^0;//蜂鸣器控制口sbit timeadd=P2^1;//调节时间加sbit timesub=P2^2;//调节时间减sbit timeclk=P2^3;//闹钟设定键sbit timefun=P2^4;//时间设定键sbit lcdrs=P2^5;//液晶的命令和数据控制口sbit ledrw=P2^6;//液晶的写数据口sbit lcden=P2^7;//液晶显示模块的使能端sbit timeds=P3^3;//时钟芯片地址闸sbit timerw=P3^4;//时钟芯片读写sbit timeas=P3^5;//时钟芯片地址闸sbit timeen=P3^6;//时钟芯片片选uchar code table[]="20 - - week ";uchar code table1[]=" : : ";//要显示的字符串char num,shi,fen,miao,nian=2000,yue,ri,week,numfun,anumfun,flag,flag1; uchar leap;void delay(uint x){uchar i,j;for(i=x;i>0;i--)for(j=110;j>0;j--);}void didi(){beep=0;delay(1000);beep=1;delay(1000);}void write_(uchar ){lcdrs=0;P0=;delay(5);lcden=1;delay(20);lcden=0;}void write_date(uchar date){lcdrs=1;P0=date;delay(5);lcden=1;delay(20);lcden=0;}void write_sfm(uchar add,uchar date){ uchar shi,ge;shi=date/10;ge=date%10;write_(0x80+0x40+add);write_date(0x30+shi);write_date(0x30+ge);}void write_nyr(uchar add,uchar date){ uchar shi,ge;shi=date/10;ge=date%10;write_(0x80+add);write_date(0x30+shi);write_date(0x30+ge);}void write_zhou(uchar add,uchar date) {write_(0x80+add);write_date(0x30+date);}void write_ds(uchar add,uchar date){ timeen=0;timeas=1;timeds=1;timerw=1;P1=add;timeas=0;timerw=0;P1=date;timerw=1;timeas=1;timeen=1;}uchar read_ds(uchar add){uchar ds_date;timeas=1;timeds=1;timerw=1;timeen=0;P1=add;timeas=0;timeds=0;P1=0xff;ds_date=P1;timeds=1;timeas=1;timeen=1;return ds_date;}void keyscan(){if(flag1==1)//用来关闭闹钟铃声{if(timeadd==0){delay(5);if(timeadd==0){while(!timeadd==0);flag1=0;}}if(timesub==0){delay(5);if(timesub==0){while(!timesub==0);flag1=0;}}}if(timefun==0){delay(5);if(timefun==0){while(!timefun);flag=1;numfun++;if(numfun==1){write_(0x80+0x40+0x0a);write_(0x0f);}if(numfun==2){write_(0x80+0x40+0x07);write_(0x0f);}if(numfun==3){write_(0x80+0x40+0x04);write_(0x0f);}if(numfun==4){write_(0x80+0x0f);write_(0x0f);}if(numfun==5){write_(0x80+0x09);write_(0x0f);}if(numfun==6){write_(0x80+0x06);write_(0x0f);}if(numfun==7){write_(0x80+0x03);write_(0x0f);}if(numfun==8){numfun=0;flag=0;}}}if(numfun!=0){if(timeadd==0){delay(5);while(!timeadd);if(numfun==1){miao++;if(miao==60)miao=0;write_sfm(9,miao);write_(0x80+0x40+9);write_ds(0,miao);}if(numfun==2){fen++;if(fen==60)fen=0;write_sfm(6,fen);write_(0x80+0x40+6);write_ds(2,fen);}if(numfun==3){shi++;if(shi==24)shi=0;write_sfm(3,shi);write_(0x80+0x40+3);write_ds(4,shi);}if(numfun==4){week++;if(week==8)week=1;write_zhou(0x0f,week);write_(0x80+0x0f);write_ds(6,week);}if(numfun==5){if(nian==0){switch(yue){case 1:ri++;if(ri==32) ri=1;break;case 2:ri++;if(ri==30) ri=1;break;case 3:ri++;if(ri==32) ri=1;break;case 4:ri++;if(ri==31) ri=1;break;case 5:ri++;if(ri==32) ri=1;break;case 6:ri++;if(ri==31) ri=1;break;case 7:ri++;if(ri==32) ri=1;break;case 8:ri++;if(ri==32) ri=1;break;case 9:ri++;if(ri==31)ri=1;break;case 10:ri++;if(ri==32)ri=1;break;case 11:ri++;if(ri==31)ri=1;break;case 12:ri++;if(ri==32)ri=1;break;}}else if(leap&&yue==2){ri++;if(ri==30)ri=1;}else if(yue==2&&leap==0){ri++;if(ri==29)ri=1;}elseswitch(yue){case 1:ri++;if(ri==32) ri=1;break;case 3:ri++;if(ri==32) ri=1;break;case 4:ri++;if(ri==31) ri=1;break;case 5:ri++;if(ri==32) ri=1;break;case 6:ri++;if(ri==31) ri=1;break;case 7:ri++;if(ri==32) ri=1;break;case 8:ri++;if(ri==32) ri=1;break;case 9:ri++;if(ri==31) ri=1;break;case 10:ri++;if(ri==32) ri=1;break;case 11:ri++;if(ri==31) ri=1;break;case 12:ri++;if(ri==32) ri=1;break;}write_nyr(8,ri);write_(0x80+0x08);write_ds(7,ri);}if(numfun==6){yue++;if(yue==13)yue=0;write_nyr(5,yue);write_(0x80+0x05);write_ds(8,yue);}if(numfun==7){nian++;if(nian==100)nian=0;leap=nian%4==0&&nian%100!=0;write_nyr(2,nian);write_(0x80+2);write_ds(9,nian);}}if(timesub==0){delay(5);while(!timesub);if(numfun==1){miao--;if(miao==-1)miao=59;write_sfm(9,miao);write_(0x80+0x40+9);write_ds(0,miao);}if(numfun==2){fen--;if(fen==-1)fen=59;write_sfm(6,fen);write_(0x80+0x40+6);write_ds(2,fen);}if(numfun==3){shi--;if(shi==-1)shi=23;write_sfm(3,shi);write_(0x80+0x40+3);write_ds(4,shi);}if(numfun==4){week--;if(week==0)week=7;write_zhou(0x0f,week);write_(0x80+0x0f);write_ds(6,week);}if(numfun==5){if(nian==0){switch(yue){case 1:ri--;if(ri==0) ri=31;break;case 2:ri--;if(ri==0) ri=29;break;case 3:ri--;if(ri==0) ri=31;break;case 4:ri--;if(ri==0) ri=30;break;case 5:ri--;if(ri==0) ri=31;break;case 6:ri--;if(ri==0) ri=30;break;case 7:ri--;if(ri==0) ri=31;break;case 8:ri--;if(ri==0) ri=31;break;case 9:ri--;if(ri==0) ri=30;break;case 10:ri--;if(ri==0) ri=31;break;case 11:ri--;if(ri==0) ri=30;break;case 12:ri--;if(ri==0) ri=31;break;}}else if(leap&&yue==2){ri--;if(ri==0)ri=29;}else if(yue==2&&leap==0){ri--;if(ri==0)ri=28;}elseswitch(yue){case 1:ri--;if(ri==0) ri=31;break;case 3:ri--;if(ri==0) ri=31;break;case 4:ri--;if(ri==0) ri=30;break;case 5:ri--;if(ri==0) ri=31;break;case 6:ri--;if(ri==0) ri=30;break;case 7:ri--;if(ri==0) ri=31;break;case 8:ri--;if(ri==0) ri=31;break;case 9:ri--;if(ri==0) ri=30;break;case 10:ri--;if(ri==0) ri=31;break;case 11:ri--;if(ri==0) ri=30;break;case 12:ri--;if(ri==0) ri=31;break;}write_nyr(8,ri);write_(0x80+0x08);write_ds(7,ri);}if(numfun==6){yue--;if(yue==-1)yue=12;write_nyr(5,yue);write_(0x80+0x05);write_ds(8,yue);}if(numfun==7){nian--;if(nian==-1)nian=99;leap=nian%4==0&&nian%100!=0;write_nyr(2,nian);write_(0x80+2);write_ds(9,nian);}}}}void set_alarm(){uchar ashi,afen,amiao;if(timeclk==0)//判断是否按下闹钟设定键{delay(5);//延时消抖if(timeclk==0){while(!timeclk);anumfun++;//按键次数加1if(anumfun==1){flag=1;write_(0x80+0x40+0x0a);write_(0x0f);}if(anumfun==2){flag=1;write_(0x80+0x40+0x07);write_(0x0f);}if(anumfun==3){flag=1;write_(0x80+0x40+0x04);write_(0x0f);}if(anumfun==4){flag=0;anumfun=0;}}}if(anumfun!=0){if(timeadd==0)//如果加功能键按下{delay(5);while(!timeadd);if(anumfun==1) //设定秒{amiao++;if(amiao==60)amiao=0;write_sfm(9,amiao);write_(0x80+0x40+9);write_ds(1,amiao);}if(anumfun==2){afen++;if(afen==60)afen=0;write_sfm(6,afen);write_(0x80+0x40+6);write_ds(3,afen);}if(anumfun==3){ashi++;if(ashi==24)ashi=0;write_sfm(3,ashi);write_(0x80+0x40+3);write_ds(5,ashi);}}}if(anumfun!=0){if(timesub==0){delay(5);while(!timesub);if(anumfun==1){amiao--;if(amiao==-1)amiao=59;write_sfm(9,amiao);write_(0x80+0x40+9);write_ds(1,amiao);}if(anumfun==2){afen--;if(afen==-1)afen=59;write_sfm(6,afen);write_(0x80+0x40+6);write_ds(3,afen);}if(anumfun==3){ashi--;if(ashi==-1)ashi=23;write_sfm(3,ashi);write_(0x80+0x40+3);write_ds(5,ashi);}}}}void init(){EA=1;//开总中断EX0=1;//开外部中断0IT0=1;//设定触发方式为负跳变沿有效lcden=0;//选通液晶显示屏ledrw=0;//设定液晶显示屏的读写方式为读write_(0x38);//设置液晶显示模式为16*2显示,5*7点阵,8位数据接口 write_(0x0c);//打开显示,并使光标不显示也不闪烁write_(0x06);//光标指针每次自动加1write_(1);//清屏write_(0x80);//送地址指针for(num=0;num<16;num++){write_date(table[num]);delay(5);}write_(0x80+0x40);//写到第二行for(num=0;num<11;num++){write_date(table1[num]);delay(5);}write_ds(0x0a,0x20);//开启时钟芯片振荡器write_ds(0x0b,0x26);//开启闹钟read_ds(0x0c);//读取时钟芯片c寄存器}void main(){init();while(1){keyscan();set_alarm();if(flag1==1)didi();if(flag==0){//读取时间miao=read_ds(0x00);fen=read_ds(0x02);shi=read_ds(0x04);yue=read_ds(0x08);ri=read_ds(0x07);nian=read_ds(0x09);week=read_ds(0x06);//写入液晶显示屏write_sfm(9,miao);write_sfm(6,fen);write_sfm(3,shi);write_nyr(2,nian);write_nyr(5,yue);write_nyr(8,ri);write_zhou(0x0f,week);}}}void exter() interrupt 0{flag1=1;read_ds(0x0c);//读时钟芯片c寄存器。
自己制作的单片机万年历程序+原理图单片机万年历仿真原理图如下仿真Altium Designer画的万年历原理图和PCB图如下:PCB原理图基于51单片机,可以完成时钟显示、公历显示、农历显示、温度显示、闹钟报警定时的LCD时钟PPT内容预览:本设计使用AT89C51来做主控芯片,其强大的功能足够实现我们设计的所有功能。
使用LCD1602的液晶显示器来进行显示。
使用Keil uVision5进行编程。
通过Proteus8.6来进行仿真。
点击一次K1进入时钟设置页面,通过点击K2切换时、秒、分、星期、年、月、日,通过K3与K4实现加减来完成时钟的设置点击两次K1进入闹钟设置页面,通过点击K2切换开关、时、秒、分,通过K3与K4实现加减完成闹钟的设置。
单片机源程序如下注释是很全的#include //调用单片机头文件#define uchar unsigned char //无符号字符型宏定义变量范围0~255#define uint unsigned int //无符号整型宏定义变量范围0~65535#include "eeprom52.h"#include "nongli.h"#include "intrins.h"bit flag_200ms ;bit flag_100ms ;sbit beep = P3^7; //蜂鸣器定义bit flag_beep_en;uint clock_value; //用作闹钟用的sbit dq = P3^1; //18b20 IO口的定义uint temperature ; //温度变量uchar flag_nl; //农历阳历显示标志位uchar menu_1,menu_2;uchar key_time,flag_value; //用做连加的中间变量bit key_500ms ;uchar n_nian,n_yue,n_ri; //农历显示的函数#include "ds1302.h"#include "lcd1602.h"/******************把数据保存到单片机内部eeprom中******************/void write_eeprom(){SectorErase(0x2000);byte_write(0x2000, fen1);byte_write(0x2001, shi1);byte_write(0x2002, open1);byte_write(0x2058, a_a);}/******************把数据从单片机内部eeprom中读出来*****************/void read_eeprom(){fen1 = byte_read(0x2000);shi1 = byte_read(0x2001);open1 = byte_read(0x2002);a_a = byte_read(0x2058);}/**************开机自检eeprom初始化*****************/void init_eeprom(){read_eeprom(); //先读if(a_a != 1) //新的单片机初始单片机内问eeprom{fen1 = 3;shi1 = 8;a_a = 1;write_eeprom(); //保存数据}}/***********************18b20初始化函数*****************************/void init_18b20(){bit q;dq = 1; //把总线拿高delay_uint(1); //15usdq = 0; //给复位脉冲delay_uint(80); //750usdq = 1; //把总线拿高等待delay_uint(10); //110usq = dq; //读取18b20初始化信号delay_uint(20); //200usdq = 1; //把总线拿高释放总线}/*************写18b20内的数据***************/void write_18b20(uchar dat){uchar i;for(i=0;i<8;i++){ //写数据是低位开始dq = 0; //把总线拿低写时间隙开始dq = dat & 0x01; //向18b20总线写数据了delay_uint(5); // 60usdq = 1; //释放总线}}/*************读取18b20内的数据***************/uchar read_18b20(){uchar i,value;for(i=0;i<8;i++){dq = 0; //把总线拿低读时间隙开始value >>= 1; //读数据是低位开始dq = 1; //释放总线if(dq == 1) //开始读写数据value |= 0x80;delay_uint(5); //60us 读一个时间隙最少要保持60us 的时间}return value; //返回数据}/*************读取温度的值读出来的是小数***************/uint read_temp(){uint value;uchar low; //在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序init_18b20(); //初始化18b20write_18b20(0xcc); //跳过64位ROMwrite_18b20(0x44); //启动一次温度转换命令delay_uint(50); //500usinit_18b20(); //初始化18b20write_18b20(0xcc); //跳过64位ROMwrite_18b20(0xbe); //发出读取暂存器命令EA = 0;low = read_18b20(); //读温度低字节value = read_18b20(); //读温度高字节EA = 1;value <<= 8; //把温度的高位左移8位value |= low; //把读出的温度低位放到value的低八位中value *= 0.625; //转换到温度值小数return value; //返回读出的温度带小数}/******************1ms 延时函数*******************/void delay_1ms(uint q){uint i,j;for(i=0;i<>< p=""><>for(j=0;j<120;j++);}/******************写星期函数*******************/void write_week(uchar hang,uchar add,uchar week)//写星期函数{if(hang==1)write_com(0x80+add);elsewrite_com(0x80+0x40+add);。
基于单片机的万年历系统设计(一)顶层文件万年历.C#include<reg51.h>#include "LCD1602.h"#include "DS1302.h"#define uchar unsigned char#define uint unsigned intsbit speaker=P2^4;bit key_flag1=0,key_flag2=0;SYSTEMTIME adjusted;uchar sec_add=0,min_add=0,hou_add=0,day_add=0,mon_add=0,yea_add=0;uchar data_alarm[7]={0};/************键盘控制******************************/int key_scan() //扫描是否有键按下{ int i=0;uint temp;P1=0xf0;temp=P1;if(temp!=0xf0)i=1;elsei=0;return i;}uchar key_value() //确定按键的值{uint m=0,n=0,temp;uchar value;uchar v[4][3]={'2','1','0','5','4','3','8','7','6','b','a','9'} ;P1=0xfe; temp=P1; if(temp!=0xfe)m=0;P1=0xfd;temp=P1 ;if(temp!=0xfd)m=1;P1=0xfb;temp=P1 ;if(temp!=0xfb)m=2;P1=0xf7;temp=P1 ;if(temp!=0xf7)m=3;P1=0xef;temp=P1 ;if(temp!=0xef)n=0;P1=0xdf;temp=P1 ;if(temp!=0xdf)n=1;P1=0xbf;temp=P1 ;if(temp!=0xbf)n=2;value=v[m][n];return value;}/***************************设置闹铃函数*******************************/void naoling(void){uchar i=0,l=0,j;init1602();while(key_flag2&&i<12)if(key_scan()){j=key_value();write_data(j);if(i%2==0)data_alarm[l]=(j-'0')*10;else {data_alarm[l]+=(j-'0');l++;}i++;delay(600);}write_com(0x01);}uchar according(void){ uchar k;if(data_alarm[0]==adjusted.Year&&data_alarm[1]==adjusted.Month&&data_alarm[2]==adj usted.Day&&data_alarm[3]==adjusted.Hour&&data_alarm[4]==adjusted.Minute&&data_al arm[5]==adjusted.Second)k=1;else k=0;return k;}void speak(void){uint i=50;while(i){speaker=0;delay(1);speaker=1;delay(1);i--;}}void alarm(void){uint i=10;while(i){speak();delay(10);i--;}}/**************************修改时间操作********************************/ void reset(void){sec_add=0;min_add=0;hou_add=0;day_add=0;mon_add=0;yea_add=0 ;}void adjust(void){if(key_scan()&&key_flag1)switch(key_value()){case '0':sec_add++;break;case '1':min_add++;break;case '2':hou_add++;break;case '3':day_add++;break;case '4':mon_add++;break;case '5':yea_add++;break;case 'b':reset();break;default: break;}adjusted.Second+=sec_add;adjusted.Minute+=min_add;adjusted.Hour+=hou_add;adjusted.Day+=day_add;adjusted.Month+=mon_add;adjusted.Year+=yea_add;if(adjusted.Second>59) adjusted.Second=adjusted.Second%60;if(adjusted.Minute>59) adjusted.Minute=adjusted.Minute%60;if(adjusted.Hour>23) adjusted.Hour=adjusted.Hour%24;if(adjusted.Day>31) adjusted.Day=adjusted.Day%31;if(adjusted.Month>12) adjusted.Month=adjusted.Month%12;if(adjusted.Year>100) adjusted.Year=adjusted.Year%100;}/**************************中断处理函数*********************************/ void changing(void) interrupt 0 using 0 //需要修改时间和日期,或者停止修改{if(key_flag1)key_flag1=0;else key_flag1=1;}void alarming(void) interrupt 3 using 0 //需要设置闹铃或者停止设置{if(key_flag2)key_flag2=0;else key_flag2=1;}/********************************主函数***********************************/ main(){uint i;uchar *l;uchar p1[]="D:",p2[]="T:";SYSTEMTIME T;EA=1;EX0=1;IT0=1;EA=1;EX1=1;IT1=1;init1602();Initial_DS1302() ;while(1){ write_com(0x80);write_string(p1,2);write_com(0xc0);write_string(p2,2);DS1302_GetTime(&T) ;adjusted.Second=T.Second;adjusted.Minute=T.Minute;adjusted.Hour=T.Hour;adjusted.Week=T.Week;adjusted.Day=T.Day;adjusted.Month=T.Month;adjusted.Year=T.Year;for(i=0;i<9;i++){adjusted.DateString[i]=T.DateString[i];adjusted.TimeString[i]=T.TimeString[i];}adjust();if(key_flag2)naoling();if(according())alarm();DateToStr(&adjusted);TimeToStr(&adjusted);write_com(0x82);write_string(adjusted.DateString,8);write_com(0xc2);write_string(adjusted.TimeString,8);delay(10);}(二)头文件1 显示模块LCD1602.H#ifndef LCD_CHAR_1602_2009_5_9#define LCD_CHAR_1602_2009_5_9#define uchar unsigned char#define uint unsigned intsbit lcdrs = P2^0;sbit lcdrw = P2^1;sbit lcden = P2^2;void delay(uint z) // 延时{uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void write_com(uchar com) // 写入指令数据到lcd {lcdrw=0;lcdrs=0;P0=com;delay(5);lcden=1;delay(5);lcden=0;}void write_data(uchar date) // 写入字符显示数据到lcd {lcdrw=0;lcdrs=1;P0=date;delay(5);lcden=1;delay(5);lcden=0;}void init1602() // 初始化设定{lcdrw=0;lcden=0;write_com(0x3C);write_com(0x0c);write_com(0x06);write_com(0x01);write_com(0x80);}void write_string(uchar *pp,uint n){int i;for(i=0;i<n;i++)write_data(pp[i]);}#endif(三)头文件2 时钟模块DS1302.H#ifndef _REAL_TIMER_DS1302_2009_5_20_#define _REAL_TIMER_DS1302_2003_5_20_sbit DS1302_CLK = P2^6; //实时时钟时钟线引脚sbit DS1302_IO = P2^7; //实时时钟数据线引脚sbit DS1302_RST = P2^5; //实时时钟复位线引脚sbit ACC0 = ACC^0;sbit ACC7 = ACC^7;typedef struct SYSTEM_TIME{unsigned char Second;unsigned char Minute;unsigned char Hour;unsigned char Week;unsigned char Day;unsigned char Month;unsigned char Year;unsigned char DateString[9]; //用这两个字符串来放置读取的时间unsigned char TimeString[9];}SYSTEMTIME; //定义的时间类型#define AM(X) X#define PM(X) (X+12) // 转成24小时制#define DS1302_SECOND 0x80#define DS1302_MINUTE 0x82#define DS1302_HOUR 0x84#define DS1302_WEEK 0x8A#define DS1302_DAY 0x86#define DS1302_MONTH 0x88#define DS1302_YEAR 0x8C#define DS1302_RAM(X) (0xC0+(X)*2) //用于计算DS1302_RAM 地址的宏/******内部指令**********/void DS1302InputByte(unsigned char d) //实时时钟写入一字节(内部函数){unsigned char i;ACC = d;for(i=8; i>0; i--){DS1302_IO = ACC0;DS1302_CLK = 1;DS1302_CLK = 0;ACC = ACC >> 1; //因为在前面已经定义了ACC0 = ACC^0;以便再次利用DS1302_IO = ACC0;}}unsigned char DS1302OutputByte(void) //实时时钟读取一字节(内部函数){unsigned char i;for(i=8; i>0; i--){ACC = ACC >>1;ACC7 = DS1302_IO;DS1302_CLK = 1;DS1302_CLK = 0;}return(ACC);}/********************************/void Write1302(unsigned char ucAddr, unsigned char ucDa) //ucAddr: DS1302地址, ucData: 要写的数据{DS1302_RST = 0;DS1302_CLK = 0;DS1302_RST = 1;DS1302InputByte(ucAddr); // 地址,命令DS1302InputByte(ucDa); // 写1Byte数据DS1302_CLK = 1;DS1302_RST = 0;}unsigned char Read1302(unsigned char ucAddr) //读取DS1302某地址的数据{unsigned char ucData;DS1302_RST = 0;DS1302_CLK = 0;DS1302_RST = 1;DS1302InputByte(ucAddr|0x01); // 地址,命令ucData = DS1302OutputByte(); // 读1Byte数据DS1302_CLK = 1;DS1302_RST = 0;return(ucData);}void DS1302_SetProtect(bit flag) //是否写保护{if(flag)Write1302(0x8E,0x10);elseWrite1302(0x8E,0x00);}void DS1302_SetTime(unsigned char Address, unsigned char Value) // 设置时间函数{DS1302_SetProtect(0);Write1302(Address, ((Value/10)<<4 | (Value%10))); //将十进制数转换为BCD码} //在DS1302中的与日历、时钟相关的寄存器存放的数据必须为BCD码形式void DS1302_GetTime(SYSTEMTIME *Time){unsigned char ReadValue;ReadValue = Read1302(DS1302_SECOND);Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将BCD码转换为十进制数ReadValue = Read1302(DS1302_MINUTE);Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_HOUR);Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_DAY);Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_WEEK);Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_MONTH);Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_YEAR);Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); }unsigned char *DataToBCD(SYSTEMTIME *Time){unsigned char D[8];D[0]=Time->Second/10<<4+Time->Second%10;D[1]=Time->Minute/10<<4+Time->Minute%10;D[2]=Time->Hour/10<<4+Time->Hour%10;D[3]=Time->Day/10<<4+Time->Day%10;D[4]=Time->Month/10<<4+Time->Month%10;D[5]=Time->Week/10<<4+Time->Week%10;D[6]=Time->Year/10<<4+Time->Year%10;return D;}void DateToStr(SYSTEMTIME *Time){//将十进制数转换为液晶显示的ASCII值Time->DateString[0] = Time->Year/10 + '0';Time->DateString[1] = Time->Year%10 + '0';Time->DateString[2] = '-';Time->DateString[3] = Time->Month/10 + '0';Time->DateString[4] = Time->Month%10 + '0';Time->DateString[5] = '-';Time->DateString[6] = Time->Day/10 + '0';Time->DateString[7] = Time->Day%10 + '0';Time->DateString[8] = '\0';}void TimeToStr(SYSTEMTIME *Time){//将十进制数转换为液晶显示的ASCII值Time->TimeString[0] = Time->Hour/10 + '0';Time->TimeString[1] = Time->Hour%10 + '0';Time->TimeString[2] = ':';Time->TimeString[3] = Time->Minute/10 + '0';Time->TimeString[4] = Time->Minute%10 + '0';Time->TimeString[5] = ':';Time->TimeString[6] = Time->Second/10 + '0';Time->TimeString[7] = Time->Second%10 + '0';Time->DateString[8] = '\0';}void Initial_DS1302(void){unsigned char Second;Second=Read1302(DS1302_SECOND);if(Second&0x80) //初始化时间DS1302_SetTime(DS1302_SECOND,0);}void DS1302_TimeStop(bit flag) // 是否将时钟停止{unsigned char Data;Data=Read1302(DS1302_SECOND);DS1302_SetProtect(0);if(flag)Write1302(DS1302_SECOND, Data|0x80);elseWrite1302(DS1302_SECOND, Data&0x7F);}#endif附录2 系统电路图10。
1. 前言1.1 课题研究背景伴随着科技的快速发展,时间的流逝,从观察太阳、摆钟到现在电子钟,人类不断的研究,不断的创新纪录。
随着人们的生活水平的提高和生活节奏加快,对时间的要求也越来越高,精准数字计时的消费需求也就越来越多。
二十一世纪的今天,最具有代表性的计时产品就是电子数字万年历,它是近代世界钟表业界的第三次革命。
第一次是摆和摆轮游丝的发明,相对较稳定的机械振荡频率源使钟表的走时差从分级缩小至秒级,代表性的产品是带有摆或摆轮游丝的机械钟或者表。
第二次革命则是石英晶体振荡器的应用,发明了走时精度更高的石英电子钟表,也使钟表的走时月差从分级缩小到秒级。
第三次革命就是单片机数码计时技术的应用(电子数字万年历),使计时产品的走时日差从分级缩小至1/600万秒,从原有的传统指针计时的方式发展成为人们日常更为熟悉的夜光数字显示方式,直观明了,并且增加了全自动日期、星期、温度以及其他日常附属带来了钟表计时业界跨跃性的进步。
国产的电子万年历有很多种,总体上来说以研究多功能电子数字万年历为主,使万年历除了原有的显示时间,日期等基本功能之外,还具有闹铃,报警等功能。
商家生产的电子数字万年历更从质量,价格,实用上考虑,不断的改进电子万年历的设计,使其更加的具有市场。
本设计为软硬件相结合的一组设计。
在软件设计过程中,应对硬件部分有相关了解,有助于对设计题目的更深了解和软件设计。
要了解一些主要器件的基本功能和作用。
除了采用集成化的时钟芯片之外,利用AT89系列单片机制成万年历电路,采用软硬件结合的方法,分别用来显示年、月、日、时、分、秒,其最大特点是:硬件电路简单,安装方便易于实现,软件设计独特,可靠。
AT89C51单片机是由ATMEL公司推出的一种小型单片机。
95年出现在中国市场。
主要特点为采用了Flash存贮器技术,降低了制造成本,其软硬件与MCS-51完全兼容,可以很快被中国广大用户接受。
1 / 331.2课题研究目的与意义二十一世纪是数字化技术高速发展的时期,同时单片机在数字化高速发展的时期扮演着非常重要的地位。
基于单片机设计的万年历显示电路电路原理图:程序:#include<reg51.h>#include"lcd1602.h"#include"ds1302.h"#include"ds18b20.h"#define uint unsigned int#define uchar unsigned charuint b[6];//年、月、日、时、分、秒uchar code row1[]={"2009-01-01"};uchar code row2[]={"00:00:00"};uchar year1[12]={31,28,31,30,31,30,31,31,30,31,30,31};//平年uchar year2[12]={31,29,31,30,31,30,31,31,30,31,30,31};//润年uchar j[6]={0x85,0x88,0x8b,0x84+0x40,0x87+0x40,0x8a+0x40};//LCD地址uchar i,k,jj=0,w,clock=0,bigclock=0,c=0,num;//i循环数,k温度缓存,jj地址位uint temp;sbit b1=P3^0;//设置sbit b2=P3^1;//上调sbit b3=P3^2;//下调sbit b4=P3^3;//转换sbit b5=P3^4;//闹钟sbit speaker=P3^5;lcdscan(){for(i=0;i<6;i++){ lcdwrite(j[i]);lcdshuju(a[11-i*2]+0x30);lcdwrite(j[i]+0x01);lcdshuju(a[10-i*2]+0x30);}}void key(){ if(b1==0){ dsaddshuju(0x80,(a[1]<<4)+a[0]+0x80);while(b1==0){for(i=0;i<6;i++){b[i]=a[11-i*2+clock]*10+a[10-i*2+clock];}if(b4==0){ delay(3);jj++;if(jj==6){jj=0;}}if(b2==0){ delay(3);b[jj]++;if(b[5]==60)b[5]=0;if(b[4]==60)b[4]=0;if(b[3]==24)b[3]=0;if((b[0]%4==0&&b[0]%100!=0)||b[0]%400==0){if(b[2]>year2[b[1]-1])b[2]=1;} else {if(b[2]>year1[b[1]-1])b[2]=1;}if(b[1]==13)b[1]=1;if(b[0]==100)b[0]=0;}if(b3==0){ delay(3);b[jj]--;if(b[5]==-1)b[5]=59;if(b[4]==-1)b[4]=59;if(b[3]==-1)b[3]=23;if((b[0]%4==0&&b[0]%100!=0) || b[0]%400==0){if(b[2]<=0)b[2]=year2[b[1]-1];}else {if(b[2]<=0)b[2]=year1[b[1]-1];}if(b[1]==0)b[1]=12;if(b[0]==-1)b[0]=99;}for(i=0;i<6;i++){ a[11-i*2+clock]=b[i]/10;a[10-i*2+clock]=b[i]%10;}lcdwrite(j[jj]);lcdshuju(0);lcdwrite(j[jj]+1);lcdshuju(0);delay(200);lcdwrite(j[jj]);lcdshuju(a[11-2*jj+clock]+0x30);lcdwrite(j[jj]+1);lcdshuju(a[10-2*jj+clock]+0x30);delay(200);if(b1==1){ dsaddshuju(0x80,(a[1]<<4)+a[0]);dson();}if(b5==0)clock=12;} }}void main(){ speaker=0;lcdrw=0;dson();lcdon();lcdwrite(0x83);for(i=0;i<10;i++){ lcdshuju(row1[i]);delay(1);}lcdwrite(0x84+0x40);for(i=0;i<8;i++){lcdshuju(row2[i]);delay(1);}dsrst=0;dssclk=0;while(1){for(i=0;i<5;i++){ dsrst=1;dswrite(0x81+i*2);k=dsread();dsrst=0;a[i*2]=k&0x0f;a[i*2+1]=(k>>4)&0x0f;}dsrst=1;dswrite(0x8d);k=dsread();dsrst=0;a[10]=k&0x0f;a[11]=(k>>4)&0x0f;delay(100);lcdscan();key();if(b5==0){ for(i=0;i<12;i++){if(a[i+12]==a[i])num++; }if(num==12)bigclock=1;else num=0;lcdwrite(0x8e);lcdshuju('&');}else{lcdwrite(0x8e);lcdshuju(0x00);}if(bigclock==1){ speaker=1;c++;if(c==100){bigclock=0;speaker=0;}}temp=readtemperature();//temp是uint型的。
电子万年历的设计学院计算机与控制工程学院专业班级自动化学生姓名指导教师2010年6月25日引言随着社会、科技的发展,人类得知时间,从观太阳、摆钟到现在电子钟,不断研究、创新。
为了在观测时间的同时,能够了解其它与人类密切相关的信息,比如温度、星期、日期等,电子万年历诞生了,它集时间、日期、星期和温度功能于一身,具有读取方便、显示直观、功能多样、电路简洁等诸多优点,符合电子仪器仪表的发展趋势,具有广阔的市场前景。
二十一世纪的今天,最具代表性的计时产品就是电子万年历,它是近代世界钟表业界的第三次革命。
第一次是摆和摆轮游丝的发明,相对稳定的机械振荡频率源使钟表的走时差从分级缩小到秒级,代表性的产品就是带有摆或摆轮游丝的机械钟或表。
第二次革命是石英晶体振荡器的应用,发明了走时精度更高的石英电子钟表,使钟表的走时月差从分级缩小到秒级。
第三次革命就是单片机数码计时技术的应用(电子万年历),使计时产品的走时日差从分级缩小到1/600万秒,从原有传统指针计时的方式发展为人们日常更为熟悉的夜光数字显示方式,直观明了,并增加了全自动日期、星期、温度以及其他日常附属信息的显示功能,它更符合消费者的生活需求!因此,电子万年历的出现带来了钟表计时业界跨跃性的进步……我国生产的电子万年历有很多种,总体上来说以研究多功能电子万年历为主,使万年历除了原有的显示时间,日期等基本功能外,还具有闹铃,报警等功能。
商家生产的电子万年历更从质量,价格,实用上考虑,不断的改进电子万年历的设计,使其更加的具有市场。
本设计主要采用AT89C51单片机作为主控核心,由DS1302时钟芯片提供时钟、LED 动态扫描显示屏显示。
AT89C51单片机是由Atmel公司推出的,功耗小,电压可选用4~6V电压供电;DS1302时钟芯片是美国DALLAS公司推出的具有涓细电流充电功能的低功耗实时时钟芯片,它可以对年、月、日、星期、时、分、秒进行计时,还具有闰年补偿等多种功能,而且DS1302的使用寿命长,误差小;数字显示是采用的LED液晶显示屏来显示,可以同时显示年、月、日、星期、时、分、秒和温度等信息。
单片机课程设计题目基于51 单片机的万年历设计学生姓名专业班级学号院(系)指导教师完成时间目录1课程设计的目的1..2课程设计的任务与要求....................... 1.2.1设计任务1..2.2设计要求.............................................. 1. .3单片机发展概况1..4设计原理与功能说明4..4.1设计思想4..4.2总体电路图5..4.3时钟模块5..4.4液晶显示模块6..4.5按键模块7..5系统测试7...5.1硬件测试.............................................. 7. .5.2软件测试8..6总结8...参考文献.............................................. 1.0 .附录一:总体电路原理图....................... 1.1附录二:主程序.............................................. 1.. 2附录三:元器件清单........................... 2.7附录四:实物图 (2)..81课程设计的目的1.通过制作万年历,可以对单片机这门课程更好的认识。
2.理论与实践结合,提高自己的动手能力。
3.学会与合作者更好的交流学习,共同进步和提高。
4.能够增长查阅资料的能力,视野更加开阔。
5.拓展其他学科的联系,全面发展。
6.培养自我发现问题,解决问题的能力。
2课程设计的任务与要求2.1设计任务1.可以去学校图书馆或者网上,搜集整理相关的资料,做好前期理论准备,为以后设计电路,看懂电路图做理论支持。
2.构想万年历电路图,并且具有可行性,画出电路图。
3.列举电路所需的电子元件,仔细对比所需的元件的参数,通过去电子元件经销商或者网购购买。
2.2设计要求1.显示年、月、日、时、分、秒。
51单片机电子万年历设计电路图及程序(总37页)本页仅作为文档封面,使用时可以删除This document is for reference only-rar21year.March摘要:电子万年历是一种非常广泛日常计时工具,对现代社会越来越流行。
它可以对年、月、日、周日、时、分、秒进行计时,还具有闰年补偿等多种功能,而且DS1302的使用寿命长,误差小。
对于数字电子万年历采用直观的数字显示,可以同时显示年、月、日、周日、时、分、秒和温度等信息,还具有时间校准等功能。
该电路采用AT89S52单片机作为核心,功耗小,能在3V的低压工作,电压可选用3~5V电压供电。
本设计是基于51系列的单片机进行的电子万年历设计,可以显示年月日时分秒及周信息,具有可调整日期和时间功能。
在设计的同时对单片机的理论基础和外围扩展知识进行了比较全面准备。
在硬件与软件设计时,没有良好的基础知识和实践经验会受到很大限制,每项功能实现时需要那种硬件,程序该如何编写,算法如何实现等,没有一定的基础就不可能很好的实现。
在编写程序过程中发现以现有的相关知识要独自完成编写任务困难重重,在老师和同学的帮助下才完成了程序部分的编写。
万年历的设计过程在硬件与软件方面进行同步设计。
硬件部分主要由AT89C52单片机,LED显示电路,以及调时按键电路等组成。
在单片机的选择上本人使用了AT89C52单片机,该单片机适合于许多较为复杂控制应用场合。
显示器使用2片7SEG-MPX8-CA和一片7SEG-MPX4-CA。
7SEG-MPX8-CA是一种八个共阳二极管显示器,7SEG-MPX4-CA是一种四个共阳二极管显示器。
为了能更轻松的控制这三片显示器,本人使用了3片74HC164来驱动。
74HC164 是 8 位边沿触发式移位寄存器,串行输入数据,然后并行输出。
软件方面主要包括日历程序、时间调整程序,公历转阴历程序,显示程序等。
程序采用汇编语言编写,以便更简单地实现调整时间及阴历显示功能。
所有程序编写完成后,在wave软件中进行调试,确定没有问题后,在Proteus软件中嵌入单片机内进行仿真。
最后总在老师同学的帮助以及自己的努力下完成了此次电子万年历的设计。
关键词:~~~~~~目录~~~~~~一、设计要求与方案论证 (4)设计要求 (4)系统基本方案选择和论证 (4)1.2.1单片机芯片的选择方案和论证 (4)1.2.2 显示模块选择方案和论证 (4)1.2.3 时钟芯片的选择方案和论证 (4)二.系统的硬件设计与实现 (5)电路设计框图 (5)系统硬件概述 (5)主要单元电路的设计 (6)2.3.1单片机主控制模块的设计 (6)2.3.2时钟电路模块的设计 (6)2.3.3电路原理及说明 (7)4显示模块的设计 (8)三、系统的软件设计 (9)程序流程框图 (9)子程序的设计 (9)3.2.1读、写DS1302子程序 (10)五、作品总结 (12)六、致谢词 (12)参考文献 (13)附录一:系统电路图 (14)附录二:系统程序清单 (15)附录三:系统使用说明书 (40)一、设计要求与方案论证设计要求:(1)基本要求①具有年、月、日、星期、时、分、秒等功能;②万年历具有闰月识别显示功能;③具备年、月、日、星期、时、分、秒校准功能;( 2 ) 创新要求①万年历具有阴历显示功能;②具有测量室内温度功能;系统基本方案选择和论证1.2.1单片机芯片的选择方案和论证:方案一:采用89C51芯片作为硬件核心,采用Flash ROM,内部具有4KB ROM 存储空间,能于3V的超低压工作,而且与MCS-51系列单片机完全兼容,但是运用于电路设计中时由于不具备ISP在线编程技术, 当在对电路进行调试时,由于程序的错误修改或对程序的新增功能需要烧入程序时,对芯片的多次拔插会对芯片造成一定的损坏。
方案二:采用AT89S52,片内ROM全都采用Flash ROM;能以3V的超底压工作;同时也与MCS-51系列单片机完全该芯片内部存储器为8KB ROM 存储空间,同样具有89C51的功能,且具有在线编程可擦除技术,当在对电路进行调试时,由于程序的错误修改或对程序的新增功能需要烧入程序时,不需要对芯片多次拔插,所以不会对芯片造成损坏。
所以选择采用AT89S52作为主控制系统.1.2.2 显示模块选择方案和论证:方案一:采用LED液晶显示屏,液晶显示屏的显示功能强大,可显示大量文字,图形,显示多样,清晰可见,但是价格昂贵,需要的接口线多,所以在此设计中不采用LED液晶显示屏.方案二:采用点阵式数码管显示,点阵式数码管是由八行八列的发光二极管组成,对于显示文字比较适合,如采用在显示数字显得太浪费,且价格也相对较高,所以也不用此种作为显示.方案三:采用LED数码管动态扫描,LED数码管价格适中,对于显示数字最合适,而且采用动态扫描法与单片机连接时,占用的单片机口线少。
所以采用了LED数码管作为显示。
1.2.3时钟芯片的选择方案和论证:方案一:直接采用单片机定时计数器提供秒信号,使用程序实现年、月、日、星期、时、分、秒计数。
采用此种方案虽然减少芯片的使用,节约成本,但是,实现的时间误差较大。
所以不采用此方案。
方案二:采用DS1302时钟芯片实现时钟,DS1302芯片是一种高性能的时钟芯片,可自动对秒、分、时、日、周、月、年以及闰年补偿的年进行计数,而且精度高,位的RAM做为数据暂存区,工作电压~范围内,时耗电小于300nA.电路设计最终方案决定综上各方案所述,对此次作品的方案选定: 采用AT89S52作为主控制系统; DS1302提供时钟;数字式温度传感器;LED数码管动态扫描作为显示。
二.系统的硬件设计与实现电路设计框图系统硬件概述本电路是由AT89S52单片机为控制核心,具有在线编程功能,低功耗,能在3V 超低压工作;时钟电路由DS1302提供,它是一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为~。
采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。
DS1302内部有一个31*8的用于临时性存放数据的RAM寄存器。
可产生年、月、日、周日、时、分、秒,具有使用寿命长,精度高和低功耗等特点,同时具有掉电自动保存功能;温度的采集由DS18B20构成;显示部份由21个数码管,74ls138、74ls47译码器构成。
使用动态扫描显示方式对数字的显示。
主要单元电路的设计2.3.1单片机主控制模块的设计AT89S52单片机为40引脚双列直插芯片,有四个I/O口P0,P1,P2,P3, MCS-51单片机共有4个8位的I/O口(P0、P1、P2、P3),每一条I/O线都能独立地作输出或输入。
单片机的最小系统如下图所示,18引脚和19引脚接时钟电路,XTAL1接外部晶振和微调电容的一端,在片内它是振荡器倒相放大器的输入,XTAL2接外部晶振和微调电容的另一端,在片内它是振荡器倒相放大器的输出.第9引脚为复位输入端,接上电容,电阻及开关后够上电复位电路,20引脚为接地端,40引脚为电源端. 如图-1 所示图-1 主控制系统2.3.2时钟电路模块的设计图-2示出DS1302的引脚排列,其中Vcc1为后备电源,Vcc2为主电源。
在主电源关闭的情况下,也能保持时钟的连续运行。
DS1302由Vcc1或Vcc2两者中的较大者供电。
当Vcc2大于Vcc1+时,Vcc2给DS1302供电。
当Vcc2小于Vcc1时,DS1302由Vcc1供电。
X1和X2是振荡源,外接32.768KHz晶振。
RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。
RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。
当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。
如果在传送过程中RSTS置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。
上电动行时,在Vcc大于等于之前,RST必须保持低电平。
中有在SCLK 为低电平时,才能将RST置为高电平,I/O为串行数据输入端(双向)。
SCLK始终是输入端。
图-2 DS1302的引脚图2.3.3电路原理及说明(1) 时钟芯片DS1302的工作原理:DS1302在每次进行读、写程序前都必须初始化,先把SCLK端置 "0",接着把RST端置"1",最后才给予SCLK脉冲;读/写时序如下图4所示。
图5为DS1302的控制字,此控制字的位7必须置1,若为0则不能把对DS1302进行读写数据。
对于位6,若对程序进行读/写时RAM=1,对时间进行读/写时,CK=0。
位1至位5指操作单元的地址。
位0是读/写操作位,进行读操作时,该位为1;该位为0则表示进行的是写操作。
控制字节总是从最低位开始输入/输出的。
表6为DS1302的日历、时间寄存器内容:"CH"是时钟暂停标志位,当该位为1时,时钟振荡器停止,DS1302处于低功耗状态;当该位为0时,时钟开始运行。
"WP"是写保护位,在任何的对时钟和RAM的写操作之前,WP必须为0。
当"WP"为1时,写保护位防止对任一寄存器的写操作。
(2) DS1302的控制字节DS1302的控制字如表-1所示。
控制字节的高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出RAM RD1 A4 A3 A2 A1 A0/ CK /WR表-1 DS1302的控制字格式(3) 数据输入输出(I/O)在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。
同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。
如下图-4所示图-4 DS1302读/写时序图(4) DS1302的寄存器DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间寄存器及其控制字见表-2。
表-2 DS1302的日历、时间寄存器此外,DS1302 还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器及与RAM相关的寄存器等。
时钟突发寄存器可一次性顺序读写除充电寄存器外的所有寄存器内容。