按键扫描方法
按键扫描

1.1.1 按键扫描运用定时中断实现按键扫描,就是将一个按键过程抽象为4个状态: S0状态:按键保持为高,即按键没有被按下。
S1状态:按键确实被按下,与S0状态结合,完成按键按下的去抖。
S2状态:按键保持低电平,即按键被按下状态的累积,在此可以对某一变量计数。
S3状态:按键被释放,与S2结合,完成释放去抖,另外判别是不是长按。
对于按键的一般的单击应用,我们通过定时扫描按键针对不同的响应要求可以将一次按键理解为S0→S1→S2(按下响应)或者S1→S2→S3(弹起响应)即可。
根据这个思想,每个按键的判断至少需要3个状态,而且其中两个状态为按下状态。
以下是两个按键单击判断的键扫描的流程和具体程序,采用按下响应,该程序每10ms 运行1次。
键扫描保存之前和再前键值读取当前键值有键按下?当前键值=之前键值?再前键值=0?YY键处理返回YN N NKEY_VALEQU R2 ;当前键值,用于存放S2状态 KEY_BACKEQU 60H ;之前键值,用于存放S1状态 KEY_PREEQU R7 ;在前键值,用于存放S0状态 ;KEY_CNT EQU R6 ;按下时间计数器,用于连击判断KEY_PORT EQU P2 ;定义P2键盘接口;*******************键扫描程序*******************KEY_SCAN: MOV KEY_PRE,KEY_BACKMOV KEY_BACK,KEY_VALLCALL READ_KEYMOV A,KEY_VALJZ KSRCJNE A,KEY_BACK,KS2CJNE KEY_PRE,#0,KS;SJMP KS1KS: ;INC KEY_CNT;CJNE KEY_CNT,#5,KSRKS1: LCALL KEY_HANDLEKS2: ;MOV KEY_CNT,#0KSR: RET;************读键码程序*********************READ_KEY: MOV A,KEY_PORTORL A,#0FCHCPL AJZ RK1 ;判断是否有按键JB K0,RK2 ;判断是否K0键按下MOV KEY_VAL,#1SJMP RKRRK1: MOV KEY_VAL,#0SJMP RKRRK2: JB K1,RKR ;判断是否K1键按MOV KEY_VAL,#2RKR: RET小提示:上述程序如果将注释掉的程序用上,就实现了连击键功能,其中KEY_CNT 用来存放按键定时计数,本例人为计数5次即按下50ms就触发一次键处理。
按键扫描程序(4)

else if(key == D_key)
........//点亮B_LED,关闭A_LED和C_LED
else if(key == S_key)
key_time_1 = 0; // 第1次单击,不返回,到下个状态判断后面是否出现双击
key_m = key_state_1;
}
else
特别操作情况定义:
1。短按操作和长按操作间隔<0.5s,以及,长按操作和短按操作间隔<0.5s,均不产生双击事件
2。连续n次(n为奇数)短按操作,且间隔均<0.5s,产生(n-1)/2次双击事件+1次单击事件
3。连续n次(n为偶数)短按操作,且间隔均<0.5s,产生n/2次双击事件
题目:多功能按键设计。利用一个I/O口,接一个按键,实现3功能操作:单击 + 双击 + 长按。
============================================================================
用户基本操作定义:
1。短按操作:按键按下,按下时间<1s,属于一次短按操作
if (!key_press)
{
key_time = 0; //
key_state = key_state_2; // 按键仍然处于按下,消抖完成,状态转换到按下键时间的计时状态,但返回的还是无键事件
}
else
key_state = key_state_0; // 按键已抬起,转换到按键初始态。此处完成和实现软件消抖,其实按键的按下和释放都在此消抖的。
按键扫描处理个人总结

