单片机课程设计实验报告-基于STC89C52RC的电子万年历设计Word格式.doc
《单片机课程设计实验报告-基于STC89C52RC的电子万年历设计Word格式.doc》由会员分享,可在线阅读,更多相关《单片机课程设计实验报告-基于STC89C52RC的电子万年历设计Word格式.doc(31页珍藏版)》请在冰点文库上搜索。
图5 DS1302时钟电路
5、按键电路
按键电路由5个轻触开关组成,如图6所示。
按键用来调整时间和设定闹钟,其一端直接接到单片机的端口,另一端接地,当按下按键时,相应的端口变为低电平,通过检测这一低电平就可以判断是哪个键按下,从而作相应的操作。
图6 按键电路
6、显示电路
显示电路采用LCD1602液晶显示,图中只画出了其相应的接口,如图7所示。
3脚用于调节LCD1602的背光,4、5、6为LCD1602的控制口,用于控制其写入或是读出指令,7至14脚为LCD1602的数据口,将数传送到LCD1602中。
图7 LCD1602接口电路
7、蜂鸣器电路
蜂鸣器电路如图8所示。
通过控制三极管的导通和截止来实现蜂鸣器的响与不响。
图8 蜂鸣器电路
四、软件设计与流程图
1、程序主流程图
主程序首先初始化定时器、LCD1602及DS1302,然后就开始查询按键,有键按下则开始调整时间和设置闹钟,若没有按下,则执行下面的时间、日期及闹钟时间的显示,最后依次循环这些相同的操作,相应流程图如图9所示:
开始
初始化
按键是否按下
显示时间、日期及闹钟时间
时间、日期、闹钟设定
结束
是
否
图9 程序主流程图
按键的检测主要是通过查询的办法来实现,利用按键进行间调整及闹钟设置,闹钟开关键是开启和关闭闹钟功能;
设置1键按下则开始设置时间及日期,同时被选择的时间和日期开始闪烁,第一次按下设置1键时,设置年,第二次按下设置月,后面依次设置日、星期、时、分、秒;
闹钟设置键按下则开始设置闹钟时间及日期,同时被选择的时间和日期开始闪烁,第一次按下闹钟设置键时,设置年,第二次按下设置月,后面依次设置日、星期、时、分、秒;
若按下下调键是减1操作,按下上调键是加1操作,无论是对时钟和闹钟的年份或月份进行加减,都会使日期归1。
五、仿真电路图
基于STC89C52RC单片机的电子万年历硬件仿真电路图如图10所示,系统由STC89C52RC单片机、按键扫描电路、显示电路、时钟电路、晶振电路、复位电路、蜂鸣器电路组成。
图10电子万年历仿真图
六、结论与心得
通过这次课程设计,我对单片机的理论知识有了进一步的掌握,对单片机的原理和实际应用有了更多地理解和掌握。
我对单片机的C语言编程有了更深刻的认识和更扎实的掌握,通过不断修改,不断尝试,对源代码各个模块的函数都有了一个非常深入的掌握。
在收获知识的同时,还收获了阅历,收获了成熟。
在此过程中,不仅培养了独立思考、动手制作的能力,在各种其它能力上也都有了提高。
更重要的是,在课程序设计里,我们学会了很多学习的方法。
而这是以后最实用的,真的是受益匪浅。
要面对社会的挑战,只有不断的学习、实践,再学习、再实践。
七、源程序
1、键盘扫描程序头文件keyscan.h:
/*-----------------------------------------------
矩阵键盘实验程序
通过反转法循环扫描矩阵键盘
------------------------------------------------*/
#include<
reg52.h>
//包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#defineucharunsignedchar
#defineuintunsignedint
/*------------------------------------------------
函数声明
------------------------------------------------*/
ucharkeyscan(void);
//键盘扫描
voiddelay(uinti);
//演示程序
主函数
延时程序
voiddelay1(uinti)//延时函数
{
while(i--);
}
键盘扫描程序
ucharkeyboard(void)//键盘扫描函数,使用行列反转扫描法
ucharcord_h,cord_l;
//行列值中间变量
P1=0x0f;
//行线输出全为0
cord_h=P1&
0x0f;
//读入列线值
if(cord_h!
=0x0f)//先检测有无按键按下
{
delay1(100);
//去抖
if(cord_h!
=0x0f)
{
cord_h=P1&
//读入列线值
P1=cord_h|0xf0;
//输出当前列线值
cord_l=P1&
0xf0;
//读入行线值
P1=0X0F;
delay1(20);
while(P1!
=0x0f);
//return(cord_h+cord_l);
//键盘最后组合码值
switch(cord_h+cord_l)
{
/*case0xee:
return(12);
break;
//0按下相应的键显示相对应的码值
case0xde:
return(8);
//1按下相应的键显示相对应的码值
case0xbe:
return(4);
//2
case0x7e:
return(0);
//3
case0xed:
return(13);
//4
case0xdd:
return(9);
//5
case0xbd:
return(5);
//6
case0x7d:
return
(1);
//7
case0xeb:
return(14);
//8
case0xdb:
return(10);
//9
case0xbb:
return(6);
//a
case0x7b:
return
(2);
//b
case0xe7:
return(15);
//c
case0xd7:
return(11);
//d
case0xb7:
return(7);
//e
case0x77:
return(3);
//f
default:
return(0xff);
*/
case0xee:
}
}return(0xff);
//返回该值
2、主程序如下:
#include"
keyscan.h"
#defineuintunsignedint
uchara,miao,shi,fen,ri=1,yue=1,nian,week=1,key1n=0,key2n=0,run,runl,bai,mstcnt,miao1=0,shi1=0,fen1=0,ril=1,yuel=1,nianl,weekl=1,Wl,Rl,Yl,Nl,W,R,Y,N;
uintcount1=0,count2=0,clk_set=0,clk_switch=0;
ucharMSB_reload_value=(65536-100)/256,LSB_reload_value=(65536-100)%256;
ucharkey=0xff;
#defineyh0x80+16//LCD第一行的初始位置,因为LCD1602字符地址首位D7恒定为1(=80)
#defineer0x80+0x40+16//LCD第二行初始位置(因为第二行第一个字符位置地址是0x40)
#defineyhl0x80
#defineer10x80+0x40
//液晶屏的与C51之间的引脚连接定义(显示数据线接C51的P0口)
sbitrs=P2^0;
sbiten=P2^2;
sbitrw=P2^1;
//如果硬件上rw接地,就不用写这句和后面的rw=0了
sbitACC0=ACC^0;
sbitACC7=ACC^7;
/************************************************************
ACC累加器=A
ACC.0=E0H
ACC.0就是ACC的第0位。
Acc可以位寻址。
累加器ACC是一个8位的存储单元,是用来放数据的。
但是,这个存储单元有其特殊的地位,
是单片机中一个非常关键的单元,很多运算都要通过ACC来进行。
以后在学习指令时,
常用A来表示累加器。
但有一些地方例外,比如在PUSH指令中,就必须用ACC这样的名字。
一般的说法,A代表了累加器中的内容、而ACC代表的是累加器的地址。
***************************************************************/
sbitbuzzer=P3^6;
//蜂鸣器,通过三极管9012驱动,端口低电平响
/**************************************************************/
ucharcodetab0[]="
WangZhe"
;
ucharcodetab1[]="
"
ucharcodetab2[]="
20--"
//年显示的固定字符
ucharcodetab3[]="
:
CLK:
OFF"
//时间显示的固定字符
//延时函数,后面经常调用
voiddelay(uintxms)//延时函数,有参函数
uintx,y;
for(x=xms;
x>
0;
x--)
for(y=110;
y>
y--);
voiddelay2(uintz) //延时
for(x=z;
for(y=500;
/********液晶写入指令函数与写入数据函数,以后可调用**************/
write_1602com(ucharcom)//****液晶写入指令函数****
rs=0;
//数据/指令选择置为指令
rw=0;
//读写选择置为写
P0=com;
//送入数据
delay
(1);
en=1;
//拉高使能端,为制造有效的下降沿做准备
en=0;
//en由高变低,产生下降沿,液晶执行命令
write_1602dat(uchardat)//***液晶写入数据函数****
rs=1;
//数据/指令选择置为数据
P0=dat;
//en置高电平,为制造下降沿做准备
//en由高变低,产生下降沿,液晶执行命令
/****************屏幕移动*********************/
voidzuoyi(ucharnum3) //屏幕左移
{
ucharl;
for(l=0;
l<
num3;
l++)
{
write_1602com(0x18);
delay2(5);
}
voidyouyi(ucharnum4) //屏幕右移
ucharr;
for(r=0;
r<
num4;
r++)
write_1602com(0x1c);
}
lcd_init()//***液晶初始化函数****
write_1602com(0x38);
//设置液晶工作模式,意思:
16*2行显示,5*7点阵,8位数据
write_1602com(0x0c);
//开显示不显示光标
write_1602com(0x06);
//整屏不移动,光标自动右移
write_1602com(0x01);
//清显示
/*****************************************/
write_1602com(0x80);
for(a=0;
a<
15;
a++)
write_1602dat(tab0[a]);
write_1602com(0x80+0x40);
write_1602dat(tab1[a]);
/*write_1602com(0x80+16);
17;
write_1602dat(tab2[a]);
write_1602com(0x80+0x40+16);
write_1602dat(tab3[a]);
*/
/*********************************************/
write_1602com(yh+1);
//日历显示固定符号从第一行第1个位置之后开始显示
14;
write_1602dat(tab2[a]);
//向液晶屏写日历显示的固定符号部分
//delay(3);
write_1602com(er);
//时间显示固定符号写入位置,从第2个位置后开始显示
16;
//写显示时间固定符号,两个冒号
delay2(600);
zuoyi(16);
/*********************over***********************/
//时分秒显示子函数
voidwrite_sfm(ucharadd,uchardat)//向LCD写时分秒,有显示位置加、现示数据,两个参数
uchargw,sw;
gw=dat%10;
//取得个位数字
sw=dat/10;
//取得十位数字
write_1602com(er+add-2);
//er是头文件规定的值0x80+0x40
write_1602dat(0x30+sw);
//数字+30得到该数字的LCD1602显示码
write_1602dat(0x30+gw);
voidwrite_sfm1(ucharadd,uchardat)//向LCD写时分秒,有显示位置加、现示数据,两个参数
write_1602com(er1+add);
//-------------------------------------
//年月日显示子函数
voidwrite_nyr(intadd,intdat)//向LCD写年月日,有显示位置加数、显示数据,两个参数
intgw,sw;
write_1602com(yh+add);
//设定显示位置为第一个位置+add
voidwrite_nyrl(intadd,intdat)//向LCD写年月日,有显示位置加数、显示数据,两个参数
write_1602com(yhl+add);
//-------------------------------------------
voidwrite_week(ucharweek)//写星期函数
write_1602com(yh+0x0c);
//星期字符的显示位置
switch(week)
case1:
write_1602dat('
M'
);
//星期数为1时,显示
write_1602dat('
O'
N'
break;
case2:
T'
//星期数据为2时显示
U'
E'
case3:
W'
//星期数据为3时显示
D'
case4:
write_1602d