目录

一、实现功能

二、思路1的分析

1、定时器0

2、外部中断0

3、主函数main

4、其他重要功能函数


一、实现功能

1、实现最基本的计时功能,显示时、分、秒,可以通过按键设置时间。

        要求:时钟计时精确,按键操作不影响计时。

2、具备秒表计时功能。

        要求:记时精度达到100ms,计时支持启动、暂停、继续和停止操作。

3、具备整点响铃提示功能。

        要求:整点闹铃五短一长,闹钟响铃时可以按键清楚响铃。

4、具备日期显示和调整功能。

二、思路1的分析

1、定时器0

进行时分秒的递增与计算,其中定时器0的采用了16位的50ms定时,

void T0_ISR(void) interrupt 1
{
	uchar i=0;
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;
	
	if(time_flag==0)
	{
		count++;
		if(count==20)
		{
			count=0;
			miao++;
		}
		if(miao==60)
		{
			miao=0;
			fen++;
		}
		if(fen==60)
		{
			fen=0;
			shi++;
		}
		if(shi==24)
		{
			shi=0;
		} 
		if(shi!=0)
		if(fen==0)
		if(miao==0)
		beep_flag=1;
	}
	else 
	{
		if(TIME_CONTROL==0)
		{
			Timing++;
			if(Timing==2)
			{
				Timing=0;
				TIME_CLK++;
			}
		}
	}
}

2、外部中断0

        实现按键触控实现调整时分秒、秒表定时设定、日期调整设定。当然受限于屏幕大小,可以通过按键调整当前显示的功能。

即按下KEY1,实现DATA-CLK,即从日期显示改为时间显示,或从时间显示切换为日期显示。

即按下KEY2,实现CLK-TIMING,即从时间显示改为定时,或从定时切换为时间显示。

前文提到过,外部定时只有一个,除了上述两个按键,还有年月日、时分秒、开始暂停等调整,如何都实现外部中断呢。

51单片机基础07 实时时钟-思路及代码参考1-LMLPHP

        可以看到通过两级与非门,实现了所有按键最后接到了外部中断,同时每个引脚再分别接到IO上,从而实现任意一个按键按下都会进入中断,在中断中再进行判断哪个按键被按下。

void keyscan()
{
	if(key1==0)
	{
		delay_ms(10);
		if(key1==0);
		{
			shi++;
		}
	}
	if(key2==0)
	{
		delay_ms(10);
		if(key2==0)
		{
			fen++;
		}
	}
	if(key3==0)
	{
		delay_ms(10);
		if(key3==0)
		{
			miao++;
		}
	}
	if(key4==0)
	{
		delay_ms(10);
		if(key4==0)
		{
			BEEP_Control=0;;
		}
	}
	if(key5==0)
	{
		delay_ms(10);
		if(key5==0)
		{
			time_flag=~time_flag;	
			lcd_clr();
			delay_ms(10);
			lcd_clr();
		}
	}
	if(key6==0)
	{
		delay_ms(10);
		if(key6==0)
		{
			TIME_CONTROL=~TIME_CONTROL;
			lcd_clr();
			delay_ms(10);
			lcd_clr();
		}
	}
	if(key7==0)
	{
		delay_ms(10);
		if(key7==0)
		{
			date_CONTROL=~date_CONTROL;
			lcd_clr();
			delay_ms(10);
			lcd_clr();
		}
	}
	if(key8==0)
	{
		delay_ms(10);
		if(key8==0)
		{
			ri++;
		}
	}
	if(key9==0)
	{
		delay_ms(10);
		if(key9==0)
		{
			yue++;
		}
	}
	if(key10==0)
	{
		delay_ms(10);
		if(key10==0)
		{
			nian++;
		}
	}				
}
void INT0_ISR(void) interrupt 0
{
	EX0=0;
	delay_ms(1);
	if(0==P3_2)
	{
 	    keyscan();
	}
	IE0=0;
	EX0=1;
}

3、主函数main

循环刷新LCD显示时分秒、秒表、日期。

