基于C51的电子钟设计Word文档格式.docx
《基于C51的电子钟设计Word文档格式.docx》由会员分享,可在线阅读,更多相关《基于C51的电子钟设计Word文档格式.docx(24页珍藏版)》请在冰点文库上搜索。
图2.3掉电保护电路
2.3独立键盘设计
此键盘是为设置时间而设计的人机交互装置。
虽然矩阵键盘操作方便,但其硬件电路和软件都较复杂,考虑各方面因素,最终决定采用独立键盘,这样的话只需三个按键即可。
电路如下列图所示
图2.4键盘电路
其中,按下set键进入时间设置方式,此时默认设置秒,按add键进展加1设置,按minus键进展减1设置,再次按下set键进入分设置,以此类推,直至年设置完成后再次按下set键,进入正常模式。
2.4显示电路设计
由于要显示年、月、日、时、分、秒,因此需14个8段数码管进展显示,为了节省单片机的I/O端口,本设计采用动态扫描的方式进展显示。
图2.5显示电路
其中,单片机的P0口与三个锁存器并行连接,P2.0,P2.1,P2.2分别作为它们的片选信号,锁存器U1的输出连接7段显示的8个引脚,锁存器U2,U3的输出分别作为14个7段显示的位选信号。
3软件设计
本设计的软件局部采用C语言编写,并将其模块化,在主程序中进展调用。
在主程序中首先要完成初始化工作,然后进入循环阶段,它包括对年月日时分秒的动态扫描子函数以及时钟设置子函数的循环调用,虽然主程序不断调用设置子函数,但只有当按下set键时才真正进入设置函数的内部,由于设置函数并不影响显示函数,因此设置时间日期的同时,可以在数码管上实时观测。
这样一来,主程序实际上主要完成数码管的动态扫描过程,与此同时,内部定时器在不断地工作着,每到1s就进入中断子程序,由CPU。
首先对电子钟的主程序进展分析,然后对各个子函数进展说明,主程序的流程图如下
图3.1主程序流程图
以下对各个模块的子函数进展说明。
3.1初始化子函数
此函数中要对各个变量和定时器进展初始化,具体流程图如下
图3.2初始化子函数流程图
其中,定时器为1s计时,1s过后引起中断,CPU进展相应的处理,本设计采用定时器0,且将其设置为方式1,由于晶振为12MHz,因此设置初值为50000,当其有20次中断时,那么1s时间到。
3.2显示子程序
本函数包括6个小局部,分别为年月日时分秒显示,在此以秒显示为例进展介绍。
由于本设计采取动态扫描的方式,因此年月日时分都采用类似的方法显示,且循环调用显示子函数以实现动态扫描。
3.3设置时间日期子函数
本函数的流程图如下
其中,flag为标志变量,当set键按下时,flag自加1,CPU会根据它的数值去判断设置哪一个变量,当flag的值到达7时,将其清0。
4优缺点分析
本设计的硬件电路简单可行,只需3个锁存器和14个7段显示数码管即可显示年月日时分秒,采用3个独立按键即可实现时间日期的修改;
软件局部采用C语言编程,应用模块化编程思想,使得程序主次清楚,构造清晰,并且具有平年、闰年、大月、小月的判断,采用动态扫描显示节省了单片机的I/O端口。
由于时间的限制,本设计还有许多地方有待于完善,例如参加蜂鸣器及相应的软件即可实现闹钟功能,参加相应的算法即可实现星期的显示,参加温度传感器及相应的算法处理即可实现温度的实时显示等等。
5学习心得
本人是单片机的初学者,赵教师理论联系实际的讲课方式很吸引我,每个例子都是以一个实际的工程为背景的,这使得我对单片机的学习不再那么枯燥无味,相反地,我对单片机产生了浓厚的兴趣。
赵教师不仅具有独到而生动的授课方式,而且还给我们传授很多思想,这些思想不仅有助于我们做学问,而且会受益终生。
通过这次课程学习,我掌握了单片机的根本原理、功能及其应用,能够熟练应用汇编和C语言进展编程。
此次电子钟的设计让我稳固了模拟电路、数字电路及单片机的理论知识,也让我体会到设计一个系统的大致流程,感触很深。
学无止境,我会在今后的日子里不断学习,提高自己。
附录1:
硬件完整电路
附录2:
源程序
#include<
reg52.h>
#defineucharunsignedchar
#defineuintunsignedint
inti,sec,min,h,date,month,year,flag;
sbitdula=P2^0;
sbitwela1=P2^1;
sbitwela2=P2^2;
sbitkey_ch=P3^5;
sbitkey_add=P3^6;
sbitkey_minus=P3^7;
ucharcodetable[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f};
//数码管显示的数字对照表
voidinit();
voiddelay(uint);
voidsecond_display();
voidminute_display();
voidhour_display();
voiddate_display();
voidmonth_display();
voidyear_display();
voidcontrol();
voidtime();
voidmain()
{
init();
while
(1)
{
second_display();
minute_display();
hour_display();
date_display();
month_display();
year_display();
control();
}
}
voidinit()//初始化子函数
i=0;
sec=0;
min=0;
h=0;
date=1;
month=1;
year=1;
flag=0;
wela1=0;
wela2=0;
EA=1;
ET0=1;
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=1;
voiddelay(uintz)//延时子函数
uintx,y;
for(x=z;
x>
0;
x--)
for(y=110;
y>
y--);
voidsecond_display()//秒显示
intsec_shi,sec_ge;
sec_shi=sec/10;
//取十位
sec_ge=sec%10;
//取个位
dula=1;
//段选
P0=table[sec_ge];
dula=0;
wela2=1;
//位选
P0=0xdf;
//给锁存器U2送11011111,选中第14个数码管
delay
(1);
P0=table[sec_shi];
P0=0xef;
//给锁存器U2送11101111,选中第13个数码管
voidminute_display()//分显示
intmin_shi,min_ge;
min_shi=min/10;
min_ge=min%10;
P0=table[min_ge];
P0=0xf7;
//给锁存器U2送11110111,选中第12个数码管
P0=table[min_shi];
P0=0xfb;
//给锁存器U2送11111011,选中第11个数码管
voidhour_display()//时显示
inth_shi,h_ge;
h_shi=h/10;
h_ge=h%10;
P0=table[h_ge];
P0=0xfd;
//给锁存器U2送11111101,选中第10个数码管
P0=table[h_shi];
P0=0xfe;
//给锁存器U2送11111110,选中第9个数码管
voiddate_display()//日显示
intdate_ge,date_shi;
date_shi=date/10;
date_ge=date%10;
P0=table[date_ge];
wela1=1;
//给锁存器U1送01111111,选中第8个数码管
P0=table[date_shi];
P0=0xbf;
//给锁存器U1送10111111,选中第7个数码管
voidmonth_display()//月显示
intmonth_ge,month_shi;
month_shi=month/10;
month_ge=month%10;
P0=table[month_ge];
P0=0xdf;
//给锁存器U1送11011111,选中第6个数码管
P0=table[month_shi];
//给锁存器U1送11101111,选中第5个数码管
voidyear_display()//年显示
intyear_qian,year_bai,year_shi,year_ge;
year_qian=year/1000;
year_bai=year%1000/100;
year_shi=year%1000%100/10;
year_ge=year%10;
P0=table[year_ge];
//给锁存器U1送11110111,选中第4个数码管
P0=table[year_shi];
//给锁存器U1送11111011,选中第3个数码管
P0=table[year_bai];
//给锁存器U1送11111101,选中第2个数码管
//给锁存器U1送11111110,选中第1个数码管
voidcontrol()//时间日期调整
if(!
key_ch)//set键按下
delay(5);
//去抖
if(!
key_ch)
{
flag++;
if(flag==7)
flag=0;
}
while(!
key_ch);
//松手检测
if(flag==1&
&
key_add==0)//设置秒加1
while(!
key_add);
sec++;
if(sec==60)
sec=0;
key_minus==0)//设置秒减1
key_minus);
sec--;
if(sec==-1)
sec=59;
if(flag==2&
key_add==0)//设置分加1
min++;
if(min==60)
min=0;
key_minus==0)//设置分减1
min--;
if(min==-1)
min=59;
if(flag==3&
key_add==0)//设置时加1
h++;
if(h==24)
h=0;
key_minus==0)//设置时减1
h--;
if(h==-1)
h=23;
if(flag==4&
key_add==0)//设置日加1
date++;
if((date==29))//平年2月判断
if((year%4!
=0)&
(month==2))
date=1;
if((date==30))//闰年2月判断
if((year%4==0)&
if((date==31))//小月判断
if((month==4)||(month==6)||(month==9)||(month==11))
if((date==32))//大月判断if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))
if(flag==5&
key_add==0)//设置月加1
month++;
if(month==13)
month=1;
if(flag==6&
key_add==0)//设置年加1
year++;
if(year==99)
year=0;
key_minus==0)//设置年减1
year--;
if(year==0)
year=99;
voidT0_rpt()interrupt1//定时器0中断子函数
//重新装入初始值
i++;
time();
voidtime()
if(i==20)
i=0;
sec++;
if(sec==60)
{
sec=0;
min++;
if(min==60)
min=0;
h++;
if(h==24)
{
h=0;
min=0;
sec=0;
date++;
if((date==29))//平年2月判断
if((year%4!
{
date=1;
month++;
if(month==13)
{
month=1;
year++;
}
}
if((date==30))//闰年2月判断
if((year%4==0)&
}
if((date==31))//小月判断
if((month==4)||(month==6)||(month==9)||(month==11))
if((date==32))//大月判断
if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))
}
}