资讯详情

单片机AT89C51基于七段数码管的电子表

仿真工具

硬件:Proteus8.9

代码:keil4.0

可参考软件下载:(15条消息) Win10 安装Proteus 8.9安装资源共享安装步骤,解决可能出现的问题和问题_博客打大怪-CSDN博客_win10安装proteus

实现功能

通过LED数字管显示时间分秒,通过模式按钮和加减按钮实现时间分秒调整。定时使用闹钟按钮报警蜂鸣器

所用元器件

AT89C51单片机,共阳极LED集数字管、按钮、电阻块、反向器

主要元器件AT89C51单片机:

是一种带4K可编程的字节闪烁可以擦除只读存储器(FPEROM—Falsh Programmable and Erasable Read Only Memory)低压,高性能CMOS8位微处理器,俗称单片机。该器件采用ATMEL高密度非易失存储器制造技术和工业标准MCS-51指令集与输出管脚兼容。多功能8位CPU在单个芯片中与闪烁存储器结合,ATMEL的AT89C51是一种高效的微控制器,为许多嵌入式控制系统提供了高灵活性和低成本的解决方案。

引脚功能说明:

VCC(40引脚):接 5V电源。

VSS(20引脚):接地。

XTAL1:(19引脚):反向振荡放大器和内部时钟电路的输入。

XTAL2:(18引脚):反向振荡器输出。

RST:高电平复位引脚有效。

EA:访问允许控制端的外部程序存储器。

ALE:低8位地址定允许信号端。

PSEN:阅读外部程序存储器的选择通信号端。

P0口漏极开路双向I/O口。

P1口:8位,准双向I/O口,内部上拉电阻。

P2:8位,准双向I/O口,内部上拉电阻。

P三口八位,准双向I/O口,内部上拉电阻。

简述工作原理

时间显示控制由单片机内部延迟程序和定时器中断实现。延迟程序和循环程序产生一秒定时,60秒为一分钟,60分钟为一小时,24小时为一天,以达到计时的目的。演示程序和循环程序根据数字管闪烁中断(即秒表中断)计算秒,闪烁两次为一秒。数字管采用动态扫描显示方案。

AT89C51的P0端口全部作为数码管的段选端,P2.0到P2.5端口作为数码管的位选端。P3.2端口闹钟按钮,P3.三个端口是模式按钮,P3.4、P3.分别是加键减键。

模式键下一共有7种模式切换,每按下一次切换一种模式:模式0为电子表正常显示状态。模式1为秒时间调整,调整时用加减键调整。模式2是分时间调整,调整也使用加减键。模式3为小时模式调整。模式4是闹钟秒的定时。模式5是定时闹钟。模式6是改变闹钟标志位的状态。模式7为复位状态,六个数字管均为0。如果按钮在10秒内不操作,则返回正常显示模式。

硬件电路图

自检程序

#include<reg51.h>   ///51单片机头文件 sbit DU=P0^0 ;     //P0^0端口控制段选端 sbit WEI=P2^0 ;    //P2^0端口控制位选端 void main() { WEI=1;             //打开位选端 P0=0xfe;           ///输入所选位置 WEI=0;             //位选端关闭 DU=1;            //打开段选端 P0=0xc0;         ///送入所选段(显示数字0) DU=0;            //位选端关闭 while(1); } 

自检程序的目的

使第一位数字管显示数字零,验证硬件的可用性

自检结果

代码编写 及注释