按键扫描处理总结一、矩阵按键扫描方法1、现在的矩阵扫描主要有两种方法:(1)行列扫描法(2)反转法。
2、行列扫描法(1)行列扫描法的基本思想:行列扫描法是将其中的一行输出为低电平,其他行输出为高电平,列设为输入,然后判断哪一列为低电平,从而确认出是哪一行哪一列有键按下。
(2)行列扫描法举例如图1所示的2*2矩阵键盘,首先:将PB1,PB2作为行,并设置为输出;PA1,PA2作为列,并设置为输入。
其次:PB1设置为低电平输出,PB2设置为高电平输出,查看此时PA1和PA2的输入状态,假设此时S1按下,则此时PB1输出低电平通过S1传到了PA1上,使得PA1输入为低电平,而PA2仍然为高电平。
说明第一行有键按下,并且是第一列有键按下然后:再将PB1设置为高电平输出,PB2设置为低电平输出,此时PA1,PA2输入都为高电平。
说明第二行上没有按键按下。
最后:至此可以判断此时的PA1与PB1上的按键被按下,即第一行第一列的S1被按下。
整个按键扫描过程结束。
3、反转法(1)反转法的基本思想:将行设为输出为低电平,列设为输入,判断此时列的输入状态;然后在将列设为输出位低电平,行设为输入,判断此时行的输入状态。
如果有键按下,则其中的列输入状态必然有其中一列为低,行的输入状态也必然有其中一行为低,记录此时的行列号即可判断出是哪一行哪一列有键按下。
(2)反转法举例:如图1所示的2*2矩阵键盘,首先:将PB1,PB2作为行,并设置为输出;PA1,PA2作为列,并设置为输入。
其次:将PB1,PB2输出为低,查看PA1,PA2输入状态,假设还是S1被按下,则此时PA1输入为低电平,PA2输入为高电平。
说明第一列有键按下。
然后:将PB1,PB2作为行,并设置为输入;PA1,PA2作为列,并设置为输出。
最后:将PA1,PA2输出为低,查看PB1,PB2输入状态,则此时PB1输入为低电平,PB2输入为高电平。
说明第一行有键按下。
键盘扫描三种方法

