基于8051单片机实现电子时钟+数字秒表设计

概述

电子时钟是一种利用数字电路来显示秒、分、时的计时装置,与传统的机械钟相比,它具有走时准确、显 示直观、无机械传动装置等优点,因而得到广泛应用。随着人们生活环境的不断改善和美化,在许多场合可以看到数字电子时钟。电子时钟是一个将“ 时”,“分”,“秒”显示于人的视觉器官的计时装置。它的计时周期为24小时,显示满刻度为23时59分59秒,具有校时功能和报时功能。因此,一个基本的数字钟电路主要由译码显示器、“时”,“分”,“秒”计数器、校时电路、报时电路和振荡器组成。主电路系统由秒信号发生器、“时、分、秒”计数器、译码器及显示器、校时电路、整点报时电路组成。秒信号产生器是整个系统的时基信号,它直接决定计时系统的精度,一般用石英晶体振荡器加分频器来实现。将标准秒信号送入“秒计数器”,“秒计数器”采用60进制计数器,每累计60秒发出一个“分脉冲”信号,该信号将作为“分计数器”的时钟脉冲。“分计数器”也采用60进制计数器,每累计60分钟,发出一个“时脉冲”信号,该信号将被送到“时计数器”。“时计数器”采用24进制计时器,可实现对一天24小时的累计。译码显示电路将“时”、“分”、“秒”计数器的输出状态用七段显示译码器译码,通过七段显示器显示出来。整点报时电路时根据计时系统的输出状态产生一脉冲信号,然后去触发一音频发生器实现报时。校时电路时用来对“时”、“分”、“秒”显示数字进行校对调整。
数字秒表是一种较先进的电子计时器,目前国产的数字秒表一般都是利用石英振荡器的振荡频率作为时间基准,采用6位液晶数字显示时间。

设计任务的基本要求

设计任务:
利用AT89C51单片机实现电子时钟和秒表计时的功能,电子时钟可以通过液晶屏显示时间,日期等信息,数字秒表要通过LCD显示当前计时信息,开始/结束,清零功能
设计要求:
基于单片机的电子时钟+数字秒表设计要求:
(1)显示当前时间;
(2)显示当前日期
(3)按键实现电子时钟和数字秒表的功能切换
(4)按键实现秒表停止计时
(5)按键实现秒表复位
用户需求用例

整体方案

此次设计主要是应用单片机来设计电子时钟,硬件部分主要分以下电路模块:显示电路用8个共阴数码管分别显示,小时、分钟和秒,通过动态扫描进行显示,从而避免了译码器的使用,同时节约了I/0端口,使电路更加简单。单片机采用AT89C51系列,这种单片机应用简单,适合电子钟设计。
在这里插入图片描述

图1.整体设计框图
3.1输入部分:
在本实验中主要用用P3口输入按键信号,还用到了特殊的P0口。对于P0口,由于其存在高阻状态,为了实现开关功能,给其添加上拉电阻,具体如下图所示:
在这里插入图片描述

在这里插入图片描述
3.2输出部分:
本电路的输出信号为7段数码管的位选和段选信号,闹铃脉冲信号,提示灯信号。本实验的数码管是共阴的,为了防止段选信号不能驱动数码管,故在P1口连接上拉电阻后,再送段选信号,以提高驱动,位选信号直接从P2口接入。
在这里插入图片描述
3.3晶振与复位电路:
本实验单片机时钟用内部时钟,复位电路为手动复位构成,模块如下:

在这里插入图片描述

电路设计原理

首先选用8051单片机为主控芯片,74LS245为六位共阴数码管的驱动芯片用于数码管显示驱动,以12MHz晶振与两个10k电阻组成该硬件系统时钟信号发生器,并选用四个按键实现功能的切换和显示控制。
数据传输采用总线模式P0端口通过上拉电阻连接74LS245芯片,为数码管驱动端,P1端口为数码管数据端,负责单片机程序输出数据传送至数码管。
12MHz晶振通过两个10uf电容输出一毫秒延迟传入单片机主程序,用于时钟和秒表程序的毫秒响应
K1按键连接P3.1接口输入TX0中断,呼叫切换显示程序请求,软件部分通过端口监听实现功能的切换,K2按键连接P3.2接口输入INT0中断,实现调时和计时开始功能,K3按键连接P3.3接口接入INT1中断,通过秒表清零消隐子程序实现秒表清零和时钟选位调节。
在这里插入图片描述

软件设计

