当前位置:文档之家› 西华大学单片机课程设计之基于单片机与DS1302的数字闹钟

西华大学单片机课程设计之基于单片机与DS1302的数字闹钟

课程设计说明书课程名称:单片机应用课程设计课程代码: 6003509题目:数字闹钟的设计学生姓名:学号: 312011080307 年级/专业/班: 2011级机电2班学院(直属系) :机械工程与自动化学院指导教师:张恕远数字闹钟的设计摘要电子时钟主要是利用电子技术将时钟电子化、数字化,拥有时钟精确、体积小、界面友好、可扩展性能强等特点,被广泛应用于生活和工作当中。

另外,在生活和工农业生产中,也常常需要温度,这就需要电子时钟具有多功能性。

本设计主要为实现一款可正常显示时钟/日历、带有定时闹铃的多功能电子时钟。

本文对当前电子钟开发手段进行了比较和分析,最终确定了采用单片机技术实现多功能电子时钟。

本设计应用AT89C52芯片作为核心,LCD1062进行显示,使用DS1302实时时钟日历芯片完成时钟/日历的基本功能。

这种实现方法的优点是电路简单,性能可靠,实时性好,时间精确,操作简单,编程容易。

该电子时钟可以应用于一般的生活和工作中,也可通过改装,提高性能,增加新功能,从而给人们的生活和工作带来更多的方便。

关键词:电子时钟;多功能;AT89C52;时钟日历目录摘要................................................I1、设计任务、目的、思路..........................................12、总体设计方案.............................................23、电路原理的设计...............................................3 3.1DS1302原理及电路....................................3 3.2晶振电路........................................3 3.3复位电路原理及电路.................................4 3.4 LCD1602原理及电路...................................4 3.5DS18B20电路.............................................5 3.6按键电路及功能.............................................53.7蜂鸣器电路.............................................64、软件系统设计.............................................7 4.1系统工作流程图.............................................74.2软件系统构成.............................................85、系统调试与结果.............................................96、课程设计体会................................................107、参考文献................................................11 附录:程序代码....................................121、设计任务、目的、思路(1)任务用LCD显示出月、日、分、星期和温度,三~四个按键可对时间进行校正,并能实现闹钟功能。

(2)目的1、掌握电子时钟的基本工作方式。

2、进一步熟悉DS1302及DS18B20芯片的特性。

3、通过使用各基本指令,进一步熟练掌握单片机的编程和程序调试。

(3)思路利用AT89C52的特点及DS1302的特点,设计一种基于DS1302单片机控制,再利用LCD显示的数字钟。

本系统硬件利用AT89S52作为CPU进行总体控制,通过DS1302时钟芯片获取准确详细的时间(年、月、日、周、日、时、分、秒准确时间),对时钟信号进行控制,同时利用液晶显示芯片LCD1602对时间进行准确显示年、月、日、周、日、时、分、秒。

2、总体设计方案根据系统设计的要求和设计思路,确定该系统的系统设计结构图。

如图所示。

硬件电路主要由AT89C52单片机控制器单元、DS1302时钟电路、复位电路、DS18B20温度模块、按键模块、晶振电路、蜂鸣器模块、LCD1602液晶显示模块等构成。

3、电路原理的设计3.1 DS1302原理及电路如下所示本设计使用的实时时钟电路芯片是美国DALLAS公司生产的一种高性能、低功耗、带RAM的实时时钟电路芯片DS1302。

VCC1为后备电源,VCC2为主电源。

在主电源关闭的情况下,也能保持时钟的连续运行。

DS1302由VCC1或VCC2两者中的较大者供电;当VCC2大于VCC1+0.2V时,VCC2给DS1302供电;当VCC2小于VCC1时,DS1302由VCC1供电。

X1和X2是振荡源,外接32.768kHz晶振。

RST非是复位/片选线,通过把RST非输入驱动置高电平来启动所有的数据传送。

图3.1-1图3.1-23.2 晶振电路如下AT89S52在工作时需要外部提供时钟信号,因此,本设计选择在其18脚19脚之间接上12MHz的晶振,为单片机提供1μs的机器振荡周期。

其电路连接图如图所示。

