全功能数字电子钟的设计.docx

上传人:b****0 文档编号:17824932 上传时间:2023-08-04 格式:DOCX 页数:43 大小:996.82KB
下载 相关 举报
全功能数字电子钟的设计.docx_第1页
第1页 / 共43页
全功能数字电子钟的设计.docx_第2页
第2页 / 共43页
全功能数字电子钟的设计.docx_第3页
第3页 / 共43页
全功能数字电子钟的设计.docx_第4页
第4页 / 共43页
全功能数字电子钟的设计.docx_第5页
第5页 / 共43页
全功能数字电子钟的设计.docx_第6页
第6页 / 共43页
全功能数字电子钟的设计.docx_第7页
第7页 / 共43页
全功能数字电子钟的设计.docx_第8页
第8页 / 共43页
全功能数字电子钟的设计.docx_第9页
第9页 / 共43页
全功能数字电子钟的设计.docx_第10页
第10页 / 共43页
全功能数字电子钟的设计.docx_第11页
第11页 / 共43页
全功能数字电子钟的设计.docx_第12页
第12页 / 共43页
全功能数字电子钟的设计.docx_第13页
第13页 / 共43页
全功能数字电子钟的设计.docx_第14页
第14页 / 共43页
全功能数字电子钟的设计.docx_第15页
第15页 / 共43页
全功能数字电子钟的设计.docx_第16页
第16页 / 共43页
全功能数字电子钟的设计.docx_第17页
第17页 / 共43页
全功能数字电子钟的设计.docx_第18页
第18页 / 共43页
全功能数字电子钟的设计.docx_第19页
第19页 / 共43页
全功能数字电子钟的设计.docx_第20页
第20页 / 共43页
亲,该文档总共43页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

全功能数字电子钟的设计.docx

《全功能数字电子钟的设计.docx》由会员分享,可在线阅读,更多相关《全功能数字电子钟的设计.docx(43页珍藏版)》请在冰点文库上搜索。

全功能数字电子钟的设计.docx

全功能数字电子钟的设计

 

课程设计

 

课程:

单片机原理与应用

题目:

全功能数字电子钟

专业:

计算机科学与技术

班级:

座号:

姓名:

 

2011年12月12日

设计题目:

全功能数字电子钟

一、设计目的:

通过单片机应用产品的设计与调试过程,巩固课程所学理论知识,初步了解单片机应用系统设计与调试的方法。

二、设计要求:

设计一个以AT89S51单片机为核心的数字电子钟控制器,实现电子钟的时间、日期交替显示、闹钟功能,并可通过按钮开关或键盘切换显示内容、调整参数、设置闹钟,在单片机实验板上模拟调试实现控制器的功能。

具体设计要求如下:

1.开机自检,检查相关接口及数码管显示器、指示灯、蜂鸣器等外设是否正常。

2.8位数码管显示器平常以一定的时间间隔、合适的格式显示时间和日期信息,时间显示时、分、秒;日期显示年(2000~2099)、月、日;设置闹钟功能时显示时、分、开/关状态。

3.可通过按键设定时间、日期、闹钟等参数、手动切换显示。

按键可用独立式按键或行列式键盘实现。

设定参数过程有合适的方式指示当前可修改的内容。

4.对开关量输入进行软件消抖动处理,参数的设定有容错处理,如:

小时不能超过23,日期中每月最大天数、闰年等。

5.用Protel设计可实现上述功能的控制器的原理图(最小应用系统)。

扩展功能(选做):

1.可设置多次闹钟。

2.显示星期功能。

3.参数设定过程中,较长时间无操作,则自动恢复为正常显示方式。

4.其它自选的扩展功能。

三、总体方案设计及说明

总体功能框图:

闹钟报警

LED显示

走时

键盘输入

参数设置

 

硬件:

8个LED采用动态扫描以节约驱动成本;

走时采用内部T0计时中断;

4x4矩阵键盘扫描采用线反转法,以中断扫描计数防止抖动;

……

软件:

采用C语言实现。

四、系统资源分配说明(接口、存储器分配)

1.接口:

89S51的P1口接8个LED小灯;

89S51的P3_2接蜂鸣器(低电平鸣响);