Delay函数模块,提供晶振时钟信号接口,用于时间和秒表的数字定时显示;
Time0,Time1为定时器函数模块,用于提供时钟和秒表的定时器接口;
Display0时间显示模块,实现六位数码管的数字位选消隐和延时;
Display1时间显示模块,实现六位数码管的数字位选消隐和延时;
Display2时间设置模块,通过if语句嵌套,判断对应接口按键
KEY_Time_Set为时间设置按键监听函数,当按下对应按键执行各位加减操作;
KEY_miaobiao为秒表功能函数,实现秒表开始,暂停,和复位功能
Mode_K1为按键模式选择函数,判断现阶段系统处于那种状态调用相对应的按键接口
在这里插入图片描述
全部代码如下

#include<reg52.h>

#define uchar unsigned char
#define uint unsigned int

uchar code Tab0[]=		//定义数码管数组,没有小数点
{
	0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f
};
uchar code Tab1[]=		//定义数码管数组,有小数点
{	
	0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef
};

sbit K1=P3^2;			//模式选择键,本程序三种模式,分别是时间显示、秒表、时间设置
sbit K2=P3^3;			//设置时间时加一/开始(暂停)秒表按键
sbit K3=P3^4;			//切换设置位/清零秒表按键

void Delay(uchar x);		//延时函数
void Display0(); 		//时间显示函数
void Display1(); 		//秒表显示函数
void Display2();		//时间设置显示函数
void Init(); 			//中断初始化函数
void Mode_K1();			//模式切换函数
void KEY_MiaoBiao();	//检测秒表操作按键
void KEY_Time_Set();	 //检测时间设置按键


uchar Hours=23,Minutes=56,seconds=55;		//分别定义三个变量表示时、分、秒
uchar Time0_bit=0;			//用于定时器0的溢出标志
bit Set_Time=0;				//设置时 闪烁时长的标志位
bit Set0=0;					//设置时间标志,确定是设置‘分’还设置‘时’
uchar K1_bit=0;		  		//用于模式切换的标志
uchar Miao_Biao0,Miao_Biao1,Miao_Biao2,Miao_Biao3,Miao_Biao4;		//用于秒表的变量

void main()
{
	Init();										//中断初始化
	while(1)									//死循环
		{
			Mode_K1();							//模式扫描
			switch(K1_bit)		 				//模式选择
				{
					case 0:
						{
							Display0();			//显示时间								
							break;
						}
					case 1:
						{
							Display1();	 		//显示秒表
							KEY_MiaoBiao();		//扫描秒表操作
							break;
						}
					case 2:
							{
								Display2();		//设置时间时的显示程序,可闪烁定位
								KEY_Time_Set();	//扫描按键
								break;
							}
				}
		}
}

void KEY_Time_Set()	   							//设置时间时的按键扫描函数
{
	if(K1_bit==2)	  							//判断是否为时间设置模式
		{
			if(K2==0)		 					//K2有按下(下同)
				{
					Delay(10);	   				//延时消抖(下同)
					if(K2==0)				 	//再次检测是否为误按
						{
							if(Set0==0)			//检测是设置‘时’还是分,Set0为0时设置‘分’,Set0为1时设置‘时’
								{
									Minutes++; 	//‘分’加1
									if(Minutes==60)	//当'分'加到60时,重新赋值0
										Minutes=0;
								}
							else
								{
									Hours++;  	//‘时’加1
									if(Hours==24)	//当'时'加到24时,重新赋值0
										Hours=0;
								}
							while(!K2);			//按键松开检测,消除松开按键时的抖动干扰
						}
				}
			if(K3==0)
				{
					Delay(10);
					if(K3==0)
						{
							Set0=~Set0;			//K3每按一次Set0取反,以确定是设置‘时’还是设置‘分’,Set0为0时设置‘分’,Set0为1时设置‘时’
							while(!K3);
						}	
				}
		}
}

void KEY_MiaoBiao()								//检测秒表按键操作
{
	if(K1_bit==1)								//判断是否为秒表模式
		{
			if(K2==0)
				{
					Delay(10);
					if(K2==0)
						{
							TR1=~TR1;			//K2每按一次TR1取反,暂停或开始定时器1,达到暂停或开始秒表的目的
							while(!K2);
						}
				}
			if(K3==0)
				{
					Delay(10);
					if(K3==0)	 				//当K3按下时秒表所有数据清零,并停止定时器1
						{
							TR1=0;	 			//停止定时器1
							Miao_Biao0=0; 		//清零数据
							Miao_Biao1=0;
							Miao_Biao2=0;
							Miao_Biao3=0;
							Miao_Biao4=0;
							while(!K3);
						}
				}
		}
}

