6、用DS1302与LCD1602可调数字万年历实验设计报告
利用时钟芯片DS1302实现万年历系别电子通信工程系组别第十组专业名称电子信息工程指导教师组内成员2013年8月19日用DS1302与LCD1602设计的可调式电子日历时钟一、总体设计1.1、设计目的为巩固所学的单片机知识,把所学理论运用到实践中,用LCD1602与DS1302 设计可调式电子日历时钟。
1.2、设计要求(1)显示:年、月、日、时、分、秒和星期;(2)设置年、月、日、时、分、秒和星期的初始状态;(3)能够用4个按键调整日历时钟的年、月、日、时、分、秒和星期;完成可调式电子日历时钟的硬件和软件的设计,包括单片机的相关内容;日历时钟模块的设计,液晶显示模块的设计,按键模块的设计。
控制程序的编写等。
备注:本程序另外添加了每到上午8:10和下午2:10的闹钟提醒功能。
1.3、系统基本方案选择和论证1.3.1、单片机芯片的选择方案方案一:采用89C51芯片作为硬件核心,采用Flash ROM,内部具有4KB ROM 存储空间,能于3V的超低压工作,而且与MCS-51系列单片机完全兼容。
方案二:采用STC12C5A60S2系列单片机是宏晶科技生产的单时钟/机器周期(1T)的单片机,是高速/低功耗/超强抗干扰的新一代8051单片机,指令代码完全兼容传统8051,但速度快8-12倍。
内部集成MAX810专用复位电路,2路PWM,8路高速10位A/D转换(250K/S),针对电机控制,强干扰场合。
但造价较高。
1.3.2 、显示模块选择方案和论证:方案一:采用点阵式数码管显示,点阵式数码管是由八行八列的发光二极管组成,对于显示文字比较适合,如采用显示数字显得太浪费,且价格也相对较高。
所以不用此种作为显示。
方案二:采用LED数码管动态扫描,虽然LED数码管价格适中,但要显示多个数字所需要的个数偏多,功耗较大,显示出来的只是拼音,而不是汉字。
所以也不用此种作为显示。
方案三:采用LCD液晶显示屏,液晶显示屏的显示功能强大,可显示大量字符,且视觉效果较好,外形美观。
LCD1602可实现显示2行十六个字符。
1.3.3、时钟芯片的选择方案和论证:方案一:直接采用单片机定时计数器提供秒信号,使用程序实现年、月、日、星期、时、分、秒计数。
采用此种方案虽然减少芯片的使用,节约成本,但是,实现的时间误差较大。
所以不采用此方案。
方案二:采用DS1302时钟芯片实现时钟,DS1302芯片是一种高性能的时钟芯片,可自动对秒、分、时、日、星期、月、年以及闰年补偿的年进行计数,而且精度高,31*8位的RAM做为数据暂存区,工作电压范围为2.5V~5.5V,2.5V时耗电小于300nA。
1.3.4、电路设计最终方案决定综上各方案所述,对此次作品的方案选定:采用80C51作为主控制系统;DS1302提供时钟;LCD1602液晶带汉字库显示屏作为显示部分。
二、硬件设计2.1、电路设计模块图如图2-1所示80C51主控制器模 块LCD 显示控制模块按键控制模块蜂鸣器闹钟提醒控制模块DS1302实时时钟控制模块图 2-12.2、系统总体设计原理图2.3、要求用proteus仿真软件仿真并抓图。
三、软件设计3.1、画出各个函数流程图。
3.1.1、DS1302实时控制芯片的流程图如图3-1开始初始时间状态设置向DS1302中写日期时间从DS1302中读日期时间送到80C51图3-13.1.2、LCD1602液晶显示控制流程图如图3-2入口对1602初始化写入显示设置命令延时一段时间检查忙标志是BF= 7>?设置字符显示位置延时一段时间向1602中写入数据LCD显示内容返回主程序图3-23.1.3、闹钟提醒控制流程如图3-3开始查询是否到定时时间P3_7置低蜂鸣器响应闹铃否是如图3-33.1.4、调时函数控制流程如图3-4开始控制键有效,调整年等待按键程序加有效减有效年加1 年减1控制键有效,调整月等待按键程序加有效减有效月加1 月减1控制键有效,调整日控制键有效,调整星期等待按键程序等待按键程序加有效减有效日加1 日减1 加有效减有效星期加 1 星期减 1控制键有效,调整时控制键有效,调整分加有效减有效加有效减有效时加1 时减1按键有效跳出调时程序,进入主循环分减1分加1等待按键程序等待按键程序图3-33.2、写出程序代码。
/*说明********************************************************************* *****曲谱存贮格式unsigned char code MusicName{音高,音长,音高,音长...., 0,0};末尾:0,0 表示结束(Important)音高由三位数字组成:个位是表示1~7 这七个音符十位是表示音符所在的音区:1-低音,2-中音,3-高音;百位表示这个音符是否要升半音: 0-不升,1-升半音。
音长最多由三位数字组成:个位表示音符的时值,其对应关系是:|数值(n): |0 |1 |2 |3 | 4 | 5 | 6|几分音符: |1 |2 |4 |8 |16 |32 |64 音符=2^n十位表示音符的演奏效果(0-2): 0-普通,1-连音,2-顿音百位是符点位: 0-无符点,1-有符点调用演奏子程序的格式Play(乐曲名,调号,升降八度,演奏速度);|乐曲名: 要播放的乐曲指针,结尾以(0,0)结束;|调号(0-11) : 是指乐曲升多少个半音演奏;|升降八度(1-3) : 1:降八度, 2:不升不降, 3:升八度;|演奏速度(1-12000): 值越大速度越快;********************************************************************* ******/#include "buzz.h"unsigned int code FreTab[12] = { 262,277,294,311,330,349,369,392,415,440,466,494 }; //原始频率表unsigned char code SignTab[7] = { 0,2,4,5,7,9,11 };//1~7在频率表中的位置unsigned char code LengthTab[7]= { 1,2,4,8,16,32,64 };static unsigned char Sound_Temp_TH0,Sound_Temp_TL0; //音符定时器初值暂存static unsigned char Sound_Temp_TH1,Sound_Temp_TL1; //音长定时器初值暂存extern int8 scan_key(void);void InitialSound(void){BeepIO = 1;Sound_Temp_TH1 = (65535-(1/1200)*SYSTEM_OSC)/256; // 计算TL1应装入的初值(10ms的初装值)Sound_Temp_TL1 = (65535-(1/1200)*SYSTEM_OSC)%256; // 计算TH1应装入的初值TH1 = Sound_Temp_TH1;TL1 = Sound_Temp_TL1;TMOD |= 0x11;ET0 = 1;ET1 = 0;TR0 = 0;TR1 = 0;EA = 1;}void BeepTimer0(void) interrupt 1 //音符发生中断{BeepIO = !BeepIO;TH0 = Sound_Temp_TH0;TL0 = Sound_Temp_TL0;}//******************************************************************** ******bit Play(unsigned char *Sound,unsigned char Signature,unsigned Octachord,unsigned int Speed){unsigned int NewFreTab[12]; //新的频率表unsigned char i,j;unsigned int Point,LDiv,LDiv0,LDiv1,LDiv2,LDiv4,CurrentFre,Temp_T,SoundLength;unsigned char Tone,Length,SL,SH,SM,SLen,XG,FD;for(i=0;i<12;i++) // 根据调号及升降八度来生成新的频率表{j = i + Signature;if(j > 11){j = j-12;NewFreTab[i] = FreTab[j]*2;}elseNewFreTab[i] = FreTab[j];if(Octachord == 1)NewFreTab[i]>>=2;else if(Octachord == 3)NewFreTab[i]<<=2;}SoundLength = 0;while(Sound[SoundLength] != 0x00) //计算歌曲长度{SoundLength+=2;}Point = 0;Tone = Sound[Point];Length = Sound[Point+1]; // 读出第一个音符和它时时值LDiv0 = 12000/Speed; // 算出1分音符的长度(几个10ms)LDiv4 = LDiv0/4; // 算出4分音符的长度LDiv4 = LDiv4-LDiv4*SOUND_SPACE; // 普通音最长间隔标准TR0 = 0;TR1 = 1;while(Point < SoundLength){if (scan_key()){BeepIO = 1;return 0;}SL=Tone%10; //计算出音符SM=Tone/10%10; //计算出高低音SH=Tone/100; //计算出是否升半CurrentFre = NewFreTab[SignTab[SL-1]+SH]; //查出对应音符的频率if(SL!=0){if (SM==1) CurrentFre >>= 2; //低音if (SM==3) CurrentFre <<= 2; //高音Temp_T = 65536-(50000/CurrentFre)*10/(12000000/SYSTEM_OSC);//计算计数器初值Sound_Temp_TH0 = Temp_T/256;Sound_Temp_TL0 = Temp_T%256;TH0 = Sound_Temp_TH0;TL0 = Sound_Temp_TL0 + 12; //加12是对中断延时的补偿}SLen=LengthTab[Length%10]; //算出是几分音符XG=Length/10%10; //算出音符类型(0普通1连音2顿音) FD=Length/100;LDiv=LDiv0/SLen; //算出连音音符演奏的长度(多少个10ms) if (FD==1)LDiv=LDiv+LDiv/2;if(XG!=1)if(XG==0) //算出普通音符的演奏长度if (SLen<=4)LDiv1=LDiv-LDiv4;elseLDiv1=LDiv*SOUND_SPACE;elseLDiv1=LDiv/2; //算出顿音的演奏长度elseLDiv1=LDiv;if(SL==0) LDiv1=0;LDiv2=LDiv-LDiv1; //算出不发音的长度if (SL!=0){TR0=1;for(i=LDiv1;i>0;i--) //发规定长度的音{while(TF1==0);TH1 = Sound_Temp_TH1;TL1 = Sound_Temp_TL1;TF1=0;}}if(LDiv2!=0){TR0=0; BeepIO=0;for(i=LDiv2;i>0;i--) //音符间的间隔{while(TF1==0);TH1 = Sound_Temp_TH1;TL1 = Sound_Temp_TL1;TF1=0;}}Point+=2;Tone=Sound[Point];Length=Sound[Point+1];}BeepIO = 1;return 1;}/** 蜂鸣器响*/void alarm_sound(void){uint16 m,n=2000;while (n--){BeepIO = ~BeepIO;for (m=0; m<100; m++);}BeepIO = 1;}四、专业实习要求1、掌握常用设备的使用;2、掌握keil 编译环境的使用,熟悉proteus仿真软件的使用;3、基本掌握电路板的焊接调试技巧;4、基本掌握51单片机最小应用系统的组装、调试。
基于DS1302和LCD1602的可调数字钟
学习情境2-可调式数字钟之基于DS1302和LCD1602的可调数字钟☆点名,复习1、DS1302的引脚及其功能,以及DS1302与单片机的硬件连接?2、如何对DS1302读写数据,如何得到DS1302的时钟?☆新课讲授2.3 基于DS1302与LCD1602设计的可调数字钟上堂课程我们学会了使用DS1302,知道了如何在单片机系统中的连接,也详细的学习了如何得到DS1302的时钟,并且我们使用了16个数码管把年月日和时分秒实时地显示出来。
但数码管的显示毕竟有其自身的缺陷,现在在工业控制的各个环节,都使用液晶进行人机联系。
在日常生活中,我们对液晶显示器并不陌生。
液晶显示模块已作为很多电子产品的通用器件,如在计算器、万用表、电子表及很多家用电子产品中都可以看到,显示的主要是数字、专用符号和图形。
在单片机的人机交流界面中,一般的输出方式有以下几种:发光管、LED 数码管、液晶显示器。
发光管和LED数码管比较常用,软硬件都比较简单,在单片机系统中应用液晶显示器作为输出器件有以下几个优点:(1)显示质量高,由于液晶显示器每一个点在收到信号后就一直保持那种色彩和亮度,恒定发光,而不像阴极射线管显示器(CRT)那样需要不断刷新新亮点。
因此,液晶显示器画质高且不会闪烁。
(2)数字式接口,液晶显示器都是数字式的,和单片机系统的接口更加简单可靠,操作更加方便。
(3)体积小、重量轻,液晶显示器通过显示屏上的电极控制液晶分子状态来达到显示的目的,在重量上比相同显示面积的传统显示器要轻得多。
(4)功耗低,相对而言,液晶显示器的功耗主要消耗在其内部的电极和驱动IC上,因而耗电量比其它显示器要少得多。
2.3.1 LCD1602技术资料2.3.1.1 液晶显示简介1、液晶显示原理:液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制,有电就有显示,这样即可以显示出图形。
液晶显示器具有厚度薄、适用于大规模集成电路直接驱动、易于实现全彩色显示的特点,目前已经被广泛应用在便携式电脑、数字摄像机、PDA移动通信工具等众多领域。
单片机实训报告万年历
一、实训目的随着科技的发展,单片机在各个领域的应用越来越广泛。
本次实训旨在通过万年历的设计与实现,让学生深入了解单片机的编程与应用,提高学生的实践能力和创新意识。
通过万年历的设计,使学生掌握单片机的基本原理、编程技巧以及相关外设的使用。
二、实训内容本次实训以AT89C51单片机为核心,结合DS1302时钟芯片、LCD1602液晶显示屏和独立键盘,设计并实现一个具有年、月、日、星期、时分秒显示以及闰年判断功能的万年历。
三、实训步骤1. 需求分析- 显示当前日期和时间,包括年、月、日、星期、时分秒。
- 判断闰年,正确显示2月的天数。
- 允许用户通过按键调整日期和时间。
- 具有电源掉电保护功能,保证数据不丢失。
2. 硬件设计- 核心模块:AT89C51单片机- 时钟模块:DS1302时钟芯片,提供精确的日期和时间。
- 显示模块:LCD1602液晶显示屏,用于显示日期、时间和星期。
- 按键模块:独立键盘,用于调整日期和时间。
- 电源模块:锂电池,提供稳定的电源。
3. 软件设计- 主程序:负责初始化硬件、读取时间、显示时间和日期、处理按键输入等。
- 时钟模块:读取DS1302芯片中的时间,并进行处理。
- 显示模块:将时间、日期和星期显示在LCD1602液晶显示屏上。
- 按键处理模块:根据按键输入调整日期和时间。
4. 程序编写- 使用C语言进行程序编写,利用Keil软件进行编译和烧录。
5. 调试与测试- 对程序进行调试,确保功能正常。
- 对万年历进行测试,验证其准确性。
四、实训结果经过设计、编程、调试和测试,成功实现了万年历的功能。
万年历能够准确显示当前日期和时间,并具有闰年判断功能。
用户可以通过按键调整日期和时间,且在电源掉电的情况下,万年历仍能保持时间。
五、实训心得1. 实践出真知:通过本次实训,深刻体会到理论知识与实践应用相结合的重要性。
只有将所学知识运用到实际项目中,才能真正掌握单片机的编程与应用。
(完整word版)万年历(DS1302+LCD1602【程序、仿真、完整】)
基于52单片机的万年历显示(采用实时芯片DS1302芯片+LCD1602液晶显示)仿真图:/************************************************************-- THE LCD1602 DISPLAY LIB -—COPYRIGHT (C) 2014 BY LLH-— ALL RIGHTS RESERVED —-ATTENTION:延时不能过长,否则无法与DS1302同步(最好小于1ms)*************************************************************/#ifndef __LCD1602_DIS_H__#define __LCD1602_DIS_H__#define uint unsigned int#define uchar unsigned charsbit lcd_rs=P2^0;sbit lcd_rw=P2^1;sbit lcd_en=P2^2;/**********延时子程序************/void delay(uint z){uint x,y;for(x=z;x〉0;x—-)for(y=65;y〉0;y--);//60刚好和DS1302同步}/***********写命令子程序**********/void write_com(uchar com){lcd_rs=0;lcd_rw=0;P0=com;delay(1);lcd_en=1;delay(1);lcd_en=0;}/***********写数据子程序**********/void write_data(uchar date){lcd_rs=1;lcd_rw=0;P0=date;delay(1);lcd_en=1;delay(1);lcd_en=0;}/**********初始化子程序************/void init_LCD1602(){lcd_en=0;write_com(0x38); //显示模式设置:16*2显示,5*7点阵,8位数据接口write_com(0x0c); //开显示,不显示光标write_com(0x06); //指针、光标自动加一,整屏不移动write_com(0x80); //初始位置设置}/*********显示子程序***********/void display(uchar *str){while(*str!='\0’){write_data(*str);str++;}}#endifDS1302的H文件:/******************************************************************—— THE DS1302 REAL_TIME LIB —-COPYRIGHT (C) 2014 BY LLH-- ALL RIGHTS RESERVED ——ATTENTION:不能使用(i=0;i<8;i++),否则,液晶无法显示确切的时间(???);星期的显示多了一天(???)********************************************************************/#ifndef __DS1302_REAL_TIME_H__#define __DS1302_REAL_TIME_H__#define uint unsigned int#define uchar unsigned charsbit DS1302_RST=P1^5;sbit DS1302_SCLK=P1^6;sbit DS1302_IO=P1^7;sbit ACC0=ACC^0;sbit ACC7=ACC^7;typedef struct{uchar second;uchar minute;uchar hour;uchar week;uchar day;uchar month;uchar year;uchar date_str[11];uchar time_str[9];}date_time;/**************写数据定义*****************/#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 ST 0x00/*************单字节写数据子程序**************/void single_byte_write(uchar date){uchar i;ACC=date;for(i=8;i〉0;i--) //不能使用(i=0;i〈8;i++),否则,液晶只显示00000{DS1302_IO=ACC0;DS1302_SCLK=1;DS1302_SCLK=0;ACC=ACC>>1;}}/*************单字节读数据子程序**************/uchar single_byte_read( ){uchar i;for(i=8;i>0;i--){ACC=ACC>〉1;ACC7=DS1302_IO;DS1302_SCLK=1;DS1302_SCLK=0;}return ACC;}/**************控制字的写入****************/void write_command(uchar addr,uchar dat){DS1302_SCLK=0;DS1302_RST=0;DS1302_RST=1;single_byte_write(addr);single_byte_write(dat);DS1302_SCLK=1;DS1302_RST=0;}/**************读取芯片内部的数据****************/uchar read_data(uchar address){uchar r_data;DS1302_SCLK=0;DS1302_RST=0;DS1302_RST=1;single_byte_write(address|0x01);//若没加(或0x01)ds1302和lcd1602都无法正常显示(?)r_data=single_byte_read();DS1302_SCLK=1;DS1302_RST=0;return r_data;}/************初始化子程序************/void init_DS1302(){uchar temp;temp=read_data(DS1302_SECOND);if(temp&0x80){write_command(0x8e,0x00); //启动读写write_command(0x84,0x00);//设置24小时模式write_command(DS1302_SECOND,ST); //写入当前时间数据}}/*************读取时间、并实现BCD和十进制间的转化***************//****************************************************************十进制转8421编码:32/10 = 3*16= 48(十进制)= 30(16进制)32%10 = 230+2 = 32 * 16 + 32 % 10 = 32(8421编码)(即:a/10*10+a%10)8421编码转十进制:51 / 16 = 5 * 10(16进制) = 50(十进制)51 % 16 = 150 + 1 = 51 / 16 + 51 % 16 = 51(十进制)(即:a/16*10+a%16)*****************************************************************/void get_time(date_time *Time){uchar value;value=read_data(DS1302_SECOND);Time—〉second=(value/16)*10+(value%16);value=read_data(DS1302_MINUTE);Time—〉minute=(value/16)*10+(value%16);value=read_data(DS1302_HOUR);(完整word版)万年历(DS1302+LCD1602【程序、仿真、完整】) Time-〉hour=(value/16)*10+(value%16);value=read_data(DS1302_WEEK);Time—〉week=(value/16)*10+(value%16-1);//星期的显示数值比正确值多一value=read_data(DS1302_DAY);Time-〉day=(value/16)*10+(value%16);value=read_data(DS1302_MONTH);Time—>month=(value/16)*10+(value%16);value=read_data(DS1302_YEAR);Time-〉year=(value/16)*10+(value%16);}/**************年-月-日-星期“字符”显示***************/void date_to_str(date_time *Time){Time-〉date_str[0]=Time-〉year/10+’0’; //加’0’转化成字符Time—〉date_str[1]=Time—〉year%10+’0';Time->date_str[2]='—’;Time->date_str[3]=Time->month/10+'0';Time->date_str[4]=Time-〉month%10+'0’;Time—>date_str[5]=’—’;Time-〉date_str[6]=Time-〉day/10+'0';Time—>date_str[7]=Time—>day%10+’0’;Time-〉date_str[8]=’-’;Time->date_str[9]=Time—〉week%10+’0’;Time-〉date_str[10]='\0';}/**************时-分-秒“字符”显示***************/void time_to_str(date_time *Time){Time—>time_str[0]=Time->hour/10+’0';Time-〉time_str[1]=Time—〉hour%10+’0';Time—>time_str[2]=’-';Time—>time_str[3]=Time—>minute/10+'0’;Time—>time_str[4]=Time—>minute%10+'0’;Time->time_str[5]='—';Time->time_str[6]=Time->second/10+'0';Time->time_str[7]=Time—>second%10+'0';Time-〉time_str[8]=’\0';}#endif万年历C文件:/********************************************************* TITLE: 实时时钟FUNCTION: DS1302+LCD1602显示实时时钟WRITER: LINLIANHUO(完整word版)万年历(DS1302+LCD1602【程序、仿真、完整】) TIME: 2014-07-30REMARK: matters need attention**********************************************************/#include 〈reg51.h〉#include <string.h〉#include ”DS1302。
DS1302设计的可调万年历(实测正常,附有程序)
DS1302设计的可调万年历(实测正常,附有程序)ds1302设计的可调万年历(本制作所用数码管全为共阳数码管)我刚开始想要搞万年历的时候就是玩游戏打听别人的程序,可是辨认出打听了很多都不理想,必须不就没有日历和时间一起表明,必须不就无法阳入时间的,后来我研究了两天,自己终于把程序编成了出。
不好了,废话我就不多说道,本制作我已经把实物搞了出,确保没问题!下面附有仿真图和实物图。
拍摄的效果不够好,但实物是不错的,本人实物中用三级管代替了仿真图的74hc04非门,用哪个都是可以的……请注意:本程序分后两个c文件的,如果不能编成,可以q我:1107588997我轻易播发程序过去给你……软件源程序:(初始化程序只在已经开始时用一次,之后必须把它屏蔽掉)#include#include#includeuchartime_data[7]={0,0,0,0,0,0,0};ucharwrite_add[7]={0x8c,0x8a,0x88,0x86,0x84,0x82,0x80};ucharread_add[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81};voidwrite_ds1302_byte(uchardat){uchari;for(i=0;i<8;i++){sck=0;io=dat&0x01;dat=dat>>1;sck=1;}}voidwrite_ds1302(ucharadd,uchardat){rst=0;_nop_();sck=0;_nop_();rst=1;_nop_();write_ds1302_byte(add);write_ds1302_byte(dat);rst=0;_nop_();io=1;sck=1;}ucharread_ds1302(ucharadd){uchari,value;rst=0;_nop_();sck=0;_nop_();rst=1;_nop_();write_ds1302_byte(add);for(i=0;i<8;i++){value=value>>1;sck=0;if(io)value=value|0x80;sck=1;}rst=0;_nop_();sck=0;_nop_();sck=1;io=1;returnvalue;}voidread_rtc(void){uchari;for(i=0;i<7;i++){time_data[i]=read_ds1302(read_add[i]);}}voidtime_pros(void){nian=time_data[0]/16*10+time_data[0];yue=time_data[2]/16*10+time_data[2];ri=ti me_data[3]/16*10+time_data[3];xi=time_data[1]/16*10+time_data[1];shi=time_data [4]/16*10+time_data[4];fen=time_data[5]/16*10+time_data[5];miao=time_data[6]/1 6*10+time_data[6];}voidmain(){//init_ds1302();//初始化while(1){read_rtc();time_pros();display();button();}}//----------------------------zichengxu.c----------------------------------------------#defineduan1p2#defineduan2p3#defineweip0#defineuintunsignedint#defineucharunsignedcharsbitsck=p1^1;sbitio=p1^0;sbitrst =p1^2;sbitk1=p1^4;sbitk2=p1^5;sbitk3=p1^6;sbitk4=p1^7;ucharshi,fen,miao,nian,yue,ri,xi,menu,y;unsignedcharcodequan[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; voidwrite_ds1302_byte(uchardat);voidwrite_ds1302(ucharadd,uchardat);ucharread_ds1302(ucharadd);//voidinit_ds1302(void);//初始化voidread_rtc(void);voidtime_pros(void);voiddisplay(void);voidbutton(void);voiddelay(uintz){ucharx,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}/*(voidinit_ds1302(void)//初始化{write_ds1302(0x8e,0x00);write_ds1302(0x80,0x00);write_ds1302(0x82,0x20);write_ ds1302(0x84,0x09);write_ds1302(0x86,0x25);write_ds1302(0x88,0x12);write_ds1302 (0x8a,0x06);write_ds1302(0x8c,0x10);write_ds1302(0x90,0x01);write_ds1302(0xc0, 0xf0);write_ds1302(0x8e,0x80);}*/voiddisplay(void){wei=0;duan1=quan[2];if(menu==3&&y<80&&k1!=0&&k2!=0&&k3!=0&&k4!=0){duan2=0xff;}elseduan2=quan[shi/10];delay(2);duan1=0xff;duan2=0xff;wei=1;duan1=quan[0];if(menu==3&&y<80&&k1!=0&&k2!=0&&k3!=0&&k4!=0){duan2=0xff;}elseduan2=quan[shi];delay(2);duan1=0xff;duan2=0xff;。
简析基于DS1302和LCD1602的万年历系统设计论文
简析基于DS1302和LCD1602的万年历系统设计论文简析基于DS1302和LCD1602的万年历系统设计论文0引言在日常生活中,无论哪一行业,哪一领域,时间授时都是不可或缺的。
从古老的钟表到现代的电子设备都提供时间授时的功能。
因此,对于单片机学习者来说,设计并实现一款低成本的,有操作性的,提供年,月,日,小时,分,秒,星期等基本计时功能的万年历系统,显得特别实用,特别有意义。
1总体设计及原理图万年历的基本功能一是要提供年月日等基本时间项的授时;二是可以修改时间项。
基于以上两个功能,我们万年历总体设计方案。
万年历有时钟计时模块,显示模块,调整时钟模块和控制器4部分组成。
接下来的任务就是对以上模块进行选型。
低成本,可操作是选型的标准。
对于控制器,选择最常用的C51系列单片机STC89C52。
STC89C52是由宏品科技生产的是一种低功耗8位基于经典C51内核的微处理器,具有8 KhyteFLASH存储器,512 byte RAM , 4 KByte EEPROM , 32位通用IO接口,可以直接用串口下载程序。
时钟模块选择由dallas公司生产的时钟芯片DS1302,DS1302是一款支持年月日,小时分秒,星期,闰年补偿的实时时钟芯片;其简单三线结构可以很方便地与单片机通用IO相连,进行串行总线读写传输。
显示模块选择16x2的字符点阵模块LCD 16020LC D 1602的控制器以Hitachi公司生产的HD44780芯片最为常见。
LC D 1602引脚主要包括3类,第1类是电源。
第2类是8位数据I/0通道,用于读写LC D 1602。
第3类是3根控制线,RS,R/W和E,其中,RS和R/W是用于实现LCD不同操作的。
E是作为读写的启动信号,有点类似一个时钟信号,数据要写人LC D 1602或从LCD 1602读出数据均需要首先置E信号为高至少1 s,然后置低。
调整时钟模块设计了4个轻触开关,用于设定和修改时间项。
数字万年历课程设计报告
数字万年历课程设计报告课程名称:微机原理课程设计题目:万年历摘要随着电子技术的迅速发展,特别是随大规模集成电路出现,给人类生活带来了根本性的改变。
由其是单片机技术的应用产品已经走进了千家万户。
电子万年历的出现给人们的生活带来的诸多方便。
本文首先描述系统硬件工作原理,并附以系统结构框图加以说明,着重介绍了本系统所应用的各硬件接口技术和各个接口模块的功能及工作过程,其次,详细阐述了程序的各个模块和实现过程。
本设计以数字集成电路技术为基础,单片机技术为核心。
本文编写的主导思想是软硬件相结合,以硬件为基础,来进行各功能模块的编写。
本设计是一种基于STC89C51单片机控制,DS1302报时的数字时钟设计。
它具有多项显示和控制功能。
能用LCD实时显示当前年、月、日、星期、时间;可对时间进行调整;具有调整时间和日期功能。
本设计通过一个基于单片机的能实现万年历功能电子时钟的设计,从而达到学习、了解单片机相关指令在各方面的应用。
系统由主控制器AT89C51、时钟电路DS1302、显示电路、按键电路和复位电路等部分构成,能实现时钟日历显示的功能,能进行时、分、秒的显示。
关键词:STC89C52单片机、LCD液晶显示、DS1302时钟芯片目录一、设计任务与要求 ........................................................................... - 6 -1.1 设计任务 .............................................................................................. - 6 -1.2 设计要求 .............................................................................................. - 6 -1.3 发挥部分 .............................................................................................. - 6 -二、方案总体设计 ..................................................................................... - 7 -2.1 显示部分 .............................................................................................. - 7 -2.2 时钟信号的选择 .................................................................................. - 8 -2.3 总体方案 .............................................................................................. - 8 -三、硬件设计 ..................................................................................... - 10 -3.1 单片机最小系统 ................................................................................ - 10 -3.2 DS1302时钟电路............................................................................... - 17 -3.3 LCD液晶显示模块............................................................................ - 19 -3.4 按键电路 ............................................................................................ - 21 -3.5 电源指示灯部分 ................................................................................ - 25 -四、软件设计 ..................................................................................... - 26 -4.1 主程序流程图显示 ............................................................................ - 26 -4.2 时间设定程序流程图 ........................................................................ - 27 -五、系统仿真与调试 ......................................................................... - 29 -5.1 Proteus仿真软件简介 ....................................................................... - 29 -5.2 仿真及实物 ........................................................................................ - 31 -六、设计总结 ..................................................................................... - 34 -七、参考文献 ..................................................................................... - 35 -一、设计任务与要求1.1 设计任务基于52单片机的DS1302万年历;1.2 设计要求基于52单片机,利用DS1302时钟芯片生成万年历,使用液晶显示年月日时分秒,显示值可通过按键修改。
制作电子万年历实训报告
一、引言随着科技的飞速发展,电子产品的普及和应用越来越广泛。
电子万年历作为一种常见的电子设备,不仅可以显示年、月、日、星期、时、分等信息,还可以实现闹钟、定时显示等功能。
为了提高我们的实践能力和创新能力,本次实训我们选择制作一款基于单片机的电子万年历。
二、实训目的1. 掌握电子万年历的基本原理和设计方法。
2. 熟悉单片机的编程和应用。
3. 培养团队协作能力和动手实践能力。
三、实训内容1. 硬件设计本实训所使用的硬件主要包括以下部分:- 单片机:AT89C52- 时钟模块:DS1302- 显示模块:LCD1602- 遥控模块:1838V- 按键模块:S1(设置键)、S2(上调键)、S3(下调键)、S4(复位键)硬件电路图如下:2. 软件设计本实训所使用的软件主要包括以下部分:- 单片机编程:C语言- 显示程序:LCD1602驱动程序- 遥控程序:1838V遥控接收程序软件流程图如下:3. 功能实现本实训所实现的电子万年历具有以下功能:- 显示年、月、日、星期、时、分等信息。
- 遥控操作:设置时间、星期、日期等。
- 定时显示:定时显示当前时间。
- 停电自动计时:采用DS1302时钟模块,停电后可继续计时。
四、实训过程1. 硬件搭建首先,我们根据电路图搭建了电子万年历的硬件电路。
在搭建过程中,我们注意了以下几点:- 确保电路连接正确,避免短路或开路。
- 选择合适的元器件,确保电路性能稳定。
- 对电路进行测试,确保电路正常工作。
2. 软件编程接下来,我们使用C语言对单片机进行编程。
在编程过程中,我们遵循以下步骤:- 分析功能需求,确定程序结构。
- 编写程序代码,实现各项功能。
- 调试程序,确保程序运行正常。
3. 测试与优化在完成软件编程后,我们对电子万年历进行测试。
在测试过程中,我们发现以下问题:- 遥控操作不稳定。
用DS1302与LCD1602设计可调数字万年历课程设计
数字开发与实践课程设计题目:用DS1302与LCD1602设计可调式电子日历时钟班级:姓名:学号:学院:年月日用DS1302与LCD1602设计的可调式电子日历时钟一、总体设计1.1、设计目的为巩固所学的单片机知识,把所学理论运用到实践中,用LCD1602与DS1302 设计可调式电子日历时钟。
1.2、设计要求(1)显示:年、月、日、时、分、秒和星期;(2)设置年、月、日、时、分、秒和星期的初始状态;(3)能够用4个按键调整日历时钟的年、月、日、时、分、秒和星期;完成可调式电子日历时钟的硬件和软件的设计,包括单片机的相关内容;日历时钟模块的设计,液晶显示模块的设计,按键模块的设计。
控制程序的编写等。
备注:本程序另外添加了每到上午8:10和下午2:10的闹钟提醒功能。
1.3、系统基本方案选择和论证1.3.1、单片机芯片的选择方案方案一:采用89C51芯片作为硬件核心,采用Flash ROM,内部具有4KB ROM 存储空间,能于3V的超低压工作,而且与MCS-51系列单片机完全兼容。
方案二:采用STC12C5A60S2系列单片机是宏晶科技生产的单时钟/机器周期(1T)的单片机,是高速/低功耗/超强抗干扰的新一代8051单片机,指令代码完全兼容传统8051,但速度快8-12倍。
内部集成MAX810专用复位电路,2路PWM,8路高速10位A/D转换(250K/S),针对电机控制,强干扰场合。
但造价较高。
1.3.2 、显示模块选择方案和论证:方案一:采用点阵式数码管显示,点阵式数码管是由八行八列的发光二极管组成,对于显示文字比较适合,如采用显示数字显得太浪费,且价格也相对较高。
所以不用此种作为显示。
方案二:采用LED数码管动态扫描,虽然LED数码管价格适中,但要显示多个数字所需要的个数偏多,功耗较大,显示出来的只是拼音,而不是汉字。
所以也不用此种作为显示。
方案三:采用LCD液晶显示屏,液晶显示屏的显示功能强大,可显示大量字符,且视觉效果较好,外形美观。
DS1302+LCD1602时钟
DS1302+LCD1602时钟1.实验目的效果:做一个不怕掉电的LCD显示时钟。
学习DS1302时钟芯片的读写,加强字符型液晶LCD1602的应用。
在LCD屏上显示格式:1)按一下SW1进入时间调整,关标会闪烁2)按一下SW2光标会在年份上闪烁,表明可以对年份进行调整,接着按SW3年份将加一,按SW4年份将减一;2)再按一下SW2,光标闪烁移到月份上,同样按SW3月份加一,按SW4月份减一;3)再按一下SW2,光标有下移到星期上,同样按SW3星期加一,按SW4星期减一;4)同样的道理可以调整时,分,秒。
5)调整完毕按一下SW1,光标闪烁退出,时间调整结束。
DS1302:1)读写时序:2)DS1302相关寄存器:(详细DS1302资料请查看ds1302.pdf文档)2.原理图:DS1302连接原理图LCD1602连接原理图3.实验板上操作:1)用三个短路冒将SCLK-P3.5,I/O-P3.6,CE-P3.7短接起来。
2)将板上的相应拨码开关拨到拨到ON上。
(建议把原来做过数码管显示的那个拨码开关全部拨到OFF那边)3)把LCD1602液晶插到实验板上的LCD1602液晶插槽上。
(提示:程序烧进单片机后,液晶上没有显示,请调节板子上左上角那个电位器)4)按一下SW1进入时间调整,关标会闪烁按一下SW2光标会在年份上闪烁,表明可以对年份进行调整,接着按SW3年份将加一,按SW4年份将减一;再按一下SW2,光标闪烁移到月份上,同样按SW3月份加一,按SW4月份减一;再按一下SW2,光标有下移到星期上,同样按SW3星期加一,按SW4星期减一;同样的道理可以调整时,分,秒。
调整完毕按一下SW1,光标闪烁退出,时间调整结束。
4.实物连接图如下:5.C语言程序:#include "A T89X51.h"#include "intrins.h"#define HIGH 1#define LOW 0#define TRUE 1#define ZERO 0#define MSB 0x80#define LSB 0x01// ds1302 PreDefinition#define DS1302_WP0x8E#define DS1302_RESET RST=LOW;SCL=LOW;RST=HIGH#define DS1302_WP_ENABLE Write_Ds1302(DS1302_WP,0X00)#define DS1302_WP_DISENABLE Write_Ds1302(DS1302_WP,0x00) #define LCDPORT P0sbit SCL = P3^5;// DS1302 Serial-Clock Input pin 5sbit SDA = P3^6;// DS1302 Serial-Data Input pin 6sbit RST = P3^7;// DS1302 Chip-Seclet Input pin 7sbit RS=P1^0;sbit RW=P1^1;sbit EN=P1^2;code unsigned char set_rtc_code[7]={0x07,0x03,0x29,0x02,0x21,0x07,0x40};code unsigned char write_rtc_address[7]={0x8c,0x88,0x86,0x8a,0x84,0x82,0x80};code unsigned char read_rtc_address[7]={0x8d,0x89,0x87,0x8b,0x85,0x83,0x81}; unsigned char read_rtc_code[7]; //DS1302读出信息(年份,星期,时间)暂存数组,/********1ms延时子程序***********/delay_nms(unsigned int n){unsigned int i;unsigned char j;for(i=0;i<n;i++)for(j=0;j<120;j++); //空操作}//*************LCD1602驱动程序***************************//void lcd_delay(unsigned char delaytime){while(delaytime)delaytime--;}void write_lcd_command(unsigned char write_command){lcd_delay(40);RS=0;RW=0;LCDPORT=write_command;EN=1;EN=0;}void write_lcd_data(unsigned char write_data){lcd_delay(40);RS=1;RW=0;LCDPORT=write_data;EN=1;EN=0;}void LCD_write_char( unsigned x,unsigned char y,unsigned char dat) //x表示行,y表示该行的位置(也就是列){//LCD_set_xy( x, y );switch(x){case 0:write_lcd_command(0x80+y);break;case 1:write_lcd_command(0xc0+y);break;}// LCD_en_dat(dat);write_lcd_data(dat|0x30); //dat或上0x30,就时把数字0123456789转换成ASIIC码}void lcd_displaystr(unsigned char x,unsigned char y,unsigned char code *str){switch(x){case 0:write_lcd_command(0x80+y);break;case 1:write_lcd_command(0xc0+y);break;}while (*str){write_lcd_data(*str);str++;}}void initial_lcd1602(void) //初始化LCD1602{unsigned char i;EN=0;for(i=200;i>0;i--)lcd_delay(248);write_lcd_command(0x38);for(i=4;i>0;i--)lcd_delay(248);write_lcd_command(0x38);for(i=4;i>0;i--)lcd_delay(248);write_lcd_command(0x0f);for(i=4;i>0;i--)lcd_delay(248);write_lcd_command(0x06);for(i=4;i>0;i--)lcd_delay(248);write_lcd_command(0x01);for(i=4;i>0;i--)lcd_delay(248);}//********************lcd1602驱动程序到此完********************/////////////////////////////////////////////////////////////////////////**************ds1302读写程序*************************//void Write_Ds1302_Byte(unsigned char temp) //写一个字节{unsigned char i;for (i=0;i<8;i++){SCL=LOW;SDA=temp&LSB;temp>>=1;SCL=HIGH;}}/****************************************************************************/ void Write_Ds1302( unsigned char address,unsigned char dat ) //写ds1302{DS1302_RESET;Write_Ds1302_Byte(address);Write_Ds1302_Byte(dat);RST=LOW;}/****************************************************************************/ unsigned char Read_Ds1302 ( unsigned char address ) //读ds1302{unsigned char i,temp=0x00,temp_temp;DS1302_RESET;Write_Ds1302_Byte(address);for (i=0;i<8;i++){if(SDA)temp|=0x80;SCL=LOW;temp>>=1;SCL=HIGH;}RST=LOW;temp_temp=temp/16;temp=temp%16;temp=temp+temp_temp*10;return (temp);}/****************************************************************************/ void Read_RTC(void) //读出DS1302里的相关信息,存放在read_rtd_code[]数组中{unsigned char i,*p;p=read_rtc_address;for(i=0;i<7;i++){read_rtc_code[i]=Read_Ds1302(*p);p++;}}/***********************************************************************/void Set_RTC(void) //初始化设置DS1302{unsigned char i,*p;p=write_rtc_address;for(i=0;i<7;i++){Write_Ds1302(*p,set_rtc_code[i]);p++;}}/******************************************************/void initial_ds1302(void) //初始化ds1302{DS1302_WP_ENABLE;Set_RTC();}/**************ds1302读写程序到此完************************//////////////////////////////////////////////////////系统初始化void system_initial(void){initial_ds1302();initial_lcd1602();}/****************************************************************************/void main(void){unsigned char count,staus;system_initial();//输出显示lcd_displaystr(0,0x00,"20");delay_nms(10);lcd_displaystr(0,0x04,"-");delay_nms(10);lcd_displaystr(0,0x07,"-");lcd_displaystr(0,0x0b,"Week:");lcd_displaystr(1,0x00,"Time:");lcd_displaystr(1,0x07,":");lcd_displaystr(1,0x0a,":");while(1){//按键扫描,实现对时间的调整,对应实验板的独立按钮//开始时间设置,staus=1if(P2_0==0){delay_nms(10);if(P2_0==0){staus^=1;count=0;while(P2_0==0);}}if(P2_1==0){delay_nms(10);if(P2_1==0){count++; //光标移位if(count==8)count=1;while(P2_1==0);}}if(P2_2==0) //加按钮{delay_nms(10);if(P2_2==0){switch(count){case 0x01:read_rtc_code[0]++;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[0],(read_rtc_code[0]+(read_rtc_code[0]/10)*6));LCD_write_char(0,0x02,(read_rtc_code[0]/10)); //年十位LCD_write_char(0,0x03,(read_rtc_code[0]%10)); //年个位break;case 0x02:read_rtc_code[1]++;if(read_rtc_code[1]==13)read_rtc_code[1]=1;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[1],(read_rtc_code[1]+(read_rtc_code[1]/10)*6));LCD_write_char(0,0x05,(read_rtc_code[1]/10)); //月十位LCD_write_char(0,0x06,(read_rtc_code[1]%10)); //月个位break;case 0x03:read_rtc_code[2]++;if(read_rtc_code[2]==31)read_rtc_code[2]=1;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[2],(read_rtc_code[2]+(read_rtc_code[2]/10)*6));LCD_write_char(0,0x08,(read_rtc_code[2]/10)); //日十位LCD_write_char(0,0x09,(read_rtc_code[2]%10)); //日个位break;case 0x04:read_rtc_code[3]++;if(read_rtc_code[3]==8)read_rtc_code[3]=1;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[3],(read_rtc_code[3]+(read_rtc_code[3]/10)*6));LCD_write_char(0,0x0f,(read_rtc_code[3]%10)); //星期break;case 0x05:read_rtc_code[4]++;if(read_rtc_code[4]==25)read_rtc_code[4]=0;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[4],(read_rtc_code[4]+(read_rtc_code[4]/10)*6));LCD_write_char(1,0x05,(read_rtc_code[4]/10)); //时十位LCD_write_char(1,0x06,(read_rtc_code[4]%10)); //时个位break;case 0x06:read_rtc_code[5]++;if(read_rtc_code[5]==60)read_rtc_code[5]=0;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[5],(read_rtc_code[5]+(read_rtc_code[5]/10)*6));LCD_write_char(1,0x08,(read_rtc_code[5]/10)); //分十位LCD_write_char(1,0x09,(read_rtc_code[5]%10)); //分个位break;case 0x07:read_rtc_code[6]++;if(read_rtc_code[6]==60)read_rtc_code[6]=0;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[6],(read_rtc_code[6]+(read_rtc_code[6]/10)*6));LCD_write_char(1,0x0b,(read_rtc_code[6]/10)); //秒十位LCD_write_char(1,0x0c,(read_rtc_code[6]%10)); //秒个位break;default:break;}while(P2_2==0);}}if(P2_3==0) //减按钮{delay_nms(10);if(P2_3==0){switch(count){case 0x01:if(read_rtc_code[0]==0){lcd_displaystr(0,0x00,"19");read_rtc_code[0]=99;}elseread_rtc_code[0]--;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[0],(read_rtc_code[0]+(read_rtc_code[0]/10)*6));LCD_write_char(0,0x02,(read_rtc_code[0]/10)); //年十位LCD_write_char(0,0x03,(read_rtc_code[0]%10)); //年个位break;case 0x02:if(read_rtc_code[1]==1)read_rtc_code[1]=12;elseread_rtc_code[1]--;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[1],(read_rtc_code[1]+(read_rtc_code[1]/10)*6));LCD_write_char(0,0x05,(read_rtc_code[1]/10)); //月十位LCD_write_char(0,0x06,(read_rtc_code[1]%10)); //月个位break;case 0x03:if(read_rtc_code[2]==1)read_rtc_code[2]=30;elseread_rtc_code[2]--;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[2],(read_rtc_code[2]+(read_rtc_code[2]/10)*6));LCD_write_char(0,0x08,(read_rtc_code[2]/10)); //日十位LCD_write_char(0,0x09,(read_rtc_code[2]%10)); //日个位break;case 0x04:if(read_rtc_code[3]==1)read_rtc_code[3]=7;elseread_rtc_code[3]--;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[3],(read_rtc_code[3]+(read_rtc_code[3]/10)*6));LCD_write_char(0,0x0f,(read_rtc_code[3]%10)); //星期break;case 0x05:if(read_rtc_code[4]==0)read_rtc_code[4]=24;elseread_rtc_code[4]--;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[4],(read_rtc_code[4]+(read_rtc_code[4]/10)*6));LCD_write_char(1,0x05,(read_rtc_code[4]/10)); //时十位LCD_write_char(1,0x06,(read_rtc_code[4]%10)); //时个位break;case 0x06:if(read_rtc_code[5]==00)read_rtc_code[5]=59;elseread_rtc_code[5]--;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[5],(read_rtc_code[5]+(read_rtc_code[5]/10)*6));LCD_write_char(1,0x08,(read_rtc_code[5]/10)); //分十位LCD_write_char(1,0x09,(read_rtc_code[5]%10)); //分个位break;case 0x07:if(read_rtc_code[6]==0)read_rtc_code[6]=59;elseread_rtc_code[6]--;DS1302_WP_ENABLE;Write_Ds1302(write_rtc_address[6],(read_rtc_code[6]+(read_rtc_code[6]/10)*6));LCD_write_char(1,0x0b,(read_rtc_code[6]/10)); //秒十位LCD_write_char(1,0x0c,(read_rtc_code[6]%10)); //秒个位break;default:break;}while(P2_3==0);}}if(staus==0){//读出DS1302寄存器里的时间信息RST=HIGH;Read_RTC();LCD_write_char(0,0x02,(read_rtc_code[0]/10)); //年十位LCD_write_char(0,0x03,(read_rtc_code[0]%10)); //年个位LCD_write_char(0,0x05,(read_rtc_code[1]/10)); //月十位LCD_write_char(0,0x06,(read_rtc_code[1]%10)); //月个位LCD_write_char(0,0x08,(read_rtc_code[2]/10)); //日十位LCD_write_char(0,0x09,(read_rtc_code[2]%10)); //日个位LCD_write_char(0,0x0f,(read_rtc_code[3]%10)); //星期LCD_write_char(1,0x05,(read_rtc_code[4]/10)); //时十位LCD_write_char(1,0x06,(read_rtc_code[4]%10)); //时个位LCD_write_char(1,0x08,(read_rtc_code[5]/10)); //分十位LCD_write_char(1,0x09,(read_rtc_code[5]%10)); //分个位LCD_write_char(1,0x0b,(read_rtc_code[6]/10)); //秒十位LCD_write_char(1,0x0c,(read_rtc_code[6]%10)); //秒个位}else{RST=LOW;switch(count){case 0x01:write_lcd_command(0x83);break;case 0x02:write_lcd_command(0x86);break;case 0x03:write_lcd_command(0x89);break;case 0x04:write_lcd_command(0x8f);break;case 0x05:write_lcd_command(0xc6);break;case 0x06:write_lcd_command(0xc9);break;case 0x07:write_lcd_command(0xcc);break;default:break;}}}}。
基于利用时钟芯片DS1302实现万年历,1602LCD显示电子表
基于利用时钟芯片DS1302实现万年历,1602LCD显示电子表电子设计大赛培训第二时期第**组报告《基于利用时钟芯片DS1302实现万年历,1602LCD显示电子表》成员姓名:*** 学号:******成员姓名:HG** 学号:******成员姓名:*** 学号:*******一、要紧功能1、在1602液晶上显示年、月、日、星期、时、分、秒以及实时温度,同时实时更新显示;2、通过按键随时调剂各显示参数,分别实现光标定位、数值增大、数值减小、闹钟和温度上下限查看的功能;3.在时刻显现乱码的情形下,具有一键初始化时刻的功能。
二、电路图三、实物图1.开关模块2、显示模块3、at89c52模块4、总体连接图四、心得体会本次设计是我们遇到过的较大的设计,因此遇到的问题也比较的多,专门是往常没有接触过如此复杂的硬件电路以及软件编程,在软、硬件设计和调试中遇到了许多的困难,在同学的关心才逐一克服了难题,学习到了许多的专业知识。
在整个设计过程之前,我差不多在网上找了相关方面的资料,万事开始难,一开始不明白从哪里下手。
后来慢慢学会分析系统,将系统模块化,各个模块能够在软件或者硬件上实现。
在确保各个模块的硬件电路和与之相搭配的程序能够正常工作后在把它们组成一个系统。
在今后的生活里,我会进一步加强自己的动手能力,丰富自己的知识面。
总之,这次设计给我的最大感触确实是,在以后的学习中勤动脑,多动手。
附录:1、元件清单AT89C52 一块LCD 一个排阻 3个DS1302 一个DS18B20 一个开关 5个晶振 2个瓷片电容 2个, 30PF电解电容一个, 33Uf插针若干杜邦线若干2、程序#include <REG51.H>#include <intrins.h>//#include "LCD1602.h"//#include "DS1302.h"#define uint unsigned int#define uchar unsigned charsbit DS1302_CLK = P1^7; //实时时钟时钟线引脚sbit DS1302_IO = P1^6; //实时时钟数据线引脚sbit DS1302_RST = P1^5; //实时时钟复位线引脚sbit wireless_1 = P3^0;sbit wireless_2 = P3^1;sbit wireless_3 = P3^2;sbit wireless_4 = P3^3;sbit ACC0 = ACC^0;sbit ACC7 = ACC^7;charhide_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; //赶忙跳出调整模式按钮sbit DQ = P1^0; //温度传送数据IO口char done,count,temp,flag,up_flag,down_flag;uchar temp_value; //温度值uchar TempBuffer[5],week_value[2];void show_time(); //液晶显示程序/***********1602液晶显示部分子程序****************///PortDefinitions********************************************************* *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 //defaultvoid 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));}//将字符输出到液晶显示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 0x8Cvoid DS1302InputByte(unsigned char d) //实时时钟写入一字节(内部函数) {unsigned char i;ACC = d;for(i=8; i>0; i--){DS1302_IO = ACC0; //相当于汇编中的 RRCDS1302_CLK = 1;DS1302_CLK = 0;ACC = ACC >> 1;}}unsigned char DS1302OutputByte(void) //实时时钟读取一字节(内部函数) {unsigned char i;for(i=8; i>0; i--){ACC = ACC >>1; //相当于汇编中的 RRCACC7 = 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_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[]数组里,跟年,月,日的分开存放,因为等一下要在最后显示}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:55Write1302(0x88,0x07);Write1302(0x86,0x25);Write1302(0x8a,0x07);Write1302(0x84,0x23);Write1302(0x82,0x59);Write1302(0x80,0x55);Write1302(0x8e,0x80); //禁止写入}}/***********ds18b20子程序*************************//***********ds18b20延迟子函数(晶振12MHz )*******/void delay_18B20(unsigned int i){while(i--);}/**********ds18b20初始化函数**********************/void Init_DS18B20(void){unsigned char x=0;DQ = 1; //DQ复位delay_18B20(8); //稍做延时DQ = 0; //单片机将DQ拉低delay_18B20(80); //精确延时大于 480usDQ = 1; //拉高总线delay_18B20(14);x=DQ; //稍做延时后假如x=0则初始化成功 x=1则初始化失败delay_18B20(20);}/***********ds18b20读一个字节**************/unsigned char ReadOneChar(void){uchar i=0;uchar dat = 0;for (i=8;i>0;i--){DQ = 0; // 给脉冲信号dat>>=1;DQ = 1; // 给脉冲信号if(DQ)dat|=0x80;delay_18B20(4);}return(dat);}/*************ds18b20写一个字节****************/void WriteOneChar(uchar dat){unsigned char i=0;for (i=8; i>0; i--){DQ = 0;DQ = dat&0x01;delay_18B20(5);DQ = 1;dat>>=1;}}/**************读取ds18b20当前温度************/void ReadTemp(void){unsigned char a=0;unsigned char b=0;unsigned char t=0;Init_DS18B20();WriteOneChar(0xCC); // 跃过读序号列号的操作WriteOneChar(0x44); // 启动温度转换delay_18B20(100); // this message is wery importantInit_DS18B20();WriteOneChar(0xCC); //跃过读序号列号的操作WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器)前两个确实是温度delay_18B20(100);a=ReadOneChar(); //读取温度值低位b=ReadOneChar(); //读取温度值高位temp_value=b<<4;temp_value+=(a&0xf0)>>4;}void temp_to_str() //温度数据转换成液晶字符显示{TempBuffer[0]=temp_value/10+'0'; //十位TempBuffer[1]=temp_value%10+'0'; //个位TempBuffer[2]=0xdf; //温度符号TempBuffer[3]='C';TempBuffer[4]='\0';}void Delay1ms(unsigned int count){unsigned int i,j;for(i=0;i<count;i++)for(j=0;j<120;j++);}/*延时子程序*/void mdelay(uint delay){ uint i;for(;delay>0;delay--){for(i=0;i<62;i++) //1ms延时.{;}}}void outkey() //跳出调整模式,返回默认显示{ uchar Second;if(out==0||wireless_1==1){ mdelay(8);count=0;hide_sec=0,hide_min=0,hide_hour=0,hide_day=0,hide_week=0,hide_mon th=0,hide_year=0;Second=Read1302(DS1302_SECOND);Write1302(0x8e,0x00); //写入承诺Write1302(0x80,Second&0x7f);Write1302(0x8E,0x80); //禁止写入done=0;while(out==0);while(wireless_1==1);}}//////////////////////////////////////////////////////////////////// ////////////////////////////////////////void Upkey()//升序按键{Up=1;if(Up==0||wireless_2==1){mdelay(8);switch(count){case 1:temp=Read1302(DS1302_SECOND); //读取秒数temp=temp+1; //秒数加1up_flag=1; //数据调整后更新标志if((temp&0x7f)>0x59) //超过59秒,清零temp=0;break;case 2:temp=Read1302(DS1302_MINUTE); //读取分数temp=temp+1; //分数加1up_flag=1;if(temp>0x59) //超过59分,清零temp=0;break;case 3:temp=Read1302(DS1302_HOUR); //读取小时数temp=temp+1; //小时数加1up_flag=1;if(temp>0x23) //超过23小时,清零temp=0;break;case 4:temp=Read1302(DS1302_WEEK); //读取星期数temp=temp+1; //星期数加1up_flag=1;if(temp>0x7)temp=1;break;case 5:temp=Read1302(DS1302_DAY); //读取日数temp=temp+1; //日数加1up_flag=1;if(temp>0x31)temp=1;break;case 6:temp=Read1302(DS1302_MONTH); //读取月数temp=temp+1; //月数加1up_flag=1;if(temp>0x12)temp=1;break;case 7:temp=Read1302(DS1302_YEAR); //读取年数temp=temp+1; //年数加1up_flag=1;if(temp>0x85)temp=0;break;default:break;}while(Up==0);while(wireless_2==1);}}//////////////////////////////////////////////////////////////////// ////////////////////////////////////////void Downkey()//降序按键{Down=1;if(Down==0||wireless_3==1){mdelay(8);switch(count){case 1:temp=Read1302(DS1302_SECOND); //读取秒数temp=temp-1; //秒数减1down_flag=1; //数据调整后更新标志if(temp==0x7f) //小于0秒,返回59秒temp=0x59;break;case 2:temp=Read1302(DS1302_MINUTE); //读取分数temp=temp-1; //分数减1down_flag=1;if(temp==-1)temp=0x59; //小于0秒,返回59秒break;case 3:temp=Read1302(DS1302_HOUR); //读取小时数temp=temp-1; //小时数减1down_flag=1;if(temp==-1)temp=0x23;break;case 4:temp=Read1302(DS1302_WEEK); //读取星期数temp=temp-1; //星期数减1down_flag=1;if(temp==0)temp=0x7;;break;case 5:temp=Read1302(DS1302_DAY); //读取日数temp=temp-1; //日数减1down_flag=1;if(temp==0)temp=31;break;case 6:temp=Read1302(DS1302_MONTH); //读取月数temp=temp-1; //月数减1down_flag=1;if(temp==0)temp=12;break;case 7:temp=Read1302(DS1302_YEAR); //读取年数temp=temp-1; //年数减1down_flag=1;if(temp==-1)temp=0x85;break;default:break;}while(Down==0);while(wireless_3==1);}}void Setkey()//模式选择按键{Set=1;if(Set==0||wireless_4==1){mdelay(8);count=count+1; //Setkey按一次,count就加1done=1; //进入调整模式while(Set==0);while(wireless_4==1);}}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)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();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);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); //日期数据转换液晶字符ReadTemp(); //开启温度采集程序temp_to_str(); //温度数据转换成液晶字符GotoXY(12,1); //液晶字符显示位置Print(TempBuffer); //显示温度GotoXY(0,1);Print(CurrentTime.TimeString); //显示时刻GotoXY(0,0);Print(CurrentTime.DateString); //显示日期GotoXY(15,0);Print(week_value); //显示星期GotoXY(11,0);Print("Week"); //在液晶上显示字母 weekDelay1ms(400); //扫描延时}main(){flag=1; //时钟停止标志LCD_Initial(); //液晶初始化Init_DS18B20( ) ; //DS18B20初始化Initial_DS1302(); //时钟芯片初始化up_flag=0;down_flag=0;done=0; //进入默认液晶显示wireless_1=0;wireless_2=0;wireless_3=0;wireless_4=0;while(1){while(done==1)keydone(); //进入调整模式while(done==0){show_time(); //液晶显示数据 flag=0;Setkey(); //扫描各功能键}}}。
