当前位置:文档之家› 基于单片机的电子闹钟的设计说明

基于单片机的电子闹钟的设计说明

课程设计报告课程名称:单片机课程设计题目:多功能电子表学院:环境与化学工程系:过程装备与测控工程专业:测控技术与仪器班级:测仪111学号: 5801211040学生:白金成起讫日期: 2012-12-28~2013-1-7指导教师:大勇、俊清、熊剑单片机自20世纪70年代问世以来,以其极高的性能价格比,受到人们的重视和关注,应用很广、发展很快。

而51单片机是各单片机中最为典型和最有代表性的一种。

本设计以AT89C52芯片为核心,辅以必要的外围电路,设计了一个结构简单,功能齐全的闹钟,它由5V直流电源供电。

在硬件方面,除了CPU外,使用1602液晶显示时钟的时间,并通过所写程序控制在某个时间点蜂鸣器的响应,即完成闹钟的功能,该闹钟设有4个独立按键,时间调整按键、闹钟调整按键和两个时间加减按键。

软件方面采用C语言编程。

整个闹钟系统能完成时间的显示、调时和定时闹钟的功能。

选用单片机最小系统应用程序,添加比较程序、时间调整程序及蜂鸣程序,通过时间比较程序触发蜂鸣,实现闹钟功能,完成设计所需求的软件环境。

介绍并使用KEIL单片机模拟调试软件,测试程序的可行性并用Proteus进行仿真。

关键词:AT89C52单片机定时器中断闹钟一、设计任务、要求 (4)1.1、设计任务: (4)1.2、设计要求: (4)二、方案总体设计 (5)2.1、显示模块 (5)2.2、实时时间计算模块 (5)2.3、按键控制模块 (5)2.4、声音报警模块 (5)2.5、总体设计: (5)三、硬件设计 (7)3.1、单片机最小系统 (7)3.1.1、时钟信号的产生 (7)3.1.2、复位电路 (7)3.2、液晶显示模块 (8)3.2.1、1602液晶引脚图及连线电路 (8)3.2.2、一般1602字符型液晶显示器实物图 (8)3.3、矩阵键盘 (8)3.4、蜂鸣器电路 (9)3.5、电源指示灯部分 (9)3.6、STC89C52芯片 (9)3.7、整体电路原理图 (10)3.8、Lockmaster硬件电路 (11)四、程序流程图 (12)五、系统仿真与调试 (14)5.1、Proteus仿真原理图 (14)5.2、实物图 (16)5.3、使用说明 (16)六、设计总结及心得体会 (17)附录: (18)一、设计任务、要求1.1、设计任务:利用单片机、4个独立按键、1602液晶显示器、无源蜂鸣器实现具有日期、时间、闹钟功能的多功能电子表。

1.2、设计要求:1、准确计时,以数字形式显示年月、日、时、分、秒。

2、小时以24小时计时形式,分秒计时为60进位,日期平年和闰年将自行更换。

3、采用4个独立按键对电子表进行控制,可进行闹钟设定、控制及时间日期的设定。

4、闹钟功能,可任意设定闹钟时间,一旦走时到该时间,能以声的形式告警提示。

5、复位电路采用按键复位电路。

二、方案总体设计本次设计闹钟,使用了STC89C52单片机芯片控制电路,单片机控制电路简单,电路简明易懂,使用键盘键上的按键来调整电子表的月、日、时、分和闹钟的设定,用蜂鸣器来进行定时提醒,编程采用KEIL C,编程简单便捷且调试方便,这样通过四个模块:按键、芯片、蜂鸣器、1602液晶显示器即可满足设计要求。

2.1、显示模块液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制,有电就有显示,这样即可以显示出图形。

液晶显示器具有厚度薄、适用于大规模集成电路直接驱动、易于实现全彩色显示的特点,目前已经被广泛应用在便携式电脑、数字摄像机、PDA移动通信工具等众多领域。

2.2、实时时间计算模块AT89S52单片机部带有定时/计数功能,此定时功能是通过对外部晶振的脉冲进行计数,从而达到计时功能,使用12MHz的晶振就能实现高精度的计时,因此可以利用此功能实现计时。

2.3、按键控制模块本设计用到的键盘有4个独立按键,分别为时间调整按键、闹钟调整按键和两个时间加减按键。

以此控制时间的调整和闹钟时间的调整。

