#include<reg52.h>
#define uch unsigned char
#define uint unsigned int
#define ulong unsigned long
sbit ADDR0=P1^0;
sbit ADDR1=P1^1;
sbit ADDR2=P1^2;
sbit ADDR3=P1^3;
sbit ENLED=P1^4;
sbit KEY_IN_1=P2^4;
sbit KEY_IN_2=P2^5;
sbit KEY_IN_3=P2^6;
sbit KEY_IN_4=P2^7;
sbit key_out_1=P2^3;
sbit key_out_2=P2^2;
sbit key_out_3=P2^1;
sbit key_out_4=P2^0;
uch code ledchar[]={ //從數字0到F的顯示碼。
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e
};
uch keysta[4][4]={
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},
};
void main()
{
uch i,j;//循環變量i和j
uch backup[4][4]={
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},
};//按鍵值備份。
EA=1;//使能總中斷
ENLED=0;//選擇數碼管DS1進行顯示。
ADDR3=1;
ADDR2=0;
ADDR1=0;
ADDR0=0;
TMOD=0x01;//定時器0工作在模式1
TH0=0xfc;
TL0=0x67;//定時中斷間隔1毫秒
ET0=1;//開定時器0中斷。
TR0=1;//啟動定時器0
P0=ledchar[0]; //LED顯示0
while(1)
{
for (i=0;i<4;i++)//外層循環,執行四次;
{
for (j=0;j<4;j++)//內層循環,執行四次
{
if (backup[i]!=keysta[i][j])
{
if (backup[i][j]!=0)//如果上次保存的狀態是非0,就是1,表明上次按鈕按下,現在狀態不同上次保存狀態,那意思就是按下后已彈起
{
P0=ledchar[i*4+j];//將編號顯示出來。i是行號,從0行開始,j是行中的第幾個元素,那么變成一維數據就是行號*列寬+列號
} //判斷按下彈起大括號
backup[i][j]=keysta[i][j];
}//判斷鍵值變化大括號
} //內層循環大括呈
}//外層循環大括號
} //while大括號
} //main函數大括號
void InterruptTimer0() interrupt 1
{
uch i;
static uch keyout=0;
static uch keybuf[4][4]={
{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff}
};
TH0=0xfc;//重新加載初值
TL0=0x67;
keybuf[keyout][0]=(keybuf[keyout][0]<<1)|KEY_IN_1;
keybuf[keyout][1]=(keybuf[keyout][0]<<1)|KEY_IN_2;
keybuf[keyout][2]=(keybuf[keyout][0]<<1)|KEY_IN_3;
keybuf[keyout][3]=(keybuf[keyout][0]<<1)|KEY_IN_4;
//消抖后更新按鍵狀態
for (i=0;i<4;i++)//每行4個按鍵,所以循環4次
{
if ((keybuf[keyout][i]&0x0f)==0x00)
{ //連續4次掃描值為0,即4*4ms內都是按下狀態時,可認為按鍵已穩定的彈起
keysta[keyout][i]=1;
}
}//外層循環大括號
//執行下一次的掃描輸出
keyout++;
keyout=keyout&0x03;//索引值加到4即歸零
switch(keyout)
{
case 0:key_out_4=1;key_out_1=0;break; //key_out_1低電平的時候,開始探測第一行按鍵。順便把上次低電平的拉高。
case 1:key_out_1=1;key_out_2=0;break; //
case 2:key_out_2=1;key_out_3=0;break;
case 3:key_out_3=1;key_out_4=0;break;
default:break;
}//switch后大括號
}//中斷大括號 |