要求
显示当前时间与日期。
手动修改时间、日期信息,修改该位信息时该数码管闪烁。
手动开启/关闭闹钟功能,而且有闹钟状态指示灯。
手动设置闹钟,而且当达到设置好的时间点时报警,报警时长为5s。
分析
万年历的整体设计如图所示:
51单片机核心模块包括51单片机最小系统模块,是设计应用的控制核心;显示模块用于显示时间与日期、设计闹钟时间等信息;指示灯包括时间日期暂停计数指示灯和闹钟开启或关闭状态指示灯;闹钟采用蜂鸣器发出声音警报;键盘输入模块用来设置和切换时间、日期,开启或关闭闹钟,设置闹钟时间等。
制作出来的实物图如下:
可用安卓接口5V供电,也可接学生电源或两个3.7V的电池通过LM7805稳压管供电。
功能介绍: 程序初始化处于时间计数状态(已设置初始值为12:12:00),按下Key2选择位校准位,按下第一次选中秒钟,第二次选中分钟,第三次选中时钟,第四次退出校时功能,被选中位不断闪烁,并且按下Key3可进行被选择位逐渐加一,实现校时。按下Key4,数码管显示界面跳转为日期显示,按下按键Key2和Key3 可实现与时间同一校准时间的功能,再次按下Key4切换为时间界面。在时间显示或者日期显示状态下,按下按键Key1可独立暂停时间计数或日期的增加,并且LED1指示灯亮。 按下按键K3开启闹钟功能,LED2亮,再次按下则关闭闹钟,LED2灭。按下K4切换为闹钟设置状态(已设置闹钟初始值为12:12:00),按下K1进行分钟位加一,按下Key2切换为时钟位调时,按下K1进行时钟位加一,在闹钟状态下秒钟不可调。在进入闹钟设置功能前,需先开启闹钟功能,否则闹钟不会到点闹铃。按下K2退出闹钟设置界面,等到实时时间与所设置闹钟时间一致时,蜂鸣器响5s钟,中途可按下K3关闭蜂鸣器,并且关闭闹钟功能。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)
程序流程图:
单片机源程序如下:
- #include<reg51.h>
- #define uChar unsigned char
- #define uInt unsigned int
- uChar a[]={~0x3f,~0x06,~0x5b,~0x4f,~0x66,~0x6d,~0x7d,~0x07,~0x7f,~0x6f}; //数码管段选码,0——9
- uChar b[]={~0xfe,~0xfd,~0xfb,~0xf7,~0xef,~0xdf,~0xbf,~0x7f}; //数码管位选码,高——低
- uChar second=0,minute=12,hour=12,month=1,day=13,count; uInt year=2019;
- uChar f_nao=12,s_nao=12; //闹钟分计数,闹钟时计数
- uChar wave=0; //定时器1对0.1ms定时时间进行计数,控制蜂鸣器响的频率
- bit flag_nao; //控制闹钟开关变量 flag_nao= 0-off;1--on
- sbit K1 = P3^0; //设置闹钟分/时位加一
- sbit K2 = P3^1; //退出设置闹钟
- sbit K3 = P3^2; //闹钟开关
- sbit K4 = P3^3; //进入设置闹钟状态
- sbit Key1 = P3^4; //计时停止
- sbit Key2 = P3^5; //调位(校准)
- sbit Key3 = P3^6; //所调位加一
- sbit Key4 = P3^7; //切换时-分-秒、年-月-日
- sbit BEEP = P2^2; //蜂鸣器端口
- sbit LED1 = P2^0; //计时停止时LED1亮
- sbit LED2 = P2^1; //闹钟开启时LED2亮
-
- //函数声明
- void Delayms(uInt t); //长延时函数
- void Dispaly1(uChar second,uChar minute,uChar hour); //时-分-秒显示
- void Dispaly2(uChar day,uChar month,uInt year); //年-月-日显示
- void Keyscan1(); //按键Key4按下次数为双数时(按键Key1~3控制时-分-秒)
- void Keyscan2(); //按键Key4按下次数为单数时(按键Key1~3控制年-月-日)
- void nao_judge(); //判断闹钟
-
- /*************时-分-秒、年-月-日闪烁函数声明*********************/
- void delay(uInt t); /***/
- void Bright1(uChar second,uChar minute,uChar hour); /***/
- void Hour_flicker(uChar second,uChar minute,uChar hour); /***/
- void Minute_flicker(uChar second,uChar minute,uChar hour); /***/
- void Second_flicker(uChar second,uChar minute,uChar hour); /***/
- void Bright2(uChar day,uChar month,uInt year); /***/
- void Year_flicker(uChar day,uChar month,uInt year); /***/
- void Month_flicker(uChar day,uChar month,uInt year); /***/
- void Day_flicker(uChar day,uChar month,uInt year); /***/
- /*************时-分-秒、年-月-日闪烁函数声明*********************/
- //主函数
- void main()
- {
- TMOD=0x11; //置T0、T1都为工作方式1
- TH0=(65536-10000)/256;
- TL0=(65536-10000)%256;
- TR0=1; //开启T0
- ET0=1; //打开T0中断允许位
- IT1=1; //设置外部中断1为下降沿触发
- IT0=0; //设置外部中断0为低电平触发
- EX1=1; //打开外部中断1允许位
- EX0=1; //打开外部中断0允许位
- PT0=1; //设置内部定时中断优先级大于外部中断优先级
- EA=1; //打开中断总允许位
- BEEP=1;
- flag_nao=0;
- while(1)
- {
- static uChar h=0;
- nao_judge();
- if(Key4==0)
- {
- Delayms(10);
- if(Key4==0)
- while(!Key4); //空操作,等待按键释放
- h++;
- }
- if(h%2==1)
- {
- Dispaly2(day,month,year);
- Keyscan2();
- }
- if(h%2==0)
- {
- Dispaly1(second,minute,hour);
- nao_judge();
- Keyscan1();
- }
- }
- }
- //长延时函数
- void Delayms(uInt t)
- {
- uInt i,j;
- for(i=0;i<t;i++)
- for(j=0;j<125;j++)
- ;
- }
- //时-分-秒显示
- void Dispaly1(uChar second,uChar minute,uChar hour)
- {
- P0=b[0];
- P1=a[hour/10];
- Delayms(1);
- P1=0xff;
- P0=b[1];
- P1=a[hour%10];
- Delayms(1);
- P1=0xff;
- P0=b[2];
- P1=0xbf;
- Delayms(1);
- P1=0xff;
- P0=b[3];
- P1=a[minute/10];
- Delayms(1);
- P1=0xff;
- P0=b[4];
- P1=a[minute%10];
- Delayms(1);
- P1=0xff;
- P0=b[5];
- P1=0xbf;
- Delayms(1);
- P1=0xff;
- P0=b[6];
- P1=a[second/10];
- Delayms(1);
- P1=0xff;
- P0=b[7];
- P1=a[second%10];
- Delayms(1);
- P1=0xff;
- }
- //年-月-日显示
- void Dispaly2(uChar day,uChar month,uInt year)
- {
- P0=b[7];
- P1=a[day%10];
- Delayms(1);
- P1=0xff;
- P0=b[6];
- P1=a[day/10];
- Delayms(1);
- P1=0xff;
- P0=b[5];
- P1=a[month%10]&0x7f;
- Delayms(1);
- P1=0xff;
- P0=b[4];
- P1=a[month/10];
- Delayms(1);
- P1=0xff;
- P0=b[3];
- P1=a[year%10]&0x7f;
- Delayms(1);
- P1=0xff;
- P0=b[2];
- P1=a[(year%100)/10];
- Delayms(1);
- P1=0xff;
- P0=b[1];
- P1=a[(year/100)%10];
- Delayms(1);
- P1=0xff;
- P0=b[0];
- P1=a[(year/1000)];
- Delayms(1);
- P1=0xff;
- }
- //按键Key4按下次数为双数时(控制时-分-秒),按键Key1~3的控制
- void Keyscan1()
- {
- static uChar i=0,j=0; //static-保存变量数据,不会清零
- if(Key1==0)
- {
- Delayms(10); //消抖
- if(Key1==0)
- while(!Key1); //等待按键弹起
- i++;
- }
- if(i%2==1) //若Key1按下次数为单数时,停止计数
- {
- LED1=0;
- TR0=0;
- }
- if(i%2==0) //若Key1按下次数为双数时,开始计数
- {
- LED1=1;
- TR0=1;
- }
-
- if(Key2==0) //按键Key2选择调位
- {
- Delayms(10);
- if(Key2==0)
- while(!Key2);
- j++;
- }
- if(j%4==1) //按键按下一次
- {
- Second_flicker(second,minute,hour); //秒显示位闪烁
- if(Key3==0)
- {
- Delayms(10);
- if(Key3==0) //按键Key3进行选定位加一
- while(!Key3);
- second++;
- if(second==60)
- second=0;
- }
- }
- if(j%4==2)//按键按下两次
- {
- Minute_flicker(second,minute,hour); //分显示位闪烁
- if(Key3==0)
- {
- Delayms(10);
- if(Key3==0)
- while(!Key3);
- minute++;
- if(minute==60)
- minute=0;
- }
- }
- if(j%4==3)//按键按下三次
- {
- Hour_flicker(second,minute,hour); //时显示位闪烁
- if(Key3==0)
- {
- Delayms(10);
- if(Key3==0)
- while(!Key3);
- hour++;
- if(hour==24)
- hour=0;
- }
- }
- }
- //按键Key4按下次数为单数时(控制年-月-日),按键Key1~3的控制
- void Keyscan2()
- {
- static uChar m=0,n=0;
- if(Key1==0)
- {
- Delayms(10);
- if(Key1==0)
- while(!Key3);
- m++;
- }
- if(m%2==1)
- {
- LED1=0;
- TR0=0;
- }
- if(m%2==0)
- {
- LED1=1;
- TR0=1;
- }
- if(Key2==0)
- {
- Delayms(10);
- if(Key2==0)
- while(!Key2);
- n++;
- }
- if(n%4==1)
- {
- Day_flicker(day,month,year); //日显示位闪烁
- if(Key3==0)
- {
- Delayms(10);
- if(Key3==0)
- while(!Key3);
- day++;
- if(day==32)
- day=1;
- }
- }
- if(n%4==2)
- {
- Month_flicker(day,month,year); //月显示位闪烁
- if(Key3==0)
- {
- Delayms(10);
- if(Key3==0)
- while(!Key3);
- month++;
- if(month==13)
- month=1;
- }
- }
- if(n%4==3)
- {
- Year_flicker(day,month,year); //年显示位闪烁
- if(Key3==0)
- {
- Delayms(10);
- if(Key3==0)
- while(!Key3);
- year++;
- if(year==10000)
- year=0;
- }
- }
- }
- //判断闹钟,当时间和设置闹钟时间相等时,闹铃响5S
- void nao_judge()
- {
- if(flag_nao==1) //如果flag_nao为真,闹钟开启
- {
- if((minute==f_nao)&&(hour==s_nao)) //判断实时时间和闹钟时间的分、时是否同时相等
- {
- while(second<5&&flag_nao) //如果second<=5和flag_nao都为真,闹铃响5s
- {
- BEEP=0; //TR1=1; //开启T0
- Dispaly1(second,minute,hour);
- }
- }
- }
- BEEP=1;
- }
- //定时器中断0,时钟计数(不断执行)
- void time0_int(void) interrupt 1
- {
- TH0=(65536-10000)/256;
- TL0=(65536-10000)%256;
- count++;
- if(count==100)
- {
- count=0;
- second++;
- if(second==60)
- {
- second=0;
- minute++;
- if(minute==60)
- {
- minute=0;
- hour++;
- if(hour==24)
- {
- hour=0;
- day++;
- if(day==32)
- {
- day=1;
- month++;
- if(month==13)
- {
- month=1;
- year++;
- if(year==10000)
- {
- year=0;
- }
- }
- }
- }
- }
- }
- }
- }
- //外部中断0,闹钟开关,控制flag_nao,按下K3关闭闹钟
- void guan_naozhong() interrupt 0
- {
- flag_nao=~flag_nao;
- LED2=~LED2;
- TR1 = 0; //K3按下,开启外部中断0,关闭定时器中断1,闹钟停止响铃
- while(!K3)
- Dispaly1(second,minute,hour);
- }
- //外部中断1,调节闹钟时间
- void naozhong() interrupt 2
- {
- static uChar n=0;
- // s_nao=12; //设置闹钟时钟初始值
- // f_nao=31; //设置闹钟分钟初始值
- while(K2) //等待按下K2退出,否则循环执行闹钟时间设置
- {
- Dispaly1(0,f_nao,s_nao); //显示闹钟设置
- if(Key2==0) //闹钟调位调时钟、分钟
- {
- Delayms(10);
- if(Key2==0)
- while(!Key2);
- n++;
- }
- if(n%2==1) //调节闹钟时钟
- {
- if(K1==0)
- {
- Dispaly1(0,f_nao,s_nao);
- if(K1==0)
- {
- if(s_nao==23)
- s_nao=0;
- else s_nao++;
- }
- while(!K1)
- Dispaly1(0,f_nao,s_nao);
- }
- }
- if(n%2==0) //调节闹钟分钟
- {
- if(K1==0)
- {
- Dispaly1(0,f_nao,s_nao);
- if(K1==0)
- {
- if(f_nao==59)
- f_nao=0;
- else f_nao++;
- }
- while(!K1)
- Dispaly1(0,f_nao,s_nao);
- }
- }
- }
- }
-
- /************************************************/
- /****************调位时选择位闪烁****************/
- /************************************************/
- //短延时
- void delay(uInt t)
- {
- uInt i;
- for(i=0;i<t;i++)
- ;
- }
- //数码管0~7位分别显示时-分-秒
- void Bright1(uChar second,uChar minute,uChar hour)
- {
- uChar p,k=10;
- for(p=0;p<50;p++)
- {
- P0=b[0];
- P1=a[hour/10];
- delay(k);
- P1=0xff;
- P0=b[1];
- P1=a[hour%10];
- delay(k);
- P1=0xff;
- P0=b[2];
- P1=0xbf;
- delay(k);
- P1=0xff;
- P0=b[3];
- P1=a[minute/10];
- delay(k);
- P1=0xff;
- P0=b[4];
- P1=a[minute%10];
- delay(k);
- P1=0xff;
- P0=b[5];
- P1=0xbf;
- delay(k);
- P1=0xff;
- P0=b[6];
- P1=a[second/10];
- delay(k);
- P1=0xff;
- P0=b[7];
- P1=a[second%10];
- delay(k);
- P1=0xff;
- }
- }
- //秒显示位闪烁
- void Second_flicker(uChar second,uChar minute,uChar hour)
- {
- uChar p,k=10;
- Bright1(second,minute,hour);
- for(p=0;p<50;p++)
- {
- P0=b[0];
- P1=a[hour/10];
- delay(k);
- P1=0xff;
- P0=b[1];
- P1=a[hour%10];
- delay(k);
- P1=0xff;
- P0=b[2];
- P1=0xbf;
- delay(k);
- P1=0xff;
- P0=b[3];
- P1=a[minute/10];
- delay(k);
- P1=0xff;
- P0=b[4];
- P1=a[minute%10];
- delay(k);
- P1=0xff;
- P0=b[5];
- P1=0xbf;
- delay(k);
- P1=0xff;
- P0=b[6]; //该位数码管灭
- P1=0xff;
- delay(k);
- P0=b[7]; //该位数码管灭
- P1=0xff;
- delay(k);
- }
- }
- //分显示位闪烁
- void Minute_flicker(uChar second,uChar minute,uChar hour)
- {
- uChar p,k=10;
- Bright1(second,minute,hour);
- for(p=0;p<50;p++)
- {
- P0=b[0];
- P1=a[hour/10];
- delay(k);
- P1=0xff;
- P0=b[1];
- P1=a[hour%10];
- delay(k);
- P1=0xff;
- P0=b[2];
- P1=0xbf;
- delay(k);
- P1=0xff;
- P0=b[3]; ////熄灭
- P1=0xff;
- delay(k);
- P0=b[4]; ////熄灭
- P1=0xff;
- delay(k);
- P0=b[5];
- P1=0xbf;
- delay(k);
- P1=0xff;
- P0=b[6];
- P1=a[second/10];
- delay(k);
- P1=0xff;
- P0=b[7];
- P1=a[second%10];
- delay(k);
- P1=0xff;
- }
- }
- //时显示位闪烁
- void Hour_flicker(uChar second,uChar minute,uChar hour)
- {
- uChar p,k=10;
- Bright1(second,minute,hour);
- for(p=0;p<50;p++)
- {
- P0=b[0]; ////熄灭
- P1=0xff;
- delay(k);
- P0=b[1]; ////熄灭
- P1=0xff;
- delay(k);
- P0=b[2];
- P1=0xbf;
- delay(k);
- P1=0xff;
- P0=b[3];
- P1=a[minute/10];
- delay(k);
- P1=0xff;
- P0=b[4];
- P1=a[minute%10];
- delay(k);
- P1=0xff;
- P0=b[5];
- P1=0xbf;
- delay(k);
- P1=0xff;
- P0=b[6];
- P1=a[second/10];
- delay(k);
- P1=0xff;
- P0=b[7];
- P1=a[second%10];
- delay(k);
- P1=0xff;
- }
- }
- //数码管0~7位分别显示年-月-日
- void Bright2(uChar day,uChar month,uInt year)
- {
- uChar p,k=10;
- for(p=0;p<50;p++)
- {
- P0=b[7];
- P1=a[day%10];
- delay(k);
- P1=0xff;
- P0=b[6];
- P1=a[day/10];
- delay(k);
- P1=0xff;
- P0=b[5];
- P1=a[month%10]&0x7f;
- delay(k);
- P1=0xff;
- P0=b[4];
- P1=a[month/10];
- delay(k);
- P1=0xff;
- P0=b[3];
- P1=a[year%10]&0x7f;
- delay(k);
- P1=0xff;
- P0=b[2];
- P1=a[(year%100)/10];
- delay(k);
- P1=0xff;
- P0=b[1];
- P1=a[(year/100)%10];
- delay(k);
- P1=0xff;
- P0=b[0];
- P1=a[(year/1000)];
- delay(k);
- P1=0xff;
- }
- }
- //日显示位闪烁
- void Day_flicker(uChar day,uChar month,uInt year)
- {
- uChar p,k=10;
- Bright2(day,month,year);
- for(p=0;p<50;p++)
- {
- P0=b[7]; ////熄灭
- P1=0xff;
- delay(k);
- P0=b[6]; ////熄灭
- P1=0xff;
- delay(k);
- P0=b[5];
- P1=a[month%10]&0x7f;
- delay(k);
- P1=0xff;
- P0=b[4];
- P1=a[month/10];
- delay(k);
- P1=0xff;
- P0=b[3];
- P1=a[year%10]&0x7f;
- delay(k);
- P1=0xff;
- P0=b[2];
- P1=a[(year%100)/10];
- delay(k);
- P1=0xff;
- P0=b[1];
- P1=a[(year/100)%10];
- delay(k);
- P1=0xff;
- P0=b[0];
- P1=a[(year/1000)];
- delay(k);
- P1=0xff;
- }
- }
- //月显示位闪烁
- void Month_flicker(uChar day,uChar month,uInt year)
- {
- uChar p,k=10;
- Bright2(day,month,year);
- for(p=0;p<50;p++)
- {
- P0=b[7];
- P1=a[day%10];
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
万年历-原理图 功能介绍 程序 PCB.zip
(14.17 MB, 下载次数: 158)
|