#include <REG51.H>  unsigned char code LEDDATA[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92, 0x82,0xf8,0x80,0x90,0xff,0x8e,0x86}; //数字管显示的代码表,后三个是灭灯,"F"、"E" unsigned char code LEDBITDATA[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,};  ///数码管扫描代码表 unsigned char LEDBuffer[6];   //定义显示缓冲区数组 unsigned char Hour;     //时单元 unsigned char Minute;     //分单元 unsigned char Second;    //秒单元 unsigned char Hourrom;     //定时单元 unsigned char Minuterom;    ///定时分单元 unsigned char Minutesw;          //秒表分单元 unsigned char Secondsw;          //秒表秒单元 unsigned char Centsw;           //秒表百分之一秒单元 unsigned char Beepflag;     //定时响铃标志 unsigned char SETFlag=0;   //模式标志 unsigned char second_tick;    //闪动标志 unsigned char Time;     //按键操作超时计数 unsigned char ALMFlag=0;   //定期打开标志  sbit ALM_KEY=P3^2;     ///闹钟模式键和端口P3.2相连 sbit SET_KEY=P3^3;       //模式按钮和端口P3.3相连 sbit UP_KEY=P3^4;     //加计数键与端口P3.4相连 sbit DOWN_KEY=P3^5;     //减数键和端口P3.5相连 sbit Beep=P1^7;      ///蜂鸣器接口引脚P1.7  void init()                         //定时器T0初始化 {  TMOD=0x01;      //T0初始化方法1,定时  TH0=(65536-2000)/256;   //TH0,TL0装入定时2mS的初值  TL0=(65536-2000)%6;  TR0=1;       //启动T0工作  ET0=1;       //允许T0溢出中断    TH1=(65536-50000)/256;          TL1=(65536-50000)%6;   TR1=0;  ET1=1;  EA=1;       //CPU开中断 }  void Delay(unsigned int t)   //去按键抖动延迟子程序 { while(t)t--; } void key()       //键盘操作子程序 { unsigned chari;				//缓冲数组LEDBuffer【i】的位数标志
	char Num;						//临时数字,存储数组合并值
	if(SET_KEY==0)					//判断模式键是否按下
	{	Delay(5000);					//排除是按键抖动的情况
		if(SET_KEY==0)				//再判断是否真得按下了
		{ 	SETFlag++;				//模式改变:调节时间位置(指时分秒的调节)状态改变
			if(SETFlag==8) SETFlag=0;	//返回正常模式
			if(SETFlag==1) i=4;			//调节读取显示数组的位数
			if(SETFlag==2) i=2;
			if(SETFlag==3) i=0;
			if(SETFlag==4) i=4;
			if(SETFlag==5) i=2;
			if(SETFlag==6) i=0;
			if(SETFlag==7) ;
		}
	while(SET_KEY==0);					//等按键释放
	}

	if((UP_KEY==0)&&(SETFlag!=0))		//判断加计数键是否按下
	{
		Delay(5000);					//去按键抖动
		if(UP_KEY==0)					//再判断是否真得按下了
		{	Num=(LEDBuffer[i+1]+LEDBuffer[i]*10);
			Num++;						//时单元的数值加1
			if((Num==24)&&((SETFlag==3)||(SETFlag==5))) Num=0;	//加到24归0
			if((Num==60)&&((SETFlag==1)||(SETFlag==2)||(SETFlag==4))) Num=0;			//加到60归0
			switch(SETFlag)				//把修改值写回时分秒单元和定时时分单元
			{	case 0: ;break;
				case 1: Second=Num;break;
				case 2: Minute=Num;break;
				case 3: Hour=Num;break;
				case 4: Minuterom=Num;break;			
				case 5: Hourrom=Num;break;
				case 6: ALMFlag=!ALMFlag;break;             //定时的开启与暂停
				case 7: TR1=!TR1;break;						//秒表开始与暂停
			}
		}
	 }

	if((DOWN_KEY==0)&&(SETFlag!=0))	//判断减计数键是否按下
	{
		Delay(5000);				//去按键抖动
		if(DOWN_KEY==0)				//再判断是否真得按下了
		{	Num=(LEDBuffer[i+1]+LEDBuffer[i]*10);
			Num--;					//时单元的数值减1
			if((Num<0)&&((SETFlag==3)||(SETFlag==5))) Num=23;	//到24归0
			if((Num<0)&&((SETFlag==1)||(SETFlag==2)||(SETFlag==4))) Num=59;			//到60归0
			switch(SETFlag)				//把修改值写回
			{	case 0: ;break;
				case 1: Second=Num;break;
				case 2: Minute=Num;break;
				case 3: Hour=Num;break;	
				case 4: Minuterom=Num;break;
				case 5: Hourrom=Num;break;				
				case 6: ALMFlag=!ALMFlag;break;
				case 7: TR1=0;Minutesw=0;Secondsw=0;Centsw=0;break;		//秒表复位(reset)			
			}
		}
	}
	if(ALM_KEY==0)                      //闹钟按键被按下
	{	SETFlag=0;						//状态返回
		if(ALMFlag==0)LEDBuffer[0]=11;	//根据闹铃状态显示F或者E
		else LEDBuffer[0]=12;			//将时,分,秒单元内容送入暂存区
		LEDBuffer[1]=10;				//关闭该数码管显示
		LEDBuffer[2]=Hourrom/10;        //定时时单元十位
		LEDBuffer[3]=Hourrom%10;        //定时时单元个位
		LEDBuffer[4]=Minuterom/10;      //定时分单元十位
		LEDBuffer[5]=Minuterom%10;      //定时分单元个位
		
		if(ALMFlag==1)                 //定时关闭
		{	Beep=1;                    //响铃关闭
			Beepflag=0;                //定时响铃标志开启
		}
	}
}			 


