基于单片机的电子闹钟设计
摘 要
本设计以AT89C51芯片为核心,辅以必要的外围电路,设计了一个结构简单,功能齐全的电子时钟,它由5V直流电源供电。 关键词:单片机;led;闹钟;定时器
Abstract
This design, adopting AT89C51 chip as the core part with some necessary peripheral circuits, is a simple electronic clock which uses 5V DC as the power supply. Keywords:single chip machine ,in fixed time machine, alarm clock,LED
1 引言
1.1设计目的
此次课程设计是在学习先修课程《单片机原理与系统设计》之后,为加强对学生系统设计和应用能力的培养而开设的综合设计训练环节。本课程设计应结合《单片机原理与系统设计》课程的基础理论,重点强调实际应用技能训练,包括单片机系统设计的软件和硬件两部分。其课程设计任务是使学生通过应用单片机系统设计的基本理论,基本知识与基本技能,掌握单片机应用系统各主要环节的设计、调试方法,初步掌握并具备应用单片机进行设备技术改造和产品开发的能力,培养学生的创新意识,提高学生的动手能力和分析问题、解决问题的能力。
1.2设计要求
结合单片机知识,以AT89C51单片机为核心,利用七段LED数码管实现计时、校时及闹钟功能。
1.3设计方法
以AT89C51单片机为核心,外加晶振电路,使用8个七段数码管显示,LED采用动态扫描,用74ls245芯片作为驱动电路。通过四个独立按键对时间进行定时、校时,从而实现闹钟提醒功能。
2 设计方案及原理
2.1设计方案
选AT89C51单片机作为系统核心,辅助外部产生时钟信号的晶振电路,再加上四个独立按键作为输入信号,使用8个七段数码管显示时间,芯片74ls245为数
--精品
精品-----
码管段选线的驱动,最后用蜂鸣器实现闹铃功能。使用单片机的定时器T0计时时间为50ms,计时20次作为1s的时间基准。第一部分,12MHz的晶振连接至单片机的时钟信号输入端;第二部分,四个独立按键加上四个上拉电阻连接至单片机的P1口的低四位;第三部分,单片机的P0口通过由芯片74ls245构成的驱动电路连接至数码管的段选线,单片机的P3口连接至数码管的位选线;第四部分,单片机的P2.1通过一个NPN型三极管连接至蜂鸣器。8个七段数码管使用动态扫描显示时间,独立按键用软件编程实现对时间和闹钟时、分、秒的设置,再通过比较所设置的闹钟与时间是否相等,达到闹铃发出声响的效果。
2.2设计原理
系统原理图如图2.1所示。
晶振 AT89C51 段码驱动 8位数码管 位码驱动 按键 蜂鸣器 图2.1 系统原理图
3 硬件设计
硬件电路分四个模块:晶振电路、键盘电路、数码管显示电路、蜂鸣器驱动电路。晶振电路使用12MHz晶体振荡器,经分频后供单片机工作。键盘采用4个独立按键配以4个上拉电阻实现对时钟和闹钟的设定及修改。由于通过数码管公共及的电流较大且避免过多地使用分立元件,采用了一片74ls245来驱动段码,用P3口作位码驱动。发音部分是通过三极管放大驱动蜂鸣器工作,再通过软件这时产生等时时间方波驱动蜂鸣器发出间断嘀声,这样就可以省去硬件振荡电路,降低成本。
系统硬件电路图如图3.1所示。
--精品
精品-----
图3.1 系统硬件图
4 软件设计
源程序清单见附录。主程序流程图如图4.1所示。
开始初始化设置闹铃判断显示时间键盘扫描 图4.1 主程序流程图
5 系统仿真及调试
--精品
精品-----
硬件部分设置了的三个按键K1、K2、K3、K4。当按键K1第一次按下时,停止计时进入闹钟1的秒设置,当按键K1第二、第三次按下时,分别进入闹钟1的分设置和时设置,当按K1第四 、第五、第六次按下时分别进入闹钟2的秒、分、时设置,当按K1第七 、第八、第九次按下时分别进入闹钟3的秒、分、时设置,当按K1第十 、第二一、第十二次按下时分别进入时间的秒、分、时设置,在K1按下的各阶段,可用按键K2、K3进行时间和闹铃时间的时、分、秒进行加减设置;当按键K1第十三次按下时恢复到时间显示功能。当显示的时间和定时设置的时间一致时,蜂鸣器发出等时间断蜂鸣声,闹铃时间设置为60秒。在各个闹钟设置阶段,如果有K4按下,则相应闹钟功能关闭或开启;如在闹铃时有K4按下则提前停止闹铃。系统仿真图如图5.1所示。
图5.1 系统仿真图
6 总结
通过两周的努力,完成了电子闹钟的设计目的,实现了时间的显示、校时、设置闹钟、闹铃等功能。这期间,我复习了单片机的相关知识,并结合查阅相关资料,设计了整体电路以及各模块的电路,对照硬件电路编写对应模块的子程序,
--精品
精品-----
最后将各个子程序整合到一个主程序中,完成了设计所需功能。
在设计中,我发现选择合适的元器件很重要,比如数码管有共阳极和共阴极两种,不同的选择会导致程序的不同,经过多次调试最终选择了共阳极数码管。另外,我觉得软件的设计比硬件设计更重要,而且难度更大。比如写一个程序看其功能很少认为编写程序简单,但到编程的时候才发现一些细微的知识或低级错误经常犯做不到最后常常失败,所以有些东西只有学精弄懂并且要细心才行,只学习理论有些东西是很难理解的,更谈不上掌握。我在这次设计中收获颇多。我对所学的理论知识在实践中加深了认识,同时更加熟练掌握了Proteus、Keil等软件的使用。做任何事都需要耐心和细心,一点小的疏忽和懈怠可能导致整个设计失败。还有一点,自己的设计思路不可能凭空产生,只有借鉴别人已有的设计并充分消化吸收成为自己的东西,才能做出更好的设计作品。
参考文献
[1] 王思明.单片机原理及应用系统设计[M].北京:科学出版社,2012. [2] 陈明荧. 89C51单片机课程设计实训教材[M].北京:清华大学出版社,2003. [3] 刘瑞新.单片机原理及应用教程[M].北京:机械工业出版社,2005. [4] 杨文龙.单片机原理及应用[M].西安:西安电子科技大学出版社,2002.
附录
--精品
精品-----
源程序清单:
//****************************头文件******************************** #include //****************************宏定义******************************** #define uchar unsigned char #define uint unsigned int //****************************位声明******************************** sbit key1=P1^0; sbit key2=P1^1; sbit key3=P1^2; sbit key4=P1^3; sbit fmq=P2^1; //************************数码管显示的数值************************** uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92, // 0 1 2 3 4 5 0x82,0xf8,0x80,0x90,0xbf,0x0ff}; // 6 7 8 9 - 灭 void jia(); //定义时间加函数 void jian(); //定义时间减函数 //********************数组定义,数组内含有8个数值****************** uchar table1[8],table2[8],table3[8],table4[8]; //**************************时间显示初始值************************** uchar shi=12,fen=0,miao=0; //**************************定义全局变量**************************** uchar shi1,fen1,miao1,shi2,fen2,miao2,shi3,fen3,miao3; uchar shi4,fen4,miao4; uchar flag, flag1, wss, cnt, cnt1, alm1, alm2, alm3; // 1秒 等时 位闪 次数 校时 闹1 闹2 闹3 uint flag2; // 蜂鸣 //*********************延时函数,用于动态扫描数码管***************** void delay(uchar i) { uchar x,y; for(x=i;x>0;x--) for(y=120;y>0;y--); } //*******************************初始化函数************************* --精品 精品----- void init() { TMOD=0x01; //工作方式1 TH0=0x3c; //定时时间为:50ms (65536-50000)/256 TL0=0x0b0; //(65536-50000)%256 ET0=1; //打开定时器 EA=1; //开总中断 TR0=1; //启动定时器 } //********************显示子函数,用于显示时间数值***************** void display() { uchar i,j; if(cnt!=10||wss==0) { table1[0]=miao%10; //分离秒的个位与十位 table1[1]=miao/10; } else { table1[0]=table1[1]=11;} if(cnt!=11||wss==0) { table1[3]=fen%10; //分离分的个位与十位 table1[4]=fen/10; } else { table1[3]=table1[4]=11;} if(cnt!=12||wss==0) { table1[6]=shi%10; //分离时的个位与十位 table1[7]=shi/10; } else { table1[6]=table1[7]=11;} table1[2]=table1[5]=10; j=0x7f; for(i=0;i<=7;i++) //从秒到时的扫描 { P3=j; //选通点亮八个数码管 P0=table[table1[i]]; //显示数值 delay(10); //调用延时程序 j=_cror_(j,1); //循环右移 } } //*******************显示子函数,用于显示定时1时间***************** --精品 精品----- void display1() { uchar i,j; if(alm1==0) { if(cnt!=1||wss==0) { table2[0]=miao1%10; //分离秒的个位与十位 table2[1]=miao1/10; } else { table2[0]=table2[1]=11;} if(cnt!=2||wss==0) { table2[3]=fen1%10; //分离分的个位与十位 table2[4]=fen1/10; } else { table2[3]=table2[4]=11;} if(cnt!=3||wss==0) { table2[6]=shi1%10; //分离时的个位与十位 table2[7]=shi1/10; } else { table2[6]=table2[7]=11;} } else table2[0]=table2[1]=table2[3]=table2[4]=table2[6]=table2[7]=10; table2[2]= table2[5]=10; j=0x7f; for(i=0;i<=7;i++) //从秒到时的扫描 { P3=j; //选通点亮八个数码管 P0=table[table2[i]]; //显示数值 delay(10); //调用延时程序 j=_cror_(j,1); //循环右移 } } //********************显示子函数,用于显示定时2时间****************** void display2() { uchar i,j; if(alm2==0) { if(cnt!=4||wss==0) { table3[0]=miao2%10; //分离秒的个位与十位 table3[1]=miao2/10; --精品 精品----- } else { table3[0]=table3[1]=11;} if(cnt!=5||wss==0) { table3[3]=fen2%10; //分离分的个位与十位 table3[4]=fen2/10; } else { table3[3]=table3[4]=11;} if(cnt!=6||wss==0) { table3[6]=shi2%10; //分离时的个位与十位 table3[7]=shi2/10; } else { table3[6]=table3[7]=11;} } else table3[0]=table3[1]=table3[3]=table3[4]=table3[6]=table3[7]=10; table3[2]= table3[5]=10; j=0x7f; for(i=0;i<=7;i++) //从秒到时的扫描 { P3=j; //选通点亮八个数码管 P0=table[table3[i]]; /显示数值 delay(10); //调用延时程序 j=_cror_(j,1); //循环右移 } } //***************显示子函数,用于显示定时3时间数值****************// void display3() { uchar i,j; if(alm3==0) { if(cnt!=7||wss==0) { table4[0]=miao3%10; //分离秒的个位与十位 table4[1]=miao3/10; } else { table4[0]=table4[1]=11;} if(cnt!=8||wss==0) { table4[3]=fen3%10; //分离分的个位与十位 table4[4]=fen3/10; --精品 精品----- } else { table4[3]=table4[4]=11;} if(cnt!=9||wss==0) { table4[6]=shi3%10; //分离时的个位与十位 table4[7]=shi3/10; } else { table4[6]=table4[7]=11;} } else table4[0]=table4[1]=table4[3]=table4[4]=table4[6]=table4[7]=10; table4[2]= table4[5]=10; j=0x7f; for(i=0;i<=7;i++) //从秒到时的扫描 { P3=j; //选通点亮八个数码管 P0=table[table4[i]]; //显示数值 delay(10); //调用延时程序 j=_cror_(j,1); //循环右移 } } //***********************时间子函数 *****************************// void shijian() { if(flag>=20) //判断是否到一秒 { wss=~wss; flag=0; //到了,则标志位清零 if(cnt1!=0) { miao4++; //秒加1 if( miao4>59) //判断秒是否到60s { miao4=0; //到了,则清零 fen4++; //分加1 if(fen4>59) //判断分是否到1min { fen4=0; //到了,则清零 shi4++; //时加1 if(shi4>23) //判断时是否到24h shi4=0; //到了,则清零 } } } --精品 精品----- else { miao++; //秒加1 if( miao>59) //判断秒是否到60s { miao=0; //到了,则清零 fen++; //分加1 if(fen>59) //判断分是否到1min { fen=0; // 到了,则清零 shi++; //时加1 if(shi>23) // 判断时是否到24h shi=0; //到了,则清零 } } } } } //**************************键盘扫描子函数************************// void key_scan() { if(key1==0) { while(!key1) //防止掉显 { if(cnt==1||cnt==2||cnt==3) { display1(); } //key1按了1、2、3次,调用闹钟1子程序 if(cnt==4||cnt==5||cnt==6) { display2(); } // key1按了4、5、6次,调用闹钟2子程序 if(cnt==7||cnt==8||cnt==9) { display3(); } // key1按了7、8、9次,调用闹钟3子程序 if(cnt==0||cnt==10||cnt==11||cnt==12||cnt==13) { display(); } // key1按了10、11、12、13次,调用计时子程序 } cnt++; //记下按键key1按下的次数 if(cnt==10&&cnt1==0) { miao4=miao; fen4=fen; shi4=shi; cnt1++; } if(cnt==13) { cnt=0; if(cnt1==1) { miao=miao4; --精品 精品----- fen=fen4; shi=shi4; } cnt1=0; } } if(key2==0) //判断key2是否按下 { while(!key2) //防止掉显 { if(cnt==1||cnt==2||cnt==3) { display1(); } if(cnt==4||cnt==5||cnt==6) { display2(); } if(cnt==7||cnt==8||cnt==9) { display3(); } if(cnt==0||cnt==10||cnt==11||cnt==12||cnt==13) { display(); } } jia(); //调用加1子函数 } if(key3==0) //判断key3是否按下 { while(!key3) //防止掉显 { if(cnt==1||cnt==2||cnt==3) { display1(); } if(cnt==4||cnt==5||cnt==6) { display2(); } if(cnt==7||cnt==8||cnt==9) { display3(); } if(cnt==0||cnt==10||cnt==11||cnt==12||cnt==13) { display(); } } jian(); //调用减1子函数 } if(key4==0) //判断key4是否按下 {while(!key4) //防止掉显 { if(cnt==1||cnt==2||cnt==3) { alm1=~alm1; display1(); } if(cnt==4||cnt==5||cnt==6) { alm2=~alm2; --精品 精品----- display2(); } if(cnt==7||cnt==8||cnt==9) { alm3=~alm3; display3(); } if(cnt==0||cnt==10||cnt==11||cnt==12||cnt==13) display(); } } } //****************************加1子函数*************************** void jia() { if(cnt==1) //判断key1按下的次数是否为1 { miao1++; //是,则秒加1 if(miao1>59) //判断秒是否大于60,是,则秒清零 miao1=0; } if(cnt==2) //判断key1按下的次数是否为2 { fen1++; //是,则分加1 if(fen1>59) //判断分是否大于60 fen1=0; //是,则分清零 } if(cnt==3) //判断key1按下的次数是否为3 { shi1++; //是,则时加1 if(shi1>23) //判断时是否大于23 shi1=0; //是,则时清零 } if(cnt==4) //判断key1按下的次数是否为4 { miao2++; //是,则秒加1 if(miao2>59) //判断秒是否大于60,是,则秒清零 miao2=0; } if(cnt==5) //判断key1按下的次数是否为5 { fen2++; //是,则分加1 if(fen2>59) //判断分是否大于60 fen2=0; //是,则分清零 } if(cnt==6) //判断key1按下的次数是否为6 { shi2++; //是,则时加1 --精品 精品----- if(shi2>23) //判断时是否大于23 shi2=0; //是,则时清零 } if(cnt==7) //判断key1按下的次数是否为7 { miao3++; //是,则秒加1 if(miao3>59) //判断秒是否大于60,是,则秒清零 miao3=0; } if(cnt==8) //判断key1按下的次数是否为8 { fen3++; //是,则分加1 if(fen3>59) //判断分是否大于60 fen3=0; //是,则分清零 } if(cnt==9) //判断key1按下的次数是否为9 { shi3++; //是,则时加1 if(shi3>23) //判断时是否大于23 shi3=0; //是,则时清零 } if(cnt==10) //判断key1按下的次数是否为10 { miao++; //是,则秒加1 if(miao>59) //判断秒是否大于60,是,则秒清零 miao=0; cnt1++; } if(cnt==11) //判断key1按下的次数是否为11 { fen++; //是,则分加1 if(fen>59) //判断分是否大于60 fen=0; //是,则分清零 cnt1++; } if(cnt==12) //判断key1按下的次数是否为12 { shi++; //是,则时加1 if(shi>23) //判断时是否大于23 shi=0; //是,则时清零 cnt1++; } } //***************************减1子函数**************************// void jian() { if(cnt==1) //判断key1按下的次数是否为1,是则秒减1 --精品 精品----- { miao1--; if(miao1==255) //判断秒是否减到255,是,则秒置59 miao1=59; } if(cnt==2) //判断key1按下的次数是否为2,是则分减1 { fen1--; if(fen1==255) //判断分是否减到255,是,则分置59 fen1=59; } if(cnt==3) //判断key1按下的次数是否为3,是则时减1 { shi1--; if(shi1==255) //判断时是否减到255,是,则时置23 shi1=23; } if(cnt==4) //判断key1按下的次数是否为4,是则秒减1 { miao2--; if(miao2==255) //判断秒是否减到255,是,则秒置59 miao2=59; } if(cnt==5) //判断key1按下的次数是否为5,是则分减1 { fen2--; if(fen2==255) //判断分是否减到255,是,则分置59 fen2=59; } if(cnt==6) //判断key1按下的次数是否为6,是则时减1 { shi2--; if(shi2==255) //判断时是否减到255,是,则时置23 shi2=23; } if(cnt==7) //判断key1按下的次数是否为7,是则秒减1 { miao3--; if(miao3==255) //判断秒是否减到255,是,则秒置59 miao3=59; } if(cnt==8) //判断key1按下的次数是否为8,是则分减1 { fen3--; if(fen3==255) //判断分是否减到255,是,则分置59 fen3=59; } if(cnt==9) //判断key1按下的次数是否为9,是则时减1 --精品 精品----- { shi3--; if(shi3==255) //判断时是否减到255,是,则时置23 shi3=23; } if(cnt==10) //判断key1按下的次数是否为10,是则秒减1 { miao--; if(miao==255) //判断秒是否减到255,是,则秒置59 miao=59; cnt1++; } if(cnt==11) //判断key1按下的次数是否为11,是则分减1 { fen--; if(fen==255) //判断分是否减到255,是,则分置59 fen=59; cnt1++; } if(cnt==12) //判断key1按下的次数是否为12,是则时减1 { shi--; if(shi==255) //判断时是否减到255,是,则时置23 shi=23; cnt1++; } } //***************************闹铃子函数***************************// void clock() //判断秒的数值是否相等 { if(miao==miao1&&alm1==0||miao==miao2&&alm2==0||miao==miao3&&alm3==0) //是,在判断分是否相等 if(fen==fen1&&alm1==0||fen==fen2&&alm2==0||fen==fen3&&alm3==0) //是,再判断时是否相等 if(shi==shi1&&alm1==0||shi==shi2&&alm2==0||shi==shi3&&alm3==0) { flag2=0; //是,则标志位,flag2清零 while(!(flag2==1200)&&(cnt==0)) //判断flag2是否到1200且不 // 为调时状态 {if(key4==0) //没有,则继续驱动蜂鸣器响 {while(!key4) flag2=1200; } if(flag1>1) //等时方波驱动蜂鸣器 --精品 精品----- { fmq=~fmq; flag1=0; } shijian(); //调用时间子函数 display(); //调用显示子函数 } fmq=1; //关闭蜂鸣器 } } //**************************主函数********************************// void main() { init(); //调用初始化子函数 while(1) { clock(); //闹钟子函数 if(cnt==1||cnt==2||cnt==3) //显示子函数 { display1(); } if(cnt==4||cnt==5||cnt==6) { display2(); } if(cnt==7||cnt==8||cnt==9) { display3(); } if(cnt==0||cnt==10||cnt==11||cnt==12||cnt==13) { display(); } shijian(); //调用时间子函数 key_scan(); //调用键盘扫描子函数 } } //**************************定时中断******************************// void time0() interrupt 1 { TH0=0x3c; //初值50ms (65536-50000)/256 TL0=0x0b0; // (65536-50000)%256 flag++; //标志位 flag1++; flag2++; } --精品 因篇幅问题不能全部显示,请点此查看更多更全内容