万年历

发布时间:   来源:文档文库   
字号:
一、述:
本项目是一种基于AT89C52单片机的万年历设计,本方案以AT89C52单片机作为主控核
心,与时钟芯片DS1302、按键、LCD1602液晶显示器组成硬件系统。在硬件系统中设有独立按键和LCD1602显示器,能显示丰富的信息,根据使用者的需要可以随时对时间进行更改,读取方便、显示直观。
二、方案设计
1、项目总体方案:
本系统以AT89C52单片机为控制核心,通过与DS1302通信获取实时时间,并将得到的数据通过1602液晶显示出来,同时通过相应的按键调整相应的值。因此本设计可分为以下模块:显示模块,实时时间计算模块,设置模块。

单片机89C52控制模块
LCD液晶显示模块
DS1302时钟模块


项目系统框图
2、系统基本方案的选择和论证
单片机芯片的选择:
方案1采用89C51芯片作为硬件核心,采用FlashROM,内部具有4KBROM存储空间,能于3V的超低压工作,而且与MCS-51系列单片机完全兼容,但是运用于电路设计中时由于不具备ISP在线编程技术,当在对电路进行调试时,由于程序的错误修改或对程序的新增功能需要烧入程序时,对芯片的多次拔插会对芯片造成一定的损坏。
方案(2
我们采用89C52单片机作为系统的核心。89C52具有高集成度、低成本、低电源电压、低功耗等优势是因为单片机具有价格低、应用灵活、面向控制的特点,而在8位单片机中,51列历史最长,形成了既具有经典性又不乏生命力的一个单片机系列,因为具有低成本的特点,在功能并不太复杂的设计中,单片机作为核心完全能够达成预定的功能,同时降低了量产化后的成本。
显示模块的选择:
方案1数码管是利用发光二极管的特性组合而成数字显示器件,通过控制相应的二极管的状态显示相应的数字,要使数码管正常显示就得有驱动电路驱动相应的段码,数码管的现实方式可分为静态显示和动态显示,静态显示方式只适合显示单个的数字,因此本设计应采

用动态显示方式,由于动态显示方式利用的是人眼视觉暂留的特性,扫描的时间应不大于20ms,占用系统资源大,而且显示的字型有限,在本设计中不易采用。
方案(2采用点阵式数码管显示,点阵式数码管是由八行八列的发光二极管组成,对于显示文字比较合适,如采用全显示数字显得太浪费,且价格也相对较高,所以也不用此种作为显示。
方案(31602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块,它有若干个5*7或者5*11等点阵字符位组成,每个点阵字符位都可以显示一个字符。每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,1602的驱动电路带有11条指令,可以很方便的控制液晶的现实效果如:清屏、左移右移、光标显示。而且1602显示的字符在下一条指令未到来之前不会改变,也就是能够维持显示的字符,1602液晶占用的系统资源也少。
综合比较上述两种方案,应采用1602液晶组成本设计的显示模块。
实时时间计算选择:
方案(1AT89C52单片机内部带有定时/计数功能,此定时功能是通过对外部晶振的脉冲进行计数,从而达到计时功能,只要使用11.0592MHZ的晶振就能实现零误差的计时,因此可以利用此功能实现计时,但因为只有单一的计时功能要实现“万年历”的功能需要较复杂的程序,而且如果单片机掉电无法继续进行计时,所以不方便。
方案(2DS1302是美国DALLAS公司推出的一种高性能、低功耗的实时时钟芯片,工作电压宽达2.5~5.5V。采用双电源供电(主电源和备用电源),可设置备用电源充电方式,提供了对后备电源进行涓细电流充电的能力。利用单片机强大的控制功能就可实现实时计时的功能,而且消耗的系统资源少,程序简单。相对于AT89C5211.0592MHZ的晶振DS1302的晶振只有32KHZ左右。
综合上述两种方案,宜采用方案(2)实现实时计时功能。键盘选择:
时钟的设置虽包含数字,但是我们不建议使用阵列按键,因为阵列按键太多,为使系统尽可能简化,键盘部分的设计在能够完成系统需求的前提下,越简单越好,所以,时钟系统的键盘可以设置三个键:确认键、加1键、减1键。
三、硬件设计介绍11602液晶显示器介绍:
1602液晶显示引脚图

引脚功能介绍:引脚号12345678910111213141516
引脚名VssVccVeeRSR/WEND0D1D2D3D4D5D6D7AK
电平0/10/11,100/10/10/10/10/10/10/10/1+Vcc接地
输入/输出输入输入输入输入/输出输入/输出输入/输出输入/输出输入/输出输入/输出输入/输出输入/输出
作用电源地电源(+5V对比调整电压
0=输入指令1=输入数据0=lcd写入指令或数据1=lcd读取信息使能信号,1时读取信息,10(下降沿)执行指令数据总线line0(最低位数据总线line1数据总线line2数据总线line3数据总线line4数据总线line5数据总线line6
数据总线line7(最高位)LCD背光电源正极LCD背光电源负极

1602液晶显示11条指令介绍:
1清屏指令指令码0x01RS=1RW=0①清除液晶显示器,即将DDRAM的内容全
部填入“空白”的字符码20H;②光标归位,即将光标撤回液晶显示屏的左上方;③将地址计数器(AC)的值设为0
2光标归位指令指令码0x02①把光标撤回到显示器的左上方;②把地址计数器
AC)的值设置为0;③保持DDRAM的内容不变;
3输入模式设置指令指令码000001I/DS
I/D=0写入新数据后光标左移I/D=1写入新数据后光标右移
S=0写入新数据后显示屏不移动S=1写入新数据后显示屏整体右移一个字
4显示开关控制指令指令码00001DCB控制显示器开/关、光标显示/关闭以及
光标是否闪烁。
D0=显示功能关1=显示功能开C0=无光标1=有光标
B0=光标不闪烁1=光标闪烁
5设定显示屏或光标移动方向指令指令码0001S/CR/L**使光标移位或使整个显示屏幕移位。
S/CR/L设定情况
00光标左移1格,且AC值减101光标右移1格,且AC值加1
10显示器上字符全部左移1格,但光标不动11显示器上字符全部右移1格,但光标不动
6功能设定指令指令码001D/LNF**设定数据总线位数、显示的行数及字

型。
D/L0=数据总线为41=数据总线为8N0=显示11=显示2
F0=5*7点阵/每字符1=5*10点阵每/字符
(7设定CGRAM地址指令自定义字符设定下一个要存入数据的CGRAM的地8设定DDRAM地址指令设定下一个要存入数据的CGRAM的地址
9读取忙信号或AC地址指令①读取忙碌信号BF的内容,BF=1表示液晶显示器
忙,暂时无法接收单片机送来的数据或指令;当BF=0时,液晶显示器可以接收单片机送来的数据或指令;②读取地址计数器(AC)的内容。
10数据写入DDRAMCGRAM指令①将字符码写入DDRAM,以使液晶显示
屏显示出相对应的字符;②将用户自己设计的图形存入CGRAM
11CGRAMDDRAM读出数据的指令读取DDRAMCGRAM中的内容
2DS1302介绍:
DS1302引脚图


DS1302各引脚功能:
1Vcc25V电源。当Vcc2>Vcc1+0.2v时,由VccDS1302供电,当Vcc2时,由
VccDS1302供电。
23X1X2是外接晶振脚(32.768KHZ的晶振)4、地(GND
5CE/RST:复位脚。6I/O:数据输入输出口。7SCLK:串行时钟,输入。8Vcc1:备用电池端;
四、程序设计(分析过程和流程图)


调整时间程序流程图



主程序流程图
五、总结
通过本次项目,我复习并强化了C语言,单片机,微机接口原理的一些知识。在软件设计中,我们起初不知道LCD1602识别ASCII码,不知道单片机人二进制码,也不知道实时时DS1302BCD码,更不知道如何转换,也就无法把单片机,LCD液晶显示模块,实时时钟的程序衔接起来,对程序存储所用存储单元的利用也不灵活,对读取数据所需要的字节常常手足无措最后经老师指导,讲解才,明白如何转换,才马马虎虎读写到了自己想要的内容。
我深感我们的知识贫乏,见识浅薄。但是我们都坚持下来了,我们都明白“学,然后知不足的道理.”项目过程中,我们很累,但获益良多。



附录:
软件程序:
//万年历//v1.2
//加入按键控制//调试完成
#include"reg52.h"
typedefunsignedcharuint8;
#defineclrdp0x01//清屏
#defineenmode0x06//进入模式设置,写入一个数据后自动+1,整屏不移动#definecurback0x02//光标回0
#defineondp0x0f//开屏,开光标,闪烁#defineoffdp0x08//关屏
#definemovd0x14//移动设置,光标自动向右移动#definefunset0x38//功能设置,8位总线,2行显示,5*7
#definebusP0//数据线
#definecontw0x8e//控制寄存器
#definesecw0x80//写秒寄存器#definesecr0x81//#defineminw0x82//#defineminr0x83
#definehourw0x84//小时#definehourr0x85
#definedatw0x86//日期#definedatr0x87
#definemonthw0x88//#definemonthr0x89
#definedayw0x8a//星期#definedayr0x8b
#defineyearw0x8c//#defineyearr0x8d
sbitK1=P3^0;//选择,确认sbitK2=P3^1;//sbitK3=P3^2;//
//1602接口

sbitBKL=P2^7;//背光
sbitRS=P2^4;//数据/指令选择,1:数据,0:指令sbitRW=P2^5;//读写选择,1:读,0:写sbitEN=P2^6;//使能,下降沿有效
//1302接口
sbitDIO=P3^4;//数据输入输出端sbitRST=P3^5;//片选
sbitSCK=P3^6;//时钟输入
bitflag=0;
uint8sel;
uint8time[7]={0};//开始的时间:2010-09-01-12-24-18uint8time_disp[32]={0};//处理后的时间
voidinit_1602(void;//初始化1602
voidwrite_com(uint8comd;//写命令
voidwrite_dat(uint8wdata;//写数据
voiddelay(void;//延时
voidlong_dleay(void;//长延时
voidinit_1302(void;
uint8read_1302(uint8addr;//读指定寄存器的内容
voidwrite_1302(uint8addr,uint8wdata;//向指定寄存器写内容
voiddisp(void;//显示
voidread_time(void;//读时间
voidsepr_time(void;//分析时间信息
voidchk_key(void;//检查按键
uint8bcd_dec(uint8wdata;//十进制转BCD
uint8dec_bcd(uint8wdata;//BCD转十进制

//
voidmain(void{
//BKL=0;
init_1302(;//初始化16021302init_1602(;while(1{
chk_key(;//检查按键read_time(;//读时间
sepr_time(;//分析时间信息disp(;//显示时间}}
//初始化1302
voidinit_1302(void{
write_1302(contw,0;//关闭写保护write_1302(secw,0;//启动1302}
//1302寄存器
voidwrite_1302(uint8addr,uint8wdata{
uint8i;
SCK=0;RST=1;
for(i=0;i<8;i++{
DIO=addr&0x01;//低电平时释放数据SCK=1;SCK=0;addr>>=1;
}//指定操作的寄存器地址
for(i=0;i<8;i++{
DIO=wdata&0x01;SCK=1;SCK=0;wdata>>=1;

}RST=0;}
//读寄存器
uint8read_1302(uint8addr{
uint8i;uint8temp;
SCK=0;RST=1;
for(i=0;i<8;i++{
DIO=addr&0x01;SCK=1;SCK=0;addr>>=1;}
for(i=0;i<8;i++{
temp>>=1;if(!DIO{
temp&=0x7f;}else{
temp|=0x80;}
SCK=1;SCK=0;}
RST=0;
returntemp;}
//1302的时间寄存器voidread_time(void{
uint8i;

uint8temp;
for(i=0;i<7;i++{
temp=read_1302(0x81+i*2;//time[i]=temp;//保存}
time[0]&=0x7f;//}
//显示时间voiddisp(void{
uint8i;
write_com(0x80;//第一行for(i=0;i<16;i++{
write_dat(time_disp[i];}
write_com(0xc0;//第二行for(i=16;i<32;i++{
write_dat(time_disp[i];}}
//分离时间信息voidsepr_time(void{
time_disp[0]='-';time_disp[1]='-';time_disp[2]='2';time_disp[3]='0';
time_disp[4]=(time[6]>>4+0x30;//time_disp[5]=(time[6]&0x0f+0x30;time_disp[6]='-';
time_disp[7]=(time[4]>>4+0x30;//time_disp[8]=(time[4]&0x0f+0x30;time_disp[9]='-';
time_disp[10]=(time[3]>>4+0x30;//time_disp[11]=(time[3]&0x0f+0x30;time_disp[12]='-';

time_disp[13]='-';
time_disp[14]=(time[5]>>4+0x30;//星期
time_disp[15]=(time[5]&0x0f+0x30;//第一行显示,年月日星期time_disp[16]='-';time_disp[17]='-';time_disp[18]='-';time_disp[19]='-';
time_disp[20]=(time[2]>>4+0x30;//time_disp[21]=(time[2]&0x0f+0x30;time_disp[22]='-';
time_disp[23]=(time[1]>>4+0x30;//time_disp[24]=(time[1]&0x0f+0x30;time_disp[25]='-';
time_disp[26]=(time[0]>>4+0x30;//time_disp[27]=(time[0]&0x0f+0x30;time_disp[28]='-';time_disp[29]='-';time_disp[30]='-';time_disp[31]='-';}
//初始化1602
voidinit_1602(void{
write_com(offdp;write_com(funset;write_com(enmode;write_com(movd;
write_com(ondp;write_com(clrdp;}
//1602写命令
voidwrite_com(uint8comd{
RS=0;RW=0;bus=comd;EN=1;EN=0;

delay(;}
//1602写数据
voidwrite_dat(uint8wdata{
RS=1;RW=0;bus=wdata;EN=1;EN=0;delay(;}
//延时
voiddelay(void{
uint8t;
for(t=0;t<250;t++;}
//长延时
voidlong_delay(void{
uint8t;
for(t=0;t<200;t++{
delay(;}}
//检查按键
voidchk_key(void{
uint8buf;uint8temp;
if(!K1{
long_delay(;
if(!K1//选择/确认//确认按下

{
if(flag//不在修改时间状态中{if((sel>=0&&(sel<8{
sel++;//}
elseif(sel==8{
temp=read_1302(secr;//temp&=0x7f;write_1302(secw,temp;//启动1302sel=0;//无效flag=0;}else{sel=8;}}else{temp=read_1302(secr;//读秒temp|=0x80;write_1302(secw,temp;//暂停1302flag=1;}}}
elseif(!K2//{
long_delay(;if(!K2{
switch(sel{
case1:temp=read_1302(yearr;//读年buf=bcd_dec(temp;//转换if(buf<99{
buf++;
temp=dec_bcd(buf;//转换write_1302(yearw,temp;//写入}

break;
case2:temp=read_1302(dayr;//读星期buf=bcd_dec(temp;if(buf<7{
buf++;temp=dec_bcd(buf;write_1302(dayw,temp;}
break;
case3:temp=read_1302(monthr;//读月buf=bcd_dec(temp;if(buf<12{
buf++;
temp=dec_bcd(buf;
write_1302(monthw,temp;}
break;
case4:temp=read_1302(datr;//读日buf=bcd_dec(temp;if(buf<31{
buf++;
temp=dec_bcd(buf;
write_1302(datw,temp;}
break;
case5:temp=read_1302(hourr;//读小时buf=bcd_dec(temp;if(buf<23{
buf++;
temp=dec_bcd(buf;
write_1302(hourw,temp;}
break;case6:temp=read_1302(minr;//读分buf=bcd_dec(temp;

if(buf<59{
buf++;
temp=dec_bcd(buf;write_1302(minw,temp;}
break;
case7:temp=read_1302(secr;//读秒temp&=0x7f;buf=bcd_dec(temp;if(buf<59{
buf++;
temp=dec_bcd(buf;temp|=0x80;
write_1302(secw,temp;}
break;
default:break;}}}elseif(!K3//{long_delay(;if(!K3{switch(sel{case1:temp=read_1302(yearr;buf=bcd_dec(temp;if(buf>0{buf--;temp=dec_bcd(buf;write_1302(yearw,temp;}break;case2:temp=read_1302(dayr;buf=bcd_dec(temp;if(buf>1



{
buf--;
temp=dec_bcd(buf;write_1302(dayw,temp;}
break;
case3:temp=read_1302(monthr;buf=bcd_dec(temp;if(buf>1{buf--;temp=dec_bcd(buf;write_1302(monthw,temp;}break;case4:temp=read_1302(datr;buf=bcd_dec(temp;if(buf>1{buf--;temp=dec_bcd(buf;write_1302(datw,temp;}break;case5:temp=read_1302(hourr;buf=bcd_dec(temp;if(buf>0{buf--;temp=dec_bcd(buf;write_1302(hourw,temp;}break;case6:temp=read_1302(minr;buf=bcd_dec(temp;if(buf>0{buf--;temp=dec_bcd(buf;write_1302(minw,temp;

}break;case7:temp=read_1302(secr;temp&=0x7f;buf=bcd_dec(temp;if(buf>0{buf--;temp=dec_bcd(buf;temp|=0x80;write_1302(secw,temp;}break;default:break;}}}}
//十进制转BCD
uint8dec_bcd(uint8wdata{
uint8temp;uint8i;uint8j;
i=wdata/10;//得商j=wdata%10;//余数temp=i;
temp=temp<<4;temp=temp|j;returntemp;}
//BCD转十进制
uint8bcd_dec(uint8wdata{
uint8temp;uint8i;uint8j;
i=wdata>>4;//高半字节j=wdata&0x0f;//低半字节temp=i*10+j;returntemp;}
//endend










引脚功能介绍:引脚号12345678910111213141516
引脚名VssVccVeeRSR/WEND0D1D2D3D4D5D6D7AK
电平0/10/11,100/10/10/10/10/10/10/10/1+Vcc接地
输入/输出输入输入输入输入/输出输入/输出输入/输出输入/输出输入/输出输入/输出输入/输出输入/输出
作用电源地电源(+5V对比调整电压
0=输入指令1=输入数据0=lcd写入指令或数据1=lcd读取信息使能信号,1时读取信息,10(下降沿)执行指令数据总线line0(最低位数据总线line1数据总线line2数据总线line3数据总线line4数据总线line5数据总线line6
数据总线line7(最高位)LCD背光电源正极LCD背光电源负极


本文来源:https://www.2haoxitong.net/k/doc/3cffdd0cba1aa8114431d92e.html

《万年历.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式