89C51与8155电子时钟设计(proteus仿真)

课程设计

用89C51的P1口(位控)和一片8155的PA口(段控)作输出口控制六数码管显示(二个数码管显示“时”、二个数码管显示“分”、二个数码管显示“秒”),8155的PB口作输入口控制按键输入,做一台电子钟。
要求:8155的PA口地址:EF01H

用一个按键控制作时钟调整状态输入(按下一次进入时钟调整状态下的“时”调整,再按下一次进入“分”调整,再按下一次进入“秒”调整,再按下一次退出时钟调整状态),一个按键用于调整时钟(在时钟调整状态下有效)。在时钟调整状态下,正在调整的“时”或“分”或“秒”要进行闪烁显示指示。

电子时钟主要功能

1、显示时间,并准确计时;
2、可以进入调整状态,对时分秒进行调整加一操作;
3、对应调整状态的数码管闪烁显示;
4、附加功能:万年历(闰年判断)。

电子元件的选择

8位共阴极数码管,89C51芯片,8155芯片,RESPACK-8(排阻,网络电阻器),电阻,反相器,按钮,电容

proteus仿真图

在这里插入图片描述
可以标注引脚连接简化接线方式,本图并未使用简化接线方式。

下面展示一些代码,条理与逻辑思路比较清晰,简化了注释