第一种------传统法uchar scanf(){P3=0xfe;temp=P3&0xf0;if(temp!=0xf0) //判断是否有键按下{delay(5);//给一个延时temp=P3&0xf0;if(temp!=0xf0) //再次判断是否有键按下{temp=P3;switch(temp){case 0xee:num=1;break;case 0xde:num=2;break;case 0xbe:num=3;break;case 0x7e:num=4;break;}}while(temp!=0xf0)//键起,推出程序{temp=P3&0xf0;}}P3=0xfd;temp=P3&0xf0;if(temp!=0xf0){delay(5);temp=P3&0xf0;if(temp!=0xf0){temp=P3;switch(temp){case 0xed:num=5;break;case 0xdd:num=6;break;case 0xbd:num=7;break;case 0x7d:num=8;break;}}while(temp!=0xf0){temp=P3&0xf0;}}P3=0xfb;temp=P3&0xf0;if(temp!=0xf0){delay(5);temp=P3&0xf0;if(temp!=0xf0){temp=P3;switch(temp){case 0xeb:num=9;break;case 0xdb:num=10;break;case 0xbb:num=11;break;case 0x7b:num=12;break;}}while(temp!=0xf0){temp=P3&0xf0;}}P3=0xf7;temp=P3&0xf0;if(temp!=0xf0){delay(5);temp=P3&0xf0;if(temp!=0xf0){temp=P3;switch(temp){case 0xe7:num=13;break;case 0xd7:num=14;break;case 0xb7:num=15;break;case 0x77:num=16;break;}}while(temp!=0xf0){temp=P3&0xf0;}}Return(num);}第二种——简单法uchar keyscan(void){uchar scancode,tmpcode;P3 = 0xf0; // 发全0行扫描码if ((P3&0xf0)!=0xf0) // 若有键按下{delay(5); // 延时去抖动if ((P3&0xf0)!=0xf0)// 延时后再判断一次,去除抖动影响{scancode = 0xfe;//相当于从第一行开始扫描1111 1110while((scancode&0x10)!=0) // 控制行我的理解while((P3&0xf0)!=0xf0)(原来的程序转了一个大弯)(原程序,首先进入,使其扫描全行,扫描一次退出;我的:按键复原后,才退出程序;我的程序要扫描多次,但前提是一定扫描得到{P3 = scancode; // 输出行扫描码其实P3变为了1101 1110(假设有键按下)其中因为有键按下,写入的1马上又变为0(只有当行和列都对应时,才会继续下面的运算)即:如果开始按的是1101 1011,那么P3显示的就是1111 1110列中就不会出现0if ((P3&0xf0)!=0xf0) // 本行有键按下(确定行){tmpcode = (P3&0xf0)|0x0f; //确定列return((~scancode)+(~tmpcode)); /* 返回特征字节码,为1的位即对应于行和列*/}elsescancode = (scancode<<1)|0x01; // 行扫描码左移一位,换另一行扫面}}}return(0); // 无键按下,返回值为0}第三种———先行扫描,再列扫描uchar keyscan(void){uchar tag1,tag2;tag1=0xff;tag2=0xff;P3 = 0xf0; // 发全0行扫描码if ((P3&0xf0)!=0xf0) // 若有键按下{delay(5); // 延时去抖动if ((P3&0xf0)!=0xf0) // 延时后再判断一次,去除抖动影响{tag1=P3;P3=0x0f;tag2=P3&0x0f;}}return(~(tag1|tag2)); }。
按键扫描原理

按键扫描原理
按键扫描原理是指通过扫描矩阵来检测键盘上的按键状态。
在常见的键盘中,按键都被布置成一个矩阵的形式,每个按键都被安排在多行多列的位置上。
按键扫描原理的实现主要依靠两个主要组成部分,即行扫描和列扫描。
行扫描是指逐行地扫描键盘的每一行,通过向每一行施加电压或地电压来判断该行上是否有按键按下。
当扫描到某一行时,如果有按键按下,那么该行和对应按键所在的列之间就会有导通的电路。
这样,扫描程序就能够检测到按键的状态。
列扫描是指在行扫描的基础上,进一步扫描每一列,以确定具体按下了哪一个按键。
通过给某一列施加电压,并扫描每一行的电平状态,就可以判断被按下的按键所在的具体位置。
基于行列扫描的原理,键盘控制芯片会不断地轮询键盘的每一行和每一列,以实时地检测键盘的按键状态。
一旦检测到按键的状态发生变化,键盘控制芯片就会将相应的按键码发送给计算机,以实现对按键的输入响应。
总结起来,按键扫描原理通过对按键布置成的矩阵进行行列扫描,以检测键盘上的按键状态。
行扫描用于判断哪一行上有按键按下,列扫描用于确定具体按下了哪一个按键。
这种扫描方式能够高效地检测键盘的按键状态,并实现按键输入的响应。
51单片机4×4矩阵按键扫描方法

key=0xf0;//低四位为0
if(key==0xf0)//若无变化,证明按键松开
return 0;//返回0
else//否则,按键未松开
return 1;//返回1
}
//*********主函数*********//
int main()
{
key=0xff;//按键初始化
led=0xff;//关闭LED灯
//送至led显示
/*
eg:如果是第三行第二列按键按下
则第3个、第6(2列+4)个LED灯亮
如下图所示(Proteus仿真电路图)
*/
}
}
led_arry[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//数组定义,便于显示
//******检测是否有按键按下*****//
uchar Check_Button()
{
key=0x0f;//高四位为0
if(key==0x0f)//若无变化,证明无按键按下
return 0;//返回0
else//否则
return 1;//返回1
}
//********行检测********//
uchar Line[]={0x0e,0x0d,0x0b,0x07}; //那个按键按下,检测出的状态则对应数组中的第几个数
void Check_Line()
{
uchar i;
key=0x0f;//高四位为0
/*****4×4按键扫描******/
/***编程要点
1.首先检测是否有按键按下
2.若有按键按下,即进行行检测,列检测
3.行检测:高4位设为0,低4位为1,进行检测0x0f
简单的按键扫描&读取程序

/*GPIOA的置位复位定义*/
#define PA0_BSRR (*(uint32_t *)0x42010a00)
#define PA1_BSRR (*(uint32_t *)0x42010a04)
//
char get_key_riseedge(char keynum)
{
char val;
u32 mid = 0;
val = (key_riseedge >> keynum) & 0x01;//将该位上升沿取出送到val
mid = ~( 1 << keynum );
key_riseedge &= mid;//该上升沿清零
key_falledge &= ~(redge);//同上
key_riseedge |= redge;//将上升沿取到寄存器中待读
key_falledge |= fedge;//同上
}
//别的函数查询某个键的键值=========================================
#define PA3_OUT (*(uint32_t *)0x4221018c)
#define PA4_OUT (*(uint32_t *)0x42210190)
#define PA5_OUT (*(uint32_t *)0x42210194)
#define PA6_OUT (*(uint32_t *)0x42210198)
//
char get_key_val(char keynum)
极其简单好用的按键扫描程序C语言

极其简单好用的按键扫描程序(C语言)不过我在网上游逛了很久,也看过不少源程序了,没有发现这种按键处理办法的踪迹,所以,我将他共享出来,和广大同僚们共勉。
我非常坚信这种按键处理办法的便捷和高效,你可以移植到任何一种嵌入式处理器上面,因为C语言强大的可移植性。
同时,这里面用到了一些分层的思想,在单片机当中也是相当有用的,也是本文的另外一个重点。
对于老鸟,我建议直接看那两个表达式,然后自己想想就会懂的了,也不需要听我后面的自吹自擂了,我可没有班门弄斧的意思,hoho~~但是对于新手,我建议将全文看完。
因为这是实际项目中总结出来的经验,学校里面学不到的东西。
以下假设你懂C语言,因为纯粹的C语言描述,所以和处理器平台无关,你可以在MCS-51,AVR,PIC,甚至是ARM平台上面测试这个程序性能。
当然,我自己也是在多个项目用过,效果非常好的。
好了,工程人员的习惯,废话就应该少说,开始吧。
以下我以AVR的MEGA8作为平台讲解,没有其它原因,因为我手头上只有AVR的板子而已没有51的。
用51也可以,只是芯片初始化部分不同,还有寄存器名字不同而已。
核心算法:unsigned char Trg;unsigned char Cont;void KeyRead( void ){unsigned char ReadData = PINB^0xff; // 1Trg = ReadData & (ReadData ^ Cont); // 2Cont = ReadData; // 3}完了。
有没有一种不可思议的感觉?当然,没有想懂之前会那样,想懂之后就会惊叹于这算法的精妙!!下面是程序解释:Trg(triger)代表的是触发,Cont(continue)代表的是连续按下。
1:读PORTB的端口数据,取反,然后送到ReadData 临时变量里面保存起来。
2:算法1,用来计算触发变量的。
一个位与操作,一个异或操作,我想学过C语言都应该懂吧?Trg为全局变量,其它程序可以直接引用。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
说到键盘扫描,相信大多数人第一反应就是行列矩阵扫描,这样我们可以用相对有限的IO口得到尽可能多的按键。
键盘扫描是单片机技术的一种基本处理方法,学校的单片机课程都会有相应章节进行阐述,只要按照课本上讲述的方法,一般都能设计出比较可靠的键盘扫描电路与程序。
课本上的键盘扫描方法(见下图接法二)不能说是尽善尽美,从易懂性、成本、程序难易程度等方面综合看应该是不错的方法,给人感觉是已经没有太多的改善空间,至少我是这么认为的。
然而前段时间一位台湾朋友画给我的键盘扫描矩阵电路(见下图接法二),让我又一次看到到自己的思维还有许多地方被自己的所谓“经验”束缚着。
单纯的从硬件接法看,两种接法并没有明显区别,接法一甚至要复杂一些,但如果结合到键盘扫描的程序来看,就会发现接法一确实更好。
两种接法我都没有把上拉电阻包含进来,来让我们看一下两种接法到底有什么不同:
接法二:
我们熟悉的传统扫键处理电路,假定键盘行列IO口标号分别为H1/H2/H3和V1/V2/V3,扫键流程通常如下。
2.1. H1设置为输出,H2/H3和V1/V2/V3设置为输入
2.2. H1分别输出1和0,读V1/V2/V3状态,如果Vy状态与H1一致,则认为H1与Vy交叉位置的键按下
2.3. H2设置为输出,H1/H3和V1/V2/V3设置为输入
2.4. H2分别输出1和0,读V1/V2/V3状态,如果Vy状态与H2一致,则认为H2与Vy交叉位置的键按下
2.5. H3设置为输出,H1/H2和V1/V2/V3设置为输入
2.6. H3分别输出1和0,读V1/V2/V3状态,如果Vy状态与H3一致,则认为H3与Vy交叉位置的键按下
接法一:
新扫键处理电路,假定键盘行列IO口标号分别为H1/H2/H3和V1/V2/V3,扫键流程通常如下。
1.1. H1/H2/H3和V1/V2/V3都设置为输入
1.2. 读H1/H2/H3和V1/V2/V3状态,如果Hx和Vy读到的状态均为0,则认为Hx与Vy交叉位置的键按下
从上面流程可以看出接法一的程序代码要简单不少,既能减少扫键的代码量,又能加快扫键处理的时间,站在软件的角度看确实要比接法二要好。
后来我反思了一下为什么我们教材上的传统处理方法没有采用接法一,虽然接法一软件上要简单一些,但硬件布局要复杂,传统的按键只有两条接线,接法一需要三条接线,所以用传统的按键是无法实现的,但现在许多电子产品的按键都用导电橡胶或锅仔片来实现,所以接法一变得可行。
注:这两种电路对于同时按键达到3个的情况都有可能形成错误的按键逻辑。