在图中,电容器C3、C4起稳定振荡频率、快速起振的作用,其电容值一般在20~50pF。

图3.23.3 复位电路原理及电路如下在AT89C52单片机中的振荡器运行时,RST非引脚上保持到少2个机器周期的高电平输入信号,复位过程即可完成。

根据此原理,本设计采用上电复位和按键复位嵌套在系统中,增强了系统的实用性。

图3.33.4 LCD1602原理及电路如下LCD1602液晶显示是一种专门用来显示字母、数字、符号等的点阵型液晶模块。

它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形(用自定义CGRAM,显示效果也不好)。

1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。

以其微功耗、体积小、显示内容丰富、超薄轻巧的诸多优点,在各种小系统中得到了更广泛的应用。

本设计中使用的液晶显示模块是LCD1602。

图3.43.5 DS18B20电路如下DS18B20,常用的温度传感器,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。

图3.53.6 按键电路如下图3.6按键功能说明:KEY0为时钟调节功能键,第一次按KEY0时,时间停止且光标在年处闪烁。

第二次按KEY0时,光标在月处闪烁。

第三次按KEY0时,光标在日处闪烁。

第四次按KEY0时,光标在星期处闪烁。

第五次按KEY0时,光标在时处闪烁。

第六次按KEY0时,光标在日处闪烁。

第七次按KEY0时,光标在秒处闪烁。

光标闪烁时可用KEY1增加相应的值或KEY2减少相应的值。

第八次按KEY0时,保存了修改的时间值并返回显示时间。

KEY3为闹钟功能键。

第一次按KEY3时,进入闹钟设置页面,光标在闹钟开关处闪烁。

第二次按KEY3时,光标在分处闪烁。

第三次按KEY3时,光标在时处闪烁。

光标闪烁时,同样可以用KEY1与KEY2修改相应的值。

当闹钟响起时,1分钟后自动关闭。

3.7 蜂鸣器电路如下图3.74、软件系统设计4.1、系统工作流程图图4.1系统工作流程图4.2软件系统构成软件系统包含引脚定义及变量申明、LCD显示部分、DS1302部分、键盘扫描部分、DS18B20温度部分、主函数等等。

LCD部分对不变的显示部分进行LCD初始化,将需要变化的部分分开显示,如将年、月、日、星期显示在第一行,将时、分、秒、温度、闹钟设置显示在第二行。

DS1302对将要显示的时间送入LCD进行显示,以及对调整后的时间进行接收存储计算及送入LCD重新显示。

键盘扫描部分对键盘进行扫描,修改时间时按键使数据的改变而送入DS1302进行时间的修改,以及闹钟时间的修改。

DS18B20部分对硬件采集到的环境温度进行数据转换并送入LCD显示。

5、系统调试与结果系统调试过程利用Proteus绘制出相应硬件电路后进行仿真,出现液晶显示无法正常显示的问题。

经过思考和查阅的资料发现AT89C52的P0在进高电平时没有接上拉电阻导致LCD1602无法正常显示时间。

修改电路后(P0口接上拉电阻)烧入程序后,程序正常运行,LCD1602准确的显示。

用Proteus仿真能够正确的现实时间,但烧入学习板出现乱码现实不能正常工作。

经过反复检查及思考发现仿真软件上的硬件电路与学习板上的硬件电路不一致无法对应起来。

最后根据学习板的硬件电路修改相应程序及仿真软件上的硬件电路,最终现实了功能。

系统调试结果:图5.16、课程设计体会本设计利用单片机AT89C512控制串行实时时钟芯DS1302构成数字时钟电路,实现计时功能。

该电路使用简单的三线接口,为单片机节省大量的接口资源,时钟芯片带有后备电池。

该时钟功能强大,性能优越,能为很多领域,特别是对时钟工作的准确性和可靠性有较高要求。

通过对电子时钟的设计的设计与制作,让我了解了电子时钟模块的编程思想,也让我明白了电子时钟的基本原理与设计理念,要设计一个电路必须先编好程序,用仿真软件测试成功后再得出结论。

通过这次学习,让我对该软件有了更熟悉的了解,我们应该自己动手,实际操作,才会有更深刻的理解。

