請教!這個矩陣鍵盤不用外部中斷如何修改?/*程序功能:
K1單擊時num+1;長擊num+2;
K2單擊時num-1;長擊num-2;
K5連擊按鍵 按著num+1;
K6連擊按鍵 按著num-1;
無按鍵時間4s led亮;有按鍵,led滅。
*/
//支持單擊(短擊)、連擊,長擊,無擊
//長擊時間到后,立即執行;短擊釋放后執行
//按鍵方式(單擊,長擊)、(只支持單擊)、(連擊)
//連擊實際上包含了單擊
#include "reg51.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define NOP() _nop_()
#define KeyPIN P1
sbit led=P3^7;
uchar num;
uchar key_code[]= {0x7e,0x7d,0x7b,0x77,0xbe,0xbd,0xbb,0xb7,0xde,0xdd,0xdb,0xd7,0xee,0xed,0xeb,0xe7};
struct
{
uchar state;//按鍵狀態 0-等待階段;1-閉合抖動階段;2-有效閉合階段;3-釋放階段
uchar type;//0-無按鍵或者按鍵已經響應 ;1-單擊 ;2-連擊 ;3-長擊;4-無擊
uchar detect;//按鍵檢測標志 1為檢測到按鍵
uchar value;//當前鍵值
uchar backvalue;//備份鍵值
uchar disable;//按鍵禁止響應標志:按鍵執行過,則標志為1.主要用于長擊。
uchar scan_en;//按鍵掃描標志 1為允許掃描
uchar tmr_no;//無鍵計數器,用于無擊。
uchar cnt_press;//按鍵閉合計數器,用于長擊。
uchar delay_con;//連擊響應延時時間,用于連擊。
#define AN_XD_DL 2//AN_XD_DL*定時器中斷20ms
#define AN_LA_DL 10//AN_LA_DL*20ms
#define AN_CJ_DL 5//長擊所需時間:AN_CJ_DL*AN_LA_DL*20ms
#define KEY_IDLE 0//按鍵等待階段
#define KEY_IS_DOWN 1//閉合抖動階段
#define KEY_DOWN 2//有效閉合階段
#define KEY_IS_UP 3//釋放階段
#define NoKey 0//無鍵
#define NoKeyTMR 200//無鍵所需時間:NoKeyTMR*20ms
} key;
unsigned char KeyScan(void);
void KeyInit(void);
void KeyProcess(void);
void KeyShortPress(void);//短擊 單擊
void KeyLongPress(void);//長擊
void KeyContinuePress(void);//連擊
void KeyNoPress(void);//無擊
void KeyAction(void);//根據按鍵類型動作 散轉程序
void main()
{
TCON=0x00;
IE=0x84;
TMOD=0x01;
TH0=0xB1;
TL0=0xE0;
ET0=1;
TR0=1;
EA = 1;
while(1)
{
KeyPIN=0x0f;
KeyProcess();
KeyAction();
P0=num/10;
P2=num%10;
}
}
//鍵盤掃描方法,反轉法
uchar KeyScan(void)
{
uchar temp,keyval=0;
KeyPIN = 0x0f;
if (KeyPIN != 0x0f)
{
temp=KeyPIN;
KeyPIN = 0xf0;
temp|=KeyPIN;
keyval=1;
while (key_code[keyval-1] != temp) //把特征碼轉換為鍵號
{
keyval++;
if(keyval>0x0f)
{
break;
}
}
}
return keyval;
}
void KeyProcess()
{
switch(key.state)
{
case KEY_IDLE://等待階段
{
key.disable=0;
key.delay_con=AN_XD_DL;
key.cnt_press=0;
if(key.detect)//有按鍵才允許掃描
{
key.tmr_no=0;//有鍵按下,無鍵計數器清零
key.type=0;
key.detect=0;
if(key.scan_en)
{
key.scan_en=0;
key.state=KEY_IS_DOWN;
}
}
else
{
if(key.tmr_no==NoKeyTMR)
{
key.type=4;
}
}
}
break;
case KEY_IS_DOWN:
{
key.tmr_no=0;
if(key.scan_en)
{
key.scan_en=0;
key.value=KeyScan();
if(key.value==key.backvalue)
{
key.state=KEY_DOWN;
}
else
{
key.backvalue=key.value;
}
}
}
break;
case KEY_DOWN:
{
key.tmr_no=0;
if(key.scan_en)
{
key.scan_en=0;
key.backvalue=key.value;//備份當前鍵值供釋放后 單擊 使用
key.value=KeyScan();
key.delay_con--;
if(key.delay_con==0)
{
key.delay_con=AN_LA_DL;
key.cnt_press++;
if(key.cnt_press>AN_CJ_DL)
{
if(!key.disable)//長擊執行過一次后,如不釋放按鍵,不執行。
{
key.type=3;
}
else
{
key.type=0;
}
}
else
{
key.type=2;
}
}
if(key.value==NoKey)
{
key.state=KEY_IS_UP;
}
}
}
break;
case KEY_IS_UP:
{
key.tmr_no=0;
if(!key.disable)//避免長擊釋放后 繼續執行單擊
{
key.type=1;
}
key.state=KEY_IDLE;
}
break;
}
}
void KeyAction(void)
{
switch(key.type)
{
case 1:
{
KeyShortPress();
}
break;
case 2:
{
KeyContinuePress();
key.type=0;
}
break;
case 3:
{
KeyLongPress();
}
break;
case 4:
{
KeyNoPress();
}
break;
}
}
void KeyNoPress(void)
{
led=0;
}
void KeyShortPress(void)
{
led=1;
switch(key.backvalue)
{
case 1:
num++;
break;
case 2:
num--;
break;
}
}
void KeyContinuePress(void)
{
led=1;
switch(key.backvalue)
{
case 5:
num++;
break;
case 6:
num--;
break;
}
}
void KeyLongPress(void)
{
led=1;
switch(key.backvalue)
{
case 1:
num+=2;
key.disable=1;
key.type=0;
break;//此處key.disable和key.type必須這樣處理
case 2:
num-=2;
key.disable=1;
key.type=0;
break;
default:
key.type=2;//因為長擊是在按下后時間足夠后就觸發的,所以為避免連擊和長擊沖突,必須加此句
}
}
void timer0() interrupt 1 using 1 //12M晶振 20ms中斷
{
TH0=0xB1;
TL0=0xE0;
key.tmr_no++;
if(key.detect)
{
key.scan_en=1; //有鍵按下才允許掃描
}
}
void EXT_INT() interrupt 2 using 1
{
key.detect=1;
}
|