外扩一片8255:

89S51单片机的P0口是低8位地址与数据复用的,现在我们用74HC373分离出地址,89S51高位地址的P2_0(A8)接8255的片选端(/CS),低位地址Q1Q0(A1A0)与8255的A1A0连接,数据位P0_7~P0_0分别接8255的D_7~D_0。

以此得到的8255端口的地址分别为:

PA:

xxxxxxx0xxxxxx00取0x0fefc;PB:

xxxxxxx0xxxxxx01取0x0fefd;

PC:

xxxxxxx0xxxxxx10取0x0fefd;CTL:

xxxxxxx0xxxxxx11取0x0feff;

8255的PA口控制LED数码管的8个显示段;PB口分别接8个LED数码管的共阳极;

PC口分别接4x4矩阵键盘的行线和列线。

2.存储分配:

struct{//闹钟时、分、秒,共设6个闹钟(初始状态默认:

00-00-F1)

ucharhour;

ucharminute;

ucharisON;

}alarm[6]={{0,0,0}};

ucharhour=12,minute=0,second=0;//时、分、秒

uchartemp_second;//用于立即切换显示时间/日期

uintyear=2011;//年

ucharmonth=12;//月

ucharday=1;//日

ucharweek=6;//星期

ucharMdays[]={0,31,28,31,30,31,30,31,31,30,31,30,31};//各月天数

ucharalarm_isON=1;//闹钟总开关

ucharalarm_station=0;//闹钟状态

ucharano;//闹钟号(当前时间到的闹钟号)

ucharstart_minute;//开始响铃的时间(也就是所定闹钟的时间)

uintcount_ms25=0;//软件计数器(计数40个25毫秒达1s)

ucharshow_model=0;//显示模式:

[0]切换显示时间/日期[1]切换显示日期/时间

constucharfixtime=0x00;//时间修正量

ucharkey=0xff;//获得的当前键值

ucharlast_key=0xff;//最后一次扫描到的按键(非0xff)

ucharkey_count=0;//扫描到同一按键的次数

ucharEdown=0;//闹钟开关键是否按下

ucharled_buf[8]={24,24,24,24,24,24,24,24};//时间日期显示缓冲区

ucharcodeled_table1[]={0x0c0,0x0f9,0x0a4,0x0b0,0x99,0x92,0x82,0x0f8,0x80,0x90,

0x88,0x83,0x0C6,0x0a1,0x86,0x8e,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,

0x08,0x03,0x46,0x21,0x06,0x0e,0x7f,0x0bf,0xff};//数码管段码

ucharcodeKBTable[]={'1','2','3','F','4','5','6','E','7','8','9','C','0','A','B','D'};//键值(可有可无)

五、软件流程图及说明

1.流程图:

2.主要程序段说明:

(1)显示:

动态显示:

即各位数码管轮流点亮,对于显示器各位数码管,每隔一段延时时间循环点亮一次。

利用人的视觉暂留功能可以看到整个显示,但须保证扫描速度足够快,人的视觉暂留功能才可察觉不到字符闪烁。

显示器的亮度与导通电流、点亮时间及间隔时间的比例有关。

调整参数可以实现较高稳定度的显示。

动态显示节省了驱动和I/O口,降低了能耗。

voidLED_show(ucharbuf[])

{

uchari,num,pLED=0x80;

for(i=0;i<8;i++)

{

num=buf[i];

PA=led_table1[num];/*送字段码*/

PB=pLED;/*送字位码*/

pLED>>=1;/*右移一位*/

Delay

(1);/*延时*/

}

}

(2)键盘(本次设计对下面两种扫描方式都进行了实现):

a.行扫描法:

依次从第一至最末行线上发出低电平信号,如果该行线所连接的键没有按下的话,则列线所接的端口得到的是全“1”信号,如果有键按下的话,则得到非全“1”信号。

