单片机课程设计带有LCD的定时闹钟.docx
《单片机课程设计带有LCD的定时闹钟.docx》由会员分享,可在线阅读,更多相关《单片机课程设计带有LCD的定时闹钟.docx(26页珍藏版)》请在冰豆网上搜索。
单片机课程设计带有LCD的定时闹钟
郑州轻工业学院之马矢奏春创作
软件学院
单片机与接口技术课程设计总结陈述
设计题目:
带有LCD的定时闹钟
学生姓名:
系别:
专业:
班级:
学号:
指导教师:
2011年12月16日
郑州轻工业学院
课程设计任务书
题目带有LCD的定时闹钟
专业、班级学号姓名
主要内容:
设使用89C51单片机结合字符型LCD显示器设计一个简易的定时闹钟LCD时钟,若LCD选择有背光显示的模块,在夜晚或黑暗的场合中也可以使用。
基本要求:
.字符型LCD(16*2)显示器
.显示格式“时时分分”。
.由LED闪动来做秒计数暗示。
.一旦时间到侧发动声响,同时继电器启动,可以扩充控制家电开启和关闭。
.程序执行后工作指示灯LED闪动,暗示程序开始执行,LCD显示“0000”,按下操纵键K1-k4动作如下:
(1)K1—设置现在的时间。
(2)K2—显示闹钟设置的时间。
(3)K3—设置闹铃的时间。
(4)K4—闹铃ON/OFF的状态设置,设置ON时连续三次发出“哗”的一声,off置为哗的一声。
设置当前时间或闹铃时间如下:
(1)K1—时的调整。
(2)K2—分的调整。
(3)K3—设置完成。
(5)OFF发出“哗”K4---闹铃时间到时,发出一阵声响,按下本键可以停止声响。
除了显示当前时间的功能外,还可以扩充如下功能;
.增加秒表计数。
.闹铃时间到侧发生音乐声。
.增加减计数功能。
.增加多组计数的功能。
参考文献
郭天祥51单片机C语言教程-入门。
余发山单片机原理及应用技术。
中国矿业大学出版社。
涂世亮,张友德。
单片微机控制技术。
清华大学出版社。
以单片机为核心的数字时钟是很有社会意义和社会价值的。
钟表原先的报时功能已经原不克不及满足人们日益增长的要求,现代的电子时钟多带有类似自动报警、按时自动打铃、时间程序自动控制、定时广播、自动起闭路灯、通断动力设备、甚至各种定时电气的自动启用等功能。
1.1本LCD电子闹钟的特点和功能介绍
数字钟介绍
时钟是将小时、分钟、秒钟显示于人的肉眼的计时装置。
而单片机模块中最罕见的正是数字钟,数字钟是一种用数字电路技术实现时、分、秒计时的装置,与机械式时钟相比具有更高的准确性和直观性,且无机械装置,具有更长的使用寿命,因此得到了广泛的使用。
而LCD电子定时闹钟是以单片机为基础的数字电路实现对时、分、秒的数字显示的数字计时装置,它的计时周期为24小时,另外应有校时功能和一些显示日期、闹钟等附加功能。
一个基本的数字钟电路主要由译码显示器、“时”,“分”,“秒”,“星期”计数器、校时电路、报时电路和振荡器组成。
目前电子钟广泛用于各种私人和公众场合,成为我们生活、工作和学习中不成缺少的好辅佐。
2总体方案设计
2.1总体设计方案
本LCD定时闹钟,是以单片机及外围接口电路为核心硬件,辅以其他外围硬件电路,用汇编语言设计的程序来实现的。
根据C51单片机的外围接口特点扩展相应的硬件电路,然后根据单片机的指令设计出数字钟相应的软件,再利用软件执行一定的程序来实现数字钟的功能。
由于采取集成芯片性的单片机来制作电子钟,这样设计制作简单而且功能多、精确度高,也可方便扩充其他功能,实现也十分简单。
本设计是利用AT89C51单片机为主控芯片,由LCD、晶振、电阻、电容、发光二极管、开关、喇叭等元件组成硬件电路,通过编写软件程序来实现和控制的数字定时闹钟
AT89C51
震荡
电路
调时电路
喇叭
LCD
片选
代码
AT89C51
震荡
电路
调时电路
喇叭
LCD
片选
代码
。
3硬件设计
3.1主控芯片AT89C51的设计
在本LCD电子闹钟设计中就是采取利用我们熟悉的AT89C51单片机为主控芯片。
AT89C51单片机由微处理器,存储器,I/O口以及特殊功能寄存器SFR等部分构成。
其存储器在物理上设计成程序存储器和数据存储器两个独立的空间,片内程序存储器的容量为4KB,片内数据存储器为128个字节。
89C51单片机有4个8位的并行I/O口:
P0口,P1口,P2口和P3口。
各个接口均由接口锁存器,输出驱动器,和输入缓冲器组成。
P1口是唯一的单功能口,仅能用作通用的数据输入/输出口。
P3口是双功能口除了具有数据输入/输出功能外,每条接口还具有分歧的第二功能,如P3.0是串行输入口线,P3.1口是串行输出口线。
在需要外部程序存储器和数据存储器扩展时,P0可作为分时复用的低8位地址/数据总线,P2口可作为高8位的地址总线。
P3口也可作为AT89C51的一些特殊功能口,同时为闪烁编程和编程校验接收一些控制信号.
3.2时钟电路部分设计
AT89C51系列的单片机的时钟方式分为内部方式和外部方式。
内部方式就是在单片机的XTAL1和XTAL2的两引脚外接晶振,就够成了自激振荡器在单片机内部发生时钟脉冲信号。
外部时钟方式是把外部已经有的时钟信号引入到单片机内部。
时钟电路在计算机系统中起着非常重要的作用,是包管系统正常工作的基础。
在一个单片机应用系统中,时钟有两方面的
含义:
一是指为包管系统正常工作的基准振荡定时信号,主要由晶振和外围电路组成,晶振频率的大小决定了单片机系统工作的快慢;二是指系统的尺度定时时钟,即定时时间。
3.2。
之所以采取高性能的振荡电路,因为:
1.单片机电子钟的计时脉冲基准是由外部晶振的频率经过12分频后提供,采取内部的定时/计数器来实现计时功能。
所以,外接晶振频率精确度直接影响电子钟计时的准确性。
2.单片机电子钟利用内部定时/计数器溢出发生中断(12M晶振一般为50ms)再乘以相应的倍率来实现秒、分、时的转换。
大家都知道从定时/计数器发生中断请求到响应中断需要3-8个机器周期,定时中断子程序中的数据入栈和重装定时/计数器的初值还需要占用数个机器周期,还有从中断入口转到中断子程序也要占用一定的机器周期。
3.3LCD显示电路部分
为了获得更好的效果本设计并没有采取罕见的LED,而是采取了型号为1602的LCD。
LCD有LED数码显示更好的更的直观效果,也更加经久耐用。
液晶显示模块体积小功耗低、显示内容丰富,现在字符型液晶显示模块已经是单片机应用设计中最经常使用的信息显示器件之一了。
本LCD是2行16列液晶可显示2行16列英文字符,有8位数据总线D0-D7,RS,R/W,EN三个控制端口(共14线),工作电压为5V。
没背光,和经常使用的1602B功能和引脚一样(除了调背光的二个线脚).该模块也可只用
D4-D7作为四位数据分两次传送。
这样的话可以节省MCU的I/O口资源。
引脚说明,见表。
VDD:
电源正极,4.5-5.5V,通常使用5V电压;
VL:
LCD对比度调节端,电压调节范围为0-5V。
接正电源时对比度最弱,接地电源时对比度最高,但对比度过高时会发生“鬼影”,因此通常使用一个10K的电位器来调整对比度或者直接串接一个电阻到地;
RS:
MCU写入数据或者指令选择端。
MCU要写入指令时,使RS为低电平;MCU要写入数据时,使RS为高电平;
R/W:
读写控制端。
R/W为高电平时,读取数据;R/W为低电平时,写入数据;
E:
LCD模块使能信号控制端。
写数据时,需要下降沿触发模块。
D0-D7:
8位数据总线,三态双向。
如果MCU的I/O口资源紧张的话,该模块也可以只使用4位数据线D4-D7接口传送数据。
本充电器就是采取4位数据传送方式;
BLA:
LED背光正极。
需要背光时,BLA串接一个限流电阻接VDD,BLK接地,实测该模块的背光电流为50mA左右;
BLK:
LED背光地端。
[12]
表LCD显示屏引脚说明
编号
符号
引脚说明
编号
符号
引脚说明
1
VCC
电源地
9
D2
双向数据口
2
VDD
电源正极
10
D3
双向数据口
3
VL
对比度调节
11
D4
双向数据口
4
RS
数据/命令选择
12
D5
双向数据口
5
R/W
读/写选择
13
D6
双向数据口
6
E
模块使能端
14
D7
双向数据口
7
D0
双向数据口
15
BLK
背光源地
8
D1
双向数据口
16
BLA
背光源正极
4软件设计
4.1软件设计概述
这里用汇编的单片机程序构成了本LCD电子闹钟的软件系统。
该程序实现时间及定时(时间以0点0分0秒为基准计算,闹铃定时以0时0分为基准计算)的显示,有外中断0和五个开关实现校时,闹钟功能。
其中程序的晶振频率为12MHz,最小计时单位为1/20秒。
主芯片p0.1-p0.7输出数据到LCD数据总线,p3.0-2.2输出LCD控制信号,P输出声音信号,.P1.0-P1.3输入外部控制信号,整个软件系统也是根据这个关系连接成一个完整的系统。
4.2主函数的设计
本LCD电子闹钟的的主程序流程图如图4.1所示:
CPU系统初始化
定时器0初始化
定时器1初始化
串口初始化
显示待机指示符
设定闹铃时间
判设置闹铃时间否?
显示刷新
启动走时
有关变量初始化
刷新显示
判断日期是否变更化否?
秒指示
判断时间是否变更
闹铃
判是否到闹铃时间?
延时
Y
Y
Y
Y
4.3.1程序初始化
液晶:
voidTimeInit()
{
write_com(0x01);//初始化1602液晶
write_com(0x80);//设置现实初始坐标
for(num=0;num<9;num++)//显示年月日
{
write_date(table[num]);
delay(5);
}
write_com(0x80+0x40+6);//写出时间显示部分的两个冒号
write_date(':
');
delay(5);
write_com(0x80+0x40+9);
write_date(':
');
delay(5);
write_sfm(4,shi);//分别送去液晶显示
write_com(0x80+0x40+4);
write_sfm(7,fen);
write_com(0x80+0x40+7);
write_sfm(10,miao);
write_com(0x80+0x40+10)
4.3.2闹钟的实现
闹钟功能的实现涉及到两个方面:
闹铃时间设定和是否闹铃判别与相应处理。
闹铃时间设定模块的设计可参照时间设定模块,这里着重论述闹铃判别与处理模块的设计问题。
闹铃判别与闹铃处理的关键在于判别何时要进行闹铃。
当时十位、时个位、分十位、分个位中任一位发生改变(进位)时,就必须进行闹铃判别。
程序设计思想如图。
[8]
时十位、个位,分十位、个位改变了
设置闹铃标记
是否设置了闹铃
清除闹铃标记
判当前时间是设定时间
中断返回
中断返回
Y
N
Y
闹铃判别处理
4.3.3显示程序
显示程序包含时钟显示和定时显示程序。
具体程序见附录。
液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标记为低电平,暗示不忙,否则此指令失效。
要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,表4.1是TC1602EL液晶模块的内部显示地址。
[15]
表4.1内部显示地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
00
01
02
03
04
05
06
07
08
09
0A
0B
0C
0D
0E
0F
40
41
42
43
44
45
46
47
48
49
4A
4B
4C
4D
4E
4F
硬件原理图
程序:
#include
#include"24C08.h"
#defineuintunsignedint
#defineucharunsignedchar
ucharcodetable[]="NOWTIME:
";
ucharcodetable1[]="SETNOWTIME:
";
ucharcodetable2[]="SETALARMTIME:
";
ucharcodealarm[]="ALARMTIME:
";
ucharcodealarmoff[]="ALARMTIME:
OFF";
ucharcodealarmon[]="ALARMTIME:
ON";
sbitlcden=P3^2;
sbitlcdrs=P3^0;
sbitlcdrw=P3^1;
sbitK1=P1^0;
sbitK2=P1^1;
sbitK3=P1^2;
sbitK4=P1^3;
sbitbeep=P2^1;
ucharflag,num,count,k1num,k2num,k3num,k4num;
charmiao,shi,fen,ashi,afen;
//延时函数
voiddelay(uintz)
{
uintx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
//蜂鸣器子程序
voiddi()
{
beep=0;
delay(100);
beep=1;
}
//写命令函数
voidwrite_com(ucharcom)
{
lcdrs=0;
lcdrw=0;
lcden=0;
P0=com;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
//写数据函数
voidwrite_date(uchardate)
{
lcdrs=1;
lcdrw=0;
lcden=0;
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
//写时间函数
voidwrite_sfm(ucharadd,uchardate)
{
ucharshi,ge;
shi=date/10;
ge=date%10;
write_com(0x80+0x40+add);
write_date(0x30+shi);
write_date(0x30+ge);
}
//显示时间初始化
voidTimeInit()
{
write_com(0x01);
write_com(0x80);
for(num=0;num<9;num++)
{
write_date(table[num]);
delay(5);
}
write_com(0x80+0x40+6);
write_date(':
');
delay(5);
write_com(0x80+0x40+9);
write_date(':
');
delay(5);
write_sfm(4,shi);
write_com(0x80+0x40+4);
write_sfm(7,fen);
write_com(0x80+0x40+7);
write_sfm(10,miao);
write_com(0x80+0x40+10);
}
//设置当前时间
voidSetNowTime()
{
if(K1==0)
{
delay(5);
if(K1==0)
{
while(!
K1);
di();
shi++;
if(shi==24)
shi=0;
write_sfm(4,shi);
write_com(0x80+0x40+4);
write_add(3,shi);
}
}
if(K2==0)
{
delay(5);
if(K2==0)
{
while(!
K2);
di();
fen++;
if(fen==60)
fen=0;
write_sfm(7,fen);
write_com(0x80+0x40+7);
write_add(2,fen);
}
}
if(K3==0)
{
delay(5);
if(K3==0)
{
while(!
K3);
di();
k1num=0;
TR0=1;
TimeInit();
}
}
}
//设置闹钟时间
voidSetAlarmTime()
{
flag=0;
if(K1==0)
{
delay(5);
if(K1==0)
{
while(!
K1);
di();
ashi++;
if(ashi==24)
ashi=0;
write_sfm(4,ashi);
write_com(0x80+0x40+4);
write_add(4,ashi);
}
}
if(K2==0)
{
delay(5);
if(K2==0)
{
while(!
K2);
di();
afen++;
if(afen==60)
afen=0;
write_sfm(7,afen);
write_com(0x80+0x40+7);
write_add(5,afen);
}
}
if(K3==0)
{
delay(5);
if(K3==0)
{
while(!
K3);
di();
k3num=0;
EA=1;
flag=1;
TimeInit();
}
}
}
//显示闹钟函数
voidDisplayAlarmTime()
{
write_com(0x01);
write_com(0x80);
for(num=0;num<11;num++)
{
write_date(alarm[num]);
delay(5);
}
write_com(0x80+0x40+6);
write_date(':
');
delay(5);
write_sfm(4,ashi);
write_com(0x80+0x40+4);
write_sfm(7,afen);
write_com(0x80+0x40+7);
}
//键盘扫描函数
voidkeyscan()
{
if(K1==0)
{
delay(5);
if(K1==0)
{
TR0=0;
while(!
K1);
di();
k1num++;
}
}
if(k1num!
=0)
{
write_com(0x80);
for(num=0;num<13;num++)
{
write_date(table1[num]);
delay(5);
}
SetNowTime();
}
else
{
if(K2==0)
{
delay(5);
if(K2==0)
{
while(!
K2);
di();
k2num++;
}
}
if(k2num==1)
{
EA=0;
DisplayAlarmTime();
k2num=2;
}
if(k2num==3)
{
k2num=0;
EA=1;
TimeInit();
}
else
{
if(K3==0)
{
delay(5);
if(K3==0)
{
while(!
K3);
di();
k3num++;
write_com(0x01);
}
}
if(k3num==1)
{
EA=0;
write_com(0x80);
for(num=0;num<15;num++)
{
write_date(table2[num]);
delay(5);
}
write_com(0x80+0x40+6);
write_date(':
');
delay(5);
write_sfm(4,ashi);
write_com(0x80+0x40+4);
write_sfm(7,afen);
write_com(0x80+0x40+7);
SetAlarmTime();
}
else
{
if(K4==0)
{
delay(5);
if(K4==0)
{
while(!
K4);
di();
k4num++;
}
}
if(k4num==1)
{
di();
k4num=2;
flag=0;
}
if(k4num==3)
{
k4num=0;
di();
delay(500);
di();
delay(500);
di();
flag=1;
}
}
}
}
if(flag==1&&shi==ashi&&fen==afen)
{
beep=~beep;
delay(500);
}
if(K4==0&&flag==1)
{
delay(5);
if(K4==0&&flag==1)
{
while(!
K4);
di();
flag=0;
k4num=0;
}
}
}
//lcd1602初始化
voidinit()
{
lcden=0;
shi=0;
fen=0;
miao=0;
ashi=0;
afen=0;
count=0;
k1num=0;
init_24c08();
write_com(0x38);//设置16X2显示,5X7点阵,8位数据接口
write_com(0x0c);//设置开显示,不显示光标
write_com(0x06);//写一个字符后地址指针加1
write_com(0x01);//显示清0,数据指针清0
miao=read_add
(1);//首次上电从AT24C08中读取出存储的数据
fen=read_add
(2);
shi=read_