万年历课程设计完整版.docx

上传人:b****6 文档编号:4831336 上传时间:2022-12-10 格式:DOCX 页数:36 大小:853.64KB
下载 相关 举报
万年历课程设计完整版.docx_第1页
第1页 / 共36页
万年历课程设计完整版.docx_第2页
第2页 / 共36页
万年历课程设计完整版.docx_第3页
第3页 / 共36页
万年历课程设计完整版.docx_第4页
第4页 / 共36页
万年历课程设计完整版.docx_第5页
第5页 / 共36页
点击查看更多>>
下载资源
资源描述

万年历课程设计完整版.docx

《万年历课程设计完整版.docx》由会员分享,可在线阅读,更多相关《万年历课程设计完整版.docx(36页珍藏版)》请在冰豆网上搜索。

万年历课程设计完整版.docx

万年历课程设计完整版

-CAL-FENGHAI-(2020YEAR-YICAI)_JINGBIAN

 

万年历课程设计(完整版)

 

 

基于51单片机的万年历的设计

学生姓名

学号

所在专业

电子信息工程

所在班级

电子1111

小组成员

指导教师

完成日期

 

基于51单片机的万年历的设计

1需求分析

1.1“需“的分析

万年历是一个可以显示当前时间、日历、温度信息以及设置闹钟报警的应用系统,其具有以下功能:

(1)可以显示当前的时间信息;

(2)可以显示当前的温度;

(3)可以手动修改时间;

(4)可以设置闹钟,并且达到设置的时间点发出音响信号。

1.2“求“的分析

设计万年历,需要考虑以下几方面的内容:

(1)如何获取当前的时间信息,这些时间信息包括时、分、秒、年、月、日、和星期;

(2)如何获得当前的温度信息,精确到1°C即可;

(3)提供必要的用户输入设置通道;

(4)提供相应的显示和报警部件;

(5)需要写出合适的软件应用代码。

2方案设计与论证

2.1时间获取方法的方案设计与论证

方案一:

使用单片机的内部定时器进行定时,使用软件算法来计算当前的时间信息。

此种方案虽然可以不使用时钟芯片,节约成本,但是时间的精准度一般,软件代码复杂。

方案二:

采用外部扩展实时时钟芯片DS12C887的方式来获取相应的时间信息。

DS12C887是一种高性能的芯片,能自动产生年、月、日、时、分、秒等信息,并有闰年修正功能。

采用双电源供电方式,可设置备用电源充电方式,提供了对后备电源进行涓细电流的充电的能力,在能满足精度要求的同时价格也比较便宜,性价比较高。

所以采用方案二。

2.2显示模块的方案设计与论证

方案一:

采用LED数码管动态扫描。

LED数码管价格适中,但只能显示数字和简单的字符,且其的接口线少。

方案二:

采用点阵式数码管显示。

点阵式数码管是由八行八列的发光二极管组成,并不太适合于对数字跟字母进行显示,其主要用于汉字的显示。

方案三:

采用LED液晶显示屏。

液晶显示屏的显示功能强大,可显示大量文字,图形,显示多样,清晰可见,虽然价格稍微贵了点,但其接口线多。

所以采用方案三。

2.3温度采集的方案设计与论证

方案一:

使用PT铂电阻采集。

PT铂电阻根据温度变化的只是其电阻值,在实际使用过程,需要额外的辅助器件将其转化为电压信号,并且通过调整后送到模/数字转换器件才能让51单片机进行处理。

方案二:

使用数字温度传感器采集。

温度传感器虽然、精度采样速度等性能比不上PT铂电阻,但是其没有额外的附加器件,且能满足系统对采集精度的要求。

所以采用数字温度传感器。

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

软件设计

5

 

图4-1万年历的工作流程

6总结

6.1仿真结果及分析

经过多次调试、修改程序,万年历终于在pruteus正常运行起来了。

前面由于初次写的代码有较多不完善的地方,所以调试的时候出了很多大的问题,第一次发现大的问题后,团队认真地讨论并修改了程序,后面调试遇到的都是些小问题,无非是打漏或者打错这类问题。

6.2心得

工程上的问题很多不是一个人的能力可以解决的,所以不能老是想着单干、蛮干,一定要发挥团队的力量,多讨论,讨论往往可以碰撞出思想的火花来。

做事的时候一定要静下心来,保持专注,不能老想着快,不然会弄出很多本可以避免的问题,敲代码的时候,为了求快,结果调试的遇到小问题花了可不少时间才解决。

本次课程设计,让我知道了要想解决工程上的问题,必须现将问题具体化、模块化,然后再逐个击破,这样才能更有效率地解决整个工程设计再到实物的问题。

附录一:

仿真图

