TX-1C单片机实现多功能电子时钟

一、实验要求:

利用定时计数器,设计一个电子时钟,使用前面使用过的显示子程序。从左到右依次显示时分秒。有两种方法实现,一种是在中断程序中计数,产生时分秒计数,送显示缓冲区。另一种是中断程序每一秒清除一个位变量,而主程序通过监视位变量的变化来知道每秒的时间。
进而要求:
①加入时间调整程序,使用两个或三个按钮,调节当前的时间。类似平常使用的电子表。可以让正在调整的位闪烁显示。
②可以加入一个闹钟钟设置,当所定的时间到时,产生断续的蜂鸣声。可以加入日历的功能。

二、实验结果

数码管显示24小时制电子时钟;
矩阵按键S11时钟界面、S15倒计时界面、S12时间设置界面;
S12按下循环调整时、分、秒,处于时间设置界面时L8闪烁;
L1亮调整时、L2亮调整分、L3亮调整秒;
S13按下数值加1,S17按下数值减1;
倒计时结束后蜂鸣器间隔鸣叫;
S16按下一键清零时分秒

三、实验思路

(一)模块整理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(二)流程图绘制

在这里插入图片描述

(三)C51编程

#include <reg51.h>

sbit L8 = P1^7;
sbit LED = P2^5;
sbit BUZZ = P2^3;
sbit DULA =	P2^6;	
sbit WELA =	P2^7;	

unsigned char num[10]={
    
    0x3F,0x06,0x5B,0x4F,0x66,0x6D,
					0x7D,0x07,0x7F,0x6F,};
 
unsigned char second,minute,hour = 0;	


void delay(unsigned int t) 
{
    
     
	while(t--);
}

void Init_Timer()	
{
    
    
	TMOD = 0x21; 	
	
	TH0 = 0x3C;  	//50ms=0.05s
	TL0 = 0xB0;  	
	TR0 = 1;  		
	ET0 = 1;  		
	
	TH1 = 0x00; 
	TL1 = 0x38;
	TR1 = 0;
	ET1 = 1;
	
	EA = 1;  		
}


unsigned char flag = 0;
unsigned char count = 0;	
void Service_Timer0() interrupt 1		//T0中断服务函数
{
    
    
	TH0 = 0x3C; 	
	TL0 = 0xB0;  	
		
	
	count++;
	if(count == 20)			//20 * 50ms = 1s
	{
    
    
		count = 0;
		if(flag == 0)		//正计时状态
		{
    
    
			second++;
			if(second == 60)
			{
    
    
				second = 0;
				minute++;
				if(minute == 60)
				{
    
    
					minute = 0;
					hour++;
					if(hour == 24)
					{
    
    
						hour = 0;		
					}
				}
			}
		}
		if(flag == 1)		//倒计时状态
		{
    
    
			if(second == 0)
			{
    
    
				if(minute == 0)
				{
    
    
					if(hour == 0)
					{
    
    
						TR0 = 0;		//终止倒计时
						TR1 = 1;
						flag = 3;		//蜂鸣器标志位
					}
					else{
    
    
						hour--;
						minute = 59;
					}
				}
				else{
    
    
					minute--;
					second = 59;
				}
			}
				else
				second--;
			
		}
	}
}


unsigned int count2 = 0;
void Service_Timer1() interrupt 3		//T1中断服务函数
{
    
    
	count2++;
	if(count2 == 1500)		//0.2ms * 1500 = 0.2s
	{
    
    
		L8 = ~L8;
		count2 = 0;
		if(flag == 3)
		{
    
    
			BUZZ = ~BUZZ;
		}
	}
}


void s_Display(unsigned char sec)
{
    
    
	DULA=1;			
	P0=num[sec%10];	
	DULA=0;			
	WELA=1;			
	P0=0XDF;		//POS_6
	WELA=0;			
	delay(150);		

	DULA=1;
	P0=num[sec/10];
	DULA=0;
	WELA=1;
	
	P0=0XEF;		//POS_5
	WELA=0;
	delay(150);
}
	
void m_Display(unsigned char min)
{
    
    
	DULA=1;
	P0=num[min%10];
	DULA=0;
	WELA=1;
	P0=0XF7;		//POS_4		
	WELA=0;
	delay(150);
	
	DULA=1;
	P0=num[min/10];	
	DULA=0;
	WELA=1;
	P0=0XFB;		//POS_3	
	WELA=0;
	delay(150);
}
	
void h_Display(unsigned char hor)
{
    
    
	DULA=1;
	P0=num[hor%10];
	DULA=0;
	WELA=1;
	P0=0XFD;		//POS_2		
	WELA=0;
	delay(150);
	
	DULA=1;
	P0=num[hor/10];	
	DULA=0;
	WELA=1;
	P0=0XFE;		//POS_1		
	WELA=0;
	delay(150);
}

void SMG_Display()
{
    
    
	s_Display(second);
	m_Display(minute);
	h_Display(hour);
}


sbit R1 = P3^0;
sbit R2 = P3^1;
sbit R3 = P3^2;
sbit R4 = P3^3;

sbit C1 = P3^4;		
sbit C2 = P3^5;
sbit C3 = P3^6;
sbit C4 = P3^7;