void Mode_K1()									//模式选择键,本程序三种模式,分别是时间显示、秒表、时间设置
{
	if(K1==0)
		{
			Delay(10);
			if(K1==0)
				{
					K1_bit++;
					if(K1_bit==3)
						{
							K1_bit=0;
						}
					while(!K1);
/***********************************************************************
*************当K1_bit为0时显示时钟,为1时进入秒表,*********************
*******************为2时进入时间设置模式********************************
***********************************************************************/
				}
		}
}
	

void Time1() interrupt 3  			//定时器1函数
{
	TH1=(65536-50000)/256;			//重装初值
	TL1=(65536-50000)%256;

	Miao_Biao0++;
	if(Miao_Biao0==2)				//以下为秒表数据处理
		{
			Miao_Biao0=0;
			Miao_Biao1++;	 		//Miao_Biao1每加1次为100ms,
			if(Miao_Biao1==10)
				{
					Miao_Biao1=0;
					Miao_Biao2++;
					if(Miao_Biao2==60)
						{
							Miao_Biao2=0;
							Miao_Biao3++;
							if(Miao_Biao3==60)
								{
									Miao_Biao3=0;
									Miao_Biao4++;
									if(Miao_Biao4==10)
										Miao_Biao4=0;
								}
						}
				}
		}
}


void Time0() interrupt 1 					//定时器0函数
{
	TH0=(65536-50000)/256;	   				//重装初值
	TL0=(65536-50000)%256;
	Time0_bit++;
	if((Time0_bit%10)==0)					//每溢出10次Time0_bit取反一次
		Set_Time=~Set_Time;	  				//0.5秒闪烁一次

	if(Time0_bit==20)						//以下为时间数据处理
		{
			Time0_bit=0;
			seconds++;
			if(seconds==60)
				{
					seconds=0;
					Minutes++;
					if(Minutes==60)
						{
							Minutes=0;
							Hours++;
							if(Hours==24)
								{
									Hours=0;
								}
						}
				}

		}
}

void Init()	 						//中断初始化函数
{
	EA=1;		 					//开总中断
	TMOD=0X11;			  			//定时器工作方式选择,定时器0和定时器1都选择第1种工作方式
	TH0=(65536-50000)/256;			//定时器0装初值,定时50ms
	TL0=(65536-50000)%256;
	ET0=1;							//开定时器0开关
	TR0=1;			   				//开定时器0小开关

	TH1=(65536-50000)/256;			//定时器1装初值,定时50ms
	TL1=(65536-50000)%256;
	ET1=1;				  			//开定时器1开关
	TR1=0;							//关定时器1小开关
}

void Display2()							//时间设置时的显示函数	
{
	if(Set0==0)							//判断是否为设置‘时’还是‘分’
		{
			P0=Tab0[seconds%10];		//显示秒的个位
			P1=0xdf;					//段选
			Delay(10);					//延时
			P0=0X00;					//消隐
		
			P0=Tab0[seconds/10];		//显示秒的十位
			P1=0xef;					//段选
			Delay(10);					//延时
			P0=0X00;					//消隐
			
			if(Set_Time)				//这个if语句实现分钟以0.5秒的频率闪烁
				{
					P0=Tab1[Minutes%10];		//显示分的个位,需要加上小数点做分隔符
					P1=0xf7;					//段选
					Delay(10);					//延时
					P0=0X00;					//消隐

					P0=Tab0[Minutes/10];		//显示分的十位
					P1=0xfb;					//段选
					Delay(10);					//延时
					P0=0X00;					//消隐
				}
			else
				{
					P0=0x00;		//显示分的个位,需要加上小数点做分隔符
					P1=0xf7;					//段选
					Delay(10);					//延时
					P0=0X00;					//消隐
		
					P0=0x00;		//显示分的十位
					P1=0xfb;					//段选
					Delay(10);					//延时
					P0=0X00;					//消隐
				}
			
			P0=Tab1[Hours%10];			//显示时的个位,需要加上小数点做分隔符
			P1=0xfd;					//段选
			Delay(10);					//延时
			P0=0X00;					//消隐
		
			P0=Tab0[Hours/10];			//显示时的十位
			P1=0xfe;					//段选
			Delay(10);					//延时
			P0=0X00;					//消隐
		}


	else			//‘时’钟闪烁
		{
			P0=Tab0[seconds%10];		//显示秒的个位
			P1=0xdf;					//段选
			Delay(10);					//延时
			P0=0X00;					//消隐
		
			P0=Tab0[seconds/10];		//显示秒的十位
			P1=0xef;					//段选
			Delay(10);					//延时
			P0=0X00;					//消隐
			
			P0=Tab1[Minutes%10];		//显示分的个位,需要加上小数点做分隔符
			P1=0xf7;					//段选
			Delay(10);					//延时
			P0=0X00;					//消隐

			P0=Tab0[Minutes/10];		//显示分的十位
			P1=0xfb;					//段选
			Delay(10);					//延时
			P0=0X00;					//消隐
			
			if(Set_Time)				//这个if语句实现‘时’钟以0.5秒的频率闪烁
				{
					P0=Tab1[Hours%10];			//显示时的个位,需要加上小数点做分隔符
					P1=0xfd;					//段选
					Delay(10);					//延时
					P0=0X00;					//消隐
				
					P0=Tab0[Hours/10];			//显示时的十位
					P1=0xfe;					//段选
					Delay(10);					//延时
					P0=0X00;					//消隐
				}
			else
				{
					P0=0x00;			//显示时的个位,需要加上小数点做分隔符
					P1=0xFF;					//段选
					Delay(10);					//延时
					P0=0X00;					//消隐
				
					P0=0X00;			//显示时的十位
					P1=0xFF;					//段选
					Delay(10);					//延时
					P0=0X00;					//消隐				
				}		
		}
}

