矩阵键盘的识别方法

矩阵键盘的识别方法,第1张

矩阵式结构的键盘显然比直接法要复杂一些,识别也要复杂一些,列线通过电阻接正电源,并将行线所接的单片机的I/O口作为输出端,而列线所接的I/O口则作为输入。这样,当按键没有按下时,所有的输入端都是高电平,代表无键按下。行线输出是低电平,一旦有键按下,则输入线就会被拉低,这样,通过读入输入线的状态就可得知是否有键按下了。

<1>确定矩阵式键盘上何键被按下介绍一种“行扫描法”。

行扫描法 行扫描法又称为逐行(或列)扫描查询法,是一种最常用的按键识别方法,如上图所示键盘,介绍过程如下。

1、判断键盘中有无键按下 将全部行线Y0-Y3置低电平,然后检测列线的状态。只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中。若所有列线均为高电平,则键盘中无键按下。

2、判断闭合键所在的位置 在确认有键按下后,即可进入确定具体闭合键的过程。其方法是:依次将行线置为低电平,即在置某根行线为低电平时,其它线为高电平。在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。

下面给出一个具体的例子:

图仍如上所示。8031单片机的P1口用作键盘I/O口,键盘的列线接到P1口的低4位,键盘的行线接到P1口的高4位。列线P10-P13分别接有4个上拉电阻到正电源+5V,并把列线P10-P13设置为输入线,行线P14-P17设置为输出线。4根行线和4根列线形成16个相交点。

1、检测当前是否有键被按下。检测的方法是P14-P17输出全“0”,读取P10-P13的状态,若P10-P13为全“1”,则无键闭合,否则有键闭合。

2、去除键抖动。当检测到有键按下后,延时一段时间再做下一步的检测判断。

3、若有键被按下,应识别出是哪一个键闭合。方法是对键盘的行线进行扫描。P14-P17按下述4种组合依次输出:

P17 1 1 1 0

P16 1 1 0 1

P15 1 0 1 1

P14 0 1 1 1

在每组行输出时读取P10-P13,若全为“1”,则表示为“0”这一行没有键闭合,否则有键闭合。由此得到闭合键的行值和列值,然后可采用计算法或查表法将闭合键的行值和列值转换成所定义的键值

4、为了保证键每闭合一次CPU仅作一次处理,必须去除键释放时的抖动。

键盘扫描程序:

从以上分析得到键盘扫描程序的流程图所示。程序如下

SCAN: MOV P1,#0FH

MOV A,P1

ANL A,#0FH

CJNE A,#0FH,NEXT1

SJMP NEXT3

NEXT1: ACALL D20MS

MOV A,#0EFH

NEXT2: MOV R1,A

MOV P1,A

MOV A,P1

ANL A,#0FH

CJNE A,#0FH,KCODE;

MOV A,R1

SETB C

RLC A

JC NEXT2

NEXT3: MOV R0,#00H

RET

KCODE: MOV B,#0FBH

NEXT4: RRC A

INC B

JC NEXT4

MOV A,R1

SWAP A

NEXT5: RRC A

INC B

INC B

INC B

INC B

JC NEXT5

NEXT6: MOV A,P1

ANL A,#0FH

CJNE A,#0FH,NEXT6

MOV R0,#0FFH

RET

<2>确定矩阵式键盘上何键被按下介绍一种“高低电平翻转法”。

首先让P1口高四位为1,低四位为0,。若有按键按下,则高四位中会有一个1翻转为0,低四位不会变,此时即可确定被按下的键的行位置。

然后让P1口高四位为0,低四位为1,。若有按键按下,则低四位中会有一个1翻转为0,高四位不会变,此时即可确定被按下的键的列位置。

最后将上述两者进行或运算即可确定被按下的键的位置。

键盘处理程序就作这么一个简单的介绍,实际上,键盘、显示处理是很复杂的,它往往占到一个应用程序的大部份代码,可见其重要性,但说到,这种复杂并不来自于单片机的本身,而是来自于 *** 作者的习惯等等问题,因此,在编写键盘处理程序之前,最好先把它从逻辑上理清,然后用适当的算法表示出来,最后再去写代码,这样,才能快速有效地写好代码。

51单片机4×4矩阵键盘仿真哪里找

44 矩阵键盘布局如下,检测按键,然后通过 LCD1602 显示出来

第一行:The key value is

第二行:每按一次键,键值依次显示出来,整行显示完后,清屏,键值

