目录
一、设计背景
电子钟是指利用数字电路或单片机等现代电子技术来实现时间计量和显示的钟表。相较于传统机械钟、石英钟等时钟,电子钟具有精度高、音响小、易于制造和调节等优点,同时也由于其美观大方的外观设计而成为了家居装饰中不可或缺的一部分。
其中,基于 51 单片机的电子钟因其简单易操作、代码共享、性能稳定等特点而广受欢迎。由于 51 单片机通过提供基本的输入输出端口和计时器模块等重要功能,使得使用者可以轻松地在自己的作品中集成时钟计时的功能。
此外,随着时钟功能的不断完善,如闹铃设置、温度显示、继电器控制等进阶功能的逐步融入,这些具有实际意义的设备进一步丰富了电子钟的应用场景。例如在育儿宝典、健康保健仪等家里或医护场所中,常常需要借助电子钟进行测量及提醒,以便用户合理安排工作和休息时间。
需要注意的是,在制作电子钟过程中,物料选择和电路设计都需要严格遵守相关标准和规范,确保生产产品符合设备安全、环保和电磁兼容性的要求。
总之,基于 51 单片机的电子钟是一项极具实用性和创意性的工程设计,不断发展与完善将带来更加优秀的产品,并为用户提供更多便利与乐趣。
二、设计要求
本设计以51单片机为控制核心,设计一种智能电子钟系统。整个系统包括MCU、晶振电路、时钟电路、按键电路以及LCD1602显示电路。可具体实现以下功能:
(1)计时:年、月、日、时、分、秒、周。闰年自动判别。
(2)时间和年、月、日、交替显示。
(3)日期和时间可以通过按键设置,按键数量不超过4个。
三、仿真演示
完整仿真图如下所示。
运行仿真,显示时分秒周以及闰年判别,RUN表示闰年,PING表示平年。
交替显示年月日周以及闰年判别。
按下设置键进入设置界面,在设置界面,默认设置秒,通过再次按动设置按键实现年月日周时分秒的依次设置。
设置分。
设置时。
设置日。
设置月。
设置年。
设置秒
设置完成后,按下确认键,回到时钟界面,按照设定的时间开始计时。修改后显示时分秒周如下。
修改后显示年月日周。
四、程序展示(部分)
#include "reg52.h"
#include "lcd.h"
sbit key1 = P3^4;//设置
sbit key4 = P3^5;//确认
sbit key2 = P3^6;//加
sbit key3 = P3^7;//减
unsigned char cnt,set_flag;
unsigned int hour=0,min=0,sec=0;
unsigned int year=2024,mon=7,day=3,week=0;
unsigned char Str_year[5],Str_month[3],Str_day[4],Str_hour[3],Str_min[3],Str_sec[4];//年,月,日,周,时,分,秒
unsigned int num=0;
bit lcd_flag;
void Inter_Init()//定时器初始化
{
TMOD = 0x01;//定时器TR0,16位
TH0 = (65536-50000)/256;//定时5ms
TL0 = (65536-50000)%256;
EA = 1;//总中断开
ET0 = 1;//允许TR0中断
TR0 = 1;//TR0启动
}
void get_week(unsigned int y,m,d)//基姆拉尔森计算公式,由日期得星期
{
if(m==1||m==2)
{
m+=12;
y--;
}
week=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7;
}
void write_week(unsigned char week)//写星期函数
{
switch(week)
{
case 1:
LcdShowStr(12,1,"MON");//星期数为1时,显示
break;
case 2:
LcdShowStr(12,1,"TUE");//星期数据为2时显示
break;
case 3:
LcdShowStr(12,1,"WED");//星期数据为3时显示
break;
case 4:
LcdShowStr(12,1,"THU");//星期数据为4是显示
break;
case 5:
LcdShowStr(12,1,"FRI");//星期数据为5时显示
break;
case 6:
LcdShowStr(12,1,"STA");//星期数据为6时显示
break;
case 0:
LcdShowStr(12,1,"SUN");//星期数据为7时显示
break;
}
}
void get_year()
{
if(((year%4)==0&&(year%100)!=0)||(year%400)==0)
{
LcdShowStr(12,0,"RUN ");//农历闰年显示
}
else
{
LcdShowStr(12,0,"PING");//农历平年显示
}
}
void Show_time()//LCD显示时间
{
get_week(year,mon,day);
write_week(week);
get_year();
Str_year[0]=(year/1000)|0x30;
Str_year[1]=(year%1000/100)|0x30;
Str_year[2]=(year%100/10)|0x30;
Str_year[3]=(year%10)|0x30;
Str_month[0]=(mon/10)|0x30;
Str_month[1]=(mon%10)|0x30;
Str_day[0]=(day/10)|0x30;
Str_day[1]=(day%10)|0x30;
Str_day[2]=' ';
Str_hour[0]=(hour/10)|0x30;
Str_hour[1]=(hour%10)|0x30;
Str_min[0]=(min/10)|0x30;
Str_min[1]=(min%10)|0x30;
Str_sec[0]=(sec/10)|0x30;
Str_sec[1]=(sec%10)|0x30;
Str_sec[2]=' ';
if(set_flag==0)
{
LcdShowStr(0,1," ");
num++;
if(num>=100)num=0;
if(num>50)
{
LcdShowStr(0,0,Str_year); //液晶显示年份
LcdShowStr(4,0,"-");
LcdShowStr(5,0,Str_month);
LcdShowStr(7,0,"-");
LcdShowStr(8,0,Str_day);
}
else
{
LcdShowStr(0,0,Str_hour); //液晶显示小时
LcdShowStr(2,0,":");
LcdShowStr(3,0,Str_min); //液晶显示分钟
LcdShowStr(5,0,":");
LcdShowStr(6,0,Str_sec); //液晶显示秒
LcdShowStr(8,0," ");
}
}
else
{
LcdShowStr(0,0,Str_year); //液晶显示年份
LcdShowStr(4,0,"-");
LcdShowStr(5,0,Str_month);
LcdShowStr(7,0,"-");
LcdShowStr(8,0,Str_day);
LcdShowStr(0,1,Str_hour); //液晶显示小时
LcdShowStr(2,1,":");
LcdShowStr(3,1,Str_min); //液晶显示分钟
LcdShowStr(5,1,":");
LcdShowStr(6,1,Str_sec); //液晶显示秒
}
}
void Delay_KEY(unsigned int KEY_ms)
{
while(KEY_ms--);
}
void Key_Scan()
{
if(key1 == 0)//设置:年1,月2,日3,时4,分5,秒6
{
Delay_KEY(100);
if(key1 == 0)
{
TR0=0;
set_flag++;
if(set_flag==7)
{
set_flag=1;
}
while(key1==0);
}
}
if(key2 == 0)//加
{
Delay_KEY(100);
if((key2 == 0)&&(set_flag == 1)&&(sec<60))
{
sec++;
}
else if((key2 == 0)&&(set_flag == 2)&&(min<60))
{
min++;
}
else if((key2 == 0)&&(set_flag == 3)&&(hour<24))
{
hour++;
}
else if((key2 == 0)&&(set_flag == 4))
{
if((mon==1||mon==3||mon==5||mon==7||mon==8||mon==10||mon==12)&&day<=30)
{
day++;
}
if((mon==4||mon==6||mon==9||mon==11)&&day<=29)
{
day++;
}
if(mon==2)
{
if(((year%4)==0&&(year%100)!=0)||(year%400)==0)//闰年
{
if(day<=28)
{
day++;
}
}
else
{
if(day<=27)
{
day++;
}
}
}
}
else if((key2 == 0)&&(set_flag == 5)&&(mon<12))
{
mon++;
}
else if((key2 == 0)&&(set_flag == 6)&&(year<10000))
{
year++;
}
while(key2==0);
}
if(key3 == 0)//减
{
Delay_KEY(100);
if((key3 == 0)&&(set_flag == 1)&&(sec>0))
{
sec--;
}
else if((key3 == 0)&&(set_flag == 2)&&(min>1))
{
min--;
}
else if((key3 == 0)&&(set_flag == 3)&&(hour>1))
{
hour--;
}
else if((key3 == 0)&&(set_flag == 4)&&(day>0))
{
day--;
}
else if((key3 == 0)&&(set_flag == 5)&&(mon>0))
{
mon--;
}
else if((key3 == 0)&&(set_flag == 6)&&(year>0))
{
year--;
}
else
{
LcdShowStr(0,0," ");
LcdShowStr(0,1," ");
Delayms(1);
key1=1;
lcd_flag=~lcd_flag;
}
while(key3==0);
}
if(key4 == 0)//确认
{
Delay_KEY(100);
if(key4 == 0)
{
set_flag=0;
TR0=1;
}
while(key4==0);
}
}
/*******************主函数***************************/
void main()
{
Inter_Init();//定时器初始化
LcdInit();
Show_time();
Delayms(1);
key1=1;
while(1)
{
Key_Scan();
Delayms(1);
if(lcd_flag==0)
{
Show_time();//LCD显示时间
Delayms(1);
key1=1;
}
}
}
void timer0_isr() interrupt 1 //定时器中断服务函数
{
TH0=(65536-50000)/256;//50ms
TL0=(65536-50000)%256;
cnt++;
if(cnt==19)//1s
{
sec++;
cnt=0;
}
if(sec==60)
{
min++;
sec=0;
}
if(min==60)
{
hour++;
min=0;
}
if(hour==24)
{
day++;
hour=0;
}
if((mon==1||mon==3||mon==5||mon==7||mon==8||mon==10||mon==12)&&day==32)
{
mon++;
day=1;
}
if((mon==4||mon==6||mon==9||mon==11)&&day==31)
{
mon++;
day=1;
}
if(mon==2&&day>=29)
{
if(((year%4)==0&&(year%100)!=0)||(year%400)==0)
{
if(day==30)
{
mon++;
day=1;
}
}
else
{
if(day==29)
{
mon++;
day=1;
}
}
}
if(mon==13)
{
year++;
if(year >= 99)year=0;
mon=1;
}
}
仿真源文件及源程序百度网盘链接:https://pan.baidu.com/s/1J3TaGyE0Nl_g_0UtCxHhpA
提取码:5c6j