万年历课程设计报告完整版Word下载.docx
《万年历课程设计报告完整版Word下载.docx》由会员分享,可在线阅读,更多相关《万年历课程设计报告完整版Word下载.docx(33页珍藏版)》请在冰豆网上搜索。
3硬件设计
3.1万年历的硬件模块
图3-1万年历的硬件模块
3.2万年历的电路
图3-2万年历的电路
3.3硬件根底
DS1302的硬件根底:
(1)时钟芯片DS1302的工作原理:
DS1302在每次进展读、写程序前都必须初始化,先把SCLK端置“0〞,接着把RST端置“1〞,最后才给予SCLK脉冲。
图5为DS1302的控制字的位7必须置1,假设为0那么不能把对DS1302进展读写数据。
对于位6,假设对程序进展读/写时RAM=1,对时间进展读/写时,CK=0。
位1至位5指操作单元的地址。
位0是读/写操作位,进展读操作时,该位为1;
该位为0那么表示进展的是写操作。
控制字节总是从最低位开场输入/输出的。
DS1302的日历、时间存放器容:
“CH〞是时钟暂停标志位,当该位为1时,时钟振荡器停顿,DS1302处于低功耗状态;
当该位为0时,时钟开场运行。
“WP〞是写保护位,在任何的对时钟和RAM的写操作之前,WP必须为0。
当“WP〞为1时,写保护位防止对任一存放器的写操作。
(2)DS1302的控制字节
DS1302的控制字如表-1所示。
控制字节的高有效位〔位7〕必须是逻辑1,如果它为0,那么不能把数据写入DS1302中,位6如果0,那么表示存取日历时钟数据,为1表示存取RAM数据;
位5至位1指示操作单元的地址;
最低有效位〔位0〕如为0表示要进展写操作,为1表示进展读操作,控制字节总是从最低位开场输出。
表3-1DS1302的控制字格式
1
RAM
/CK
A4
A3
A2
A1
A0
RD
/WR
(3)数据输入输出〔I/O〕
在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位即位0开场。
同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7。
如下列图3-3所示:
图3-3DS1302读/写时序图
(4)DS1302的存放器
DS1302有12个存放器,其中有7个存放器与日历、时钟相关,存放的数据位为BCD码形式,其日历、时间存放器及其控制字见表3-2。
表3-2DS1302的日历、时间存放器
此外,DS1302还有年份存放器、控制存放器、充电存放器、时钟突发存放器及与RAM相关的存放器等。
时钟突发存放器可一次性顺序读写除充电存放器外的所有存放器容。
DS1302与RAM相关的存放器分为两类:
一类是单个RAM单元,共31个,每个单元组态为一个8位的字节,其命令控制字为C0H~FDH,其中奇数为读操作,偶数为写操作;
另一类为突发方式下的RAM存放器,此方式下可一次性读写所有的RAM的31个字节,命令控制字为FEH(写)、FFH(读)。
1602液晶的硬件根底:
1602通常有14条引脚线或16条引脚线的LCD,多出来的2条线是背光电源线VCC(15脚)和地线GND(16脚),其控制原理与14脚的LCD完全一样,引脚定义如表3-3所示:
表3-31602的引脚及其对应的功能
1602支持的一系列指令:
〔1〕清屏指令:
表3-4清屏指令
(2)归零指令:
表3-5归零指令
〔3〕输入方式选择指令:
表3-6输入方式选择指令
〔4〕显示开关控制指令:
表3-7显示开关控制指令
(5)光标和画面移动指令:
表3-8光标和画面移动指令
〔6〕功能设定指令:
表3-9功能设定指令
(7)CGRAM设置指令:
表3-10CGRAM设置指令
(8)DDRAM设置指令:
表3-11DDRAM设置指令
〔9〕读BF和AC指令:
表3-12读BF和AC指令
〔10〕写数据指令:
表3-13写数据指令
〔11〕读数据指令:
表3-14读数据指令
4
软件设计
是
否
图4-1万年历的工作流程
5总结
5.1仿真结果及分析
经过屡次调试、修改程序,万年历终于在pruteus正常运行起来了。
前面由于初次写的代码有较多不完善的地方,所以调试的时候出了很多大的问题,第一次发现大的问题后,团队认真地讨论并修改了程序,后面调试遇到的都是些小问题,无非是打漏或者打错这类问题。
5.2心得
工程上的问题很多不是一个人的能力可以解决的,所以不能老是想着单干、蛮干,一定要发挥团队的力量,多讨论,讨论往往可以碰撞出思想的火花来。
做事的时候一定要静下心来,保持专注,不能老想着快,不然会弄出很多本可以防止的问题,敲代码的时候,为了求快,结果调试的遇到小问题花了可不少时间才解决。
本次课程设计,让我知道了要想解决工程上的问题,必须现将问题具体化、模块化,然后再逐个击破,这样才能更有效率地解决整个工程设计再到实物的问题。
附录一:
仿真图
附录二:
程序
#include<
AT89X52.H>
INTRINS.H>
#defineTIME(0X10000-50000)
#defineFLAG0XEF//闹钟标志
//引脚连接图
sbitrst=P3^5;
sbitclk=P3^4;
sbitdat=P3^3;
sbitrs=P1^5;
sbitrw=P1^6;
sbite=P1^7;
sbitDQ=P1^4;
//温度输入口
sbitACC_7=ACC^7;
//全局变量及常量定义
unsignedchari=20,j,time1[16];
unsignedcharalarm[2],time2[15],time[3];
unsignedcharcodeDay[]={31,28,31,30,31,30,31,31,30,31,30,31};
//12个月的最大日期(非闰年)
//音律表
unsignedintcodetable1[]={64260,64400,64524,64580,64684,64777,
64820,64898,64968,65030,65058,65110,65157,65178,65217};
//发声局部的延时时间
unsignedcharcodetable2[]={0x82,1,0x81,0xf4,0xd4,0xb4,0xa4,
0x94,0xe2,1,0xe1,0xd4,0xb4,0xc4,0xb4,4,0};
//LCD自建字
unsignedcharcodetab[]={0x18,0x1b,5,4,4,5,3,0,
0x08,0x0f,0x12,0x0f,0x0a,0x1f,0x02,0x02,//年
0x0f,0x09,0x0f,0x09,0x0f,0x09,0x11,0x00,//月
0x0f,0x09,0x09,0x0f,0x09,0x09,0x0f,0x00};
//日
//*******温度小数局部用查表法**********//
unsignedcharcodeditab[16]={0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};
//闹钟中用的全局变量
unsignedcharth1,tl1;
unsignedchartemp_data[2]={0x00,0x00};
//读出温度暂放
bitflag;
//18b20存在标志位
/***********11微秒延时函数**********/
delay(unsignedintt)
{
for(;
t>
0;
t--);
}
/***********18B20复位函数**********/
RST18B20(void)
unsignedchari;
DQ=1;
_nop_();
DQ=0;
//
delay(50);
//550us
//
delay(6);
//66us
for(i=0;
i<
0x30;
i++)
{
if(!
DQ)
gotod1;
}
flag=0;
//清标志位,表示ds1820不存在
return;
d1:
delay(45);
//延时500us
flag=1;
//置标志位,表示ds1820存在
}
/**********18B20写命令函数*********/
//向1-WIRE总线上写一个字节
voidWrite1Byte18B20(unsignedcharval)
for(i=8;
i>
i--)//
DQ=1;
DQ=0;
//5us
DQ=val&
0x01;
//最低位移出
delay(6);
//66us
val=val/2;
//右移一位
delay
(1);
/*********18B20读1个字节函数********/
//从总线上读取一个字节
unsignedcharRead1Byte18B20(void)
unsignedcharvalue=0;
i>
i--)
value>
>
=1;
_nop_();
//4us
//4us
if(DQ)
value|=0x80;
return(value);
/***********读出温度函数**********/
Read18B20()
RST18B20();
//总线复位
if(!
flag)//判断ds1820是否存在?
假设ds18b20不存在那么返回
return;
//Write1Byte18B20(0xCC);
//SkipROM
//Write1Byte18B20(0x44);
//发转换命令
//delay(70);
Write1Byte18B20(0xCC);
//发SkipROM命令
Write1Byte18B20(0xBE);
//发读命令
temp_data[0]=Read1Byte18B20();
//温度低8位
temp_data[1]=Read1Byte18B20();
//温度高8位
Write1Byte18B20(0x44);
/***********温度数据处理函数**********/
DealTempData()
unsignedcharn=0,m;
if(temp_data[1]>
127)//负温度求补码
temp_data[1]=(256-temp_data[1]);
temp_data[0]=(256-temp_data[0]);
n=1;
time2[13]=ditab[temp_data[0]&
0x0f]+'
0'
;
time2[12]='
.'
m=((temp_data[0]&
0xf0)>
4)|((temp_data[1]&
0x0f)<
<
4);
//
if(n)
m-=16;
time2[9]=m/100+'
time2[11]=m%100;
time2[10]=time2[11]/10+'
time2[11]=time2[11]%10+'
if(time2[9]=='
)//最高位为0时都不显示
time2[9]=0x20;
if(n)//负温度时最高位显示"
-"
{
time2[9]='
-'
}
if(time2[10]=='
)
if(n)
{
time2[10]='
time2[9]=0x20;
}
else
time2[10]=0x20;
if(time2[11]=='
&
time2[13]=='
time2[11]=time2[12]=0x20;
}
delay1ms(unsignedchartime)//延时1ms
unsignedchari,j;
time;
for(j=0;
j<
250;
j++);
//使能1602
EnableLCD()
rs=0;
rw=0;
e=0;
delay1ms(3);
e=1;
//写LCD函数
WriteLCD(unsignedchari)
P0=i;
rs=1;
delay1ms
(2);
//写LCD部地址函数
WriteLCDRAM(unsignedchardata*address,m)
m;
i++,address++)
j=*address;
WriteLCD(j);
//LCD显示
LCDSHOW()
P0=0XC;
//显示器开、光标关
EnableLCD();
P0=0x80;
//写入显示起始地址
WriteLCDRAM(time1,16);
P0=0xc1;
WriteLCDRAM(time2,15);
//自建字函数库
DesignHZ()
P0=0x40;
32;
WriteLCD(tab[i]);
delay1ms
(2);
//写DS1302子程序
WriteDS1302(unsignedcharaddress)
clk=0;
_nop_();
rst=1;
8;
dat=address&
1;
clk=1;
address>
clk=0;
//读DS1302子程序
unsignedcharReadDS1302()
unsignedchari,j=0;
j>
if(dat)
j|=0x80;
return(j);
//局部显示数据初始化
TimeInit()
time1[1]=time1[13]=time2[8]=time2[9]=time2[10]=0x20,time2[14]=0;
time1[6]=1,time1[9]=2,time1[12]=3,time1[2]='
2'
time1[3]='
time1[14]='
W'
time2[2]=time2[5]='
:
'
WriteDS1302(0xc1);
alarm[0]=ReadDS1302();
rst=0;
WriteDS1302(0xc3);
alarm[1]=ReadDS1302();
WriteDS1302(0xc5);
time1[0]=ReadDS1302();
//读取时间
ReadTime()
unsignedchari,m,n;
WriteDS1302(0x8d);
//读取年份
m=ReadDS1302();
time1[4]=m/16+0x30;
time1[5]=m%16+0x30;
WriteDS1302(0x8b);
//读取星期
time1[15]=m+0x30;
for(i=7,n=0x89;
11;
i+=3,n-=2)//读取月份和日期
WriteDS1302(n);
m=ReadDS1302();
rst=0;
time1[i]=m/16+0x30;
time1[i+1]=m%16+0x30;
for(m=0,i=0,n=0x85;
7;
i+=3,n-=2,m++)//读取时,分,秒
time[m]=ReadDS1302();
time2[i]=time[m]/16+0x30;
time2[i+1]=time[m]%16+0x30;
time0()interrupt1using1
i--;
if(i==0)
if(j!
=0)
j--;
i=20;
TH0=TIME/256,TL0=TIME%256;
//闹钟局部
intime1()interrupt3
TH1=th1,TL1=tl1;
P3_2=!
P3_2;
//显示闹钟设置数据
showalarm()
unsignedchari,j,a,b,n;
ET1=1;
for(j=0;
6;
j++)
i=0;
while
(1)
a=table2[i];
if(a==0)
break;
b=a&
0xf;
a>
=4;
TR1=0;
gotoD1;
a=((--a)<
1)/2;
TH1=th1=table1[a]/256,TL1=tl1=table1[a]%256;
TR1=1;
D1:
do
b--;
for(n=0;
n<
3;
n++)
{
ReadTime();
LCDSHOW();
P2=0xf7;
if(P2==0xe7)
{
delay1ms(100);
if(P2==0xe7)
{
TR1=0;
ET1=0;
return;
}
}
}
}while(b!
=0);
i++;
TR1=0;
ET1=0;
//根据日期的变动自动调整星期
unsignedcharsetweek()
unsignedchari=5,j,n;
j=(time1[4]&
0xf)*10+(time1[5]&
0xf);
n=j/4;
i=i+5*n;
n=j%4;
if(n==1)
i+=2;
elseif(n==2)
i+=3;
elseif(n==3)
i+=4;
j=(time1[7]&
0xf)*10+(time1[8]&
if(j==2)
elseif(j==3)
elseif(j==4)
i+=6;
elseif(j==5)
i+=1;
elseif(j==6)
elseif(j==7)
elseif(j==8)
elseif(