附录二:

程序

#include

#include

#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_();_nop_();

DQ=0;//

delay(50);//550us

DQ=1;//

delay(6);//66us

for(i=0;i<0x30;i++)

{

if(!

DQ)

gotod1;

}

flag=0;//清标志位,表示ds1820不存在

DQ=1;

return;

d1:

delay(45);//延时500us

flag=1;

DQ=1;//置标志位,表示ds1820存在

}

/**********18B20写命令函数*********/

//向1-WIRE总线上写一个字节

voidWrite1Byte18B20(unsignedcharval)

{

unsignedchari;

for(i=8;i>0;i--)//

{

DQ=1;_nop_();_nop_();

DQ=0;_nop_();_nop_();_nop_();_nop_();_nop_();//5us

DQ=val&0x01;//最低位移出

delay(6);//66us

val=val/2;//右移一位

}

DQ=1;

delay

(1);

}

/*********18B20读1个字节函数********/

//从总线上读取一个字节

unsignedcharRead1Byte18B20(void)

{

unsignedchari;

unsignedcharvalue=0;

for(i=8;i>0;i--)

{

DQ=1;_nop_();_nop_();

value>>=1;

DQ=0;//

_nop_();_nop_();_nop_();_nop_();//4us

DQ=1;_nop_();_nop_();_nop_();_nop_();//4us

if(DQ)

value|=0x80;

delay(6);//66us

}

DQ=1;

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位

RST18B20();

Write1Byte18B20(0xCC);//SkipROM

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+'0';

time2[11]=m%100;

time2[10]=time2[11]/10+'0';

time2[11]=time2[11]%10+'0';

if(time2[9]=='0')//最高位为0时都不显示

{

time2[9]=0x20;

if(n)//负温度时最高位显示"-"

{

time2[9]='-';

}

if(time2[10]=='0')

{

if(n)

{

time2[10]='-';

time2[9]=0x20;

}

else

time2[10]=0x20;

if(time2[11]=='0'&&time2[13]=='0')

time2[11]=time2[12]=0x20;

}

}

}

delay1ms(unsignedchartime)//延时1ms

{

unsignedchari,j;

for(i=0;i

{

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;

rw=0;

e=0;

delay1ms

(2);

e=1;

}

//写LCD内部地址函数

WriteLCDRAM(unsignedchardata*address,m)

{

unsignedchari,j;

for(i=0;i

{

j=*address;

WriteLCD(j);

}

}

//LCD显示

LCDSHOW()

{

P0=0XC;//显示器开、光标关

EnableLCD();

P0=0x80;//写入显示起始地址

EnableLCD();

WriteLCDRAM(time1,16);

P0=0xc1;//写入显示起始地址

EnableLCD();

WriteLCDRAM(time2,15);

}

//自建字函数库

DesignHZ()

{

unsignedchari;

P0=0x40;

EnableLCD();

for(i=0;i<32;i++)

{

WriteLCD(tab[i]);

delay1ms

(2);

}

}

//写DS1302子程序

WriteDS1302(unsignedcharaddress)

{

unsignedchari;

clk=0;

_nop_();

rst=1;

_nop_();

for(i=0;i<8;i++)

{

dat=address&1;

_nop_();

clk=1;

address>>=1;

clk=0;

}

}

//读DS1302子程序

unsignedcharReadDS1302()

{

unsignedchari,j=0;

for(i=0;i<8;i++)

{

j>>=1;

_nop_();

clk=0;

_nop_();

if(dat)

j|=0x80;

_nop_();

clk=1;

}

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]='0';

time1[14]='W',time2[2]=time2[5]=':

';

WriteDS1302(0xc1);

alarm[0]=ReadDS1302();

rst=0;

WriteDS1302(0xc3);

alarm[1]=ReadDS1302();

rst=0;

WriteDS1302(0xc5);

time1[0]=ReadDS1302();

rst=0;

}

//读取时间

ReadTime()

{

unsignedchari,m,n;

WriteDS1302(0x8d);//读取年份

m=ReadDS1302();

rst=0;

time1[4]=m/16+0x30;

time1[5]=m%16+0x30;

WriteDS1302(0x8b);//读取星期

m=ReadDS1302();

rst=0;

time1[15]=m+0x30;

for(i=7,n=0x89;i<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;i<7;i+=3,n-=2,m++)//读取时,分,秒

{

WriteDS1302(n);

time[m]=ReadDS1302();

rst=0;

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;j<6;j++)

{

i=0;

while

(1)

{

a=table2[i];

if(a==0)

break;

b=a&0xf;

a>>=4;

if(a==0)

{

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]&0xf);

if(j==2)

i+=3;

elseif(j==3)

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 商业计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1