2.4、声音报警模块此模块采用无源蜂鸣器实现,通过编写相应的程序,当满足要求时,给蜂鸣器提供不同频率的方波,使其发出不同频率的声音,把不同频率的声音按一定的时序输出,从而发出音乐。

2.5、总体设计:总体框架如图2-1所示:图2-1 总体硬件框架图总体构思如图2-2所示:图2-2 总体构思框架图三、硬件设计3.1、单片机最小系统3.1.1、时钟信号的产生89C52芯片部有一个高增益法相放大器,用于构成振荡器。

反相放大器的输入端为XTAL1,输出端为XTAL2,两端跨接石英晶体及两个电容就可以构成稳定的自己振荡器,电路如图3-1所示。

图3-1 晶振电路3.1.2、复位电路复位操作有上电自动复位和按键手动复位两种方式,本设计采用按键电平复位,结构如图3-2所示。

图3-2 复位电路3.2、液晶显示模块3.2.1、1602液晶引脚图及连线电路图3-3 1602液晶显示器3.2.2、一般1602字符型液晶显示器实物图字符型液晶显示模块是一种专门用于显示字母、数字、符号等点阵式LCD,目前常用16*1,16*2,20*2和40*2行等的模块。

下面以太阳人电子的1602字符型液晶显示器为例,介绍其用法。

一般1602字符型液晶显示器实物如图3-4图3-4 1602液晶显示器实物图3.3、矩阵键盘本设计采用4个独立按键控制,按键的接口、序号及接线图如下图所示:图3-5 独立按键连线电路图3.4、蜂鸣器电路本课程设计使用的蜂鸣器是有源蜂鸣器,通过对给蜂鸣器一定频率的方波,驱动蜂鸣器蜂鸣器发出相应频率的声音,其中方波可对端口进行连续取反实现,取反频率由定时器控制,驱动电路如下图所示:图3-6 蜂鸣器连线电路图3.5、电源指示灯部分电源指示灯部分包括一个开关,发光二级管和限流电阻。

当电源接通时发光二级管点亮,表明电路已上电。

电源指示灯原理图如图3-7所示:图3-7电源指示灯原理图3.6、STC89C52芯片STC89C52是一个低功耗,高性能CMOS8位单片机,片含具有如下特点:40个引脚(引脚图如图1-1所示),4kBytesFlash片程序存储器,128bytes的随机存取数据存储器(RAM),32个外部双向输入/输出(I/O)口,5个中断优先级2层中断嵌套中断,2个16位可编程定时计数器,2个全双工串行通信口,看门狗(WDTC)电路,片时钟振荡器。

此外,STC89C52设计和配置了振荡频率可为0Hz并可通过软件设置省电模式。

空闲模式下,CPU暂停工作,而RAM定时计数器,串行口,外中断系统可继续工作,掉电模式冻结振荡器而保存RAM的数据,停止芯片其它功能直至外中断激活或硬件复位。

同时该芯片还具有PDIP、TQFP和PLCC等三种封装形式,以适应不同产品的需求。

单片机引脚图如图3-8所示:图3-8单片机引脚图3.7、整体电路原理图整体电路原理图如图3-9所示:图3-9 总体电路原理图3.8、Lockmaster硬件电路图3-10 硬件电路正面视图图3-11 硬件电路背面视图四、程序流程图程序主要流程如图4-1所示,时间、日期、闹钟设置部分流程如图4-2所示。

图4-1 程序流程图图4-2 程序流程图时间、日期设置部分图4-3 程序流程图闹钟设置部分五、系统仿真与调试5.1、Proteus仿真原理图Proteus软件是英国electronics公司出版的EDA工具软件。

它不仅具有其它EDA工具软件的仿真功能,还能仿真单片机及外围器件。

它是目前最好的仿真单片机及外围器件的工具。

Proteus是世界上著名的EDA工具(仿真软件),从原理图布图、代码调试到单片机与外围电路协同仿真,一键切换到PCB设计,真正实现了从概念到产品的完整设计。

它是目前世界上唯一将电路仿真软件、PCB设计软件和虚拟模型仿真软件三合一的设计平台。