void api()
{
	uchar i=0;
	if(date_CONTROL==0)
	{
		TIME_CLK=0;
		shi=fen=miao=0;
	    date_display();
	    for(i=0;i<8;i++)
	    {
		    lcd_wcom(0x8B+i);   
		    lcd_wdat(table5[i]); 
	    }	
	}
	else
	{
		if(time_flag==0)
		{
			TIME_CLK=0;
			if(beep_flag==1)
			{
			   beep_flag=0;
			   beep_on();
			}
			time_display();
			for(i=0;i<7;i++)
			{
				lcd_wcom(0x88+i);   
				lcd_wdat(table1[i]); 
			}
		}
		else  
		{
			timing_display();
			if(TIME_CONTROL==0)
			{
			  shi=fen=miao=0;
			  for(i=0;i<11;i++)
				{
					lcd_wcom(0x86+i);   
					lcd_wdat(table2[i]); 
				}
			}
			else
			{
			  for(i=0;i<11;i++)
				{
					lcd_wcom(0x86+i);   
					lcd_wdat(table3[i]); 
				}				
			}	
		}
	}
}
void main(void)            //主函数,单片机开机后就是从这个函数开始运行
{

		lcd_init(); 	//液晶初始化
 		time_init();
		while(1)
		{
			api();	
		}
}

其中timing_display实现了定时的显示;data_display实现了日期的显示;time_display实现了时间的显示;beep_on实现了准点蜂鸣器响(该缺点暂时使用了delay_ms(50)此类操作,从而占用了单片机前台刷新LCD,但是由于定时、日期等后台计数不会影响;可以考虑加入定时器1来进行延时的计算,保证LCD的刷新)

4、其他重要功能函数

void time_display()
{
	lcd_wcom(0x80);   
	lcd_wdat(table[shi/10]); 	
	lcd_wcom(0x81);  
	lcd_wdat(table[shi%10]); 
	lcd_wcom(0x82);  
	lcd_wdat(table[10]); 

	lcd_wcom(0x83);  
	lcd_wdat(table[fen/10]); 
	lcd_wcom(0x84);  
	lcd_wdat(table[fen%10]); 
	lcd_wcom(0x85);  
	lcd_wdat(table[10]); 

	lcd_wcom(0x86);  
	lcd_wdat(table[miao/10]);
	lcd_wcom(0x87);   
	lcd_wdat(table[miao%10]); 
	lcd_wcom(0x88);  
}

void timing_display()
{
	if(TIME_CLK==1000)
	TIME_CLK=0;
	lcd_wcom(0x80);   
	lcd_wdat(table[TIME_CLK/1000]); 	
	lcd_wcom(0x81);  
	lcd_wdat(table[TIME_CLK/100%10]); 
	lcd_wcom(0x82);  
	lcd_wdat(table[TIME_CLK%100/10]); 
	lcd_wcom(0x83);  
	lcd_wdat(table[11]); 
 	lcd_wcom(0x84);  
	lcd_wdat(table[TIME_CLK%10]); 
}

void date_display()
{
	int a[12]={31,28,31,30,31,30,31,31,30,31,30,31};
	int b[12]={31,29,31,30,31,30,31,31,30,31,30,31};
	if(nian%100==0)
	{	if(nian%4==0)
			if(ri>b[yue])
				{
					ri=1;
					yue+=1;
				}
	}
	else if(nian%4==0)
	{
		if(ri>b[yue])
			{
				ri=1;
				yue+=1;
			}
	}
	else 
	{
		if(ri>a[yue])
			{
				ri=1;
				yue+=1;
			}	
	}	
	if(yue==13)
	{
		yue=1;
		nian+=1;
	}
	lcd_wcom(0x80);   
	lcd_wdat(table4[nian/1000]); 	
	lcd_wcom(0x81);  
	lcd_wdat(table4[nian/100%10]); 
	lcd_wcom(0x82);  
	lcd_wdat(table4[nian%100/10]); 
	lcd_wcom(0x83);  
	lcd_wdat(table4[nian%10]); 
	lcd_wcom(0x84);  
	lcd_wdat(table4[10]); 

	lcd_wcom(0x85);  
	lcd_wdat(table4[yue/10]); 
	lcd_wcom(0x86);  
	lcd_wdat(table4[yue%10]); 
	lcd_wcom(0x87);  
	lcd_wdat(table4[10]); 

	lcd_wcom(0x88);  
	lcd_wdat(table4[ri/10]);
	lcd_wcom(0x89);   
	lcd_wdat(table4[ri%10]); 
	lcd_wcom(0x8A);
	 
}
void beep_on()
{
	BEEP_Control=1;
	BEEP=0;
	delay_ms(50);
	BEEP=1;
	delay_ms(50);
	BEEP=0;
	delay_ms(50);
	BEEP=1;
	delay_ms(50);
	BEEP=0;
	delay_ms(50);
	BEEP=1;
	delay_ms(50);
	BEEP=0;
	delay_ms(50);
	BEEP=1;
	delay_ms(50);
	BEEP=0;
	delay_ms(50);
	BEEP=1;
	delay_ms(50);
	BEEP=0;
	delay_ms(1000);
	BEEP=1;
	delay_ms(1000);

}

后续还有其他两个方法,在下一个博客进行介绍。

11-18 10:48