基于单片机的电子钟设计报告.docx
《基于单片机的电子钟设计报告.docx》由会员分享,可在线阅读,更多相关《基于单片机的电子钟设计报告.docx(44页珍藏版)》请在冰豆网上搜索。
基于单片机的电子钟设计报告
物理机电学院课程设计报告
课程名称:
基于单片机的电子钟
系部:
物理与机电工程学院
专业班级:
09电子信息工程
(2)班
学生姓名:
///////////
指导教师:
王清辉
完成时间:
2012年3月18日
报告成绩:
评阅意见:
评阅教师日期
基于单片机的电子钟设计报告
一、设计任务与要求
基于单片机的电子钟,设计要求是
(1)具有小时分秒时间显示。
(2)能够设置闹钟至少5次闹钟时间。
(3)可利用按键修改时间,具有上午下午的提示信息。
二、方案设计与论证
本次方案的设计以单片机中的定时为主,分别实现时、分、秒、时、年、月、日上的显示和正常进位,在此基础上,总体方案可分为以下四个功能模块:
模块一:
计时功能模块,以微机开发系统中51单片机的定时功能为主,本次设计采用的计时方式为方式2,并且采用中断方式进行一秒计时,由于51单片机的功能特性的限制,计时的方案由采用100ms计时并且在这个基础上连续循环10次进行秒钟计时,在秒的基础上再分别进行其他时间单位的转化,如此逐渐递进实现总体时间计时的实现。
时进制采用24小时进制,年份显示只能实现0~~99之间的显示。
模块二:
显示功能模块,主要以微机开发系统中的七段液晶显示实现,显示的主要格式为“时/年—分/月—秒/日”,其中,年、月、日的显示由微机开发系统中的按键实现切换。
模块三:
闹钟功能模块:
以蜂鸣器的蜂鸣为标志,蜂鸣器工作则表示预定时间到达。
闹钟的设定由按键开关实现,闹钟的开关有拨键开关控制。
模块四:
控制功能模块:
主要以微机开发系统中的按键和拨键开关实现,按键开关主要用作时间设置,日期设置和闹钟设置以及对时间和日期的显示的转换。
拨键开关主要用来实现闹钟的开关设置。
在按键开关的防抖动处理上,以在程序中进行10ms的延时来进行处理。
电子钟的总体功能原理是以AT89S51单片机为主要的控制核心,通过外接8个独立式键盘作为控制信号源,两个四位一体数码管作为显示器件,单片机实时的去执行相应的功能。
在数码管上显示出来,此时通过不同的按键来观察和调节各种数据
三、硬件电路设计
3.1硬件功能模块介绍
3.1.1时钟功能模块
时钟电路用于产生MCS-51单片机工作时所需要的时钟控制信号,MCS-51单片机的内部电路在时钟信号控制下,严格地按照时序执行指令进行工作,而时序所研究的是指令执行中各个信号在时间上的关系。
单片机各个功能部件的运行都是以时钟控制信号为基准,有条不紊的一拍一拍地工作。
因为,时序频率直接影响单片机的速度。
时钟电路通过在芯片的外部XTAL1和XTAL2两个引脚跨接晶体振荡器和微调电容,形成反馈电路,就构成了一个稳定的自激振荡电路。
时钟电路为单片机产生时钟脉冲序列,晶振频率为12MHz。
3.1.2键盘功能模块
为了方便时钟调整与秒表的控制,在单片P1口口线上接了独立键盘,采用低电平有效地方法。
在本次电子钟设计中,调整是与键盘脱不了关系的,因为键盘是机械按钮,所以在触点闭合及释放的瞬间将出现电压抖动,所以在键扫描时应该要消除抖动,而且对于一键多功能的按钮必须要判释放,以免某个程序段多次执行。
3.1.3数码管显示模块
数码管显示器是单片机重要的输出设备,它不仅具有发光响应快,高频特性好,而且机械性能好,工作电压低,随着工艺发展,可以发出不同颜色的光。
在本次设计中,采用共阳极数码管,利用三极管驱动器段控口以便LED发出较亮的光。
在本次设计中采用了两个四位一体数码管,数码管的段控接在AT89S52单片机的P0口线上,从a到dp与P0.0到P0.7对应连接,位控制线接在AT89S52单片机的P2口线上,从LED0到LED7与P2.0到P2.7对应连接
3.1.4复位电路模块
复位是单片机的初始操作,其主要功能是把PC初始化为0000H,使单片机从0000H单元开始执行程序。
除了进入系统的正常初始化之外,当由于程序运行出错或操作错误使系统处于死锁状态时,为摆脱困境,也需安装复位键以重新启动。
复位操作有上电自动复位和按键手动复位两种方式。
复位电路通过极性电容和1个电阻串联,电容接VCC,电阻接地完成了上电复位,在电容两端并联一个电阻就可以实现按键电平复位。
3.2原理图、PCB图、元器件布局图
3.2.1电路原理图
3.2.2PCB图
3.2.3原件清单
元件序号
型号
主要参数
数量
1
电阻
1K
1个
2
电阻
200欧
1个
3
瓷片电容
104
1个
4
瓷片电容
30PF
2个
5
三极管
Pnp9012
1个
6
蜂鸣器
5V
1个
7
晶振
12M
1个
8
轻触按键
6个
9
单片机
STC89S51
1个
10
排阻
10K
1排
11
排针
4个
12
IC座
40脚
1个
13
蓝白可调
1个
14
LCD1602
1个
15
1602液晶插针
1个
四、软件设计
4.1单片机资源使用说明
(1)单片机片内定时/计数器0:
用于定时50ms。
(2)单片机片内定时/计数器1:
用于定时10ms。
(3)单片机P1口接按键:
用于对电子钟、秒表调整与控制
(4)单片机P0口接数码管段控口:
P0.0~P0.7对应于LED的a~dp
(5)单片机P2口接数码管位控:
P2.7~P2.0对应于LED的7~0
(6)单片机P3.1接蜂鸣器:
作为电子钟调整时提醒信号
4.2软件系统各模块功能介绍
(1)主程序模块:
程序的初始化及复位后显示P.,此时进入功能选择状态,按下K0选择电子钟并同时启动电子钟,按下K1选择秒表并进入秒表等待状态。
两功能中一种功能被选择与令外一种功能无半点关系,两者是互不影响。
(2)电子钟程序模块:
当电子钟选择键按下时,先给缓冲区内清零,在通过查表给缓冲区一次送00-00-00并实现让00-00-00从左向右显示,一旦显示完则开启定时器开始计时,如果没有键按下则不断计时一直从00-00-00到23-59-59,然后重新从00-00-00开始。
这里采用定时器中断完成计时功能。
如果有键按下则启动2s定时,累计2s内K0按下的次数,按下1次则进入调秒状态,按下2次则进入调分状态,按下3次则进入调时,按下多次则无效,进入调整状态时,调整的改两位闪动显示并且蜂鸣器鸣叫以示提醒,次数按下K0键作为确认,按下K1就加1,按下K2就减1。
(3)秒表程序模块:
当秒表选择键按下时,先给缓冲区送灭代码序号。
再依次送00H代码序号以实现00000000依次从右向左显示,显示到最左端则进入秒表等待状态。
按下K1开始计时,秒表最小计时单元是0.01s,采用定时器中断的方法。
秒表运行时再次按下K1键则暂停计时,此时可以选择继续和重新计时,分别按K1和K0。
(4)主要子程序模块:
为了方便软件程序编写,编写了许多子程序,有键扫描程序,用来判是否有键按下;有显示子程序,用于数码管的显示;有加1、减1子程序,用于对电子钟时分秒的调整;还有延时程序,用于数码管动态显示、键扫描消抖动、延时。
4.3软件系统程序流程框图
主程序流程框图如图3.1所示
电子钟功能程序流程框图如下图3.2所示,左半部分为定时器0中断服务程序,右部分为电子钟主体程序。
图3.2整个电子钟程序框图
4.4软件系统的程序
#include
#defineucharunsignedchar
#defineuintunsignedint
sbitlcden=P3^4;
sbitrs=P3^5;
sbitFM=P2^3;
sbits4=P1^3;
sbits1=P1^0;
sbits2=P1^1;
sbits3=P1^2;
ucharcount,date,s1num,temp,csnum;
uintnian=2012;
charyue=03,ri=22,xq=2,shi,fen,miao,shi_c,fen_c,s_c[5],f_c[5],num_c=1,ri_c;
bitflag,setpage,shuaxin;
ucharcodetable[]="2012.03.22Thu";
ucharcodetable1[]="00:
00:
00";//初始化要在这里改数值
ucharcodetable3[]="HELLO!
!
^_^!
!
!
";//
ucharcodetable4[]="welcome!
";
ucharcodetable5[]="Successfully";
ucharcodetable6[]="Saved!
!
^_^";
ucharcodetable7[]="am";
ucharcodetable8[]="pm";
ucharcodetable9[]="";
voidkeyscan();
voiddelay(uintz);
voidwrite_com(ucharcom);
voidwrite_date(uchardate);
voidwrite_sfm(ucharadd,uchardate);
voidword(ucharadd,unsignedchar*str);//写字符串
voidwrite_nyr(ucharadd,uchardate);
voidwrite_nian();
voidinit();
voidclock();
voidwelcome();
voidbeep(uchart);
voiddelay1(uintz);
voidsave();
voidmyupdate();
voidcolon();
voidmychar();
voidmain()
{
welcome();
delay(500);
init();
while
(1)
{
keyscan();
clock();//执行闹钟程序
//以下为时钟程序
if((miao%2)&&csnum==0)
{
colon();
mychar();
}
if(count>=20)
{
count=0;
miao++;
if(miao==60)//如果秒不到60,则只刷新秒
{
miao=0;
fen++;
if(fen==60)
{fen=0;
shi++;
if(shi==24)
{
shi=0;
xq++;
write_com(0x80+12);
if(xq==8)xq=1;if(xq==1)word(12,"Mon");
if(xq==2)word(12,"Tue");
if(xq==3)word(12,"Wed");
if(xq==4)word(12,"Thu");
if(xq==5)word(12,"Fri");
if(xq==6)word(12,"Sat");
if(xq==7)word(12,"Sun");
ri++;//接下来要大小月,在二月时要判断是否闰年
//如果是闰年,则为29天
if(yue<=7)
{
temp=yue%2;
switch(temp)
{
case0:
//0为小月
if(yue==2)//如果为二月,则判断是不是闰年,是为29天,不是为28天
{
if((nian%4==0)&&nian%100!
=0||(nian%400==0))
{
if(ri==30)
{
ri=1;
yue++;
write_nyr(6,yue);
}
}
else
{
if(ri==29)
{
ri=1;
yue++;
write_nyr(6,yue);
}
}
}//if(yue==2)
if(ri==31)
{
ri=1;//yue++
yue++;
if(yue==13)
{
yue=1;
nian++;
write_nian();
}
write_nyr(6,yue);
}
break;
case1:
//1为大月
if(ri==32)
{
ri=1;
yue++;
if(yue==13)
{
yue=1;
nian++;
write_nian();
}
write_nyr(6,yue);
}
break;
}
}//if(yue<=7)
if(yue>7)
{
temp=yue%2;
switch(temp)
{
case0:
//0为大月
if(ri==32)
{
ri=1;//yue++
yue++;
if(yue==13)
{
yue=1;
nian++;
write_nian();
}
write_nyr(6,yue);
}
break;
case1:
//1为小月
if(ri==31)
{
ri=1;//yue++
yue++;
if(yue==13)
{
yue=1;
nian++;
write_nian();
}
write_nyr(6,yue);
}
break;
}
}//if(yue>7)
write_nyr(9,ri);
}//if(shi==24)
if(shuaxin==0)write_sfm(4,shi);
}//if(fen==60)
if(shuaxin==0)write_sfm(7,fen);
}//if(miao==60)
if(shuaxin==0)write_sfm(10,miao);
}//if(count==20)
}//while
(1)
}
voiddelay(uintz)
{
intx,y;
for(x=110;x>0;x--)
for(y=z;y>0;y--);
}
voidwrite_com(ucharcom)//写指令函数
{
rs=0;
lcden=0;
P0=com;
delay
(2);
lcden=1;
delay
(2);
lcden=0;
}
voidwrite_date(uchardate)//写数据函数
{
rs=1;
lcden=0;
P0=date;
delay
(2);
lcden=1;
delay
(2);
lcden=0;
}
voidinit()
{
ucharnum;
write_com(0x38);//显示模式设置
write_com(0x0c);//光标设置
write_com(0x06);//光标指针设置
write_com(0x01);//显示清屏
write_com(0x80);//从第一行开始写
for(num=0;num<15;num++)
{
write_date(table[num]);
delay
(2);
}
write_com(0x80+0x40);//从第二行开始写
for(num=0;num<12;num++)
{
write_date(table1[num]);
delay
(2);
}
for(num=0;num<5;num++)//初始化闹钟存放数组
{
s_c[num]=0;
f_c[num]=0;
}
RCAP2H=(65536-50000)/256;
RCAP2L=(65536-50000)%256;//设置自动重装初值
T2CON=0x04;//启动定时器
EA=1;//总中断
ET2=1;//开定时器中断
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=0;
ET0=1;
}
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);
}
voidwrite_nyr(ucharadd,uchardate)//写月日
{
ucharshi,ge;
shi=date/10;
ge=date%10;
write_com(0x80+add);
write_date(0x30+shi);
write_date(0x30+ge);
}
voidwrite_nian()
{
ucharshi,ge;
shi=nian%100/10;
ge=nian%10;
write_com(0x80+1);
write_date(0x30+2);
write_date(0x30);
write_date(0x30+shi);
write_date(0x30+ge);
}
voidword(ucharadd,unsignedchar*str)//写字符串,如"MON"
{
while(*str!
='\0')
{
write_date(*str++);
}
*str=0;
write_com(0x80+add);
}
voidkeyscan()
{
if(s1==0)//ok
{
delay(5);
if(s1==0)
{
shuaxin=1;
s1num++;
while(!
s1);//为假就退出,松手后即为假
beep
(1);
if(csnum==1)
{
csnum=2;
}
if(csnum==0)//刚开始一定要执行的
{
write_com(0x01);
write_com(0x0f);
write_com(0x80+4);
word(4,"a.Time");
write_com(0xc0+4);
word(0x44,"b.Clock");
write_com(0x84);//光标停在时间那里
csnum=1;
flag=1;
}
if(csnum==2)//调时间
{
//************************//调时间画面初始化
while(setpage==0)
{
flag=0;
write_com(0x01);//显示清屏
myupdate();
write_com(0x0f);//光标闪烁
setpage=1;//setpage为1,则不用再次初始化调时画面
}//while(setpage==0)
//*************************
if(s1num==1)//调秒
{
TR2=0;
shuaxin=1;
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)//调日
{
write_com(0x80+9);
}
if(s1num==6)//调月份
{
write_com(0x80+6);
}
if(s1num==7)//调年
{
write_com(0x80+3);
}
if(s1num==8)
{
save();
myupdate();
TR2=1;
s1num=0;
csnum=0;//调完会到初始状态