以下是用Proteus仿真调试图:图5-1 日期时间显示图5-2 闹钟设置5.2、实物图图5-5 实物正面视图5.3、使用说明按键序号及对应具体功能为:按键1:时间与日期调整进入与退出键按键2:加一调整功能键按键3:减一调整功能键按键4:闹钟调整进入与退出键六、设计总结及心得体会单片机是我所学专业的主要课程之一,因此我认为单片机课程设计是十分必要而且十分重要的。

尽管刚刚拿到课程设计题目时有点迷惘,不知道如何着手,但通过上网和图书馆查阅相关资料,自己认真钻研以及虚心询问同学,终于解决了一个又一个的困难和障碍,成功完成了任务。

通过本次的单片机课程设计,不仅大丰富了我的理论知识,而且在实践过程中更令我学会了坚持、耐心和努力。

此次单片机课程设计需要运用到许多之前所学过的知识,令我认识到自己以前学习的一些不足之处,例如对以前所学知识的理解不够深刻,掌握得不够牢固,运用不够灵活。

这让我懂得了认真学习的重要性,以及要孜孜不倦地钻研所学过的知识,做得融会贯通,不能一览而过,不求甚解。

在边学习边动手的过程中,我对电子时钟的构造以及原理有了进一步的了解,同时也加深和巩固了我对单片机汇编语言的认识。

除此之外,由于是第一次做单片机,因此在此次课程设计的过程中,无论是电路绘制还是汇编语言编写都难免遇到了不少困难和障碍,例如汇编语言编写出错、电路元件无从入手等。

在面对困难和障碍时,我庆幸自己没有退缩和逃避,而是通过各种方法,迎难而上,以坚持、耐心和努力勇敢无畏地面对困难,克服困难,解决困难。

让我发现问题、分析问题、解决问题以及动手实践的能力都有了很大的提高,并了解到理论知识与实践相结合的重要意义。

从这次的课程设计中,我真真正正的意识到,在以后的学习中,要理论联系实际,把我们所学的理论知识用到实际当中,学习单机片机更是如此,程序只有在经常的练习的过程中才能提高。

