单片机课程设计万年历.docx
- 文档编号:8441708
- 上传时间:2023-01-31
- 格式:DOCX
- 页数:29
- 大小:301.69KB
单片机课程设计万年历.docx
《单片机课程设计万年历.docx》由会员分享,可在线阅读,更多相关《单片机课程设计万年历.docx(29页珍藏版)》请在冰豆网上搜索。
单片机课程设计万年历
单片机课程设计
题目名称:
姓名:
学号:
系别:
班级:
指导老师:
完成时间:
华南理工大学广州学院课程设计任务书
一、实现功能
利用51单片机芯片和DS1302芯片设计电子万年历
功能图如下
通过四个按键输入调整,在LCD液晶模块上能显示阳历年、月、日、星期、时、分、秒和阴历月、日,在显示农历时间时,能标明是否为闰年。
当切断主5V电源时,由3.3V备用电池供电,1302内时钟仍然工作。
当重新接上5V电源后,则可以实时显示当前时间。
二、开发环境
操作系统:
windowsXP
开发芯片:
89C52RC+
编译器:
keil51
三、硬件实现
1、整体仿真图如下
2、12864LCD
12864采用8位并行数据传送方式,占用单片机的P0口。
由于P0口用作普通I/O口时为开漏输出,所以为了输出高电平,增大负载能力,需在每个P0位接一个上拉电阻,本设计中采用10K的排阻接线。
图中的RV1为LCD背光调节电位器,可调节屏幕的亮度。
3、DS1302
1脚接+5V电源;8脚接3.3V备份电源;2、3脚接晶振;4脚接地;5脚接P2.6;
6脚接P2.4;7脚接P2.5;
+5V工作时,DS1302的7脚时钟信号由单片机的P2.5口提供,当以3.3V工作时时钟由其2、3脚外接的晶振提供时钟,晶振的震荡频率为32.768KHz。
4、按键
选择按键一端接P2.0,另一端接地;
加按键一端接P2.1,另一端接地;
减按键一端接P3.1,另一端接地;
确定按键一端接P3.2,另一端接地;
四、软件实现
程序流程图如下
1、农历为复杂的历法,因此适宜采用查表法进行编程;
2、编程中接按键的四个管脚皆为查询方式,单片机上电默认为高电平,当按键按下去的时候变为低电平,输入有效,并执行相应的事件处理程序;
3、12864采用8位并行数据传送方式,占用单片机的P0口;
4、DS1302位一线串行方式,所以在编程中对时序的要求非常严格,应认真注意时序的先后;
主要程序源代码
ucharRead1302(ucharADDRorCOMM)
{
uchardat;
DS1302_RST=0;//禁止数据传输
DS1302_SCLK=0;//确保写写之前SCLK被拉低
DS1302_RST=1;//启动数据传输
DS1302InputByte(ADDRorCOMM);//写入命令或地址
dat=DS1302OutputByte();//读出数据
DS1302_SCLK=1;//将时钟电平置于高电平状态置高是为了让下次写的时候能准确的被拉低保证电平状态的正确性//
DS1302_RST=0;//禁止数据传输
return(dat);
}
voidInit_1302(void)//(2008年7月12日12时00分00秒星期六)
{
ucharflag;
flag=Read1302(0x81);//读秒寄存器
if(flag&0x80)//CH为0(flag最高位是0),时钟走动,不用初始化。
{
Write1302(0x8e,0x00);//允许写操作
Write1302(0x8c,((8/10)<<4|(8%10)));//YEAR
Write1302(0x8a,0x01);//DAY
Write1302(0x88,((3/10)<<4|(3%10)));//MONTH
Write1302(0x86,((14/10)<<4|(14%10)));//DATE
Write1302(0x84,((12/10)<<4|(12%10)));//HR
Write1302(0x82,((0/10)<<4|(0%10)));//MIN
Write1302(0x80,((0/10)<<4|(0%10)));//SEC
Write1302(0x90,0xa5);//打开充电功能
Write1302(0x8e,0x80);//禁止写操作
}
}
typedefstruct_SYSTEMTIME_
{
ucharSecond;
ucharMinute;
ucharHour;
ucharWeek;
ucharDay;
ucharMonth;
ucharYear;
ucharDateString[11];
ucharTimeString[9];
}SYSTEMTIME;
SYSTEMTIMECurrentTime;
voidDS1302_GetTime(SYSTEMTIME*Time)
{
ucharReadValue;
ReadValue=Read1302(0x81);//从秒寄存器里读数据
Time->Second=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);//把读出的数据转换成BCD码
ReadValue=Read1302(0x83);//从分寄存器里读数据
Time->Minute=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);//把读出的数据转换成BCD码
ReadValue=Read1302(0x85);//从小时寄存器里读数据
Time->Hour=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);//把读出的数据转换成BCD码
ReadValue=Read1302(0x8b);//从星期寄存器里读数据
Time->Week=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);//把读出的数据转换成BCD码
ReadValue=Read1302(0x87);//从日寄存器里读数据
Time->Day=riqi=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);//把读出的数据转换成BCD码
ReadValue=Read1302(0x89);//从月寄存器里读数据
Time->Month=yuefen=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);//把读出的数据转换成BCD码
ReadValue=Read1302(0x8d);//从年寄存器里读数据
Time->Year=nianfen=((ReadValue&0xf0)>>4)*10+(ReadValue&0x0f);//把读出的数据转换成BCD码//注意是0xF0
}
voidDate2Str(SYSTEMTIME*Time)
{
uchartab[]={0xd2,0xbb,0xbb6,0xfe,0xc8,0xfd,0xcb,0xc4,0xce,0xe5,0xc1,0xf9,0xc8,0xd5};//?
?
?
?
?
//uchartab[]={"一二三四五六日"};
if(hide_year<2)////这里的if,else语句都是判断位闪烁,<2显示数据,>2就不显示,
{
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]=tab[2*(Time->Week%10)-2];//星期的数据另外放到week_value[]数组里,跟年,月,日的分开存放,因为等一下要在最后显示//
week_value[1]=tab[2*(Time->Week%10)-1];
}
else
{
week_value[0]='';
week_value[1]='';
}
week_value[2]='\0';
Time->DateString[10]='\0';//字符串末尾加'\0',判断结束字符
}
voidTime2Str(SYSTEMTIME*Time)
{
if(hide_hour<2)
{
Time->TimeString[0]=Time->Hour/10+'0';
Time->TimeString[1]=Time->Hour%10+'0';
linshi0=Time->Hour/10+'0';
linshi1=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';
linshi3=Time->Minute/10+'0';
linshi4=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->TimeString[8]='\0';
}
voidSetkey(void)
{
Set=1;//为按键输入做好准备//
if(Set==0)//Set按下//
{
delaynms(15);
if(Set==0)//确认按下//
{
count++;
while(Set==0);
}
}
}
voidUpkey(void)
{
Up=1;
if(Up==0)
delaynms(15);
if(Up==0)
{Up=1;
switch(count)
{
case1:
temp=Read1302(0x81);//读取秒数
temp=((temp&0x70)>>4)*10+(temp&0x0f);//转化成BCD码
temp++;//秒加1
up_flag=1;//数据调整后更新标志
if(temp>59)//超过59秒,清0
temp=0;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
case2:
temp=Read1302(0x83);//读取分
temp=((temp&0x70)>>4)*10+(temp&0x0f);
temp++;//分加1
up_flag=1;
if(temp>59)//超过59分,清0
temp=0;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
case3:
temp=Read1302(0x85);//读取小时
temp=((temp&0x70)>>4)*10+(temp&0x0f);//转化成BCD码
temp++;//时加1
up_flag=1;//数据调整后更新标志
if(temp>23)//超过23时,清0
temp=0;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
case4:
temp=Read1302(0x8b);//读取星期
temp=((temp&0x70)>>4)*10+(temp&0x0f);//转化成BCD码
temp++;//星期加1
up_flag=1;//数据调整后更新标志
if(temp>7)//超过7,
temp=1;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
case5:
temp=Read1302(0x87);//读取日
temp=((temp&0x70)>>4)*10+(temp&0x0f);//转化成BCD码
temp++;//日加1
up_flag=1;//数据调整后更新标志
if(temp>31)//超过31,
temp=1;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
case6:
temp=Read1302(0x89);//读取月
temp=((temp&0x70)>>4)*10+(temp&0x0f);//转化成BCD码
temp++;//月加1
up_flag=1;//数据调整后更新标志
if(temp>12)//超过12,
temp=1;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
case7:
temp=Read1302(0x8d);//读取年
temp=((temp&0xf0)>>4)*10+(temp&0x0f);//转化成BCD码
temp++;//年加1
up_flag=1;//数据调整后更新标志
if(temp>99)//超过99,清0
temp=0;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
default:
break;
}
}
}
voidDownkey(void)
{
Down=1;
if(Down==0)
delaynms(15);
if(Down==0)//确认Upkey按下
{Down=1;
switch(count)
{
case1:
temp=Read1302(0x81);//读取秒数
temp=((temp&0x70)>>4)*10+(temp&0x0f);//转化成BCD码
temp--;//秒减1
down_flag=1;//数据调整后更新标志
if(temp<0)//小于0秒,置59
temp=59;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
case2:
temp=Read1302(0x83);//读取分
temp=((temp&0x70)>>4)*10+(temp&0x0f);
temp--;//分减1
down_flag=1;
if(temp<0)//小于0分,置59
temp=59;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
case3:
temp=Read1302(0x85);//读取小时
temp=((temp&0x70)>>4)*10+(temp&0x0f);//转化成BCD码
temp--;//时减1
down_flag=1;//数据调整后更新标志
if(temp<0)//小于0时,置23
temp=23;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
case4:
temp=Read1302(0x8b);//读取星期
temp=((temp&0x70)>>4)*10+(temp&0x0f);//转化成BCD码
temp--;//星期减1
down_flag=1;//数据调整后更新标志
if(temp<1)//小于1,置7
temp=7;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
case5:
temp=Read1302(0x87);//读取日
temp=((temp&0x70)>>4)*10+(temp&0x0f);//转化成BCD码
temp--;//日减1
down_flag=1;//数据调整后更新标志
if(temp<1)//小于1,置31
temp=31;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
case6:
temp=Read1302(0x89);//读取月
temp=((temp&0x70)>>4)*10+(temp&0x0f);//转化成BCD码
temp--;//月减1
down_flag=1;//数据调整后更新标志
if(temp<1)//小于1,置12
temp=12;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
case7:
temp=Read1302(0x8d);//读取年
temp=((temp&0xf0)>>4)*10+(temp&0x0f);//转化成BCD码
temp--;//年加1
down_flag=1;//数据调整后更新标志
if(temp<0)//小于0,置99
temp=99;
temp=temp/10*16+temp%10;//把新的BCD码转化回去
break;
default:
break;
}
}
}
voidkeydone(void)
{
Setkey();//扫描模式切换按键
switch(count)
{
case1:
do{//count=1,调整秒
Upkey();//扫描加按键,如果按下,up_flag置1
Downkey();//扫描减按键,如果按下,down_flag置1
if(up_flag==1||down_flag==1)//数据更新,重新写入新的数据
{
Write1302(0x8e,0x00);//写入允许
Write1302(0x80,temp);//写入新的秒数
Write1302(0x8e,0x80);//禁止写入,写保护
up_flag=0;//标志位清0
down_flag=0;
}
if(Down!
=0&&Up!
=0)//如果加键和减键都没按
{
hide_sec++;
if(hide_sec>3)
hide_sec=0;
}
else
hide_sec=0;
show_all();//液晶显示数据
}while(count==2);
break;
case2:
do{//count=2,调整分
hide_sec=0;//
Upkey();//扫描加按键,如果按下,up_flag置1
Downkey();//扫描减按键,如果按下,down_flag置1
if(up_flag==1||down_flag==1)//数据更新,重新写入新的数据
{
Write1302(0x8e,0x00);//写入允许
Write1302(0x82,temp);//写入新的分
Write1302(0x8e,0x80);//禁止写入,写保护
up_flag=0;//标志位清0
down_flag=0;
}
if(Down!
=0&&Up!
=0)//如果加键和减键都没按
{
hide_min++;
if(hide_min>3)/
hide_min=0;
}
else
hide_min=0;
show_all();//液晶显示数据
}while(count==3);
break;
case3:
do{//count=3,调整小时
hide_min=0;
Upkey();//扫描加按键,如果按下,up_flag置1
Downkey();//扫描减按键,如果按下,down_flag置1
if(up_flag==1||down_flag==1)//数据更新,重新写入新的数据
{
Write1302(0x8e,0x00);//写入允许
Write1302(0x84,temp);//写入新的小时
Write1302(0x8e,0x80);//禁止写入,写保护
up_flag=0;//标志位清0
down_flag=0;
}
if(Down!
=0&&Up!
=0)//如果加键和减键都没按
{
hide_hour++;
if(hide_hour>3)
hide_hour=0;
}
else
hide_hour=0;
show_all();//液晶显示数据
}while(count==4);
break;
case4:
do{//count=4,调整星期
hide_hour=0;
Upkey();//扫描加按键,如果按下,up_flag置1
Downkey();//扫描减按键,如果按下,down_flag置1
if(up_flag==1||down_flag==1)//数据更新,重新写入新的数据
{
Write1302(0x8e,0x00);//写入允许
Write1302(0x8a,temp);//写入新的星期
Write1302(0x8e,0x80);//禁止写入,写保护
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 单片机 课程设计 万年历