unsigned char stat = 0; 
void Key_Scan()
{
    
    
	C2 = 0;
	C1 = C3 = C4 = 1;
	if(R2 == 0)			//S11按下,暂停/启动正计时界面
	{
    
    
		flag = 0;
		SMG_Display();
		TR1 = 0;		//不属于调整时间状态
		
		LED = 1;
		P1 = 0xff;
		LED = 0;
		
		if(R2 == 0)
		{
    
    
			TR0 = ~TR0;		
		}
		while(R2 == 0)
		{
    
    
			SMG_Display();
		}
	}
	if(R3 == 0)			//S16按下,暂停/启动倒计时界面
	{
    
    
		flag = 1;
		SMG_Display();
		TR1 = 0;		//不属于调整时间状态
		
		LED = 1;
		P1 = 0xff;
		LED = 0;
		
		if(R3 == 0)
		{
    
    
			TR0 = ~TR0;		
		}
		while(R3 == 0)
		{
    
    
			SMG_Display();
		}
	}
	
	
	C3 = 0;
	C1 = C2 = C4 = 1;
	if(R2 == 0)			//S12按下,调整时间界面按键
	{
    
    
		LED = 1;
		SMG_Display();
		if(R2 == 0)
		{
    
    
			if(TR0 == 0)		//必须在停止界面下调整时间
			{
    
    
				TR1 = 1;
				switch(stat)
				{
    
    
					case 0: stat = 1; P1 = 0xFE; break;		//s位调整
					case 1: stat = 2; P1 = 0xFD; break;		//m位调整
					case 2: stat = 0; P1 = 0xFB; break;		//h位调整
				}
			}
			
		}
		while(R2 == 0)
		{
    
    
			SMG_Display();
		}
	}
	if(R3 == 0)			//S15按下,复位按键
	{
    
    
		SMG_Display();
		
		LED = 1;
		P1 = 0xff;
		LED = 0;
		
		if(R3 == 0)
		{
    
    
			TR0 = 0;		
			TR1 = 0;
			LED = 0;
			second = minute = hour = 0;	
			
		}
		while(R3 == 0)
		{
    
    
			SMG_Display();
		}
	}
	
	
	C4 = 0;
	C1 = C2 = C3 = 1;
	if(R2 == 0)		//S13按下,加1
	{
    
    
		SMG_Display();
		if(TR1 == 1)
		{
    
    
			if(R2 == 0)
		{
    
    
			switch(stat)
			{
    
    
				case 1 : 
					second++;
					if(second == 60)
					second = 0;
					break;
				case 2 :
					minute++;
					if(minute == 60)
					minute = 0;
					break;
				case 0 : 
					hour++;
					if(hour == 24)
					hour = 0;
					break;
			}
		}
		}
		
		while(R2 == 0)
		{
    
    
			SMG_Display();
		}
	}
	if(R3 == 0)		//S17按下,减1
	{
    
    
		SMG_Display();
		if(TR1 == 1)
		{
    
    
			if(R3 == 0)
			{
    
    
				switch(stat)
				{
    
    
					case 1 : 
						if(second == 0)		//先判断,后减1
						second = 59;
						else
						second--;
						break;
					case 2 :
						if(minute == 0)
						minute = 59;
						else
						minute--;
						break;
					case 0 : 
						if(hour == 0)
						hour = 23;
						else
						hour--;
						break;
				}
			}
		}
		while(R3 == 0)
		{
    
    
			SMG_Display();
		}
	}
		
}

 
void main(){
    
    
	second = 54;		
	minute = 59;
	hour = 23;
	LED = 0;
	Init_Timer();		
	while(1)
	{
    
    	
		SMG_Display();	
		Key_Scan();		
	}
}

四、实验总结

(一)未完成的部分

1.让正在调整的位数码管闪烁显示。
从TX-1C的原理图中可以看到其位选和段选都需要通过P0口赋值,所以分别用了两个74HC573锁存器来分别锁存两个值,使两者互不干扰。所以想要实现位闪烁,一方面应该要选中相应的位选,在该位上实现闪烁功能;另一方面利用定时器写一个延时程序,赋当前要显示的值持续一段时间,再赋熄灭数码管显示的值持续一段时间,两个赋值之间循环,间隔点亮实现闪烁功能。
2.实现日历功能。实际上也是一个数码管显示界面,需要对年、月、日进行设定。方法一,通过定时器对日期进行累加,但是稍显麻烦,且中断需要快进快出,所以这个方法不太理想;方法二,通过时钟的24小时计时对日进行累加,再到月、年的累加,用此方法实现较为可行。

(二)待优化的部分

1.进一步实现从倒计时界面切换到时钟界面时,不影响时钟持续的运行。此实验中,时钟和倒计器用了同一个定时器,所以没能够实现两者之间互不影响的功能。后续可以用两个定时器将二者功能分开,利用switch-case状态机实现按键控制时钟和倒计时之间循环切换,且不干扰时钟的持续运行。
2.进一步实现温度显示界面。TX-1C实验板上有DS18B20温度模块,可以编写相关程序,实现时钟、闹钟、温度相互切换显示的功能

猜你喜欢

转载自blog.csdn.net/Taylor_Kurt/article/details/131277949