天天看點

STC89C52單片機——定時器鬧鐘

一、功能概述

        概述:通過按下矩陣鍵盤輸入數字讓數位管顯示,然後按下獨立鍵盤通過定時器開始倒計時,倒計時結束蜂鳴器響。

二、所使用的功能子產品

        矩陣鍵盤、獨立鍵盤、蜂鳴器、數位管

三、程式設計過程中所遇到的問題及改進措施

        問題1: 如何通過矩陣鍵盤點亮數位管并将按鍵值傳遞給定時子產品?

        措施:(代碼子產品如下)

                (1)矩陣鍵盤掃描 0~15。

                注意:<1>受單片機I/O口數量所限,注意到矩陣鍵盤第一排和獨立鍵盤共用一組I/O口,是以如果忽略,當按下矩陣鍵盤第一排後會自動進入倒計時子產品。

                           <2>掃描末尾要将P3口拉高,否則在程式執行過程中由于程式段開始時進行列掃描将P3口部分拉高,導緻矩陣鍵盤二、三、四排其中一個按鍵被按下時都有可能自動進入倒計時子產品。

uchar KeyScan(uint KeyValue)
{
	P3 = 0XF0;//列掃描  
	if(P3 != 0XF0)//判斷按鍵是否被按下
	{
		delay(10);//軟體消抖10ms
		if(P3 != 0XF0)//判斷按鍵是否被按下
		{
			switch(P3) //判斷那一列被按下
			{
				case 0xe0:	KeyValue = 0;	break;//第一列被按下
				case 0xd0:	KeyValue = 1;	break;//第二列被按下
				case 0xb0:	KeyValue = 2;	break;//第三列被按下
				case 0x70:	KeyValue = 3;	break;//第四列被按下 
			}
			P3 = 0X0F;//行掃描
			switch(P3) //判斷那一行被按下
			{
				case 0x0e:	KeyValue = KeyValue;	  break;//第一行被按下
				case 0x0d:	KeyValue = KeyValue + 4;  break;//第二行被按下
				case 0x0b:	KeyValue = KeyValue + 8;	break;//第三行被按下
				case 0x07:	KeyValue = KeyValue + 12;	break;//第四行被按下
			}
			while(P3 != 0X0F);//松手檢測  /***重點***/ 		
		}	
	}
	P3=0xff;  /***重點***/
	return KeyValue;
}
           

                (2)按鍵數字顯示和值傳遞

uchar Key_input(uint z)
{
	uint temp1=0;
	uint temp2=0;
	while(!temp1)
	{
		P0=0xfe;
		WE=1;
		WE=0;
		temp1=KeyScan(temp1);
		P0=tabel[temp1];
		DU=1;
		DU=0;
		temp1=temp1 * 10;
	}
	while(!temp2)
	{
		P0=0xfd;
		WE=1;
		WE=0;			  
		temp2=KeyScan(temp2);
		P0=tabel[temp2];
		DU=1;
		DU=0;
	}
	z=temp1+temp2;
	return z;		
}
           

        問題2: 如何精确控制倒計時的時間間隔(1s)?

        措施:(代碼子產品如下)

                (1) 使用定時器0,通過配置16位定時器的初始值,溢出一次為50ms,溢出二十次即為1s。

                (2)具體轉換步驟:

                        <1> 50ms=50 000us

                        <2>一個機器周期為1.085us(晶振頻率為11.0592)

                        <3>50 000/1.085=46082 個機器周期

                        <4>16位定時器,1111 1111 1111 1111 轉換為十進制為65535,是以65535-46082=19453   轉換為二進制為4BFD,  故高八位為 0x4B, 低八位為0xFD.

void timer0() interrupt 1 //T0溢出中斷,中斷入口為1
{
     TH0=(65535-46080)/256;	//高四位
	 TL0=(65535-46080)%256;	//低四位
	 m++;
}
//定時器開關
void timer_open()
{
	TMOD=0x01; //定時器工作模式1,16位定時器計數模式
	TR0=1;	//啟動定時器0
	TH0=(65536-46080)/256;//4bfd
	TL0=(65536-46080)%256;//定時50ms
	EA=1; //cpu的總中斷允許控制位,開放中斷	
	ET0=1; //T0的溢出中斷允許?				
}
           

                (4)主程式段

                        *注意标志位flag的使用

