电子时钟设计及程序
电子时钟设计及程序
电子时钟设计
简介
该设计主要由单片机AT89C51和液晶显示器组成,实现常用的实时电子钟功能。利用可编程芯片AT89C51强大的功能,我们了实现日历功能、时钟功能。该时钟使用液晶显示器作为显示模块,使用3个弹性小按键作为输入模块,调节年、月、日、星期、时、分、秒。
一. 方案比较与论证
根据设计要求,该时钟系统可分输入部分、处理部分和显示数据部分。其中输入部分是键盘输入数据调整要显示的内容,处理部分单片机接收并通过算法处理键盘输入的信息变成显示模块所能接受的信息,显示部分是用来实时显示处理部分处理后的数据。
处理显示
输入模块我们选用三个独立弹性小按键来实现,选用矩阵式键盘则太浪费资
处理模块我们选用了STC公司的STC89C52芯片来,与Atmel公司生产的
AT89S52一样,也是40脚双列直插式封装,这里芯片对刚学单片机的人来说容易入手,其功能也很强大,用来实现一个电子钟完全足够了。
显示部分我们可有两种选择:数码管和1602液晶显示器。实现一个电子钟
若用数码管则需6个,所占空间相对大了些,而且我们还要实现日历的功能,需要更多的数码管,所点空间翻倍,而且还会造成单片机I/O引脚滥用甚至不够用,用液晶显示器来实现则方便得多,界面也相对友好,但液晶显示器有个缺点就是价格比较贵。因此我们最终选择了1602液晶显示器。另处独立弹性小
按键具有价格便宜、容易获得、容易控制等特点。
二. 系统理论分析、计算与电路仿真
1、定时器与中断原理
电子钟主要是利用单片机的定时器/计数器和中断来实现。定时器实际是加1计数器,单片机每运行一个机器周期定时器就自动加1,当计到所定的数N时, 单片机就产生一次中断,停下所做的工作,转而去执行中断服务程序。单片机
每个机器周期等于外部晶振的12个振荡周期,当外部晶振是12MHz 时,则每个 机器周期的时间是
T cy = 12 X 1/12=1 um (2-1 )
定数器设为N 时,即每计到N 时产生一次中断,而一次中断的时间为:
t = N X T cy u m (2 -2)
当产生X (x 根据N 来设置,两者之积为1000000)次中断后我就知道过了 1s , 再通过液晶显示出来,这样就达到了让液晶每隔一秒跳一下的目的了。
2、proteus 仿真结果 ? KITTLED - Id Pr^i.^ri 丹 1?
河| 十* Ldc 序", ■'碎 JT 孕 I 巾即F 打寸:l 屮卩
1;占? 鼻旳 轴导 J]';'
+ + A ■? 4? M X 丄?l
| 卜 | |* | W I . ■ $比记仔利 J :r1H i-i.. .ih ::MJk=-iiii
3、液晶部分
图4-3
液晶1、2端口分别是工作电源的负、正极,15、16是液晶背光灯电源正负 极,R4起限流作用,避免电流过大烧坏背光灯。第 3端口还可接一电位器,调 节液晶显示对比度。无标号的 8个端口是数据端,通过一上拉电阻接到单片机 的
WAI *r-m
Hun
FPITiB PM r r Fi
PM Mf
lifl
W 冲口 FTD
Ku 心
W?W>I rv
Pl 1i*
mufE
LCD1-
?卫
F^I^IL
n??H
pjJjwiiS
2VI2-OT-0S SAI
12ISSISI
竺-
--
三. 系统的软件设计(如必要,含有流程图)
1、程序流程图
流程图中的X 表示液晶中秒、分、时、星期、年、月、日中的任一个 扫描键
盘是否
---- 1 Y
往液晶送
图5-2扫描键盘的子程序流程
四. 系统测试及结果
测试结果总的来说很满意,比预计的还要好。但由于中断函数中代码较长, 故存在一定程度的误差,用秒表测试大约为每 5分钟慢了一秒,这个问题是用 单片机定时器来数时所无法解决的,中断函数必定会较长,处理这一函数会花 费一定的时间这就无法做到让时钟走得很精确。解决方法是用一时钟芯片来实 现,由于时钟芯片不好买又比较贵(新的 20几块一片),暂时就不考虑了,有 机会再尝试。
1. 源程序
〃主函数放在最后面
#in elude
#defi ne uchar un sig ned char
r
■
1 丿
厶士
图5-1主程序流程图
#define uint unsigned int
sbit rs=P2人4;〃定义液晶数据命令选择端sbit Icden=P2八5;//液晶使能端
sbit s1=P2A0;// 按键 1
sbit s2=P2A1;// 按键 2
sbit s3=P2A2;// 按键 3
uchar count,s1num;
char shi,fen,miao;// 时、分、秒
char year,month,day,week;// 年月日星期
void deIay(uint x)// 延时子程序
{
uint j,k;
for(j=x;j>0;j--)
for(k=110;k>0;k--); }
// - 液晶写命令功能--
void write_com(uchar com) {
rs=0;
lcden=0;
P0=com;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
//--- 液晶写数据功能
void write_date(uchar date)
{
rs=1;
lcden=0;
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
// ----- 写入时、分、秒 ----?
void write_sfm(uchar add,uchar date) uchar shi,ge;
shi=date/10;
ge=date%10;
write_com(0x80+0x40+add);
write_date(0x30+shi);
write_date(0x30+ge);
}
// ---- 写入年、月、日------
void write_nyr(uchar add,uchar date) { uchar shi,ge;
shi=date/10;
ge=date%10;
write_com(0x80+add);
write_date(0x30+shi);
write_date(0x30+ge);
}
// -------- 写入星期X ----------
void write_week(uchar we)
{
write_com(0x80+12);
switch(we)
{
case 1: write_date('M');delay(5);
write_date('O');delay(5);
write_date('N'); break;
case 2: write_date('T');delay(5);
write_date('U');delay(5);
write_date('E');
break;
case 3: write_date('W');delay(5);
write_date('E');delay(5);
write_date('D');
break;
case 4: write_date('T');delay(5);
write_date('H');delay(5);
write_date('U'); break;
case 5: write_date('F');delay(5);
write_date('R');delay(5);
write_date('I');
break;
case 6: write_date('S');delay(5);
write_date('A');delay(5);
write_date('T');
break;
case 7: write_date('S');delay(5);
write_date('U');delay(5);
write_date('N');
break;
}
}
// -- 实现初始化功能---
void init()
{
lcden=0;
shi=1;
fen=1;
miao=1;
day=1;
month=1;
year=1;
week=1;
count=0; s1num=0; write_com(0x38);
write_com(0x0c); write_com(0x06);
write_com(0x01); write_com(0x80+1);
write_date('2');
write_com(0x80+2);
write_date('0');
write_com(0x80+5);
write_date('-');
write_com(0x80+8); write_date('-');
write_nyr(9,day);
write_nyr(6,month); write_nyr(3,year); write_week(week);
write_com(0x80+0x40+6); write_date(':');
write_com(0x80+0x40+9);
write_date(':');
write_sfm(10,miao);
write_sfm(7,fen);
write_sfm(4,shi);
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;
ET0=1;
TR0=1;
}
// ------- 键盘扫描功能 ---------
void keyscan()
{
if(s仁=0)//键盘1是否被按下
delay(5);// 如果检测到键盘被按下,延时约if(s1==0)//5 毫秒看是否为键下,这样可越
过按
{ // 键盘时的抖动时间,防止误判s1num++;
while(!s1);
if(s1num==1)
{
TR0=0; write_com(0x80+0x40+10);
write_com(0x0f);
}
if(s1num==2)
{ write_com(0x80+0x40+7);
}
if(s1num==3)
{
write_com(0x80+0x40+4);
}
if(s1num==4)
write_com(0x80+12); } if(s1num==5)
{
w
r
i
t
e
_
c
o
m
(
x
8
+
9
)
;
} if(s1num==6)
{
w
r
i
t
e
_
c
o
m
(
x
8
+
6
)
;
} if(s1num==7) {
w
r
i
t
e
_
c
o
m
(
x
8
+
3
)
;
} if(s1num==8)
{ s1num=0; write_com(0x0c); TR0=1;
}
}
}
if(s1num!=0)// 键盘 2 是否被按下
{
if(s2==0)
{
delay(5);
if(s2==0)
{
while(!s2);
if(s1num==1)
{
miao++; if(miao==60) miao=0;
write_sfm(10,miao);
write_com(0x80+0x40+10);
}
if(s1num==2)
{
fen++;
if(fen==60)
fen=0; write_sfm(7,fen);
write_com(0x80+0x40+7);
}
if(s1num==3)
{
shi++;
if(shi==24)
shi=0;
write_sfm(4,shi);
write_com(0x80+0x40+4); }
if(s1num==4)
{
week++;
if(week==8)
week=1;
write_week(week);
write_com(0x80+12);
}
if(s1num==5)
{
day++;
if(day==32)
day=1; write_nyr(9,day);
write_com(0x80+9);
}
if(s1num==6)
{
month++;
if(month==13)
month=1;
write_nyr(6,month);
write_com(0x80+6); }
if(s1num==7)
{
year++;
if(year==100)
year=0; write_nyr(3,year);
write_com(0x80+3);
}
if(s3==0)〃键盘3是否被按下
{
delay(5);
if(s3==0)
{
while(!s3);
if(s1num==1)
{
miao--;
if(miao==-1)
miao=59; write_sfm(10,miao);
write_com(0x80+0x40+10);
}
if(s1num==2)
{
fen--;
if(fen==-1)
fen=59;
write_sfm(7,fen);
write_com(0x80+0x40+7); if(s1num==3)
{
shi--;
if(shi==-1)
shi=23;
write_sfm(4,shi);
write_com(0x80+0x40+4); }
if(s1num==4)
{
week--;
if(week==0)
week=7;
write_week(week);
write_com(0x80+12);
}
if(s1num==5)
{
day--;
if(day==0) day=31;