/*按键程序的总结
110xia 发表于 2007-11-9 21:24:00 按键程序的总结
关于按键程序偶总结出以下几个关键点:
1. 按键数值的抓取
第一,在这个过程中一定要有去抖动处理的,可以使用硬件去抖动,一般在按键输入口外加电容就可以了;也可以使用软件处理去抖动,程序中使用延时再判断的办法,一般延时10ms就可以了。
第二,根据实际情况,设计多个按键同时按下,或某个(某些)按键先按下不松开,是否响应其他按键按下。
第三,根据实际情况,设计某些按键是否有长按功能。
2. 按键数值的处理
在这个过程中,根据实际情况,有些是需要按键按下就动作,还有些是需要按键松开就动作,大多数情况是要求按键按下就动作的。
为了不丢掉
例一,定时扫描按键,按键松开动作 软件处理抖动 4*4的键盘程序,定时10ms 调用 Matrix_Key_Detect() 这个函数,这是个普通的处理方法,在实际应用中,建议把它优化后在使用*/
// 矩阵键盘通用程序(引脚输入输出方向不切换)
//KEY_PINS 低4位为ROW(监听) 高4位为COL(输出,低电平)
// 7 6 5 4 3 2 1 0
// Co4 Co3 Co2 Co1 Ro4 Ro3 Ro2 Ro1
/* COL 4 3 2 1
ROW 4
3
2
1
*/
//Matrix_Key (row 行 col 列 从1开始计数)
#define KEY_PINS P0
sbit ROW1 = P0^0;
sbit ROW2 = P0^1;
sbit ROW3 = P0^2;
sbit ROW4 = P0^3;
sbit COL1 = P0^4;
sbit COL2 = P0^5;
sbit COL3 = P0^6;
sbit COL4 = P0^7;
unsigned char row="0",col=0;
//<返回其列号(col) 需要事先准备其行号掩码>
static unsigned char Matrix_Key_Scan_Col(const unsigned char rowbitmask)
{
unsigned char i="0";
unsigned char colmask;
KEY_PINS = 0x0f;
colmask=0x0f;
while ( (KEY_PINS & rowbitmask)==0)
{
colmask = colmask<<1;
KEY_PINS = colmask | 0x0f;
i++;
}
return i;
}
//<检测是否有按键按下,并返回其行号(row)>
static unsigned char Matrix_Key_Scan_Row()
{
KEY_PINS = 0x0f;
if (ROW1 == 0)
{
return 1;
}
else if (ROW2 == 0)
{
return 2;
}
else if (ROW3 == 0)
{
return 3;
}
else if (ROW4 == 0)
{
return 4;
}
return 0;
}
unsigned char Matrix_Key_Detect() //行/列
{
static unsigned char keep_time;
static unsigned char keep_row;
static unsigned char keep_col;
static unsigned char state = 0;
unsigned char uScanReturn;
switch (state)
{
case 0: //检测是否有按钮按下
if (Matrix_Key_Scan_Row() != 0 )
{ //<初始化>
keep_time = 0;
keep_row = 0;
keep_col = 0;
state++;
}
break;
case 1:
uScanReturn = Matrix_Key_Scan_Row();
if (uScanReturn != 0 ) //按键按下姿态
{
if (keep_time<250) keep_time++;
if (keep_row == 0)
{
keep_row = uScanReturn;
}
if (keep_row != 0 && keep_col == 0)
{
keep_col = Matrix_Key_Scan_Col( 0x01<<(keep_row-1) );
}
}
else //按键松起姿态
{
if (keep_time>5) //检测到有效按键
{
keep_time = 0;
state++;
}
else //按键无效
{
state = 0;
}
}
break;
case 2:
if (Matrix_Key_Scan_Row() == 0 ) //按键松起姿态(保持)
{
if (keep_time<250) keep_time++;
if (keep_time>5) //检测到有效松起
{
/* 返回信息:检测到有效按键,并可以执行对应操作 */
state = 0;
row = keep_row;
col = keep_col;
return 1;
}
}
else //按键被重新按下
{
keep_time=0; //重新计时
}
break;
}
return 0;
}
//例二 是将例一该善后的程序, 一个2*4的键盘, 当一个按键按下,不在响应其他按键盘。
//key 扫描
unsigned char data key_io;
unsigned char data keyflag;
unsigned char data keyedge_old;
uchar Key_Det_col(uchar keycol){
uchar keyrow;
P0=(~keycol);
_nop_();
_nop_();
keyrow=(~P0);
return(keyrow);
}
/*----------------------------- Subroutine -------------------------------------
Name: Key_Detect
Function:
Entry: key_io
Exit: keyflag,keyedge_old,keyedge
Caution:
-------------------------------------------------------------------------------*/
void Key_Detect(void){
static unsigned char state="2";
unsigned char keybuf;
state++;
if(state>2)
state="0x00";
if(state<2)
keybuf="Key"_Det_col(state+1);
switch (state){
case 0:
key_io&=0xf0; //first cow
key_io|=(keybuf>>4);
break;
case 1: //second cow
key_io&=0x0f;
keybuf&=0xf0;
key_io|=keybuf;
break;
case 2:
keybuf="keyflag"&key_io;
if(keybuf==0){
keyflag="key"_io;
keyedge_old=0x00;
}
else {
keyedge|=(keybuf&(~keyedge_old));
keyedge_old=keybuf;
}
break;
}
}
//例三 根据需要当一个按键按下时,还需要响应其他按键盘,可以把 例二 改善一下,只需要改 void Key_Detect(void); 这个函数里面的内容:
/*----------------------------- Subroutine -------------------------------------
Name: Key_Detect
Function:
Entry: key_io
Exit: keyflag,keyedge_old,keyedge
Caution:
-------------------------------------------------------------------------------*/
void Key_Detect(void){
static unsigned char state="2";
unsigned char keybuf;
state++;
if(state>2)
state="0x00";
if(state<2)
keybuf="Key"_Det_col(state+1);
switch (state){
case 0:
key_io&=0xf0; //first cow
key_io|=(keybuf>>4);
break;
case 1: //second cow
key_io&=0x0f;
keybuf&=0x70;
key_io|=keybuf;
break;
case 2:
keybuf="keyflag"&key_io;
keyflag="key"_io;
keyedge|=(keybuf&(~keyedge_old));
keyedge_old=keybuf;
break;
}
}