单片机考试论文.docx
《单片机考试论文.docx》由会员分享,可在线阅读,更多相关《单片机考试论文.docx(17页珍藏版)》请在冰豆网上搜索。
单片机考试论文
《单片机原理实验》
考
试
报
告
题目:
基于DS1302数字钟
姓名:
学号:
班级:
专业:
电子信息工程
指导老师:
提交时间:
基于DS1302数字钟
摘要:
本设计选取串行接口时钟芯片DS1302与单片机同步通信构成数字时钟电路。
其简单的三线接口能为单片机节省大量资源,DS1302的后背电源及对后背电源进行涓细电流充电的能力保证电路断电后仍能保存时间和数据信息等。
这些优点解决了目前常用的实时时钟所无法解决的问题。
该时钟电路强大的功能和优越的性能,在很多领域的应用中,尤其是某些自动化控制、长时间无人看守的测控系统等对时钟精确性和可靠性有较高要求的场合,具有很高的使用价值。
关键词:
AT89C52LCD1602DS1302数字钟
1.引言
从古代的滴漏更鼓到近代的机械钟,从电子表到目前的数字时钟,为了准确的测量和记录时间,人们一直在努力改进着计时工具。
钟表的数字化,大力推动了计时的精确性和可靠性。
在单片机构成的装置中,实时时钟是必不可少的部件。
目前常用的实时时钟,很多采用单片机的中断服务来实现,这种方式一方面需要采用计数器,占用硬件资源,另一方面需要设置中断、查询等,同样耗费单片机的资源,而且某些测控系统可能不允许;有的则使用并行接口的时钟芯片,如MC146818、DS12887等,它们虽然能满足单片机系统对实时时钟的要求,但是这些芯片与单片机接口复杂,占用地址、数据总线多,芯片体积大,占用空间多,给其它设计带来诸多不便。
本设计选取串行接口时钟芯片DS1302与单片机同步通信构成数字时钟电路。
其简单的三线接口能为单片机节省大量资源,DS1302的后背电源及对后背电源进行涓细电流充电的能力保证电路断电后仍能保存时间和数据信息等。
这些优点解决了目前常用的实时时钟所无法解决的问题。
该时钟电路强大的功能和优越的性能,在很多领域的应用中,尤其是某些自动化控制、长时间无人看守的测控系统等对时钟精确性和可靠性有较高要求的场合,具有很高的使用价值。
2.原理
2.1DS1302
DS1302的引脚功能如图所示:
DS1302控制字:
控制字节最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入到DS1302中。
位6如果为0,则表示存取日历时钏娄据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写操作,为1表示进行读操作,控制字节总是从最低位开始输出。
DS1302的复位引脚:
通过把RST输入驱动置高电平来启动所有的数据传送。
RST输入有两种功能:
首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供了终止单字节或多字节数据的传送手段。
当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。
如果在传送过程中置RST为低电平,则会终止此次数据传送,并且I/O引脚变为高阴态。
上电运行时,在Vcc≥2.5V之前,RST必须保持低电平。
只有在SCLK为低电平时,才能将RST置为高电平。
DS1302的数据输入与输出:
在控制指令字输入后的下一个SCLK时钟的上升沿时数据被写入DS1302,数据输入从低位即位0开始。
同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0至高位7,数据读写时序如下图:
DS1302寄存器:
DS1302共有12个寄存器,其中有7个寄存器与日历、时钟相关,存放的数据为BCD码形式。
此外,DS1302还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器及与RAM相关的寄存器等。
2.2LCD1602
接口信号说明:
基本操作时序:
读状态:
输入:
RS=L,RW=H,E=H输出:
D0~D7=状态字
写指令:
输入:
RS=L,RW=L,D0~D7=指令码,E=高脉冲输出:
无
读数据:
输入:
RS=H,RW=H,E=H输出:
D0~D7=数据
写数据:
输入:
RS=H,RW=L,D0~D7=数据,E=高脉冲输出:
无
读操作时序:
写操作时序:
2.3AT89C52
功能特性概述:
AT89C52提供以下标准功能:
8k字节Flash闪速存储器,256字节内部RAM,32个I/O口线,3个16位定时/计数器,一个6向量两级中断结构,一个全双工串行通信口,片内振荡器及时钟电路。
同时,AT89C52可降至0Hz的静态逻辑操作,并支持两种软件可选的节电工作模式。
空闲方式停止CPU的工作,但通话RAM,定时/计数器,串行通信口及中断系统继续工作。
掉电方式保存RAM中的内容,但振荡器停止工作并禁止其它所有部件工作直到下一个硬件复位。
引脚功能说明:
Vcc:
电源电压GND:
地
P0口:
P0口是一组8位漏极开中型双向I/O口,也即地址/数据总线复用口。
作为输出口用时,每位能吸收电流的方式驱动8个TTL逻辑门电路,对端口P0写“1”时,可作为高阻抗输入端用。
P1口、P2口、P3口:
是一组带内部上拉电阻的8位双向I/O口,其输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。
对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。
作输入口使用时,因为内部存在上拉电阻某个引脚被外部信号拉低时会输出一个电流。
2.4设计方案
以AT89C52为主控芯片,串行时钟芯片DS1302为核心计时芯片,LCD1602为主要显示器件,组成数字时钟电路。
将AT89C52的P0口分别与LCD1602的D0~D7相连,P2.0接DS1302的SCKL引脚,P2.1接DS1302的RST引脚,P2.2接DS1302的I/O引脚,P2.4接LCD1602的使能端E,P2.5接LCD1602的RS引脚,P2.6接LCD1602的RW引脚。
此方案中,由于仿真看不出效果,未在DS1302的备用电源VCC2端接入备用电源。
3.电路
4.程序
#include
sbitmode=P1^0;//功能键
sbitadd=P1^1;//加键
sbitsub=P1^2;//减键
sbitSCLK=P2^0;
sbitDAT=P2^2;
sbitRST=P2^1;
sbitlcden=P2^4;
sbitrs=P2^5;
sbitrw=P2^6;
#defineds1302_second_write0x80
#defineds1302_second_read0x81
#defineds1302_minute_write0x82
#defineds1302_minute_read0x83
#defineds1302_hour_write0x84
#defineds1302_hour_read0x85
#defineds1302_date_write0x86
#defineds1302_date_read0x87
#defineds1302_month_write0x88
#defineds1302_month_read0x89
#defineds1302_week_write0x8a
#defineds1302_week_read0x8b
#defineds1302_year_write0x8c
#defineds1302_year_read0x8d
#definelcd1602_year3
#definelcd1602_month6
#definelcd1602_date9
#definelcd1602_week12
#definelcd1602_hour0x40+4
#definelcd1602_minute0x40+7
#definelcd1602_second0x40+10
unsignedintnian;
unsignedchartt,nummode,flag=0;
charhour,minute,second,year,month,date,week;
unsignedcharcodetable1[]="20--";
unsignedcharcodetable2[]=":
:
";
unsignedcharcodetable_week[][3]={"MON","TUE","WED","THU","FRI","SAT","SUN"};
unsignedchardays[]={31,29,31,30,31,30,31,31,30,31,30,31};//每月天数
voidds1302_init();//函数声明
voiddelayus(unsignedchartemp);
voiddelayms(unsignedchartemp);
voidds1302_write_byte(unsignedchardat);
unsignedchards1302_read_byte();
voidds1302_write(unsignedcharaddress,unsignedchardat);
unsignedchards1302_read(unsignedcharaddress);
unsignedchards1302_read_data(unsignedcharaddress);
voidlcd1602_write_data(unsignedchardate);
voidlcd1602_write_com(unsignedcharcom);
voidlcd1602_init();
voidlcd1602_write(unsignedcharaddress,chardate);
voidlcd1602_display();
voidinit();
voidkeyscan();
voidrunnian();
voidmain()//主函数
{
init();
while
(1)
{
runnian();
keyscan();
}
}
voidinit()//整体初始化
{
TMOD=0x01;
TL0=(65536-20000)%256;
TH0=(65536-20000)/256;
EA=1;
ET0=1;
TR0=1;
ds1302_init();
lcd1602_init();
}
voidds1302_init()//初始化DS1302
{
ds1302_write(0x8e,0x00);//关闭写保护
ds1302_write(ds1302_second_write,0x00);//初始化时间
ds1302_write(ds1302_minute_write,0x23);
ds1302_write(ds1302_hour_write,0x21);
ds1302_write(ds1302_date_write,0x04);
ds1302_write(ds1302_month_write,0x06);
ds1302_write(ds1302_week_write,0x01);
ds1302_write(ds1302_year_write,0x12);
}
voidlcd1602_init()//初始化lcd1602
{
unsignedcharn=0;
lcden=0;
lcd1602_write_com(0x38);
lcd1602_write_com(0x0c);
lcd1602_write_com(0x06);
lcd1602_write_com(0x01);//清屏
lcd1602_write_com(0x80);
delayms(10);
for(n=0;n<10;n++)//初始化显示格式
{
lcd1602_write_data(table1[n]);
delayus(5);
}
lcd1602_write_com(0xc0);
for(n=0;n<10;n++)
{
lcd1602_write_data(table2[n]);
delayus(5);
}
}
voiddelayus(unsignedchartemp)//延时微秒
{
for(;temp>0;temp--);
}
voiddelayms(unsignedchartemp)//延时毫秒
{
unsignedchari,j;
for(i=0;ifor(j=0;j<120;j++);
}
voidds1302_write_byte(unsignedchardat)//向ds1302写一个字节
{
unsignedcharn;
delayus
(2);
for(n=0;n<8;n++)
{
SCLK=0;
DAT=dat&0x01;//从低位开始写入
delayus
(2);
SCLK=1;//产生上升延
delayus
(2);
dat>>=1;
}
}
unsignedchards1302_read_byte()//从ds1302读一个字节
{
unsignedcharn,dat=0;
SCLK=1;
delayus
(2);
for(n=0;n<8;n++)
{
dat>>=1;//从低位开始
SCLK=0;//产生下降沿
delayus
(2);
if(DAT==1)dat|=0x80;
SCLK=1;
delayus
(2);
}
returndat;
}
voidds1302_write(unsignedcharaddress,unsignedchardat)
{//向ds1302指定地址寄存器写入数据
RST=0;
SCLK=0;
RST=1;
ds1302_write_byte(address);
ds1302_write_byte(dat);
RST=0;
}
unsignedchards1302_read(unsignedcharaddress)
{//从ds1302指定地址寄存器读出数据
unsignedchardat;
RST=0;
SCLK=0;
RST=1;
ds1302_write_byte(address);
dat=ds1302_read_byte();
RST=0;
returndat;
}
unsignedchards1302_read_data(unsignedcharaddress)
{//将二进制BCD码转成十进制
unsignedchardat,x;
dat=ds1302_read(address);
x=((dat&0xf0)>>4)*10+(dat&0x0f);
returnx;
}
voidlcd1602_write_data(unsignedchardate)//向lcd1602写数据
{
rs=1;
rw=0;
P0=date;
lcden=1;
delayus(5);
lcden=0;
}
voidlcd1602_write_com(unsignedcharcom)//向lcd1602写指令
{
rs=0;
rw=0;
P0=com;
lcden=1;
delayus(5);
lcden=0;
}
voidlcd1602_write(unsignedcharaddress,chardate)
{//在lcd1602指定位置写数据
charshiwei,gewei;
lcd1602_write_com(0x80+address);
shiwei=date/10;
gewei=date%10;
lcd1602_write_data(0x30+shiwei);
lcd1602_write_data(0x30+gewei);
lcd1602_write_com(0x80+address);
}
voidlcd1602_write_week(charweek)//lcd1602显示星期
{
unsignedcharn;
lcd1602_write_com(0x80+lcd1602_week);
for(n=0;n<3;n++)lcd1602_write_data(table_week[week-1][n]);
}
voidlcd1602_display()//lcd1602刷新数据
{
hour=ds1302_read_data(ds1302_hour_read);
minute=ds1302_read_data(ds1302_minute_read);
second=ds1302_read_data(ds1302_second_read);
week=ds1302_read_data(ds1302_week_read);
year=ds1302_read_data(ds1302_year_read);
date=ds1302_read_data(ds1302_date_read);
month=ds1302_read_data(ds1302_month_read);
lcd1602_write(lcd1602_year,year);
lcd1602_write(lcd1602_month,month);
lcd1602_write(lcd1602_date,date);
lcd1602_write_week(week);
lcd1602_write(lcd1602_hour,hour);
lcd1602_write(lcd1602_minute,minute);
lcd1602_write(lcd1602_second,second);
}
voidrunnian()//处理闰年二月天数
{
nian=2000+year;
if(((nian%4==0)&&(nian%100!
=0))||((nian%100==0)&&(nian/100%4==0)))days[1]=29;
elsedays[1]=28;
}
voidtimer0()interrupt1//定时器0中断函数
{
TL0=(65536-20000)%256;
TH0=(65536-20000)/256;
if(nummode==0)lcd1602_display();
}
voidkeyscan()//按键扫描
{
if(mode==0)
{
delayms(10);//消抖
if(mode==0)
{
while(mode==0);//等待按键松开
nummode++;
if(nummode==8)
{
ds1302_write(ds1302_second_write,((second/10)<<4)|(second%10));//取消DS1302暂停,进入正常工作
nummode=0;
}
}
}
switch(nummode)
{
case0:
lcd1602_write_com(0x0c);break;//不显示光标
case1:
ds1302_write(ds1302_second_write,((second/10)<<4)|(second%10)|0x80);
lcd1602_write_com(0x80+lcd1602_year-2);//定位到年
lcd1602_write_com(0x0f);break;
case2:
ds1302_write(ds1302_second_write,((second/10)<<4)|(second%10)|0x80);
lcd1602_write_com(0x80+lcd1602_month);//定位到月
lcd1602_write_com(0x0f);break;
case3:
ds1302_write(ds1302_second_write,((second/10)<<4)|(second%10)|0x80);
lcd1602_write_com(0x80+lcd1602_date);//定位到日
lcd1602_write_com(0x0f);break;
case4:
ds1302_write(ds1302_second_write,((second/10)<<4)|(second%10)|0x80);
lcd1602_write_com(0x80+lcd1602_week);//定位到星期
lcd1602_write_com(0x0f);break;
case5:
ds1302_write(ds1302_second_write,((second/10)<<4)|(second%10)|0x80);
lcd1602_write_com(0x80+lcd1602_hour);//定位到时
lcd1602_write_com(0x0f);break;
case6:
ds1302_write(ds1302_second_write,((second/10)<<4)|(second%10)|0x80);
lcd1602_write_com(0x80+lcd1602_minute);//定位到分
lcd1602_write_com(0x0f);break;
case7:
ds1302_write(ds1302_second_write,((second/10)<<4)|(second%10)|0x80);
lcd1602_write_com(0x80+lcd1602_second);//定位到秒
lcd1602_write_com(0x0f);break;
}
if(nummode&&add==0)
{
delayms(10);
if(add==0)
{
while(add==0);
switch(nummode)
{
case1:
year++;if(year==99)year=0;
lcd1602_write(lcd1602_year,year);
ds1302_write(ds1302_year_write,((year/10)<<