从左开始显示

仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)

0png

单片机源程序如下:

/

LCD1602液晶显示实验

实现现象:下载程序后插上LCD1602液晶在开发板上,即可显示

注意事项:如果不想让点阵模块显示,可以将74HC595模块上的JP595短接片拔掉。

/

#include "reg52h" //此文件中定义了单片机的一些特殊功能寄存器

#include "lcdh"

typedef unsigned int u16; //对数据类型进行声明定义

typedef unsigned char u8;

#define LCD1602_DATAPINS P0

#define GPIO_KEY P1

u8 KeyValue,k=0,n=0,miss=1;

u8 Disp[]="The key value is";

u8 cmy[17]={'1','2','3','/','4','5','6','%','7','8','9','@','','0','#','='};

u8 dp[17]={' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};

/

函 数 名 : main

函数功能 : 主函数

输 入 : 无

输 出 : 无

/

void KeyDown(void)

{

char a=0;

GPIO_KEY=0x0f;

if(GPIO_KEY!=0x0f)//读取按键是否按下

{

Lcd1602_Delay1ms(10);//延时10ms进行消抖

if(GPIO_KEY!=0x0f)//再次检测键盘是否按下

{ n=1;

//测试列

GPIO_KEY=0X0F;

switch(GPIO_KEY)

{

case(0X07): KeyValue=0;break;

case(0X0b): KeyValue=1;break;

case(0X0d): KeyValue=2;break;

case(0X0e): KeyValue=3;break;

}

//测试行

GPIO_KEY=0XF0;

switch(GPIO_KEY)

{

case(0X70): KeyValue=KeyValue;break;

case(0Xb0): KeyValue=KeyValue+4;break;

case(0Xd0): KeyValue=KeyValue+8;break;

case(0Xe0): KeyValue=KeyValue+12;break;

}

while((a<50)&&(GPIO_KEY!=0xf0)) //检测按键松手检测

{

Lcd1602_Delay1ms(1);

a++;

}

}

}

}

void main(void)

{

u8 i,m;

LcdInit();

for(i=0;i<16;i++)

{

LcdWriteData(Disp[i]);

}

while(miss)

{

LcdWriteCom(0x80+0x40);

KeyDown();

if(n==1)

{dp[k]=cmy[KeyValue];

n=0;

k++;

}

for(m=0;m<16;m++)

{LcdWriteData(dp[m]);}

if(k==16)

{ for(m=0;m<16;m++)

{dp[m]=' ';}

Lcd1602_Delay1ms(1000);

LcdWriteCom(0x01);

Lcd1602_Delay1ms(1000);

k=0;

for(i=0;i<16;i++)

{

LcdWriteData(Disp[i]);

}

}

}

}

这个一般是结合硬件的。

但是单单看代码,猜测如下

你这个键盘矩阵是44的,而且所有8根线都是接到B口的。所以:

PORTB=0x7f;                    // 将最高位(也就是你说的第三行)行选电平拉低。

keynum=PORTB;                  // 读取端口B

keynum=keynum&0x0f;            // 提取端口B第四位,也就是出现键值的那几个引脚

if(keynum!=0x0f){           // 如果有数据说明有键按下

delay(10);                   // 消抖延时

keynum=PORTB;                  // 再次读取端口数据

keynum=keynum&0x0f;            // 消抖后第二次处理

if(keynum!=0x0f) {          // 保证前后两次扫描键盘都是按下的

keynum=keynum|0x0f;            // 这一句有意思,键值被修改成0x0F了,这可能不是程序的本意,因为keynum里面已经是可用的键值了,直接用它去调用其它的 *** 作就可以。最后一句 *** 作却把键值擦除了。

}}

//msp430F149

44矩阵键盘P1口中断扫描

#include<msp430x14xh>

#define

KEY_DIR

P1DIR

#define

KEY_OUT

P1OUT

#define

KEY_IN

P1IN

#define

KEY_IE

P1IE

#define

KEY_IES

P1IES

#define

KEY_IFG

P1IFG

/全局变量/

unsigned

char

Key_Val;

//存放键值

void

CtrlKey(unsigned

char

sw);

//控制键盘开关//sw=0关

sw=1开

/

函数名称:Init_Keypad

能:初始化扫描键盘的IO端口

数:无

返回值

:无

/

void

Init_Keypad(void)

{

KEY_DIR

=

0x0f;

//P10~P13设置为输出状态,P14~P17输入

状态(上拉H)

KEY_OUT=0;

KEY_IES

=0xf0;

//P14~P17允许中断

KEY_IE

=0xf0;

//P14~P17下降沿触发中断

KEY_IFG=0;

//中断标志清0

Key_Val

=

0;

}

/

函数名称:Check_Key

能:扫描键盘的IO端口,获得键值

数:无

返回值

:无

/

//p14\5\6\7

接上拉电阻

/

key_Val

对应键值

列:[p14]

[p15]

[p16]

[p17]

行:

[p13]→

1

2

3

4

[p12]→

5

6

7

8

[p11]→

9

10

11

12

[p10]→

13

14

15

16

/

void

Check_Key(void)

{

unsigned

char

row

,col,tmp1,tmp2;

unsigned

char

keymap[]

=

{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};//设置键盘逻辑键值

与程序计算键值的映射

tmp1

=

0x08;

for(row

=

0;row

<

4;row++)

//行扫描

{

KEY_OUT

=

0x0f;

//P14~P17输出全1

KEY_OUT

-=

tmp1;

//P14~p17输出四位中有一个为0

tmp1

>>=1;

if((KEY_IN

&

0xf0)<0xf0)

//是否P1IN的P10~P13中有一位为0

{

tmp2

=

0x10;

//

tmp2用于检测出哪一位为0

for(col

=

0;col

<

4;col++)

//

列检测

{

if((KEY_IN

&

tmp2)

==

0x00)

//

是否是该列,等于0为是

{

Key_Val

=

keymap[row4

+

col];

//

获取键值

return;

//

退出循环

}

tmp2

<<=

1;

//

tmp2右移1位

}

}

}

}

/

函数名称:delay

能:延时约15ms,完成消抖功能

数:无

返回值

:t=

tmp5clk

根据使用时钟调整tmp值

/

void

delay(void)

{

unsigned

int

tmp;

for(tmp

=

12000;tmp

>

0;tmp--);

}

/

函数名称:Key_Event

能:检测按键,并获取键值

数:无

返回值

:无

/

void

Key_Event(void)

{

unsigned

char

tmp;

KEY_OUT

=0;

//

设置P1OUT全为0,等待按键输入

tmp

=

KEY_IN;

//

获取

p1IN

if((tmp

&

0xf0)

<

0xf0)

//如果有键按下

{

delay();

//消除抖动

Check_Key();

//

调用check_Key(),获取键值

}

}

/

控制打开或者关闭键盘中断

SW=

0:关闭;

ELSE:打开

/

void

CtrlKey(unsigned

char

sw)

{

if(sw==0)

KEY_IE

=0;

//关闭端口中断

else

KEY_IE

=0xf0;

//打开端口中断

}

/端口1按键中断/

#pragma

vector=PORT1_VECTOR

__interrupt

void

Port(void)

{

if((KEY_IFG&0xf0)!=0)

{

Key_Event();

if(Key_Val!=0)

//键值!=0有键按下

{

CtrlKey(0);

//关键盘中断

}

}

KEY_IFG=0;KEY_OUT=0;

//清中断标志

}

你按键要是没有松手检测的话,按键按下后程序会执行一次按键一的数据,然后在执行按键2的数据,按键1和按键2就成了循环检测了,执行两个按键事件,如果按键有松手检测的话,例如按键1按下,程序会在按键1哪里等待按键松手后,才会跳出按键,否则按键会一直死在哪里等待按键松手,希望我的回答对你有帮助!

那就用这种方法解决:

if(keyxxx == 0)

{

if(++i <= 10)

return;

//

if(keyxxx == 0)

{

i = 0;

//处理按键程序

}

}

if(keyxxx == 0)

{

if(++y <= 10)

return;

//

if(keyxxx == 0)

{

y = 0;

//处理按键程序

}

}

按键消抖动程序估计有问题,给你看个消抖动的例子程序

while(key1==0)

{

delayms(10);

if(key1==0)

{

num=1;

}

}

以上就是关于矩阵键盘的识别方法全部的内容,包括:矩阵键盘的识别方法、51单片机4×4矩阵键盘仿真哪里找、有pic单片机的高手解释一下下面这段代码是怎么实现对矩阵键盘第三行的检测的吗在下毕竟学渣! PO等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9690136.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-01
下一篇 2023-05-01

发表评论

登录后才能评论

评论列表(0条)

保存