#include<reg51.h>
#include<absacc.h>
#define uchar unsigned char
#define uint unsigned int
#define COM8155 XBYTE[0xef00]
#define PA8155 XBYTE[0xef01]
#define PB8155 XBYTE[0xef02]
uchar a[12]={
    
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x00}; 
uchar xs[8]={
    
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uchar b[8]={
    
    0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
uint pn[12]={
    
    31,28,31,30,31,30,31,31,30,31,30,31};
uint rn[12]={
    
    31,29,31,30,31,30,31,31,30,31,30,31};
uchar SS=50,MM=59,HH=23,count,flash,count1;
uint Day=27,Month=2,Year=2000,*p;   
bit flag=0;

void Delay(uint t)		//延迟函数
{
    
    
	while(t)
	{
    
    
	t--;
	}
}

void Dispaly1(uchar SS,uchar MM,uchar HH)	 //时分秒显示函数 
{
    
    
    uint i;
	xs[0]=SS%10;
	xs[1]=SS/10;
	xs[2]=10;
	xs[3]=MM%10;
	xs[4]=MM/10;
	xs[5]=10;
	xs[6]=HH%10;
	xs[7]=HH/10;

	if(flag==1)
		{
    
    
		if(flash==0)
		xs[0]=xs[1]=11;
		else if(flash==1)
		xs[3]=xs[4]=11;
		else if(flash==2)
		xs[6]=xs[7]=11;
		}

	for(i=0;i<8;i++)
	   {
    
    
	    P1=b[7-i];
		PA8155=a[xs[i]];
		Delay(5);
		P1=0xff;
		Delay(5);
		P1=0xff;
	    }
}

void Dispaly2(uint Day,uint Month,uint Year)	 //年月日显示函数 
{
    
    
    uint i;
	xs[0]=Day%10;
	xs[1]=Day/10;
	xs[2]=Month%10;
	xs[3]=Month/10;
	xs[4]=Year%10;
	xs[5]=(Year%100)/10;
	xs[6]=(Year%1000)/100;
	xs[7]=Year/1000;
	
	if(flag==1)
		{
    
    
		if(flash==0)
		xs[0]=xs[1]=11;
		else if(flash==1)
		xs[2]=xs[3]=11;
		else if(flash==2)
		xs[4]=xs[5]=xs[6]=xs[7]=11;
		}

	for(i=0;i<8;i++)
	   {
    
    
	    P1=b[7-i];
		PA8155=a[xs[i]];
		Delay(5);
		P1=0xff;
	    }
}

void Keyscan1()   //时钟调位和数值加一功能
{
    
    
	static uchar j = 0;
	if(PB8155==0X01)   //进入调整状态
		{
    
    
		Delay(10000);     //消抖
		if(PB8155==0X01)
		{
    
    
		TR0=0;     //关闭定时器0
        TR1=1;     //打开定时器1
		while(PB8155==0X01)
		{
    
    
		}
		j++; 		  //进行状态调整按键次数计数
		}
		}
	if(j==1)		   //调整秒状态
		{
    
    
		flash=0;
		if(PB8155==0X02)
			{
    
    
			Delay(10); 
			if(PB8155==0X02)
			{
    
    
				while(PB8155==0X02)
				{
    
    	
				}
				SS++;
				if(SS==60)
				SS=0;	
			}
			}
		}
	if(j==2)		   //调整分状态
		{
    
    
		flash=1;
		if(PB8155==0X02)
			{
    
    
            Delay(10); 
			if(PB8155==0X02)
			{
    
    
			while(PB8155==0X02)
			{
    
    
			}
			MM++;
			if(MM==60)
			MM=0;
			} 
			}
		}
	if(j==3)		   //调整时状态
		{
    
    
		flash=2;
		if(PB8155==0X02)
			{
    
     
			Delay(10); 
			if(PB8155==0X02)
			{
    
    
			while(PB8155==0X02)
			{
    
    
			}
			HH++;
			if(HH==24)
			HH=0;
			} 
			}
		}
	if(j==4)		  //退出调整状态
		{
    
    
		TR0=1;       //打开定时器0
        TR1=0; 
		j=0;		 //计数清零
		}
}

void Keyscan2()   //日期调位和数值加一功能
{
    
    
	static uchar m = 0; 
	if(((Year%4==0)&&(Year%100!=0))||(Year%400==0))        //闰年判断
	p=rn; 
	else
	p=pn;   
	if(PB8155==0X01)   //进入调整状态
		{
    
    
		Delay(10000);     //消抖
		if(PB8155==0X01)
		{
    
    
		TR0=0;     //关闭定时器0
        TR1=1;     //打开定时器1
		while(PB8155==0X01)
		{
    
    
		}
		m++; 		  //进行状态调整按键次数计数
		}
		}
	if(m==1)		   //调整日状态
		{
    
    
		flash=0;
		if(PB8155==0X02)
			{
    
    
			Delay(10); 
			if(PB8155==0X02)
			{
    
    
				while(PB8155==0X02)
				{
    
    	
				}
				Day++;
				if(Day==p[Month-1]+1)
				Day=1;	
			}
			}
		}
	if(m==2)		   //调整月状态
		{
    
    
		flash=1;
		if(PB8155==0X02)
			{
    
    
            Delay(10); 
			if(PB8155==0X02)
			{
    
    
			while(PB8155==0X02)
			{
    
    
			}
			Month++;
			if(Month==13)
			Month=1;
			} 
			}
		}
	if(m==3)		   //调整年状态
		{
    
    
		flash=2;
		if(PB8155==0X02)
			{
    
     
			Delay(10); 
			if(PB8155==0X02)
			{
    
    
			while(PB8155==0X02)
			{
    
    
			}
			Year++;
            if(Year>9999)
			Year=0;	
			} 
			}
		}
	if(m==4)		  //退出调整状态
		{
    
    
		TR0=1;       //打开定时器0
        TR1=0; 
		m=0;		 //计数清零
		}
}

void main()	 //主函数
{
    
    						
	TMOD=0x01; 	 //定时器以方式一工作
	TH0=(65536-10000)/256;
	TL0=(65536-10000)%256;   //10ms计时
	ET0=1;  //允许定时器0中断
	TR0=1;  //打开定时器0
	TMOD=0x01; 	 //定时器以方式一工作
	TH1=(65536-10000)/256;
	TL1=(65536-10000)%256;   //10ms计时
	EA=1;
	ET1=1;  //允许定时器1中断
	TR1=0;  //关闭定时器1
	COM8155=0x01;
	while(1)
	{
    
    
	static uchar h=0;
	if(PB8155==0X04)    //时钟和日期切换
		{
    
    
		Delay(100); 
		if(PB8155==0X04)
		while(PB8155==0X04);
		h++;
		}
	if(h%2==0)          //如果按键偶数次则显示时钟
	    {
    
    
		Dispaly1(SS,MM,HH);
		Keyscan1();
		}
	if(h%2==1)         //如果按键偶数次则显示日期
		{
    
    
		Dispaly2(Day,Month,Year);
		Keyscan2();
		}
	}
}

void time0_int(void) interrupt 1		   //计时中断函数
{
    
    											  
	TH0=(65536-10000)/256;
	TL0=(65536-10000)%256;
	count++;
	if(((Year%4==0)&&(Year%100!=0))||(Year%400==0))        //闰年判断
	p=rn; 
	else
	p=pn; 
	if(count==100)         //10ms
	{
    
    
		count=0;
		SS++;
		if(SS==60)
		{
    
    
		SS=0;
		MM++;
		}
		if(MM==60)
		{
    
    
		MM=0;
		HH++;	
		}
        if(HH==24)
		{
    
    
		HH=0;
		Day++;
		}
		if(Day==p[Month-1]+1)
		{
    
    
		Day=1;
		Month++;
		}
		if(Month==13)
		{
    
    
		Month=1;
		Year++;
		}
	}
}

void time1_int(void) interrupt 3		   //闪烁中断函数
{
    
    											  
	TH1=(65536-10000)/256;
	TL1=(65536-10000)%256;
	count1++;
	if(count1%50==0)     //500ms计时
	flag=~flag;
}

效果图

在这里插入图片描述
日期显示效果,2000年为闰年2月有29天,达到预期效果

在这里插入图片描述
时间显示无任何问题

本次还有一问题没有解决,定时器1的定时效果一直达不到理想状态,希望有大佬能指正。感谢!

猜你喜欢

转载自blog.csdn.net/S_calpel/article/details/108662960