本次课程设计尽管时间不长,但从中所获,将令我受益终生附录:#include<reg52.h>#define uchar unsigned char#define uint unsigned intuchar code table[]=" 2014-01-06 MON";uchar code table1[]=" 01:00:00";uchar code table2[7][3]= {{"MON"},{"TUE"},{"WED"},{"THU"},{"FRI"},{"SAT"},{"SUN"}}; //定义二维字符数组sbit RW=P2^6;sbit EN=P2^5; // 1602液晶使能端sbit RS=P2^7; // 1602液晶命令/数据端sbit key1=P1^0; // 声明s1按键sbit key2=P1^1; // 声明s2按键sbit key3=P1^2; // 声明s3按键sbit key4=P1^3; // 声明s4按键sbit beep=P3^7;uint a,s,spak,i,flag; // 声明蜂鸣器uchar num1,yue,ri,keynum1,week; //定义时分秒变量char shi=01,fen,miao,shi1,fen1,miao1;uint nian=2014; //定义年变量void delay(uint z){uint i,j;for(i=z;i>0;i--) //定义带参数延时函数for(j=100;j>0;j--);}void write_(uchar ) //1602液晶写指令函数{RW=0;RS=0;P0=;delay(5);EN=1;delay(5);EN=0;}void write_date(uchar date) //1602液晶写数据函数{RW=0;RS=1;P0=date;delay(5);EN=1;delay(5);EN=0;}void write_addate1(uchar add,uint date) //定义显示年的函数{uint qian;uchar bai,shi,ge;qian=date/1000;bai=date%1000/100;shi=date%1000%100/10;ge=date%10;write_(add+0x80);write_date(0x30+qian);write_date(0x30+bai);write_date(0x30+shi);write_date(0x30+ge);}void write_addate3(uchar add3,uint date3) //定义显示年的函数{uint qian;uchar bai,shi,ge;qian=date3/1000;bai=date3%1000/100;shi=date3%1000%100/10;ge=date3%10;write_(add3+0x80);write_date(0x30+qian);write_date(0x30+bai);write_date(0x30+shi);write_date(0x30+ge);}void write_addate2(uchar add,uchar date) //定义显示月、日、时、分、秒函数{uchar shi,ge;shi=date/10;ge=date%10;write_(add+0x80);write_date(0x30+shi);write_date(0x30+ge);}void write_rq(uchar i) //定义显示星期的函数{ uchar x;for(x=0;x<3;x++){ write_date(table2[i][x]);delay(5);}}void init () //定义初始化函数{beep=0;flag=1;yue=01;ri=06;TMOD=0x01; // 定时器0工作方式为16位TH0=(65536-50000)/256; // 装初值TL0=(65536-50000)%256;EA=1; // 开总中断ET0=1; // 开定时器0中断write_(0x38); // 设置16*2显示,5*7点阵,8位数据口write_(0x06); // 写一个字符后地址指针加1 write_(0x0c); // 设置开显示,不显示光标write_(0x01); // 显示清0,数据清0 write_(0x80); // 使指针指向第1行第1列}void keyscan() // 定义按键函数{uchar keynum;if(key1==0) //s1按键被按下{ delay(3); //去抖延时if(key1==0) //确认s1按键被按下,进入调时间模式{keynum++;while(!key1); //松手检测}if(keynum==1) //s1按下一次{ TR0=0; //关闭定时器0write_(0x81); //指针指向第1行2列write_(0x0f); //开启光标显示,光标闪烁}if(keynum==2){write_(0x86); //光标跳到月份}if(keynum==3){write_(0x89); //光标跳到日}if(keynum==4){write_(0x8c); //光标跳到星期}if(keynum==5){write_(0x80+0x40+4); //光标跳到时}if(keynum==6){write_(0x80+0x40+7); //光标跳到分}if(keynum==7){write_(0x80+0x40+10); //光标跳到秒}if(keynum==8){keynum=0; //退出调时间模式TR0=1; //开启定时器0write_(0x0c); //关闭光标显示}}if(keynum) //当进入调时间模式时{if(key2==0) //s2按键按下{delay(5); //去抖延时if(key2==0){if(keynum==1){nian++; //s2每按下一次年份加1if(nian==10000) // 加满清0nian=0;write_addate1(1,nian); // 显示年份write_(0x81); //写完数据指针指向年份原来位置}if(keynum==2){yue++; //s2每按下一次月份加1if(yue==13)yue=0; //加满清0write_addate2(6,yue); //显示月份write_(0x86); //写完数据指针指向月份原来位置}if(keynum==3){ ri++;if(yue==1||yue==3||yue==5||yue==7||yue==8||yue==10||yue==12) //1,3,5,7,8,10,12月有31天{if(ri==32) //加满还原ri=1;}if(yue==4||yue==6||yue==9||yue==11) //4,6,9,11月有30天 {if(ri==31)ri=1;}if(yue==2&&((nian%4==0&&nian%100!=0)||nian%400==0)) //闰年2月有30天{if(ri==30)ri=1;}if(yue==2&&(nian%4!=0)||(nian%100==0&&nian%400!=0)) //非闰年2月有31天{if(ri==29)ri=1;}write_addate2(9,ri); //显示日write_(0x89); //写完数据指针指向日原来位置}if(keynum==4){week++;//s2每按下一次星期加1if(week==7)//加满还原week=0;write_rq(week);//显示星期write_(0x8c); //写完数据指针指向星期原来位置}if(keynum==5){shi++;//s2每按下一次时加1if(shi==24)shi=0;//加满还原write_addate2(0x44,shi); //显示时write_(0xc4); //写完数据指针指向时原来位置}if(keynum==6){fen++;//s2每按下一次分加1if(fen==60)fen=0;//加满还原write_addate2(0x47,fen); //显示分write_(0xc7);//写完数据指针指向分原来位置}if(keynum==7){miao++;//s2每按下一次秒加1if(miao==60)miao=0;//加满还原write_addate2(0x4a,miao);//显示秒write_(0xca);//写完数据指针指向秒原来位置}while(!key2); //松手检测}}if(key3==0){delay(5);if(key3==0){ //s3按下时减1if(keynum==1){nian--;if(nian==-1)nian=9999;write_addate1(1,nian);write_(0x81);}if(keynum==2){ yue--;if(yue==-1)yue=12;write_addate2(6,yue);write_(0x86);}if(keynum==3){ri--;if(ri==0){if(yue==1||yue==3||yue==5||yue==7||yue==8||yue==10||yue==12)ri=31;if(yue==4||yue==6||yue==9||yue==11)ri=30;if(yue==2&&((nian%4==0&&nian%100!=0)||nian%400==0))ri=29;if(yue==2&&(nian%4!=0)||(nian%100==0&&nian%400!=0))ri=28;}write_addate2(9,ri);write_(0x89);}if(keynum==4){week--;if(week==-1)week=6;write_rq(week);write_(0x8c);}if(keynum==5){shi--;if(shi==-1)shi=23;write_addate2(0x44,shi);write_(0xc4);}if(keynum==6){fen--;if(fen==-1)fen=59;write_addate2(0x47,fen);write_(0xc7);}if(keynum==7){miao--;if(miao==-1)miao=59;write_addate2(0x4a,miao);write_(0xca);}while(!key3);//松手检测}}}if(key4==0) //s4被按下进入调闹钟模式{ delay(3);if(key4==0){while(!key4);keynum1++;}if(keynum1==1){ write_(0x01); //清屏,指针清0write_(0xc6); //在时分之间显示":"write_date(':');write_(0xc9); //在分秒之间显示":"write_date(':');write_(0x0f); //开启光标write_(0xc4); //光标指向时}if(keynum1==2){write_(0xc7);//光标指向分}if(keynum1==3){write_(0xca); //光标指向秒}if(keynum1==4){ keynum1=0;write_(0x0c); //关闭光标}}if(keynum1){if(key2==0)//s2按下加1{delay(5);if(key2==0){while(!key2);if(keynum1==1){shi1++;if(shi1==24)shi1=0;write_addate2(0x44,shi1);write_(0xc4);}if(keynum1==2){fen1++;if(fen1==60)fen1=0;write_addate2(0x47,fen1);write_(0xc7);}if(keynum1==3){miao1++;if(miao1==60)miao1=0;write_addate2(0x4a,miao1);write_(0xca);}}}if(key3==0) //s3每按一次减1{delay(3);if(key3==0){while(!key3);if(keynum1==1){shi1--;if(shi1==-1)shi1=23;write_addate2(0x44,shi1);write_(0xc4);}if(keynum1==2){fen1--;if(fen1==-1)fen1=59;write_addate2(0x47,fen1);write_(0xc7);}if(keynum1==3){miao1--;if(miao1==-1)miao1=59;write_addate2(0x4a,miao1);write_(0xca);}}}}}void main(){ uchar num;init();for(num=0;num<15;num++){ write_date(table[num]);delay(5);} //显示初始时间write_(0xc0);for(num=0;num<12;num++){ write_date(table1[num]);delay(5);}TR0=1; //开启定时器0while(1){if(shi==shi1&&fen==fen1&&miao==miao1){flag=1;while(flag){beep=1;if(key2==0){beep=0;flag=0;}}}keyscan(); //扫描键盘}}void time() interrupt 1 //中断函数{TH0=(65536-50000)/256;TL0=(65536-50000)%256; //进入中断装初值num1++;if(num1==20) //一秒到了{ num1=0; //清0miao++;if(miao==60) //一分到了{ miao=0; fen++; }if(!keynum1) write_addate2(0x4a,miao); //当调闹钟模式按下时不显示当前时间if(fen==60){ fen=0;shi++;}if(!keynum1) write_addate2(0x47,fen); //当调闹钟模式按下时不显示当前时间if(shi==24){shi=0;ri++;week++;}if(!keynum1) write_addate2(0x44,shi);//当调闹钟模式按下时不显示当前时间if(yue==1||yue==3||yue==5||yue==7||yue==8||yue==10||yue==12)if(ri==32){ ri=1; yue++; }if(yue==4||yue==6||yue==9||yue==11)if(ri==31){ ri=1; yue++; }if(yue==2&&((nian%4==0&&nian%100!=0)||nian%400==0))if(ri==30){ ri=1; yue++; }if(yue==2&&(nian%4!=0)||(nian%100==0&&nian%400!=0))if(ri==29){ ri=1; yue++; }if(!keynum1)write_addate2(9,ri); //当调闹钟模式按下时不显示当前时间if(week==7)week=0;if(!keynum1)//当调闹钟模式按下时不显示当前时间{ write_(0x8c);write_rq(week);}if(yue==13){ yue=0;nian++;}if(!keynum1)//当调闹钟模式按下时不显示当前时间{write_addate2(6,yue);write_(0x88);write_date('-');}if(nian==10000)nian=0;if(!keynum1){ write_addate3(1,nian);//当调闹钟模式按下时不显示当前时间write_(0x85);write_date('-');}}}。

相关主题