void Display1()			//显示秒表
{
	P0=Tab0[Miao_Biao1%10];		//显示1/10秒的个位
	P1=0xdf;					//段选
	Delay(10);					//延时
	P0=0X00;					//消隐

	P0=Tab1[Miao_Biao2%10];		//显示秒的个位,需要加上小数点做分隔符
	P1=0xef;					//段选
	Delay(10);					//延时
	P0=0X00;					//消隐

	P0=Tab0[Miao_Biao2/10];		//显示秒的十位
	P1=0xf7;					//段选
	Delay(10);					//延时
	P0=0X00;					//消隐

	P0=Tab1[Miao_Biao3%10];		//显示分的个位,需要加上小数点做分隔符
	P1=0xfb;					//段选
	Delay(10);					//延时
	P0=0X00;					//消隐

	P0=Tab0[Miao_Biao3/10];		//显示分的十位
	P1=0xfd;					//段选
	Delay(10);					//延时
	P0=0X00;					//消隐

	P0=Tab1[Miao_Biao4%10];		//显示时的个位,需要加上小数点做分隔符
	P1=0xfe;					//段选
	Delay(10);					//延时
	P0=0X00;					//消隐
}

void Display0()			//显示时钟
{
	P0=Tab0[seconds%10];		//显示秒的个位
	P1=0xdf;					//段选
	Delay(10);					//延时
	P0=0X00;					//消隐

	P0=Tab0[seconds/10];		//显示秒的十位
	P1=0xef;					//段选
	Delay(10);					//延时
	P0=0X00;					//消隐

	P0=Tab1[Minutes%10];		//显示分的个位,需要加上小数点做分隔符
	P1=0xf7;					//段选
	Delay(10);					//延时
	P0=0X00;					//消隐

	P0=Tab0[Minutes/10];		//显示分的十位
	P1=0xfb;					//段选
	Delay(10);					//延时
	P0=0X00;					//消隐

	P0=Tab1[Hours%10];			//显示时的个位,需要加上小数点做分隔符
	P1=0xfd;					//段选
	Delay(10);					//延时
	P0=0X00;					//消隐

	P0=Tab0[Hours/10];			//显示时的十位
	P1=0xfe;					//段选
	Delay(10);					//延时
	P0=0X00;					//消隐
}


void Delay(uchar x)		  		//延时
{
	uchar i,j;
	for(i=x;i>0;i--)
		for(j=110;j>0;j--);
}


元件清单

元件清单:

器件名称 数量
按键SPST Push Button 4
12MHz 晶振 1
10uf电容 9
74LS245单片机 1
7SEG-MPX6-CA-BLUE六位共阴极数码管 1
8051单片机 1

项目下载地址

链接: 下载地址.

版权声明:本文为CSDN博主「锋面反气旋@」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43798715/article/details/122046083

锋面反气旋@

我还没有学会写个人说明!

暂无评论

相关推荐

基于AT89C51的蓝牙循迹避障小车

基于AT89C51的蓝牙循迹避障小车 对标题的解读: AT89C51:在下使用的是STC89C52这款芯片,c51和c52在新手入门阶段是一样的,所以不必纠结于到底是哪个名字&#xff

立创EDA从零开始教学

结合自己为公司设计的产品的经验上,推出一套立创EDA的硬件教学设计课程。或者说是一系列文章。# 系列文章目录第一章 前言和软件介绍# 前言 大家可以叫我小刘,我大学是自动化专业,在大二开始接触单片机&#