单片机仿真课程设计基于51单片机的实时时钟.docx
- 文档编号:9190304
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:12
- 大小:18.38KB
单片机仿真课程设计基于51单片机的实时时钟.docx
《单片机仿真课程设计基于51单片机的实时时钟.docx》由会员分享,可在线阅读,更多相关《单片机仿真课程设计基于51单片机的实时时钟.docx(12页珍藏版)》请在冰豆网上搜索。
单片机仿真课程设计基于51单片机的实时时钟
基于51系列单片机及DS1302时钟芯片的实时时钟仿真设计
一、课程设计目的意义
通过本次课程设计可以灵活运用单片机的基础知识,依据课程设计内容,能够完成从硬件电路图设计,到软件编程及系统调试实现系统功能,完成课程设计,加深对单片机基础知识的理解并灵活运用。
二、实现目标
本设计主要为实现一款可正常显示时钟/日历的实时电子时钟。
对当前电子钟开发手段进行了比较和分析,最终确定了采用单片机技术实现电子时钟。
本设计应用AT89C52芯片作为核心,LCD显示屏,使用DS1302实时时钟日历芯片完成时钟/日历的基本功能。
这种实现方法的优点是电路简单,性能可靠,实时性好,时间精确,操作简单,编程容易。
三、硬件设计
本设计采用具有32根I/O引脚的AT89C52单片机。
AT89C52单片机是一款低功耗,低电压,高性能CMOS8位单片机,片内含4KB(可经受1000次擦写周期)的FLASH可编程可反复擦写的只读程序存储器(EPROM),器件采用CMOS工艺和ATMEI公司的高密度、非易失性存储器(NURAM)技术制造,其输出引脚和指令系统都与MCS-52兼容。
片内的FLASH存储器允许在系统内可改编程序或用常规的非易失性存储器编程器来编程。
因此,AT89C52是一种功能强,灵活性高且价格合理的单片机,可方便的应用在各个控制领域。
AT89C52具有以下主要性能:
1.4KB可改编程序Flash存储器;
2.全静态工作:
0——24Hz;
3.128×8字节内部RAM;
4.32个外部双向输入/输出(I/O)口;
5.6个中断优先级;2个16位可编程定时计数器;
6.可编程串行通道;
7.片内时钟振荡器。
DS1302是美国DALLAS公司推出的一种高性能、低功耗的实时时钟日历芯片,附加31字节静态RAM,采用SPI三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号和RAM数据。
实时时钟可提供秒、分、时、日、星期、月和年,一个月小于31天时可以自动调整,且具有闰年补偿功能。
工作电压宽达2.5~5.5V。
采用双电源供电(主电源和备用电源),可设置备用电源充电方式,提供了对后备电源进行涓细电流充电的能力。
有主电源和备份电源双引脚,而且备份电源可由大容量电容(>1F)来替代。
需要强调的是,DS1302需要使用32.768KHz的晶振。
四、原理图
五、程序源代码
#include
#include"LCD1602.h"
#include"DS1302.h"
voidDelay1ms(unsignedintcount)
{
unsignedinti,j;
for(i=0;i for(j=0;j<120;j++); } main() { SYSTEMTIMECurrentTime; LCD_Initial(); Initial_DS1302(); GotoXY(0,0); Print("Date: "); GotoXY(0,1); Print("Time: "); while (1) { DS1302_GetTime(&CurrentTime); DateToStr(&CurrentTime); TimeToStr(&CurrentTime); GotoXY(6,0); Print(CurrentTime.DateString); GotoXY(6,1); Print(CurrentTime.TimeString); Delay1ms(300); } } #ifndef_REAL_TIMER_DS1302 #define_REAL_TIMER_DS1302 sbitDS1302_CLK=P1^6;//实时时钟时钟线引脚 sbitDS1302_IO=P1^7;//实时时钟数据线引脚 sbitDS1302_RST=P1^5;//实时时钟复位线引脚 sbitACC0=ACC^0; sbitACC7=ACC^7; typedefstruct__SYSTEMTIME__ { unsignedcharSecond; unsignedcharMinute; unsignedcharHour; unsignedcharWeek; unsignedcharDay; unsignedcharMonth; unsignedcharYear; unsignedcharDateString[9]; unsignedcharTimeString[9]; }SYSTEMTIME;//定义的时间类型 #defineAM(X)X #definePM(X)(X+12)//转成24小时制 #defineDS1302_SECOND0x80 #defineDS1302_MINUTE0x82 #defineDS1302_HOUR0x84 #defineDS1302_WEEK0x8A #defineDS1302_DAY0x86 #defineDS1302_MONTH0x88 #defineDS1302_YEAR0x8C #defineDS1302_RAM(X)(0xC0+(X)*2)//用于计算DS1302_RAM地址的宏 voidDS1302InputByte(unsignedchard)//实时时钟写入一字节(内部函数) { unsignedchari; ACC=d; for(i=8;i>0;i--) { DS1302_IO=ACC0;//相当于汇编中的RRC DS1302_CLK=1; DS1302_CLK=0; ACC=ACC>>1; } } unsignedcharDS1302OutputByte(void)//实时时钟读取一字节(内部函数) { unsignedchari; for(i=8;i>0;i--) { ACC=ACC>>1;//相当于汇编中的RRC ACC7=DS1302_IO; DS1302_CLK=1; DS1302_CLK=0; } return(ACC); } voidWrite1302(unsignedcharucAddr,unsignedcharucDa)//ucAddr: DS1302地址,ucData: 要写的数据 { DS1302_RST=0; DS1302_CLK=0; DS1302_RST=1; DS1302InputByte(ucAddr);//地址,命令 DS1302InputByte(ucDa);//写1Byte数据 DS1302_CLK=1; DS1302_RST=0; } unsignedcharRead1302(unsignedcharucAddr)//读取DS1302某地址的数据 { unsignedcharucData; DS1302_RST=0; DS1302_CLK=0; DS1302_RST=1; DS1302InputByte(ucAddr|0x01);//地址,命令 ucData=DS1302OutputByte();//读1Byte数据 DS1302_CLK=1; DS1302_RST=0; return(ucData); } voidDS1302_SetProtect(bitflag)//是否写保护 { if(flag) Write1302(0x8E,0x10); else Write1302(0x8E,0x00); } voidDS1302_SetTime(unsignedcharAddress,unsignedcharValue)//设置时间函数 { DS1302_SetProtect(0); Write1302(Address,((Value/10)<<4|(Value%10))); } voidDS1302_GetTime(SYSTEMTIME*Time) { unsignedcharReadValue; 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); } voidDateToStr(SYSTEMTIME*Time) { 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'; } voidTimeToStr(SYSTEMTIME*Time) { 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'; } voidInitial_DS1302(void) { unsignedcharSecond=Read1302(DS1302_SECOND); if(Second&0x80) DS1302_SetTime(DS1302_SECOND,0); } #endif #ifndefLCD_CHAR_1602 #defineLCD_CHAR_1602 #include //PortDefinitions sbitLcdRs=P2^0; sbitLcdRw=P2^1; sbitLcdEn=P2^2; sfrDBPort=0x80;//P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口 //内部等待函数 unsignedcharLCD_Wait(void) { LcdRs=0; LcdRw=1;_nop_(); LcdEn=1;_nop_(); //while(DBPort&0x80);//在用Proteus仿真时,注意用屏蔽此语句,在调用GotoXY()时,会进入死循环, //可能在写该控制字时,该模块没有返回写入完备命令,即DBPort&0x80==0x80 //实际硬件时打开此语句 LcdEn=0; returnDBPort; } //向LCD写入命令或数据 #defineLCD_COMMAND0//Command #defineLCD_DATA1//Data #defineLCD_CLEAR_SCREEN0x01//清屏 #defineLCD_HOMING0x02//光标返回原点 voidLCD_Write(bitstyle,unsignedcharinput) { LcdEn=0; LcdRs=style; LcdRw=0;_nop_(); DBPort=input;_nop_();//注意顺序 LcdEn=1;_nop_();//注意顺序 LcdEn=0;_nop_(); LCD_Wait(); } //设置显示模式 #defineLCD_SHOW0x04//显示开 #defineLCD_HIDE0x00//显示关 #defineLCD_CURSOR0x02//显示光标 #defineLCD_NO_CURSOR0x00//无光标 #defineLCD_FLASH0x01//光标闪动 #defineLCD_NO_FLASH0x00//光标不闪动 voidLCD_SetDisplay(unsignedcharDisplayMode) { LCD_Write(LCD_COMMAND,0x08|DisplayMode); } //设置输入模式 #defineLCD_AC_UP0x02 #defineLCD_AC_DOWN0x00//default #defineLCD_MOVE0x01//画面可平移 #defineLCD_NO_MOVE0x00//default voidLCD_SetInput(unsignedcharInputMode) { LCD_Write(LCD_COMMAND,0x04|InputMode); } //初始化LCD voidLCD_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递增,画面不动 } voidGotoXY(unsignedcharx,unsignedchary) { if(y==0) LCD_Write(LCD_COMMAND,0x80|x); if(y==1) LCD_Write(LCD_COMMAND,0x80|(x-0x40)); } voidPrint(unsignedchar*str) { while(*str! ='\0') { LCD_Write(LCD_DATA,*str); str++; } } #endif 六、仿真结果 七、实验心得 通过本次课程设计,我不仅加深了对单片机理论的理解,而且能够完成从硬件电路图设计,到软件编程及系统调试实现系统功能这一流程。 还学会了如何应用proteus进行仿真,应用keil软件进行编程,加深了对51系列单片机的理解。 在本次课程设计中遇到了一连串的问题,经过同学们的帮助,最终完成了本次课程设计,我不仅学会了如何将所学的理论知识和实际结合起来,也学会了和他人的合作,而且锻炼了我的实践能力。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 单片机 仿真 课程设计 基于 51 实时 时钟