/*键盘扫描(行扫描法,延时消抖)********************************************************

ucharcodeKBTable[]={

0xEE,'1',0xDE,'4',0xBE,'7',0x7E,'0',

0xED,'2',0xDD,'5',0xBD,'8',0x7D,'A',

0xEB,'3',0xDB,'6',0xBB,'9',0x7B,'B',

0xE7,'F',0xD7,'E',0xB7,'C',0x77,'D',

0x00,0xff};

ucharGet_key(void);//获取最终键值

{uchari;

ucharline,row,k_value;

staticucharlastkey=0xff;

CTL=0x88;//CH输入,CL输出10001000

PC=PC&0xf0;//PC0~PC3输出0,输入PC4~PC7(默认1无键按下)

if((PC&0xf0)==0xf0)

{

lastkey=0xff;

return0xff;//无键按下

}

row=PC;

Delay(4);//延时,消除抖动

if(row!

=PC)

{

lastkey=0xff;

return0xff;//判为抖动

}

line=0xFE;

for(i=0;i<4;i++)

{PC=line;//输出扫描信号

row=PC;//读键盘口

if((row&0xf0)!

=0xf0)

break;

line=(line<<1)+1;

}

if(i==4)

{lastkey=0xff;return0xff;}

k_value=(row&0xf0)|(line&0x0f);

for(i=0;i<32;i+=2)

if(k_value==KBTable[i])

break;

if(lastkey==KBTable[i+1])

return0xff;

lastkey=KBTable[i+1];

returnKBTable[i+1];

}

b.线反转法:

线反转法也是识别闭合键的一种常用方法,该法比行扫描速度快,但在硬件上要求行线与列线外接上拉电阻。

先将行线作为输出线,列线作为输入线,行线输出全“0”信号,读入列线的值,那么在闭合键所在的列线上的值必为0;然后从列线输出全“0”信号,再读取行线的输入值,闭合键所在的行线值必为0。

这样,当一个键被按下时,必定可读到一对唯一的行列值。

再由这一对行列值可以求出闭合键所在的位置。

//一次键盘扫描(线反转法,中断扫描计数去抖)*********************************************************

ucharcodeKBTable[]={'1','2','3','F','4','5','6','E','7','8','9','C','0','A','B','D'};

//key_index0123456789101112131415

ucharkey_scan(void)//返回'0','1','2'...'E','F',0xff

{ucharkey_index,temp=0;

CTL=0x88;//CH输入,CL输出10001000

PC=PC&0xf0;//将低四位置0

if(PC!

=0xF0)//判断按键是否按下如果按钮按下会拉低CH其中的一个端口

{

temp=PC;//读PC口

temp=temp&0xf0;//屏蔽低四位

temp=~((temp>>4)|0xf0);//高四位取反值~(1111****)

if(temp==1)//pC.4被拉低1110第一行

key_index=0;

elseif(temp==2)//PC.5被拉低1101第二行

key_index=4;

elseif(temp==4)//PC.6被拉低1011第三行

key_index=8;

elseif(temp==8)//PC.7被拉低0111第四行

key_index=12;

else//没有键按下

return0xff;

CTL=0x81;//CL输入,CH输出10000001

PC=PC&0xf0;//CH输出0000初始:

00001111若有键按下,根据低4位哪一位被拉低确定第二维坐标

temp=PC;//读PC口

temp=temp&0x0f;

temp=~(temp|0xf0);//低四位取反值~(1111****)

if(temp==1)//PC.0被拉低1110第一列

key_index+=0;

elseif(temp==2)//PC.1被拉低1101第二列

key_index+=1;

elseif(temp==4)//PC.2被拉低1011第三列

key_index+=2;

elseif(temp==8)//PC.3被拉低0111第四列

key_index+=3;

else//没有键按下

return0xff;

returnKBTable[key_index];

}

elsereturn0xff;

}

c.消抖方法:

(1)硬件消抖法:

就是在键盘中附加去抖动电路,从根上消除抖动产生的可能性。

右图所示电路实际上是由R-S触发器构成的单脉冲电路。

当按钮开关按下时Q端输出低电平,当开关松开时Q端恢复高电平,即输出一个负脉冲,以此消除抖动。

(2)软件消抖法:

键按下的时间与操作者的按键动作有关,约为十分之几到几秒不等。

而键抖动时间与按键的机械特性有关,一般为5~10ms不等。

软件消抖法即是采用延时(一般延时10~20ms)的方法,以避开按键的抖动,即在按键已稳定地闭合或断开时才读出其状态。

(3)定时中断扫描计数消抖法:

把扫描函数放在定时中断里调用,扫描有键值则保存至kast_key并计数(key_count++),下次中断时再扫描,键值与上次相同则计数累加,若键值不同则计数从1开始,……,直到相同的键值被计数>=6,则认为该键按下。

假设1s最快可以按5下,则每下约持续200ms,每次25ms中断时就扫描一次键盘,在这8次(或更多)里若有6次以上检测到有同一键则判为有效键。

ucharGet_key(void)//返回'0','1','2'...'E','F',0xff

{

if(key_count>=6)

{

key_count=0;

returnlast_key;

}

elsereturn0xff;

}

(3)中断服务子程序

/*25ms中断子函数**********************************************************************/

