前言
使用了一种新的写法先单次扫描所有行列IO口,然后定时调用此函数,每次将此次IO口结果与上次对比,有变化则被视为按键按下或者释放。
代码
//此次使用的为三行四列,(相同IO口输出的为同一行,相同IO口输入的为同一列)
//键盘扫描函数需要先安装gpio.ko驱动模块
int gpioValuePrev[3][4] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; //存储上次GPIO值
int key_scan(void)
{
int gpioValue[3][4]; //存储本次GPIO值
int gpioValueTemp1[3][4]; //临时存储GPIO值,用于防抖
int gpioValueTemp2[3][4];
int i, j;
for(i = 0; i < 3; i++)
{
switch (i)
{
case 0: //第一行
GpioWriteBit(5, 30, 0);
GpioWriteBit(5, 31, 1);
GpioWriteBit(6, 0, 1);
break;
case 1:
GpioWriteBit(5, 30, 1);
GpioWriteBit(5, 31, 0);
GpioWriteBit(6, 0, 1);
break;
case 2:
GpioWriteBit(5, 30, 1);
GpioWriteBit(5, 31, 1);
GpioWriteBit(6, 0, 0);
break;
default:
break;
}
/* 一个尝试
//usleep(100);
//COL_WRITE(0);
//COL_WRITE(1);
//COL_WRITE(2);
//COL_WRITE(3);
//COL_READ(0);
//COL_READ(1);
//COL_READ(2);
//COL_READ(3);
//usleep(500);
*/
delay_ms(15);
gpioValueTemp1[i][0] = COL_READ(0);
gpioValueTemp1[i][1] = COL_READ(1);
gpioValueTemp1[i][2] = COL_READ(2);
gpioValueTemp1[i][3] = COL_READ(3);
delay_ms(1);
gpioValueTemp2[i][0] = COL_READ(0);
gpioValueTemp2[i][1] = COL_READ(1);
gpioValueTemp2[i][2] = COL_READ(2);
gpioValueTemp2[i][3] = COL_READ(3);
for(j = 0; j < 4; j++)
{
if(gpioValueTemp1[i][j] == gpioValueTemp2[i][j]) //防抖判断
{
gpioValue[i][j] = gpioValueTemp1[i][j];
}
else
{
gpioValue[i][j] = gpioValuePrev[i][j];
}
}
}
for(i = 0; i < 3; i++)
{
for(j = 0; j < 4; j++)
{
if(gpioValue[i][j] != gpioValuePrev[i][j]) //与上次对比,判断按键变化状态
{
if(1 == gpioValuePrev[i][j]) //key down
{
(*event_function)((i * 4 + j) * 2 + 1); //功能函数,传入按键值
}
else
{
(*event_function)((i * 4 + j) * 2 + 2);
}
}
}
}
memcpy(gpioValuePrev, gpioValue, sizeof(int)* 3 * 4);
return 0;
}
然后每10ms调用一次本函数。
问题
1 尾迹
当某按键,在其电平检测为0时恰好释放,此时该输入IO口相当于对外界空悬,会缓慢充电。
表现为,按下某一按键时,一定概率会错误显示其他异行同列按键被按下抬起。

尾迹图片
通过观察尾迹,原因就很明显:
我们是依次拉低某一行的IO口电平,此时若该行某按键被按下,此时该行IO就会与该按键对应列输入IO口短路,此时列输入IO口就会检测到低电平。
注意:IO口为输入状态时,空悬时大概有一个3V电压。
而3.3VIO口, 输入高电平低门限为2.3V ,输入低电平高门限为1.0V;
但是,由于尾迹的影响,低电平被延展得很长,当我们未按下另一行按键时,该输入IO口仍未空闲,会缓慢升压至3V,我们若在此时检测输入,明显会检测到低电平,就会误认为下一行同列按钮被按下,随着输入IO口缓慢升压至3V,又会误以为其被抬起。

尾迹延时精确测量
经过测量,尾迹的延时,在15ms时,可确定可跳过高电平低门限。因此,每次行扫描时,延时15ms即可解决。
2 异行同列按键之间无法同时按下
表现为,异行同列按键当同时按下时,会错误返回第一次按下的按键被抬起。。
原因很明显,当同时按下时,本该是低电平的IO口输入电压电压变高了。

单个按键被按下

异行同列两个按键同时按下
原因是,我们是分时扫描不同行,而同一时刻,不同行的输出IO口电平,应该有一个0,其他为1。当我们同时按下两个按键,则两个输出IO口(一个为0,一个为1)与输入IO口被同时短接了,因此不0不1,“高不成,低不就”。
因此,异行同列按键同时被按下是不可行的。
感悟
矩阵键盘,以前一直以为很简单。但是若深究其用法,想要实现检测多个按键等功能,其中的问题细节也很丰富。
学不可以已。
学者不可以不深思,而慎取之也
浙公网安备 33010602011771号