7、参考文献[1] 黄惟公.单片机原理与应用技术:西安电子科大出版社2007[2] 张毅刚.MC-51单片机应用设计(二版):哈工大出版社 2005[3] 宋戈. 黄鹤松. 51单片机应用开发范例大全:人民邮电出版社 2010[4] 刘建清. 51单片机新颖实例非常入门与视频演练:电子工业出版社2012[5] 郭天祥. 新概念51单片机C语言教程:电子工业出版社 2009附录:程序代码:#include<reg52.h>#define uchar unsigned char#define uint unsigned int/*----------------引脚定义-------------------*/sbit RST=P3^5; //DS1302片选sbit DIO=P3^4; //DS1302数据信号sbit SCLK=P3^6; //DS1302时钟信号sbit ACC7=ACC^7;sbit ACC0=ACC^0;sbit LCD_E=P2^7; //液晶使能端sbit LCD_RS=P2^6; //液晶数据命令选择端sbit LCD_RW=P2^5; //液晶读写选择端sbit key0=P1^0; //功能键sbit key1=P1^1; //增大键sbit key2=P1^2; //减小键sbit key3=P1^3; //闹钟调节按键sbit beep=P3^3; //蜂鸣器sbit DQ=P3^7; //18b20温度输入输出端void INITIAL_1302(); //初始化1302uchar READ_1302(uchar addr); //读1302void WRITE_1302(uchar addr,uchar date); //写1302uint temp; //定义整型的温度数据float f_temp; //定义浮点型的温度数据char hour,minute,second,week,day,month,year,tem;unsigned char num,num1,flag;bit alarmon,alarmoff;uchar xx,yy;unsigned char clkhh=0,clkmm=0,clkflag,clkvalue;unsigned char str1[]="20 - - ";unsigned char str2[]=" : : . C ";unsigned char str3[]="alarm : ";void delay(uchar z); //延时函数void LCD_WRITE_COM(uchar com); //LCD写函数void LCD_WRITE_DATA(uchar date); //LCD写数据void LCD_WRITE_SFM(uchar addr,uchar date); //LCD写时分秒void LCD_WRITE_NYR(uchar addr,uchar date); //LCD写年月日void LCD_WRITE_WEEK(uchar week); //LCD写星期void LCD_INITIAL(); //LCD初始化void LCD_WRITE_TEMP(uchar addr,uchar temp); //LCD写温度void keyscan(); //键盘扫描void dis_temp(uint t);void tempchange(void);void tempwritebyte(uchar dat);uchar tempread(void);bit tempreadbit(void);void dsreset(void);uint get_temp(); //获取温度/*************主函数**************/void main(){LCD_INITIAL(); //液晶初始化INITIAL_1302(); //DS1302初始化dsreset();while(1){keyscan(); //按键扫描if(flag==0) //当标志位为0,允许读取DS1302数据,将数据送入液晶显示{second=READ_1302(0x81);LCD_WRITE_SFM(6,second);minute=READ_1302(0x83);LCD_WRITE_SFM(3,minute);hour=READ_1302(0x85);LCD_WRITE_SFM(0,hour);week=READ_1302(0x8b);LCD_WRITE_WEEK(week);day=READ_1302(0x87);LCD_WRITE_NYR(8,day);month=READ_1302(0x89);LCD_WRITE_NYR(5,month);year=READ_1302(0x8d);LCD_WRITE_NYR(2,year);tempchange();dis_temp(get_temp());}}}/**********************LCD1602***************************/void delay(uchar z) //1602de延时函数{unsigned char x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void LCD_WRITE_COM(uchar com) //1602写函数{LCD_RS=0;LCD_RW=0;LCD_E=1;P0=com;delay(5);LCD_E=0;}void LCD_WRITE_DATA(uchar date) //1602写数据{LCD_RS=1;LCD_RW=0;LCD_E=1;P0=date;delay(5);LCD_E=0;}void LCD_WRITE_SFM(uchar addr,uchar date) //LCD写时分秒{unsigned char shi,ge;shi=date/10;ge=date%10;LCD_WRITE_COM(0x80+0x40+addr);LCD_WRITE_DATA(0x30+shi);LCD_WRITE_DATA(0x30+ge);}void LCD_WRITE_NYR(unsigned char addr,unsigned char date)//LCD写年月日{char shi,ge;shi=date/10;ge=date%10;LCD_WRITE_COM(0x80+addr);LCD_WRITE_DATA(0x30+shi);LCD_WRITE_DATA(0x30+ge);}void LCD_WRITE_CLK(unsigned char addr,unsigned char date)//LCD写闹钟{char shi,ge;shi=date/10;ge=date%10;LCD_WRITE_COM(0x80+0x40+addr);LCD_WRITE_DATA(0x30+shi);LCD_WRITE_DATA(0x30+ge);}void LCD_WRITE_WEEK(uchar week)//LCD写星期{LCD_WRITE_COM(0x80+11);switch(week){case 1: LCD_WRITE_DATA('S');delay(5);LCD_WRITE_DATA('U');delay(5);LCD_WRITE_DATA('N');break;case 2: LCD_WRITE_DATA('M');delay(5);LCD_WRITE_DATA('O');delay(5);;LCD_WRITE_DATA('N');break;case 3: LCD_WRITE_DATA('T');delay(5);LCD_WRITE_DATA('U');delay(5);LCD_WRITE_DATA('E');break;case 4: LCD_WRITE_DATA('W');delay(5);LCD_WRITE_DATA('E');delay(5);LCD_WRITE_DATA('D');break;case 5: LCD_WRITE_DATA('T');delay(5);LCD_WRITE_DATA('H');delay(5);LCD_WRITE_DATA('U');break;case 6: LCD_WRITE_DATA('F');delay(5);LCD_WRITE_DATA('R');delay(5);LCD_WRITE_DATA('I');break;case 7: LCD_WRITE_DATA('S');delay(5);LCD_WRITE_DATA('A');delay(5);LCD_WRITE_DATA('T');break;}}void LCD_WRITE_TEMP(uchar addr,uchar temp) //LCD写温度{LCD_WRITE_COM(0x80+0x40+addr);LCD_WRITE_DATA(0x30+temp);}void CLK_INITIAL(uchar addr,uchar clknum)//闹钟初始化{uchar i;char shi,ge;shi=clknum/10;ge=clknum%10;LCD_WRITE_COM(0x38);LCD_WRITE_COM(0x0c);LCD_WRITE_COM(0x06);LCD_WRITE_COM(0x80);LCD_WRITE_COM(0x80+0x40);//液晶第二行显示for(i=0;i<16;i++){LCD_WRITE_DATA(str3[i]);delay(5);}LCD_WRITE_COM(0x80+0x40+addr);LCD_WRITE_DATA(shi/10+0x30);LCD_WRITE_DATA(ge%10+0x30);}void LCD_INITIAL() //LCD初始化{unsigned char i;LCD_WRITE_COM(0x38);LCD_WRITE_COM(0x0c);LCD_WRITE_COM(0x06);LCD_WRITE_COM(0x80);for(i=0;i<16;i++) //液晶第一行显示{LCD_WRITE_DATA(str1[i]);delay(5);}LCD_WRITE_COM(0x80+0x40);//液晶第二行显示for(i=0;i<16;i++){LCD_WRITE_DATA(str2[i]);delay(5);}}/****************1302*************/void WRITE_1302(uchar addr,uchar date)//向1302写数据{unsigned char i;RST=0;SCLK=0;RST=1;for(i=8;i>0;i--){SCLK=0;ACC=addr;DIO=ACC0;addr>>=1;SCLK=1;}for(i=8;i>0;i--){SCLK=0;ACC=date;DIO=ACC0;date>>=1;SCLK=1;}RST=0;}unsigned char READ_1302(unsigned char addr)//从1302读数据{unsigned char i,date1,date2;RST=0;SCLK=0;RST=1;for(i=8;i>0;i--){SCLK=0;ACC=addr;DIO=ACC0;addr>>=1;SCLK=1;}for(i=8;i>0;i--){ACC7=DIO;SCLK=1;ACC>>=1;SCLK=0;}RST=0;date1=ACC;date2=date1/16;date1=date1%16;date1=date1+date2*10;return(date1) ;}void INITIAL_1302()//初始化1302{WRITE_1302(0x80,READ_1302(0x81)&0x7f); //启动DS1302 0x80写秒地址}/****************键盘扫描部分*************************/void keyscan(){if(key0==0)//确认功能键按下{delay(20);if(key0==0)//去抖{while(!key0);//释放num++;switch(num){case 1: flag=1; //修改时间,禁止从DS1302读数据LCD_WRITE_COM(0x0f); //光标开始闪烁LCD_WRITE_COM(0x80+3);//第一次按下,光标定位到年位置break;case 2: LCD_WRITE_COM(0x80+6);//第二次按下,光标定位到月位置break;case 3: LCD_WRITE_COM(0x80+9);//第三次按下,光标定位到日位置break;case 4: LCD_WRITE_COM(0x80+13);//第四次按下,光标定位到星期位置break;case 5: LCD_WRITE_COM(0x80+0x40+1);//第五次按下,光标定位到时位置break;case 6: LCD_WRITE_COM(0x80+0x40+4);//第六次按下,光标定位到分位置break;case 7: LCD_WRITE_COM(0x80+0x40+7);//第七次按下,光标定位到秒位break;case 8: num=0; //第八次按下,记录清零LCD_WRITE_COM(0x0c); //不显示光标WRITE_1302(0x8E,0x00); //允许写操作0x8E写保护WRITE_1302(0x80,(second/10*16)+second%10);//将调节后的秒写入DS1302WRITE_1302(0x82,(minute/10*16)+minute%10);//将调节后的分写入DS1302WRITE_1302(0x84,(hour/10*16)+hour%10);//将调节后的时写入DS1302WRITE_1302(0x8a,(week/10*16)+week%10);//将调节后的星期写入DS1302WRITE_1302(0x86,(day/10*16)+day%10);//将调节后的日写入DS1302WRITE_1302(0x88,(month/10*16)+month%10);//将调节后的月写入DS1302WRITE_1302(0x8c,(year/10*16)+year%10);//将调节后的年写入DS1302WRITE_1302(0x8E,0x80); //开写保护flag=0; //时间修改完毕,允许液晶从DS1302读数据break;}}}if(num!=0){if(key1==0)//确认增大键按下{delay(20);if(key1==0)//增大键确实按下{while(!key1);switch(num){case 1: year++;//调节年if(year==100)year=0;LCD_WRITE_NYR(2,year);//将调节后的年送入液晶显示LCD_WRITE_COM(0x80+3);//光标回到指定处break;case 2: month++;//调节月if(month==13)month=0;LCD_WRITE_NYR(5,month);//将调节后的月送入液晶显示LCD_WRITE_COM(0x80+6);//光标回到指定处break;case 3: day++;//调节日if(day==32)day=0;LCD_WRITE_NYR(8,day);//将调节后的日送入液晶显示LCD_WRITE_COM(0x80+9);//光标回到指定处break;case 4: week++;if(week==8)week=0;LCD_WRITE_WEEK(week);//将调节后的星期送入液晶显示LCD_WRITE_COM(0x80+13);//光标回到指定处break;case 5: hour++;if(hour==24)hour=0;LCD_WRITE_SFM(0,hour);//将调节后的小时送入液晶显示LCD_WRITE_COM(0x80+0x40+1);//光标回到指定处break;case 6: minute++;if(minute==60)minute=0;LCD_WRITE_SFM(3,minute);//将调节后的分送入液晶显示LCD_WRITE_COM(0x80+0x40+4);//光标回到指定处break;case 7: second++;if(second==60)second=0;LCD_WRITE_SFM(6,second);//将调节后的秒送入液晶显示LCD_WRITE_COM(0x80+0x40+7);//光标回到指定处break;default:break;}}}if(key2==0)//确认减小键按下{delay(20);if(key2==0)//减小键确实按下{while(!key2);switch(num){case 1: year--;//调节年if(year==-1)year=99;LCD_WRITE_NYR(2,year);LCD_WRITE_COM(0x80+3);break;case 2: month--;//调节月if(month==-1)month=12;LCD_WRITE_NYR(5,month);LCD_WRITE_COM(0x80+6);break;case 3: day--;//调节日if(day==-1)day=31;LCD_WRITE_NYR(8,day);LCD_WRITE_COM(0x80+9);break;case 4: week--;//调节星期if(week==0)week=7;LCD_WRITE_WEEK(week);LCD_WRITE_COM(0x80+13);break;case 5: hour--;//调节时if(hour==-1)hour=23;LCD_WRITE_SFM(0,hour);LCD_WRITE_COM(0x80+0x40+1);break;case 6: minute--;//调节分if(minute==-1)minute=59;LCD_WRITE_SFM(3,minute);LCD_WRITE_COM(0x80+0x40+4);break;case 7: second--;//调节秒if(second==-1)second=59;LCD_WRITE_SFM(6,second);LCD_WRITE_COM(0x80+0x40+7);break;default:break;}}}}/**************闹钟部分******************/if(key3==0) //闹钟调节键{delay(20);if(key3==0){while(!key3);num1++;switch(num1){case 1: CLK_INITIAL(6,clkhh);CLK_INITIAL(9,clkmm);flag=1;LCD_WRITE_COM(0x0f); //光标开始闪烁LCD_WRITE_COM(0x80+0x40+12);//第一次按//下,光标定位到闹钟开关位置break;case 2: LCD_WRITE_COM(0x80+0x40+10);//第二次按下,//光标定位到闹钟分钟位置break;case 3: LCD_WRITE_COM(0x80+0x40+7);//第二次按下,//光标定位到闹钟分钟位置break;case 4: num1=0;LCD_WRITE_COM(0x0c);LCD_INITIAL();flag=0;break;}}}if(num1!=0){if(key1==0)//确认增大键按下{delay(20);if(key1==0)//增大键确实按下{while(!key1);switch(num1){case 1: clkflag++;switch(clkflag){case 1:clkvalue=1;LCD_WRITE_DATA('O');LCD_WRITE_DATA('N');LCD_WRITE_DATA(' ');LCD_WRITE_COM(0X80+0X40+12);break;case 2:clkvalue=0;clkflag=0;LCD_WRITE_DATA('O');LCD_WRITE_DATA('F');LCD_WRITE_DATA('F');LCD_WRITE_COM(0X80+0X40+12);break;};break;case 3: clkhh++;if(clkhh==24)clkhh=0;LCD_WRITE_CLK(6,clkhh);LCD_WRITE_COM(0x80+0x40+7);//光标回到指定处break;case 2: clkmm++;if(clkmm==60)clkmm=0;LCD_WRITE_CLK(9,clkmm);LCD_WRITE_COM(0x80+0x40+10);//光标回到指定处break;default: break;}}}}if(key2==0)//确认减小键按下{delay(20);if(key2==0)//减小键确实按下{while(!key2);switch(num1){case 1: clkflag--;switch(clkflag){case -1:clkvalue=1;LCD_WRITE_DATA('O');LCD_WRITE_DATA('N');LCD_WRITE_DATA(' ');LCD_WRITE_COM(0X80+0X40+12);break;case -2:clkvalue=0;clkflag=0;LCD_WRITE_DATA('O');LCD_WRITE_DATA('F');LCD_WRITE_DATA('F');LCD_WRITE_COM(0X80+0X40+12);break;};break;case 3: clkhh--;if(clkhh==-1)clkhh=23;LCD_WRITE_CLK(6,clkhh);LCD_WRITE_COM(0x80+0x40+7);//光标回到指定处break;case 2: clkmm--;if(clkmm==-1)clkmm=59;LCD_WRITE_CLK(9,clkmm);LCD_WRITE_COM(0x80+0x40+10);//光标回到指定处break;default:break;}}}xx=READ_1302(0x83); //yy=READ_1302(0x85);if(clkhh==yy&&clkmm==xx&&clkvalue==1) //读取时间值与闹钟值比较,若相同//且闹钟开关为开则闹钟响{alarmon=1;}else{alarmon=0; //响一分钟后闹钟关闭。

相关主题