voidTime_over(void)interrupt1using2

{

ucharkey_temp;

TH0=0x0A6;//晶振频率11.0592MHz下,定时25ms的计数初值

TL0=0x00+fixtime;//(2^16-X)*(12*1/11.0592)=25ms;-->X=42496=A600H

count_ms25++;

if(count_ms25>=40)//达到1秒

{

DateTime_change();//走时更新时分秒等

count_ms25=0;

}

//每次25ms中断就扫描一次按键

key_temp=key_scan();

if((last_key==0xff)&&(key_temp!

=0xff))

{

last_key=key_temp;

key_count++;

}

else

{

if(key_temp==last_key)

{key_count++;}

else

if(key_temp!

=0xff){last_key=key_temp;key_count=1;}

}

}

 

六、系统功能与操作说明;

1.系统功能:

时间、日期(包括星期)、闹钟显示及其设置;

支持6个闹钟,可设置闹钟总开关及分开关;

完善的设置容错处理;

可自动/手动切换时间/日期显示模式;

设置位闪烁标识;

设置过程30s无操作,自动恢复为正常显示方式;

4x4矩阵键盘扫描采用线反转法,以中断扫描计数去抖;

开机自检功能;

......

2.显示格式说明:

时间显示:

12-30-0212时-30分-02秒

日期显示:

11.01.01-62011年01月01日-星期六

闹钟设置显示:

-123456-等待选择要设置的闹钟号

06-00-E1定时在06:

00,闹钟1开(E开,F关)

闹钟总开关:

时间显示时最后一位小数点亮代表总开,否则为关

3.键盘操作说明:

(1)数字键“0”~“9”,用于设置时输入时间和日期,正常工作时无效。

(2)“时间设置”、“日期设置”、“闹钟设置”,用于进入相应功能的设置状态。

(3)“闹钟开关”在闹钟设置状态时,用于设置当前闹钟开或关,正常工作时,用于手动关闹铃的声音和设置闹钟总开关。

(4)“确认”用于设置参数的确认,并检查参数是否合理,如果符合要求,则参数有效;否则本次修改无效,保持原值。

正常工作情况下按该键无操作。

(5)“显示切换”用于正常工作时手动切换时间、日期的显示。

七、调试记录(主要问题及解决方法)

1.在写设置模块特别是容错处理时比较耗时,要求对各个细节都进行仔细地调试,修修改改在所难免,都是些小问题,略过;

2.在实现功能模块的相互任意跳转时,起初只是直接调用功能入口函数fun_key(),出现递归调用的警告,因为要堆栈保护现场,而在任意跳转时多次递归调用必然会空间不足(即使通过reenstrant也不妥,也是这个问题),这样就有可能会造成数据覆盖使系统不稳定。

对此,我在主函数里采用以下方法避免递归调用:

while

(1)

{

Show_control();

alarm_scan();

key=Get_key();

while(key=='A'||key=='B'||key=='C')fun_key();//功能跳转(可避免递归调用的处理)

fun_key();

}

3.在键盘的实验过程中,我几乎尝试了所有的键盘处理方法,包括行扫描法、线反转法、延时消抖、定时中断扫描计数消抖……其间曾导致LED动态刷新速度不足,闪烁严重,把LED_show()里的Delay(8)改为Delay

(1)即可;条件key_count>=6判为有效也是针对我自己的程序根据实际情况调试得出的经验值。

听说有一种类似的按键扫描,可以很方便识别出短按、短按抬起、长按、长按抬起共4种按键动作,大概思路如下:

用定时器中断2mS扫描一次,如果按键被按下则计数累加,否则计数清零并记按键抬起动作。

1、累加到5次(10mS完成消斗)认为是短按;

2、累加超过5次且小于500次(1秒),并已产生按键抬起动作,认为是短按抬起;

3、累加超过500次,认为是长按;

4、累加超过500次,并已产生按键抬起动作,认为是长按抬起。

据此方法,我小试了下牛刀,具体实现未果,有空再试。

八、课程设计总结

其实以前就用Freescale单片机写过一个带温度显示和闹钟的数字时钟,只是实现走时、温度采集和键盘的基本功能,未考虑日期、容错处理、功能的完善性等细节问题。

这次原打算尝试改用汇编实现,但后来迫于形式,时间有限,只好先用C顶着,也算是对这一类小产品的改进与完善吧。

至于时间的精确性,如果只用晶振是很难做到精确的,即使嵌入汇编精确计算或者调出一个最佳的时间偏差量、偏差函数,也难以确保其精确性,毕竟每个晶振的振荡频率与标称值存在误差也会老化。

所以这里我没有做这方面的工作,目前普遍的做法是外接一个时钟芯片,比如说DS1302,价格也不贵。

九、附录:

1.Protel绘制的最小系统板原理图:

2.程序清单及详细注释

/*****************************************************

描述:

全功能数字电子钟

作者:

2011.12.12写于福建工程学院.

平台:

Atmel89S51单片机

实现功能:

时间、日期(包括星期)、闹钟及其设置;

支持6个闹钟,可设置闹钟总开关及分开关;

完善的设置容错处理;

可自动/手动切换时间/日期显示模式;

设置位闪烁标识;

设置过程30s无操作,自动恢复为正常显示方式;

4x4矩阵键盘扫描采用线反转法,以中断扫描计数去抖;

开机自检功能;

......

******************************************************/

#include

#include

#definePAXBYTE[0x0fefc]

#definePBXBYTE[0x0fefd]

#definePCXBYTE[0x0fefe]

#defineCTLXBYTE[0x0feff]

#defineucharunsignedchar

#defineuintunsignedint

//PA、PB、PC、CTL分别为8255的控制口

sbitP3_2=P3^2;//蜂鸣器引脚定义

struct{//闹钟时、分、秒,共设6个闹钟(初始状态默认:

00-00-F1)

ucharhour;

ucharminute;

ucharisON;

}alarm[6]={{0,0,0}};

ucharhour=12,minute=0,second=0;//时、分、秒

uchartemp_second;//用于立即切换显示时间/日期

uintyear=2011;//年

ucharmonth=12;//月

ucharday=1;//日

ucharweek=6;//星期

ucharMdays[]={0,31,28,31,30,31,30,31,31,30,31,30,31};//各月天数

ucharalarm_isON=1;//闹钟总开关

ucharalarm_station=0;//闹钟状态

ucharano;//闹钟号(当前时间到的闹钟号)

ucharstart_minute;//开始响铃的时间(也就是所定闹钟的时间)

uintcount_ms25=0;//软件计数器(计数40个25毫秒达1s)

ucharshow_model=0;//显示模式:

[0]切换显示时间/日期[1]切换显示日期/时间

constucharfixtime=0x00;//时间修正量

ucharkey=0xff;//获得的当前键值

ucharlast_key=0xff;//最后一次扫描到的按键(非0xff)

ucharkey_count=0;//扫描到同一按键的次数

ucharEdown=0;//闹钟开关键是否按下

ucharled_buf[8]={24,24,24,24,24,24,24,24};//时间日期显示缓冲区

ucharcodeled_table1[]={0x0c0,0x0f9,0x0a4,0x0b0,0x99,0x92,0x82,0x0f8,0x80,0x90,0x88,0x83,0x0C6,0x0a1,0x86,0x8e,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x08,0x03,0x46,0x21,0x06,0x0e,0x7f,0x0bf,0xff};

//0123456789abcdef0.1.2.3.4.5.6.7.8.9.A.B.C.D.E.F..-全灭

//10111213141516171819202

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 教学研究 > 教学计划

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2