void display()							//显示暂存区内容对应的代码显示
{ 	unsigned char LEDScanCount,i;		//位选扫描计数器
P0=0xff;								//消影,适应仿真需要
if((UP_KEY==0)||(DOWN_KEY==0)) i=0x00;	//加减键有操作放弃闪烁
 	else i = 0xff*second_tick;			//设定闪烁变量
P2= LEDBITDATA[LEDScanCount];			//送出位选数据(P2端口控制位选数据)
switch(SETFlag)
	{	case 0:	P0=LEDDATA[LEDBuffer[LEDScanCount]];break; 	//送出段选数据 (P0端口控制段选数据)
	 	case 1:	if(LEDScanCount>=4)							//判断出是最高两位数码管
					 P0=i|LEDDATA[LEDBuffer[LEDScanCount]];	//使小时闪烁
				else P0=LEDDATA[LEDBuffer[LEDScanCount]];break;	//其他位正常显示
	 	case 2:	if((LEDScanCount==2)||(LEDScanCount==3))	 	//判断出是中间两位数码管
					 P0=i|LEDDATA[LEDBuffer[LEDScanCount]];	//使分钟闪烁
				else P0=LEDDATA[LEDBuffer[LEDScanCount]];break;	//其他位正常显示
		case 3:	if(LEDScanCount<=1)                           //判断出是最低两位数码管
					 P0=i|LEDDATA[LEDBuffer[LEDScanCount]];   //使秒闪烁
				else P0=LEDDATA[LEDBuffer[LEDScanCount]];break;  //其他位正常显示
		case 4:	if(LEDScanCount>=4)
					 P0=i|LEDDATA[LEDBuffer[LEDScanCount]];
				else P0=LEDDATA[LEDBuffer[LEDScanCount]];break;
	 	case 5:	if((LEDScanCount==2)||(LEDScanCount==3))
					 P0=i|LEDDATA[LEDBuffer[LEDScanCount]];
				else P0=LEDDATA[LEDBuffer[LEDScanCount]];break;
		case 6:	if(LEDScanCount<=1)
					 P0=i|LEDDATA[LEDBuffer[LEDScanCount]];
				else P0=LEDDATA[LEDBuffer[LEDScanCount]];break;
		case 7:	P0=LEDDATA[LEDBuffer[LEDScanCount]];break; 
	}
LEDScanCount++; 						//扫描指针加计数
if(LEDScanCount==6) LEDScanCount=0 ;	//扫描完从头开始;
}


