请问如何用单片机 获取矩阵键盘各按键的按下与松开的状态

2024-11-25 05:51:04
推荐回答(3个)
回答1:

用按键等待程序 ,把第二次判断有无按键按下的if语句变为
while(P1!=0xf0); //若按键一直处于按下状态,则等待按键释放 ;若按键释放,则往下执行
Key_Value = Keyscan();
SBUF=Key_Value;

这样,把主循环while(1)变为
while(1)
{
P1 = 0xf0;

if(P1 != 0xf0) //判断有无按键按下

{
Delay_1ms(20); //按键消抖
while(P1!=0xf0); //若按键一直处于按下状态,则等待按键释放 ;若按键释放,则往下 执行
Key_Value = Keyscan();
SBUF=Key_Value;

}
}
但看了你的程序 , 虽然不知道你的按键扫描程序keyscan()写的怎么样,但是按照一般思路,按键消抖都在按键扫描程序里面,你这里把按键扫描程序
Key_Value = Keyscan();
SBUF=Key_Value;
放在目标执行程序位置,结构上感觉冗余了,希望能帮到你!

回答2:

有问题,当按下多个按键时,消抖都没用了。
有计数法,但是需要消耗更多的内存。可以识别具体的键位,键的按下弹起状态,消抖。每个按键状态独立识别,无需等待延时。
typedef enum{
Key_No,
Key_Down,
Key_Up,
} KeyStateEnum;
vkey[4] = {0}; //4组按键
uchar keyDownNum[16] = {0}; //按下计数
uchar keyDownUp[16] = {0};//弹起计数
//判断键状态
uchar stateKey(uchar keySta, uchar *downNum, uchar *upNum, uchar del){
uchar sta = Key_No;
if(keySta){
upNum[0] = 0;
if(downNum[0] == del){
sta = Key_Down;
}
if(downNum[0] <= del)
downNum[0]++;
} else {
downNum[0] = 0;
if(upNum[0] == del){
sta = Key_Up;
}
if(upNum[0] <= del)
upNum[0]++;
}
return sta;
}

void ScanKey(){
uchar i, j, key;
for(i = 0; i < 4; i++){
for(j = 0; j < 4; j++){
key = i * 4 + j;
switch(stateKey(!(vkey[i] & (1 << j)), &keyDownNum[key], &keyDownUp[key], 10)){
case Key_Down : //键key按下
SBUF = key; //...
break;
case Key_Up : //键key弹起
SBUF = key + 0x80; //...
break;
}
}
}
}
void Readkey(){ //直接读4组状态,放到vkey[i]的低4位
uchar i;
for(i = 0; i < 4; i++){
P1 = ~(1 << i);
vkey[i] = (P1 >> 4);
}
}
void main(){
...
while(1){
Readkey(); //
ScanKey();
}
}

回答3:

/* 键扫描函数 */
uchar keyscan(void)
{
uchar scancode,tmpcode;
P1 = 0xf0; // 发全0行扫描码
if ((P1&0xf0)!=0xf0) // 若有键按下
{
delay(10); // 延时去抖动
if ((P1&0xf0)!=0xf0) // 延时后再判断一次,去除抖动影响
{
scancode = 0xfe;
while((scancode&0x10)!=0) // 逐行扫描
{
P1 = scancode; // 输出行扫描码
if ((P1&0xf0)!=0xf0) // 本行有键按下
{
tmpcode = (P1&0xf0)|0x0f;
/* 返回特征字节码,为1的位即对应于行和列 */
return((~scancode)+(~tmpcode));
}
else scancode = (scancode<<1)|0x01; // 行扫描码左移一位
}
}
}
return(0); // 无键按下,返回值为0
以上是4x4 矩阵键盘的哪一个键按下 的判断方法