void main()
{	
	uchar a1,a0;
	uchar flag=0;
	while(1)  /***重點***/
	{
		if(flag==0)  /***重點***/
		{
			Sec=Key_input(Sec);
			flag=1;   /***重點***/	
		}
		if(flag==1)  /***重點***/
		{
			if(Key_s2==0)  
			{			
				delay(20);
				if(Key_s2==0)
				{	
					timer_open();
					while(1)
					{	
						if(m==20) //中斷20次,1秒
						{
					      m=0;//m置零
					      Sec--;//秒減一
						}
						a0=Sec%10;//實時顯示十位數字
						a1=Sec/10;//實時顯示個位數字
						display(a1,a0); 
						if(Sec==0)//倒計時結束
						{
						   TR0=0;//關閉定時器0
						   beep=0;
						}
					}
				}
			}
		}
	}	
}
           

 //完整代碼如下:

#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit DU = P2^6;
sbit WE = P2^7;
sbit beep=P2^3;
sbit Key_s2=P3^0;
uint i,m,KeyValue;
uint Sec;
//共陰數位管段選表
uchar  code tabel[]= {
//0		1	  2     3          
0x3F, 0x06, 0x5B, 0x4F,
//4     5     6     7
0x66, 0x6D, 0x7D, 0x07, 
//8		9     A     B
0x7F, 0x6F, 0x77, 0x7C,
//C	    D	  E	    F		 
0x39, 0x5E, 0x79, 0x71};

void delay(uint z)
{
	uint x,y;
	for(x = z; x > 0; x--)
		for(y = 114; y > 0 ; y--); 		
}
//定時器0初始化
void timer0() interrupt 1 //T0溢出中斷,中斷入口為1
{
     TH0=(65535-46080)/256;	//高四位
	 TL0=(65535-46080)%256;	//低四位
	 m++;
}
//定時器開關
void timer_open()
{
	TMOD=0x01; //定時器工作模式1,16位定時器計數模式
	TR0=1;	//啟動定時器0
	TH0=(65536-46080)/256;//4bfd
	TL0=(65536-46080)%256;//定時50ms
	EA=1; //cpu的總中斷允許控制位,開放中斷	
	ET0=1; //T0的溢出中斷允許位			
}
//4*4矩陣鍵盤掃描
uchar KeyScan(uint KeyValue)
{
	P3 = 0XF0;//列掃描  
	if(P3 != 0XF0)//判斷按鍵是否被按下
	{
		delay(10);//軟體消抖10ms
		if(P3 != 0XF0)//判斷按鍵是否被按下
		{
			switch(P3) //判斷那一列被按下
			{
				case 0xe0:	KeyValue = 0;	break;//第一列被按下
				case 0xd0:	KeyValue = 1;	break;//第二列被按下
				case 0xb0:	KeyValue = 2;	break;//第三列被按下
				case 0x70:	KeyValue = 3;	break;//第四列被按下 
			}
			P3 = 0X0F;//行掃描
			switch(P3) //判斷那一行被按下
			{
				case 0x0e:	KeyValue = KeyValue;	  break;//第一行被按下
				case 0x0d:	KeyValue = KeyValue + 4;  break;//第二行被按下
				case 0x0b:	KeyValue = KeyValue + 8;	break;//第三行被按下
				case 0x07:	KeyValue = KeyValue + 12;	break;//第四行被按下
			}
			while(P3 != 0X0F);//松手檢測 		
		}	
	}
	P3=0xff; 
	return KeyValue;
}

uchar Key_input(uint z)
{
	uint temp1=0;
	uint temp2=0;
	while(!temp1)
	{
		P0=0xfe;
		WE=1;
		WE=0;
		temp1=KeyScan(temp1);
		P0=tabel[temp1];
		DU=1;
		DU=0;
		temp1=temp1 * 10;
	}
	while(!temp2)
	{
		P0=0xfd;
		WE=1;
		WE=0;			  
		temp2=KeyScan(temp2);
		P0=tabel[temp2];
		DU=1;
		DU=0;
	}
	z=temp1+temp2;
	return z;		
}

void display(uchar sh,uchar g)
{
	P0=tabel[sh];
	DU=1;
	DU=0;
	P0=0xfe;
	WE=1;
	WE=0;
	delay(5);

	P0=tabel[g];
	DU=1;
	DU=0;
	P0=0xfd;
	WE=1;
	WE=0;
	delay(5);
}

void main()
{	
	uchar a1,a0;
	uchar flag=0;
	while(1)  
	{
		if(flag==0)  
		{
			Sec=Key_input(Sec);
			flag=1;   
		}
		if(flag==1)  
		{
			if(Key_s2==0)  
			{			
				delay(20);
				if(Key_s2==0)
				{	
					timer_open();
					while(1)
					{	
						if(m==20) 
						{
					      m=0;
					      Sec--;
						}
						a0=Sec%10;
						a1=Sec/10;
						display(a1,a0); 
						if(Sec==0)//
						{
						   TR0=0;
						   beep=0;
						}
					}
				}
			}
		}
	}	
}