摘 要 ............................................................................................................................................. 1 1 方案论证 ..................................................................................................................................... 2
1.1 单片机芯片的选择方案和论证 ....................................................................................... 2 1.2 显示模块选择方案和论证 ............................................................................................... 2 1.3 时钟芯片的选择方案和论证 ........................................................................................... 3 1.4 电路设计最终方案决定 ................................................................................................... 3 2 系统的硬件设计与实现 ............................................................................................................. 3
2.1 电路设计框图 ................................................................................................................... 3 2.2 系统硬件概述 ................................................................................................................... 3 2.3 主要单元电路的设计 ....................................................................................................... 4
2.3.1 单片机主控制模块的设计 ..................................................................................... 4 2.3.2 时钟电路模块的设计 ............................................................................................. 5 2.3.3 电路原理及说明 ..................................................................................................... 5 2.3.4 显示模块的设计 ..................................................................................................... 6
3 系统的软件设计 ......................................................................................................................... 7
3.1 程序流程框图 ................................................................................................................... 7 4 测试与结果分析 ......................................................................................................................... 9
4.1 软件测试 ........................................................................................................................... 9 4.2 测试结果分析与结论 ....................................................................................................... 9
4.3.1 测试结论 ................................................................................................................. 9
5 课程设计总结 ............................................................................................................................. 9 参考文献 ....................................................................................................................................... 10 附录一:系统电路图 ................................................................................................................... 11 附录二:元器件清单 ................................................................................................................... 12 附录三:系统程序清单 ............................................................................................................... 12
摘 要
随着科技的快速发展,时间的流逝,至从观太阳、摆钟到现在电子钟,人类不断研究,不断创新纪录。美国DALLAS公司推出的具有涓细电流充电能的低功耗实时时钟电路DS1302,它可以对年、月、日、周日、时、分、秒进行计时,还具有闰年补偿等多种功能,而且DS1302的使用寿命长,误差小。对于数字电子时钟采用直观的数字显示,可以同时显示年、月、日、周日、时、分、秒和温度等信息,还具有时间校准等功能。该电路采用AT89S52单片机作为核心,功耗小,能在3V的低压工作,电压可选用3~5V电压供电。
综上所述此电子时钟具有读取方便、显示直观、功能多样、电路简洁、成本低廉等诸多优点,符合电子仪器仪表的发展趋势,具有广阔的市场前景。
关键词:电子时钟 DS1302 动态扫描 单片机
1
1 方案论证
1.1 单片机芯片的选择方案和论证
方案一:
采用89C51芯片作为硬件核心,采用Flash ROM,内部具有4KB ROM 存储空间,能于3V的超低压工作,而且与MCS-51系列单片机完全兼容,但是运用于电路设计中时由于不具备ISP在线编程技术, 当在对电路进行调试时,由于程序的错误修改或对程序的新增功能需要烧入程序时,对芯片的多次拔插会对芯片造成一定的损坏。 方案二:
采用AT89S52,片内ROM全都采用Flash ROM;能以3V的超底压工作;同时也与MCS-51系列单片机完全该芯片内部存储器为8KB ROM 存储空间,同样具有89C51的功能,且具有在线编程可擦除技术,当在对电路进行调试时,由于程序的错误修改或对程序的新增功能需要烧入程序时,不需要对芯片多次拔插,所以不会对芯片造成损坏,所以选择采用AT89S52作为主控制系统。
1.2 显示模块选择方案和论证
方案一:
采用LED数码管动态扫描,LED数码管价格适中,对于显示数字合适,采用动态扫描法与单片机连接时,虽然占用的单片机口线少,但连线还需要花费一点时间,所以也不用此种作为显示。 方案二:
采用点阵式数码管显示,点阵式数码管是由八行八列的发光二极管组成,对于显示文字比较适合,如采用在显示数字显得太浪费,且价格也相对较高,所以也不用此种作为显示。 方案三:
采用LCD液晶显示屏,液晶显示屏的显示功能强大,可显示大量文字,图形,显示多样,清晰可见,并且我做的最小系统上带一个TS1620-1,和AT89S52已经接好,省了很多麻烦,所以在此设计中采用LCD液晶显示屏。
2
1.3 时钟芯片的选择方案和论证
方案一:
直接采用单片机定时计数器提供秒信号,使用程序实现年、月、日、星期、时、分、秒计数。采用此种方案虽然减少芯片的使用,节约成本,但是,实现的时间误差较大,所以不采用此方案。 方案二:
采用DS1302时钟芯片实现时钟,DS1302芯片是一种高性能的时钟芯片,可自动对秒、分、时、日、周、月、年进行计数,而且精度高,位的RAM做为数据暂存区,工作电压2.5V~5.5V范围内,2.5V时耗电小于300nA。
1.4 电路设计最终方案决定
综上各方案所述,对此次作品的方案选定:采用AT89S52作为主控制系统;DS1302提供时钟;LCD液晶显示屏作为显示。
2 系统的硬件设计与实现
2.1 电路设计框图
键盘模块 DS1302 时钟模块 RST SCLK I/O P2.0 P0.7 P2.3 P0.0 AT89S52 单片机 P1.5 RST P1.7 图2-1 系统原理图
D7 D0 LCD液晶显示屏显示模块 复位电路 2.2 系统硬件概述
本电路是由AT89S52单片机为控制核心,具有在线编程功能,低功耗,能在3V超低压工作;时钟电路由DS1302提供,它是一种高性能、低功耗、带RAM的实时时钟电路,它
3
可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302内部有一个31*8的用于临时性存放数据的RAM寄存器。可产生年、月、日、周日、时、分、秒,具有使用寿命长,精度高和低功耗等特点,同时具有掉电自动保存功能;显示部份由LCD液晶显示屏显示。
2.3 主要单元电路的设计 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引脚为电源端。如图2-2所示:
图2-2 主控制系统
4
2.3.2 时钟电路模块的设计
图2-3显示出DS1302的引脚排列,其中Vcc1为后备电源,Vcc2为主电源。在主电源关闭的情况下,也能保持时钟的连续运行。DS1302由Vcc1或Vcc2两者中的较大者供电。当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。当Vcc2小于Vcc1时,DS1302由Vcc1供电。X1和X2是振荡源,外接32.768KHz晶振。RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。如果在传送过程中RSTS置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。上电动行时,在Vcc大于等于2.5V之前,RST必须保持低电平。中有在SCLK 为低电平时,才能将RST置为高电平,I/O为串行数据输入端(双向)。SCLK始终是输入端。
图2-3 DS1302的引脚图
2.3.3 电路原理及说明
(1) 时钟芯片DS1302的工作原理:
DS1302在每次进行读、写程序前都必须初始化,先把SCLK端置 “0”,接着把RST端置“1”,最后才给予SCLK脉冲。DS1302的控制字的位7必须置1,若为0则不能把对DS1302进行读写数据。对于位6,若对程序进行读/写时RAM=1,对时间进行读/写时,CK=0,位1至位5指操作单元的地址。位0是读/写操作位,进行读操作时,该位为1;该位为0则表示进行的是写操作。控制字节总是从最低位开始输入/输出的。表.2为DS1302的日历、时间寄存器内容:“CH”是时钟暂停标志位,当该位为1时,时钟振荡器停止,DS1302处于低功耗状态;当该位为0时,时钟开始运行。“WP”是写保护位,在任何的对时钟和RAM
5
的写操作之前,WP必须为0。当“WP”为1时,写保护位防止对任一寄存器的写操作。 (2) DS1302的控制字节:
DS1302控制字节的高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出 (3) 数据输入输出(I/O)
在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开始。同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。 (4) DS1302的寄存器
DS1302有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据位为BCD码形式。
此外,DS1302 还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器及与RAM相关的寄存器等。时钟突发寄存器可一次性顺序读写除充电寄存器外的所有寄存器内容。 DS1302与RAM相关的寄存器分为两类:一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;另一类为突发方式下的RAM寄存器,此方式下可一次性读写所有的RAM的31个字节,命令控制字为FEH(写)、FFH(读)。
2.3.4 显示模块的设计
如图2-4为LCD显示模块,和最小系统上的连线一样,无需修改。
6
图2-4 LCD液晶显示屏显示模块
3 系统的软件设计
3.1 程序流程框图
开始 初始化 读日期、时间 写日期、时间 显示子程序 开关控制子程序 日期修改子程序 时间修改子程序 显示结果 返回 图3-1 主程序流程图
7
图3-2 时间调整程序流程图
8
4 测试与结果分析
4.1 仿真测试
电子时钟是多功能的数字型,可以看当前日期,时间。电子万年历功能很多,所以对于它的程序也较为复杂,所以在编写程序和调试时出现了相对较多的问题。最后经过多次的模块子程序的修改,一步一步的完成,最终解决了软件。在软件的调试过程中遇到的主要问题是:
1.烧入程序后,LCD液晶显示屏显示亮度不好。
解决:一遍旋转10K欧的滑动变阻器,一遍观看LCD显示屏,知道看到合适的亮度为止。
4.2 测试结果分析与结论 4.3.1 测试结论
经过多次的反复测试与分析,可以对电路的原理及功能更加熟悉,同时提高了设计能力与及对电路的分析能力。同时在软件的编程方面得到更到的提高,对编程能力得到加强,同时对所学的知识得到很大的提高与巩固。
5 课程设计总结
在整个设计过程中,充分发挥人的主观能动性,自主学习,学到了许多没学到的知识。较好的完成了作品,达到了预期的目的,完了最初的设想。对电路的设计、布局要先有一个好的构思,才显得电路板美观、大方。程序编写中,由于思路不清晰,开始时遇到了很多的问题,经过静下心来思考,和同组员的讨论,理清了思路,反而得心应手。在此次设计中,知道了做凡事要有一颗平常的心,不要想着走捷径,一步一脚印。也练就了我们的耐心,做什么事都在有耐心。此次课程设计学到了很多很多东西,这是最重要的。总之,此次课设使我的能力得到了全方位的提高。
9
参考文献
[1]电气与电子信息工程学院.单片机实验指导书
[2]彭为等.单片机典型系统设计实例精讲.北京:电子工业出版社,2007 [3]王庆利等.单片机设计案例实践教程.北京:北京邮电大学出版社,2008 [4]皮大能等.单片机课程设计指导书.北京:北京理工大学出版社,2010 [5]张毅刚等.单片机原理及应用.北京:高等教育出版社,2010
10
附录一:系统电路图
11
附录二:元器件清单
附表1 电子时钟主要元器件清单
元件名称 单片机 LCD液晶显示屏 晶振 电容 电容 按键 电阻 上拉电阻 排阻 电源变压器
规格型号 AT89S51 LM016L 12MHz 22pF 20uF button 1k 10k RESPACK-8/10K 9V 数量(个) 1 1 2 2 1 5 1 1 1 1 附录二:系统程序清单
#include sbit DS1302_CLK = P1^7; //实时时钟时钟线引脚 sbit DS1302_IO = P1^6; //实时时钟数据线引脚 sbit DS1302_RST = P1^5; //实时时钟复位线引脚 sbit ACC0 = ACC^0; sbit ACC7 = ACC^7; char hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year; //秒,分,时到日,月,年位闪的计数 sbit Set = P2^0; //模式切换键 sbit Up = P2^1; //加法按钮 sbit Down = P2^2; //减法按钮 sbit out = P2^3; //立刻跳出调整模式按钮 char done,count,temp,flag,up_flag,down_flag; uchar TempBuffer[5],week_value[2]; void show_time(); //液晶显示程序 /***********1602液晶显示部分子程序****************/ 12 //Port Definitions********************************************************** sbit LcdRs = P2^5; sbit LcdRw = P2^6; sbit LcdEn = P2^7; sfr DBPort = 0x80; //P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口 //内部等待函数************************************************************************** unsigned char LCD_Wait(void) {LcdRs=0;LcdRw=1; _nop_();LcdEn=1; _nop_(); LcdEn=0;return DBPort; } //向LCD写入命令或数据************************************************************ #define LCD_COMMAND 0 // Command #define LCD_DATA 1 // Data #define LCD_CLEAR_SCREEN 0x01 // 清屏 #define LCD_HOMING 0x02 // 光标返回原点 void LCD_Write(bit style, unsigned char input) {LcdEn=0;LcdRs=style;LcdRw=0; _nop_();DBPort=input; _nop_();//注意顺序 LcdEn=1; _nop_();//注意顺序 LcdEn=0; _nop_();LCD_Wait(); } //设置显示模式************************************************************ #define LCD_SHOW 0x04 //显示开 #define LCD_HIDE 0x00 //显示关 #define LCD_CURSOR 0x02 //显示光标 #define LCD_NO_CURSOR 0x00 //无光标 #define LCD_FLASH 0x01 //光标闪动 #define LCD_NO_FLASH 0x00 //光标不闪动 void LCD_SetDisplay(unsigned char DisplayMode) {LCD_Write(LCD_COMMAND, 0x08|DisplayMode); } //设置输入模式************************************************************ #define LCD_AC_UP 0x02 #define LCD_AC_DOWN 0x00 // default #define LCD_MOVE 0x01 // 画面可平移 #define LCD_NO_MOVE 0x00 //default void LCD_SetInput(unsigned char InputMode) {LCD_Write(LCD_COMMAND, 0x04|InputMode);} //初始化LCD************************************************************ void LCD_Initial() {LcdEn=0; LCD_Write(LCD_COMMAND,0x38); //8位数据端口,2行显示,5*7点阵 LCD_Write(LCD_COMMAND,0x38); LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR); //开启显示, 无光标 LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏 LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE); //AC递增, 画面不动} //液晶字符输入的位置************************ void GotoXY(unsigned char x, unsigned char y) {if(y==0)LCD_Write(LCD_COMMAND,0x80|x); if(y==1)LCD_Write(LCD_COMMAND,0x80|(x-0x40));} 13 //将字符输出到液晶显示 void Print(unsigned char *str) {while(*str!='\\0') {LCD_Write(LCD_DATA,*str);str++;}} /***********DS1302时钟部分子程序******************/ typedef struct __SYSTEMTIME__ { unsigned char Second; unsigned char Minute; unsigned char Hour; unsigned char Week; unsigned char Day; unsigned char Month; unsigned char Year; unsigned char DateString[11]; unsigned char TimeString[9]; }SYSTEMTIME; //定义的时间类型 SYSTEMTIME CurrentTime; #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 void DS1302InputByte(unsigned char d) //实时时钟写入一字节(内部函数) { unsigned char i;ACC = d; for(i=8; i>0; i--) {DS1302_IO = ACC0; //相当于汇编中的 RRC DS1302_CLK = 1; DS1302_CLK = 0; ACC = ACC >> 1; } } unsigned char DS1302OutputByte(void) //实时时钟读取一字节(内部函数) { unsigned char i; for(i=8; i>0; i--) { ACC = ACC >>1; //相当于汇编中的 RRC 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; 14 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_GetTime(SYSTEMTIME *Time) //获取时钟芯片的时钟数据到自定义的结构型数组 {unsigned char ReadValue; ReadValue = Read1302(DS1302_SECOND); Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); 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); } void DateToStr(SYSTEMTIME *Time) //将时间年,月,日,星期数据转换成液晶显示字符串,放到数组里DateString[] { if(hide_year<2) //这里的if,else语句都是判断位闪烁,<2显示数据,>2就不显示,输出字符串为 2007/07/22 { Time->DateString[0] = '2'; Time->DateString[1] = '0'; Time->DateString[2] = Time->Year/10 + '0'; Time->DateString[3] = Time->Year%10 + '0';} else{ Time->DateString[0] = ' '; Time->DateString[1] = ' '; Time->DateString[2] = ' '; Time->DateString[3] = ' ';} Time->DateString[4] = '/'; if(hide_month<2) {Time->DateString[5] = Time->Month/10 + '0'; Time->DateString[6] = Time->Month%10 + '0';} else{ Time->DateString[5] = ' '; Time->DateString[6] = ' ';} Time->DateString[7] = '/'; if(hide_day<2) {Time->DateString[8] = Time->Day/10 + '0'; Time->DateString[9] = Time->Day%10 + '0';} else{Time->DateString[8] = ' ';Time->DateString[9] = ' '; } if(hide_week<2){ week_value[0] = Time->Week%10 + '0'; //星期的数据另外放到 week_value[]数组里,跟年,月,日的分开存放,因为等一下要在最后显示} 15 else { week_value[0] = ' ';} week_value[1] = '\\0'; Time->DateString[10] = '\\0'; //字符串末尾加 '\\0' ,判断结束字符} void TimeToStr(SYSTEMTIME *Time) //将时,分,秒数据转换成液晶显示字符放到数组 TimeString[]; { if(hide_hour<2) { Time->TimeString[0] = Time->Hour/10 + '0'; Time->TimeString[1] = Time->Hour%10 + '0';} else{ Time->TimeString[0] = ' ';Time->TimeString[1] = ' ';} Time->TimeString[2] = ':'; if(hide_min<2){ Time->TimeString[3] = Time->Minute/10 + '0'; Time->TimeString[4] = Time->Minute%10 + '0';} else {Time->TimeString[3] = ' ';Time->TimeString[4] = ' '; } Time->TimeString[5] = ':'; if(hide_sec<2) {Time->TimeString[6] = Time->Second/10 + '0'; Time->TimeString[7] = Time->Second%10 + '0';} else{Time->TimeString[6] = ' ';Time->TimeString[7] = ' '; } Time->DateString[8] = '\\0';} void Initial_DS1302(void) //时钟芯片初始化 { unsigned char Second=Read1302(DS1302_SECOND); if(Second&0x80) //判断时钟芯片是否关闭 {Write1302(0x8e,0x00); //写入允许 Write1302(0x8c,0x07); //以下写入初始化时间 日期:07/07/25.星期: 3. 时间: 23:59:55 Write1302(0x88,0x07);Write1302(0x86,0x25); Write1302(0x8a,0x07);Write1302(0x84,0x23);Write1302(0x82,0x59); Write1302(0x80,0x55);Write1302(0x8e,0x80); //禁止写入}} void Delay1ms(unsigned int count) {unsigned int i,j;for(i=0;i { uint i;for(;delay>0;delay--){for(i=0;i<62;i++) //1ms延时. {;}}} void outkey() //跳出调整模式,返回默认显示 { uchar Second;if(out==0) { mdelay(8); count=0; hide_sec=0,hide_min=0,hide_hour=0,hide_day=0,hide_week=0,hide_month=0,hide_year=0; Second=Read1302(DS1302_SECOND); Write1302(0x8e,0x00); //写入允许 Write1302(0x80,Second&0x7f); Write1302(0x8E,0x80); //禁止写入 done=0; while(out==0); }} //////////////////////////////////////////////////////////////////////////////////////////////////////////// void Upkey()//升序按键 { Up=1;if(Up==0) { mdelay(8); switch(count) 16 {case 1: temp=Read1302(DS1302_SECOND); //读取秒数 temp=temp+1; //秒数加1 up_flag=1; //数据调整后更新标志 if((temp&0x7f)>0x59) //超过59秒,清零 temp=0; break; case 2: temp=Read1302(DS1302_MINUTE); //读取分数 temp=temp+1; //分数加1 up_flag=1; if(temp>0x59) //超过59分,清零 temp=0;break; case 3: temp=Read1302(DS1302_HOUR); //读取小时数 temp=temp+1; //小时数加1 up_flag=1; if(temp>0x23) //超过23小时,清零 temp=0; break; case 4: temp=Read1302(DS1302_WEEK); //读取星期数 temp=temp+1; //星期数加1 up_flag=1; if(temp>0x7) temp=1; break; case 5: temp=Read1302(DS1302_DAY); //读取日数 temp=temp+1; //日数加1 up_flag=1; if(temp>0x31) temp=1; break; case 6: temp=Read1302(DS1302_MONTH); //读取月数 temp=temp+1; //月数加1 up_flag=1; if(temp>0x12) temp=1; break; case 7: temp=Read1302(DS1302_YEAR); //读取年数 temp=temp+1; //年数加1 up_flag=1; if(temp>0x85) temp=0; break; default:break;} 17 while(Up==0); }} //////////////////////////////////////////////////////////////////////////////////////////////////////////// void Downkey()//降序按键 { Down=1;if(Down==0) { mdelay(8); switch(count) {case 1: temp=Read1302(DS1302_SECOND); //读取秒数 temp=temp-1; //秒数减1 down_flag=1; //数据调整后更新标志 if(temp==0x7f) //小于0秒,返回59秒 temp=0x59; break; case 2: temp=Read1302(DS1302_MINUTE); //读取分数 temp=temp-1; //分数减1 down_flag=1; if(temp==-1) temp=0x59; //小于0秒,返回59秒 break; case 3: temp=Read1302(DS1302_HOUR); //读取小时数 temp=temp-1; //小时数减1 down_flag=1; if(temp==-1) temp=0x23; break; case 4: temp=Read1302(DS1302_WEEK); //读取星期数 temp=temp-1; //星期数减1 down_flag=1; if(temp==0) temp=0x7;; break; case 5: temp=Read1302(DS1302_DAY); //读取日数 temp=temp-1; //日数减1 down_flag=1; if(temp==0) temp=31; break; case 6: temp=Read1302(DS1302_MONTH); //读取月数 temp=temp-1; //月数减1 down_flag=1; if(temp==0) 18 temp=12; break; case 7: temp=Read1302(DS1302_YEAR); //读取年数 temp=temp-1; //年数减1 down_flag=1; if(temp==-1) temp=0x85; break; default:break;}while(Down==0); }} void Setkey()//模式选择按键 {Set=1;if(Set==0) { mdelay(8); count=count+1; //Setkey按一次,count就加1 done=1; //进入调整模式 while(Set==0); }} void keydone()//按键功能执行 { uchar Second; if(flag==0) //关闭时钟,停止计时 { Write1302(0x8e,0x00); //写入允许 temp=Read1302(0x80); Write1302(0x80,temp|0x80); Write1302(0x8e,0x80); //禁止写入 flag=1; } Setkey(); //扫描模式切换按键 switch(count) {case 1:do //count=1,调整秒 { outkey(); //扫描跳出按钮 Upkey(); //扫描加按钮 Downkey(); //扫描减按钮 if(up_flag==1||down_flag==1) //数据更新,重新写入新的数据 { Write1302(0x8e,0x00); //写入允许 Write1302(0x80,temp|0x80); //写入新的秒数 Write1302(0x8e,0x80); //禁止写入 up_flag=0; down_flag=0; } hide_sec++; //位闪计数 if(hide_sec>3) hide_sec=0; show_time(); //液晶显示数据 }while(count==2);break; case 2:do //count=2,调整分 { hide_sec=0; outkey(); Upkey(); Downkey(); if(temp>0x60) 19 temp=0; if(up_flag==1||down_flag==1) { Write1302(0x8e,0x00); //写入允许 Write1302(0x82,temp); //写入新的分数 Write1302(0x8e,0x80); //禁止写入 up_flag=0; down_flag=0; } hide_min++; if(hide_min>3) hide_min=0; show_time(); }while(count==3);break; case 3:do //count=3,调整小时 { hide_min=0; outkey(); Upkey(); Downkey(); if(up_flag==1||down_flag==1) { Write1302(0x8e,0x00); //写入允许 Write1302(0x84,temp); //写入新的小时数 Write1302(0x8e,0x80); //禁止写入 up_flag=0; down_flag=0; } hide_hour++; if(hide_hour>3) hide_hour=0; show_time(); }while(count==4);break; case 4:do //count=4,调整星期 { hide_hour=0; outkey(); Upkey(); Downkey(); if(up_flag==1||down_flag==1) { Write1302(0x8e,0x00); //写入允许 Write1302(0x8a,temp); //写入新的星期数 Write1302(0x8e,0x80); //禁止写入 up_flag=0; down_flag=0;} hide_week++; if(hide_week>3) hide_week=0; show_time(); }while(count==5);break; case 5:do //count=5,调整日 {hide_week=0; outkey(); 20 Upkey(); Downkey(); if(up_flag==1||down_flag==1) {Write1302(0x8e,0x00); //写入允许 Write1302(0x86,temp); //写入新的日数 Write1302(0x8e,0x80); //禁止写入 up_flag=0; down_flag=0; } hide_day++; if(hide_day>3) hide_day=0; show_time(); }while(count==6);break; case 6:do //count=6,调整月 { hide_day=0; outkey(); Upkey(); Downkey(); if(up_flag==1||down_flag==1) { Write1302(0x8e,0x00); //写入允许 Write1302(0x88,temp); //写入新的月数 Write1302(0x8e,0x80); //禁止写入 up_flag=0; down_flag=0; } hide_month++; if(hide_month>3) hide_month=0; show_time(); }while(count==7);break; case 7:do //count=7,调整年 { hide_month=0; outkey(); Upkey(); Downkey(); if(up_flag==1||down_flag==1) { Write1302(0x8e,0x00); //写入允许 Write1302(0x8c,temp); //写入新的年数 Write1302(0x8e,0x80); //禁止写入 up_flag=0; down_flag=0; } hide_year++; if(hide_year>3) hide_year=0; show_time(); }while(count==8);break; case 8: count=0;hide_year=0; //count8, 跳出调整模式,返回默认显示状态 Second=Read1302(DS1302_SECOND); 21 Write1302(0x8e,0x00); //写入允许 Write1302(0x80,Second&0x7f); Write1302(0x8E,0x80); //禁止写入 done=0; break; //count=7,开启中断,标志位置0并退出 default:break; }} void show_time() //液晶显示程序 { DS1302_GetTime(&CurrentTime); //获取时钟芯片的时间数据 TimeToStr(&CurrentTime); //时间数据转换液晶字符 DateToStr(&CurrentTime); //日期数据转换液晶字符 GotoXY(0,1); Print(CurrentTime.TimeString); //显示时间 GotoXY(0,0); Print(CurrentTime.DateString); //显示日期 GotoXY(15,0); Print(week_value); //显示星期 GotoXY(11,0); Print(\"Week\"); //在液晶上显示 字母 week Delay1ms(400); //扫描延时} main() { flag=1; //时钟停止标志 LCD_Initial(); //液晶初始化 Initial_DS1302(); //时钟芯片初始化 up_flag=0; down_flag=0; done=0; //进入默认液晶显示 while(1) { while(done==1) keydone(); //进入调整模式 while(done==0) { show_time(); //液晶显示数据 flag=0; Setkey(); }}} 22 扫描各功能键 // 因篇幅问题不能全部显示,请点此查看更多更全内容