void time0() interrupt 1               //第一个中断:用于按键调整时间时的中断
{   unsigned int SecondCount;
	unsigned int timercp;				//秒计数器
	TH0=(65536-2000)/256;				//TH0,TL0装入定时2mS的初值
	TL0=(65536-2000)%256;	 
	display();							//调用显示函数
	timercp++;		
	if((SETFlag!=0)&&(SETFlag!=7)) 						//SETFlag:模式标志。
		{	if((SET_KEY==0)||(UP_KEY==0)||(DOWN_KEY==0)) Time=0;	//任意键有操作放弃按键超时计数
		 	if (Time>=10){SETFlag=0;Time=0;}                        //10秒不操作自动返回
		}
	if (timercp == 250)				
		{	timercp= 0; 
			second_tick = !second_tick;		//设定0.5秒闪动一次 
			SecondCount++;
			if(SecondCount==2) 				//1秒的时间
			{	SecondCount=0;				//计数器清零
				Time++;					
	 			Second++;					//时间的秒加1
				if(Second==60)
				{	Second=0;		 		//秒清零
					Minute++;		 		//分进一
					if(Minute==60)
					{	Minute=0;
						Hour++;
						if(Hour==24)Hour=0;	//小时清零
					}
				}
			}
	if(SETFlag<=3)				 			//状态模式小于3是加载时钟时间
			{ LEDBuffer[0]=Hour/10;
				LEDBuffer[1]=Hour%10;
				LEDBuffer[2]=Minute/10;
				LEDBuffer[3]=Minute%10;
				LEDBuffer[4]=Second/10;
				LEDBuffer[5]=Second%10; 
			
			}
			else							 //调整闹钟时间时加载闹钟时间
			{	if(ALMFlag==0)LEDBuffer[0]=11; //ALMFlag==0:定时开启标志。显示闹钟为激活状态
		 		else LEDBuffer[0]=12;
				LEDBuffer[1]=10;			 //关闭倒数第二位
				LEDBuffer[2]=Hourrom/10;     //定时时单元的十位
				LEDBuffer[3]=Hourrom%10;     //定时时单元的个位
				LEDBuffer[4]=Minuterom/10;   //定时分单元十位
				LEDBuffer[5]=Minuterom%10;	 //定时分单元个位	
			}
			if(SETFlag==7)                        //秒表模式:电子表在计时的时候是秒表模式一秒一秒加上去的。
			{
				LEDBuffer[0]=Minutesw/10;    //秒表分单元十位
				LEDBuffer[1]=Minutesw%10;    //秒表分单元个位
				LEDBuffer[2]=Secondsw/10;    //秒表秒单元十位
				LEDBuffer[3]=Secondsw%10;    //秒表秒单元个位
				LEDBuffer[4]=Centsw/10;      //秒表百分之一秒单元十位
				LEDBuffer[5]=Centsw%10;      //秒表百分之一秒单元个位
			}
	}
	
}
void time1() interrupt 3      //秒表中断程序
{
	unsigned int Count;
	TH1=(65536-50000)/256;        
	TL1=(65536-50000)%256; 
	display();	
	Count++;
	if(Count==2)
	{
	Count=0;            //计数清零
	Centsw++;           //秒表百分之一秒单元++
	if(Centsw==100)     //判断是否到一秒
	{
		Centsw=0;       //到一秒则秒表百分之一秒单元清零
		Secondsw++;     //秒表秒单元加一
		if(Secondsw==60)     //判断是否到一分钟
		{
			Secondsw=0;      //到一分钟则秒表秒单元清零
			Minutesw++;         //秒表分单元加一
			if(Minutesw==60)    //判断是否到一小时
			{
				Minutesw=0;    //到一小时则秒表分单元清零
			}
		}
	}
	

	}
	LEDBuffer[0]=Minutesw/10;            //数据缓存
	LEDBuffer[1]=Minutesw%10;
	LEDBuffer[2]=Secondsw/10;
	LEDBuffer[3]=Secondsw%10;
	LEDBuffer[4]=Centsw/10;
	LEDBuffer[5]=Centsw%10;
	
}
	



void main()
{	init();								//初始化
	while(1)
{		key();							//调用键盘
		if(ALMFlag==1)                  //判断定时是否关闭,如果关闭则进入下边的判断语句。
		{	if(Minute!=Minuterom) Beepflag=1;	//定时和现在不同,关闭蜂鸣器
			if((Hour==Hourrom)&&(Minute==Minuterom)&&(Beepflag==1)) Beep=0;
					//时分相同并闹铃打开就响铃
		}
} 
}

运行结果展示

上图为59分58秒 

标签: 放大电路数码管

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台