矩阵按键
在我的印象中,从我学单片机开始,就很少写矩阵按键的程序,但是原理差不多都清楚,不过在这里不仅要考虑程序的执行,而且需考虑程序的完整与完善。
一针见血,看原理图
将开发板上面的J5跳线帽接到KBD端,也就是J5的1和2相接。
这里注意:在开发板上,根据转接板原理图,WR端接到单片机的P42管脚,RD端接到单片机的P44管脚。
我们知道,按键按下通常会保持100ms以上,如果在按键扫描中断中,每次让矩阵按键的一个KeyOut输出低电平其他三个输出高电平,判断当前所有Keyln的状态,下次中断时再让下一个KeyOut输出低电平,其他三个输出高电平.再次判断所有KeyIn,通过快速的中断不停地循环进行判断,就可以最终确定哪个按键按下了。
这个原理是不是跟数码管动态扫描有点类似?数码管在动态赋值,而按键在动态读取状态。至于扫描间隔时间和消抖时间,因为现在有4个KeyOut输出,要中断4次才能完成一次全部按键的扫描,显然2ms中断时间较长,这里我们使用1ms。
//main.c
#define u16 unsigned int
#define u8 unsigned char
u8 Led_flag = 0;
u8 Led_dat; //led显示状态
u8 KeySta[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}}; //当前按键状态
u8 Key_backup[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}}; //按键状态备份,保存前一次的按键值
void main(void)
{
u8 i,j;
All_Init();
Time0_Init();
Led_dat = 0xfe;
while(1)
{
for(i = 0;i < 4;i ++) //循环检测4×4的矩阵按键
{
for(j = 0;j < 4;j ++)
{
if(Key_backup [j] != KeySta[j]) //检测按键当前动作
{
if(Key_backup[j] != 0) //按键按下时执行动作
Key_backup[j] = KeySta[j]; //更新前一次的备份值
}
}
}
}
}
//key.c
//按键扫描
void Key_Scan(void)
{
u8 i;
static u8 keyout = 0; //矩阵按键扫描输出索引
static u8 keybuff[4][4] = {{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff},{0xff,0xff,0xff,0xff}}; //矩阵按键扫描缓存区
keybuff[keyout][0] = (keybuff[keyout][0] << 1) | KEY_IN_1; //将每一行的4个按键值移入缓存区
keybuff[keyout][1] = (keybuff[keyout][1] << 1) | KEY_IN_2;
keybuff[keyout][2] = (keybuff[keyout][2] << 1) | KEY_IN_3;
keybuff[keyout][3] = (keybuff[keyout][3] << 1) | KEY_IN_4;
//消抖后更新按键状态
for(i = 0;i < 4;i ++)
{
if((keybuff[keyout] & 0x0f) == 0x00)
KeySta[keyout] = 0; //连续4次扫描值都是0,即4×4s内都是按下状态,认为按键已平稳按下
else if((keybuff[keyout] & 0x0f) == 0x0f)
KeySta[keyout] = 1; //连续4次扫描值都是1,即4×4s内都是松开状态,认为按键已稳定弹起
}
//执行下一次的扫描输出
keyout ++;
keyout = keyout & 0x03; //索引加到4就归零
switch(keyout) //根据索引,释放当前输出引脚,拉低下次的输出引脚
{
case 0:KEY_OUT_4 = 1;KEY_OUT_1 = 0;break;
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;
}
}
|
|
2021-10-27 11:02:10
评论
举报
|
|
|