经典的按键扫描
按键扫描程序(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)); }。
矩阵式键盘的按键识别方法
矩阵式键盘的按键识别方法确定矩阵式键盘上何键被按下介绍一种“行扫描法”。
行扫描法行扫描法又称为逐行(或列)扫描查询法,是一种最常用的按键识别方法,如上图所示键盘,介绍过程如下。
1、判断键盘中有无键按下将全部行线Y0-Y3置低电平,然后检测列线的状态。
只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中。
若所有列线均为高电平,则键盘中无键按下。
2、判断闭合键所在的位置在确认有键按下后,即可进入确定具体闭合键的过程。
其方法是:依次将行线置为低电平,即在置某根行线为低电平时,其它线为高电平。
在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。
若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。
下面给出一个具体的例子:图仍如上所示。
8031单片机的P1口用作键盘I/O口,键盘的列线接到P1口的低4位,键盘的行线接到P1口的高4位。
列线P1.0-P1.3分别接有4个上拉电阻到正电源+5V,并把列线P1.0-P1.3设置为输入线,行线P1. 4-P.17设置为输出线。
4根行线和4根列线形成16个相交点。
1、检测当前是否有键被按下。
检测的方法是P1.4-P1.7输出全“0”,读取P1.0-P1.3的状态,若P1.0-P1.3为全“1”,则无键闭合,否则有键闭合。
2、去除键抖动。
当检测到有键按下后,延时一段时间再做下一步的检测判断。
3、若有键被按下,应识别出是哪一个键闭合。
方法是对键盘的行线进行扫描。
P1.4-P1.7按下述4种组合依次输出:P1.7 1 1 1 0P1.6 1 1 0 1P1.5 1 0 1 1P1.4 0 1 1 1在每组行输出时读取P1.0-P1.3,若全为“1”,则表示为“0”这一行没有键闭合,否则有键闭合。
由此得到闭合键的行值和列值,然后可采用计算法或查表法将闭合键的行值和列值转换成所定义的键值。
经典的矩阵键盘扫描程序1
取键值以启动相应的功能程序。
/***************************************************File Name :LED Debug*Autor :HR*Version :V1.0*Data :*Descrption :none*********************************************************************************************************/#include "include.h"JOB Job_Data; ----------1SYS_TimeHandler SYS_Time; ---------2MSG Msg_Key; /* 按键任务使用的结构体消息*/ ---------3uint16 test_a; ---------4 uint16 TX_Buff_Byte[25]; ---------4uint8 TX_Buff_ASIC[25]; ---------4/************************************************主程序************************************************/int main(){BSP_Init(); ---------5SYSTEM_LogShow (); ---------6for(;;) {SYS_100US_handler(); ---------7SYS_10MS_handler(); ---------8SYS_100MS_handler(); ---------9SYS_200MS_handler(); ---------10 }}JOB Job_Data;typedef struct WELD /* 任务用的焊接数据包(结构体数据类型) */{// 临时标记uint8 FgWeldRunEn; // 焊接输出标记uint8 FgGasRunEn; // 焊接气体输出标记uint8 FgPowerRunEn; // 系统工作标记uint8 FgMotorRunEn; // 送丝机系统工作标记uint8 FgLcmFlickerEn; // 显示闪烁工作标记uint8 FgRoughMachiningEn; // 粗调节有效uint8 FgCURRENTIndicateLedEn; // 输出正常电流指示LEDuint8 FgMotorCheckEn; // 送丝机系统检测标记uint8 FgEepromSaveEn; // 数据记忆标记uint8 FgLcmHoldEn; // 冻结显示内容uint8 FgVRDReset; // VRD复位辅助标记uint8 LockState; // 4T焊接辅助指令uint8 Fg_RXFinish; // 串口接收数据完成标记uint8 Fg_ShowLog; // 开机LOG辅助标记uint8 Fg_UsartConnect; // USART连接标记uint8 FgACV oltageState; // 网压状态标记uint8 FgSystemFault; // 系统故障标记uint8 FgFactoryTest; // 工厂调试标记uint8 FgDisChannel; // 公英制切换uint8 RunV olatgeTest; // 关机检测状态// 临时数据处理uint16 FaultOrderSet; /* 设备故障指令数据缓存*/uint16 SystemOrderSet; /* 传递系统指令数据缓存*/uint16 LcmOrderSet; /* 传递LCM显示指令数据缓存*/uint16 DriveOrderSet; /* 传递驱动组件指令数据缓存*/uint16 WorkOrderSet; /* 焊接工作指令数据缓存*/uint16 MainMenu; /* 主目录数据缓存*/uint16 CheckOrderSet;uint16 LcmV oltageData; /* 焊接显示电压数据缓存*/uint16 LcmCurrentData; /* 焊接显示电流数据缓存*/uint16 LcmV oltageDataDis; /* 焊接显示电压数据缓存*/uint16 LcmCurrentDataDis; /* 焊接显示电流数据缓存*/uint16 LcmMotorData; /* 焊接显示电机数据缓存*/uint16 LcmTempData; /* 焊接显示温度数据缓存*/uint16 LcmACSupplyState; /* 网压显示数据缓存*/uint16 LCMDataBuff_1; /* LCM1显示数据缓存*/uint16 LCMDataBuff_2; /* LCM2显示数据缓存*/uint16 SystemV oltageData; /* 焊接实际电压数据缓存*/uint16 SystemCurrentData; /* 焊接实际电流数据缓存*/uint16 SystemCurrentBuff;// 设备数据处理(需要记忆) //uint16 WeldWorkSetMode; // 焊接类型选择:MMA,TIG,MIG uint16 WeldRunSetVRD; // VRD setuint16 WeldRunSetMode; // 焊接方式选择:2T,4T// MMA //uint16 MMASetCurrent; // MMA手工焊电流设置// TIG //uint16 TIGSetCurrent; // TIG焊接电流// MIG //uint16 MIGSetV oltage; // MIG焊接电压uint16 MIGSetMotorSpeed; // MIG送丝速度uint16 MIGSetInductance; // MIG电子电抗uint16 MIGSetV oltageFine; // MIG焊接电压微调uint8 MIGSetV oltageCorrect; // 系统给定焊接电压修正uint8 MIGDisV oltageCorrect; // 系统显示焊接电压修正uint8 MIGSetCurrentCorrect; // 系统给定焊接电流修正uint8 MIGDisCurrentCorrect; // 系统显示焊接电流修正//外置MIG //uint16 Ext_MIGSetVoltage; // MIG焊接电压// 已更改uint16 Ext_MIGSetMotorSpeed; // MIG送丝速度// 已更改uint16 Ext_MIGSetInductance; // MIG电子电抗// 已更改uint16 Ext_MIGSetVoltageFine; // MIG焊接电压微调// 已更改uint8 Ext_MIGSetV oltageCorrect; // 系统给定焊接电压修正// 已更改uint8 Ext_MIGDisVoltageCorrect; // 系统显示焊接电压修正// 已更改uint8 Ext_MIGSetCurrentCorrect; // 系统给定焊接电流修正// 已更改uint8 Ext_MIGDisCurrentCorrect; // 系统显示焊接电流修正// 已更改uint8 CheckW_VRD_RunI_2T4T;int16 V_Set_Value_08;} JOB;{unsigned char row,col,tmp1,tmp2;tmp1 = 0x10; //tmp1用来设置P1口的输出,取反后使P1.4~P1.7中有一个为0for(row=0;row<4;row++) // 行检测{P1 = 0x0f; // 先将p1.4~P1.7置高P1 =~tmp1; // 使P1.4~p1.7中有一个为0tmp1*=2; // tmp1左移一位if ((P1 & 0x0f) < 0x0f) // 检测P1.0~P1.3中是否有一位为0,只要有,则说明此行有键按下,进入列检测{tmp2 = 0x01; // tmp2用于检测出哪一列为0for(col =0;col<4;col++) // 列检测{if((P1 & tmp2)==0x00) // 该列如果为低电平则可以判定为该列{key_val =key_Map[ row*4 +col ]; // 获取键值,识别按键;key_Map为按键的定义表return; // 退出循环}tmp2*=2; // tmp2左移一位}}}}。
按键扫描原理
按键扫描原理
按键扫描原理是指通过扫描矩阵来检测键盘上的按键状态。
在常见的键盘中,按键都被布置成一个矩阵的形式,每个按键都被安排在多行多列的位置上。
按键扫描原理的实现主要依靠两个主要组成部分,即行扫描和列扫描。
行扫描是指逐行地扫描键盘的每一行,通过向每一行施加电压或地电压来判断该行上是否有按键按下。
当扫描到某一行时,如果有按键按下,那么该行和对应按键所在的列之间就会有导通的电路。
这样,扫描程序就能够检测到按键的状态。
列扫描是指在行扫描的基础上,进一步扫描每一列,以确定具体按下了哪一个按键。
通过给某一列施加电压,并扫描每一行的电平状态,就可以判断被按下的按键所在的具体位置。
基于行列扫描的原理,键盘控制芯片会不断地轮询键盘的每一行和每一列,以实时地检测键盘的按键状态。
一旦检测到按键的状态发生变化,键盘控制芯片就会将相应的按键码发送给计算机,以实现对按键的输入响应。
总结起来,按键扫描原理通过对按键布置成的矩阵进行行列扫描,以检测键盘上的按键状态。
行扫描用于判断哪一行上有按键按下,列扫描用于确定具体按下了哪一个按键。
这种扫描方式能够高效地检测键盘的按键状态,并实现按键输入的响应。
简单的按键扫描&读取程序
/*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)
键盘扫描方法
键盘扫描方法传统的键盘扫描方法如图1所示,该方法虽然被广泛应用于很多场合,但有一个不足的地方,如果按键一直没有释放,或者按键坏了,一直处于闭合状态,则程序一直处于检测按键是否释放,系统将无法运行。
只要对其稍加改进,就可以避免产生这个问题。
假设键盘接口电路采用独立式键盘接口,所有按键公共端接地,而且没有按键按下时IO口为高电平。
当按键没有按下时,IO口为高电平;当按键按下时,IO口为低电平;当按键释放时,IO口为高电平。
一个完整的按键过程是——按键未按下,按键按下,按键释放,而对应的IO口的电平变化为——高电平,低电平,高电平。
所以,可以通过判断IO口电平变化的变化顺序是否满足高电平→低电平→高电平,来判断是否有按键按下,而对于其它的电平变化顺序都是无效的。
那么该如何实现呢?在键盘扫描过程中,如果IO口为高电平,则需要判断是由于未按键,还是按键按下后释放引起的;如果IO口为低电平,则需要判断是由于未按键还是扫描之前本来就是低电平引起的。
所以我们需要引入一个全局位变量KEY_EN,来标志按键的状态, KEY_EN=0表示按键未按下;KEY_EN=1表示按键按下。
另外,我们还需引入一个全局字节变量KEY_TP来暂存键值,这是因为只有当IO口电平变化满足高电平→低电平→高电平,才表示一个按键有效,而只有在IO口为低电平的时候才能够读取到键值。
具体的键盘扫描流程如图2所示,键盘初始化KEY_EN=0。
图1 传统键盘扫描图2 改进后键盘扫描接下来我们介绍一种代码效率极高的键盘扫描方法。
键盘接口电路同样采用独立式,假设有8个按键,所有按键公共端接地,键盘扫描口为P0.7~P0.0,而且没有按键按下时为高电平,键盘扫描程序如下:unsigned char Trigger;unsigned char Continue;void delayms(unsigned char n){……}void key_scan(){unsigned char ReadData;if (P0!=0xff&&Trigger==0x00) delayms(20);ReadData = P0 ^ 0xff;Trigger = ReadDate & (ReadData ^ Continue);Continue = ReadData;}程序中的Trigger就是键值。
极其简单好用的按键扫描程序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. 软件扫描法:
- 工作原理:通过不断查询键盘状态来检测按键的按下和释放。
- 优点:编程相对简单,不需要了解具体的硬件细节,适用于大多数常见的应用。
- 缺点:可能会消耗一定的CPU 资源,因为需要不断地查询键盘状态。
这两种方法各有优缺点,需要根据具体的应用场景和需求来选择。
在现代编程中,通常使用操作系统提供的键盘事件处理机制,它会自动将按键事件通知给应用程序,从而简化了按键识别的过程。
单片机经典长短按程序
新型的按键扫描程序不过我在网上游逛了很久,也看过不少源程序了,没有发现这种按键处理办法的踪迹,所以,我将他共享出来,和广大同僚们共勉。
我非常坚信这种按键处理办法的便捷和高效,你可以移植到任何一种嵌入式处理器上面,因为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.容量触摸法除了物理按键,一些矩阵式键盘还具有触摸功能。
这种键盘使用触摸传感器来检测手指触摸的位置,以实现按键的识别。
具体操作步骤如下:-键盘上的每个按键都带有一个触摸传感器。
-当手指触摸一些按键时,触摸传感器会检测到电容的变化。
-根据电容的变化,我们可以确定手指触摸的位置,从而确定按下的按键以及对应的键值。
总结起来,矩阵式键盘的按键识别方法可以通过矩阵扫描法、矩阵编码法和容量触摸法来实现。
无论采用哪种方法,都需要通过适当的硬件和软件设计来实现按键的检测和识别。
这些方法的选择通常取决于键盘的设计要求和成本限制。
矩阵键盘的三种扫描方法
矩阵键盘的三种扫描方法矩阵键盘是一种常见的输入设备,它由多个按键组成,并通过矩阵扫描的方式来检测用户的按键输入。
矩阵键盘的扫描方法可以分为三种:行扫描、列扫描和交错扫描。
下面将详细介绍这三种扫描方法。
1.行扫描行扫描是最简单的一种扫描方法。
它的原理是将矩阵键盘的每一行连接到一个IO口,通过轮询检测每一行的电平变化来获取用户的按键输入。
行扫描的工作流程如下:1)将矩阵键盘的每一行连接到一个IO口,并设置为输入模式。
2)逐个地将每一行的IO口设置为高电平,并检测列的电平状态。
3)如果其中一列的电平为低电平,说明该列有按键按下。
此时,记录下这个按键的位置(行号和列号)以及按键的值(键码或字符),然后将这个按键的位置和值传递给上层应用或处理器。
4)将当前行的IO口设置为低电平,然后继续下一行的检测,重复2)~3)步骤,直到所有行都被检测完毕。
行扫描的优点是实现简单,只需要一个IO口来检测按键的状态。
但是它的缺点是扫描速度较慢,因为需要逐个地检测每一行。
2.列扫描列扫描是一种比较常用的扫描方法。
它的原理是将矩阵键盘的每一列连接到一个IO口,通过轮询检测每一列的电平变化来获取用户的按键输入。
列扫描的工作流程如下:1)将矩阵键盘的每一列连接到一个IO口,并设置为输入模式。
2)逐个地将每一列的IO口设置为高电平,并检测行的电平状态。
3)如果其中一行的电平为低电平,说明该行有按键按下。
此时,记录下这个按键的位置(行号和列号)以及按键的值(键码或字符),然后将这个按键的位置和值传递给上层应用或处理器。
4)将当前列的IO口设置为低电平,然后继续下一列的检测,重复2)~3)步骤,直到所有列都被检测完毕。
列扫描的优点是速度较快,因为只需要逐个地检测每一列。
但是它的缺点是需要多个IO口来检测按键的状态。
3.交错扫描交错扫描是一种综合了行扫描和列扫描的扫描方法,它可以有效地减少扫描的时间。
交错扫描的原理是将矩阵键盘的行和列交错地连接到多个IO口,通过并行检测行和列的电平变化来获取用户的按键输入。
经典的矩阵键盘扫描程序
经典的矩阵键盘扫描程序矩阵键盘是一种常见的输入设备,广泛应用于电子产品中。
为了实现对矩阵键盘的扫描和输入响应,需要编写一个矩阵键盘扫描程序。
本文将详细介绍如何编写一个经典的矩阵键盘扫描程序。
1. 程序功能描述矩阵键盘扫描程序的主要功能是实现对矩阵键盘的扫描,并根据按键的状态进行相应的处理。
程序需要实现以下功能:- 扫描矩阵键盘的按键状态;- 根据按键状态进行相应的处理;- 输出按键的值或执行相应的操作。
2. 程序设计思路矩阵键盘通常由多行多列的按键组成,每个按键都有一个唯一的行列地址。
程序的设计思路如下:- 初始化矩阵键盘的引脚和状态变量;- 循环扫描矩阵键盘的按键状态;- 检测按键状态变化,并根据变化进行相应的处理;- 输出按键的值或执行相应的操作。
3. 程序代码示例下面是一个简单的矩阵键盘扫描程序的代码示例:```#include <stdio.h>#include <stdbool.h>// 定义矩阵键盘的行列数#define ROWS 4#define COLS 4// 定义矩阵键盘的引脚int rowPins[ROWS] = {2, 3, 4, 5}; int colPins[COLS] = {6, 7, 8, 9}; // 定义矩阵键盘的按键值char keys[ROWS][COLS] = {{'1', '2', '3', 'A'},{'4', '5', '6', 'B'},{'7', '8', '9', 'C'},{'*', '0', '#', 'D'}};// 初始化矩阵键盘void setup() {// 设置引脚模式为输入for (int i = 0; i < ROWS; i++) { pinMode(rowPins[i], INPUT); }// 设置引脚模式为输出for (int i = 0; i < COLS; i++) {pinMode(colPins[i], OUTPUT);}}// 扫描矩阵键盘void scanKeypad() {for (int i = 0; i < COLS; i++) {// 将当前列引脚设置为高电平digitalWrite(colPins[i], HIGH);for (int j = 0; j < ROWS; j++) {// 检测当前行引脚的状态bool state = digitalRead(rowPins[j]); // 如果按键状态发生变化if (state != lastState[i][j]) {// 更新按键状态lastState[i][j] = state;// 如果按键被按下if (state == LOW) {// 输出按键的值Serial.println(keys[j][i]);// 执行相应的操作switch (keys[j][i]) {case '1':// 执行操作1break;case '2':// 执行操作2break;// 其他按键的操作}}}}// 将当前列引脚设置为低电平 digitalWrite(colPins[i], LOW); }}void loop() {// 扫描矩阵键盘scanKeypad();// 延时一段时间,避免频繁扫描delay(10);}```4. 程序运行结果编写完成矩阵键盘扫描程序后,可以将程序上传到相应的开发板或单片机上进行测试。
反转法键盘扫描原理
反转法键盘扫描原理
标题:反转法键盘扫描原理
引言概述:
反转法键盘扫描原理是一种常用的键盘输入检测方法,通过利用键盘矩阵的特性,实现对按键的扫描和识别。
本文将从五个大点来详细阐述反转法键盘扫描原理,包括键盘矩阵的构成、按键扫描的流程、按键状态的判断、消除按键冲突的方法以及常见的应用场景。
正文内容:
1. 键盘矩阵的构成
1.1 键盘矩阵的基本概念
1.2 键盘矩阵的物理结构
1.3 键盘矩阵的电气结构
2. 按键扫描的流程
2.1 初始化键盘矩阵
2.2 逐行扫描键盘矩阵
2.3 判断按键状态
2.4 输出按键值
3. 按键状态的判断
3.1 按键按下的检测
3.2 按键释放的检测
3.3 按键状态的保存与更新
4. 消除按键冲突的方法
4.1 基于时间分片的消除方法
4.2 基于硬件编码的消除方法
4.3 基于软件算法的消除方法
5. 常见的应用场景
5.1 电脑键盘
5.2 手机触摸屏键盘
5.3 数字键盘
5.4 游戏手柄
总结:
通过本文的阐述,我们了解了反转法键盘扫描原理的基本概念和工作原理。
键盘矩阵的构成、按键扫描的流程、按键状态的判断、消除按键冲突的方法以及常见的应用场景都被详细介绍。
反转法键盘扫描原理在各种输入设备中得到广泛应用,为我们提供了高效、准确的输入方式。
在今后的技术发展中,我们可以进一步优化反转法键盘扫描原理,提升输入设备的性能和用户体验。
堪称一绝的键盘扫描方法
堪称一绝的键盘扫描方法
键盘扫描是计算机视觉系统中经常使用的一种技术,它的作用是检测
用户输入的键盘输入,从而实现用户与计算机的交互。
目前,键盘扫描技
术有许多种形式,它们的特点是方式不同,用于输入控制信息的类型也不同。
其中最为出色的键盘扫描方法之一就是时序扫描。
时序扫描是一种用以检测用户输入的键盘扫描方法,它具有以下特点:
1、可以识别出按下的每个按钮:通过识别连接在芯片上的每一排的
按钮,可以检测到按下的每一个按钮,并能够识别出其它按键的状态;
2、具有低成本:时序扫描不需要复杂而昂贵的硬件,也不需要任何
软件,只要在芯片上使用一些简单的电路就可以实现;
3、可用于多行键盘:时序扫描可以非常方便地支持多行键盘,而且
用户还可以使用灯光状态监视器来指示按键状态。
4、具有高可靠性:在使用时序扫描技术进行键盘扫描时,用户可以
忽略硬件布线和失效的可能性,这是其他技术无法实现的;
5、可以使用多种程序进行实现:时序扫描可以使用不同的芯片、不
同的程序,以及不同的键盘应用来实现控制;
6、可以在低压下工作:时序扫描可以在低电压和低功耗的情况下工作,具有非常好的电气性能。
单片机按键扫描原理
单片机按键扫描原理一、引言单片机按键扫描是嵌入式系统中常见的功能,其主要作用是检测按键输入并进行相应处理。
本文将从硬件和软件两个方面详细介绍单片机按键扫描的原理。
二、硬件原理1. 按键电路按键电路是单片机按键扫描的基础,其主要由按键、上拉电阻和接线组成。
其中,按键是一个开关元件,上拉电阻则用于保持输入引脚的高电平状态,避免因为按键未被按下而导致输入引脚处于低电平状态。
2. 输入引脚输入引脚是单片机检测外部信号的接口,其主要作用是将外部信号转换为数字信号供单片机内部使用。
在单片机中,每个输入引脚都有一个对应的寄存器位来存储该引脚的状态。
3. 外部中断外部中断是一种特殊类型的中断,在单片机中通常用于检测外部事件。
当外部事件发生时,单片机会立即停止当前任务并转而执行外部中断服务程序。
4. 定时器定时器可以在固定时间间隔内产生一个定时中断,并执行相应的服务程序。
在单片机按键扫描中,定时器可以用于检测按键是否被长按。
三、软件原理1. 软件扫描软件扫描是一种简单的按键检测方法,其主要思路是通过循环不断地读取每个输入引脚的状态,并判断是否有按键被按下。
这种方法简单易懂,但效率较低,容易导致系统响应速度慢。
2. 硬件扫描硬件扫描是一种高效的按键检测方法,其主要思路是通过将多个按键连接到同一个输入引脚上,并使用矩阵式接线方式来进行扫描。
这种方法可以大大提高系统响应速度和效率。
3. 中断服务程序中断服务程序是一种特殊的程序,在单片机中通常用于处理中断事件。
在单片机按键扫描中,可以通过外部中断和定时器中断来实现相应的功能。
四、总结单片机按键扫描是嵌入式系统中常见的功能之一,其主要作用是检测按键输入并进行相应处理。
在硬件方面,需要使用合适的电路和接线方式来实现按键检测;在软件方面,则需要根据实际需求选择合适的扫描方法和中断服务程序。
综合来看,单片机按键扫描需要硬件和软件两个方面的配合,才能实现稳定、高效的功能。
经典按键扫描程序
经典按键扫描程序核心算法: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为全局变量,其它程序可以直接引用。
3:算法2,用来计算连续变量。
看到这里,有种“知其然,不知其所以然”的感觉吧?代码很简单,但是它到底是怎么样实现我们的目的的呢?好,下面就让我们绕开云雾看青天吧。
我们最常用的按键接法如下:AVR是有内部上拉功能的,但是为了说明问题,我是特意用外部上拉电阻。
那么,按键没有按下的时候,读端口数据为1,如果按键按下,那么端口读到0。
下面就看看具体几种情况之下,这算法是怎么一回事。
(1)没有按键的时候端口为0xff,ReadData读端口并且取反,很显然,就是0x00了。
Trg = ReadData & (ReadData ^ Cont); (初始状态下,Cont也是为0的)很简单的数学计算,因为ReadData为0,则它和任何数“相与”,结果也是为0的。
Cont = ReadData;保存Cont其实就是等于ReadData,为0;结果就是:ReadData=0;Trg=0;Cont=0;(2)第一次PB0按下的情况端口数据为0xfe,ReadData读端口并且取反,很显然,就是0x01了。
经典的矩阵键盘扫描程序
键盘是单片机常用输入设备,在按键数量较多时,为了节省I/O口等单片机资源,一般采取扫描的方式来识别到底是哪一个键被按下。
即通过确定被按下的键处在哪一行哪一列来确定该键的位置,获取键值以启动相应的功能程序。
4*4矩阵键盘的结构如图1(实物参考见万用板矩阵键盘制作技巧)。
在本例中,矩阵键盘的四列依次接到单片机的P1.0~P1.3,四行依次接到单片机的P1.4~P1.7;同时,将列线上拉,通过10K电阻接电源。
查找哪个按键被按下的方法为:一个一个地查找。
先第一行输出0,检查列线是否非全高;否则第二行输出0,检查列线是否非全高;否则第三行输出0,检查列线是否非全高;如果某行输出0时,查到列线非全高,则该行有按键按下;根据第几行线输出0与第几列线读入为0,即可判断在具体什么位置的按键按下。
下面是具体程序:1 / 2void Check_Key(void){unsigned char row,col,tmp1,tmp2;tmp1 = 0x10; //tmp1用来设置P1口的输出,取反后使P1.4~P1.7中有一个为0for(row=0;row<4;row++) // 行检测{P1 = 0x0f; // 先将p1.4~P1.7置高P1 =~tmp1; // 使P1.4~p1.7中有一个为0tmp1*=2; // tmp1左移一位if ((P1 & 0x0f) < 0x0f) // 检测P1.0~P1.3中是否有一位为0,只要有,则说明此行有键按下,进入列检测{tmp2 = 0x01; // tmp2用于检测出哪一列为0for(col =0;col<4;col++) // 列检测{if((P1 & tmp2)==0x00) // 该列如果为低电平则可以判定为该列{key_val =key_Map[ row*4 +col ]; // 获取键值,识别按键;key_Map为按键的定义表return; // 退出循环}tmp2*=2; // tmp2左移一位}}}} //结束这是一种比较经典的矩阵键盘识别方法,实现起来较为简单,程序短小精炼。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
PDF 文件使用 "pdfFactory Pro" 试用版本创建
PDF 文件使用 "pdfFactory Pro" 试用版本创建
大家以前是怎么做的呢?对比一下看谁的方便? #define KEY_BEEP 0x01 void KeyProc(void) { if (Trg & KEY_BEEP) // 如果按下的是 KEY_BEEP { Beep(); // 执行蜂鸣器处理函数 } } 怎么样?够和谐不?记得前面解释说 Trg 的精粹是什么?精粹就是只会出现一 次。所以你按下按键的话,Trg & KEY_BEEP 为“真”的情况只会出现一次,所 以处理起来非常的方便,蜂鸣器也不会没事乱叫,hoho~~~或者你会认为这 个处理简单,没有问题,我们继续。 应用 2:长按键的处理 项目中经常会遇到一些要求,例如:一个按键如果短按一下执行功能 A,如果长 按 2 秒不放的话会执行功能 B, 又或者是要求 3 秒按着不放, 计数连加什么什么 的功能,很实际。不知道大家以前是怎么做的呢?我承认以前做的很郁闷。但是 看我们这里怎么处理吧,或许你会大吃一惊,原来程序可以这么简单,这里举个 简单例子,为了只是说明原理,PB0 是模式按键,短按则切换模式,PB1 就是 加,如果长按的话则连加(玩过电子表吧?没错,就是那个!) #define KEY_MODE 0x01 // 模式按键 #define KEY_PLUS 0x02 // 加 void KeyProc(void) { if (Trg & KEY_MODE) // 如果按下的是 KEY_MODE, 而且你常按这按键也 没有用, { //它是不会执行第二次的哦 , 必须先松开再按下 Mode++; // 模式寄存器加 1,当然,这里只是演示,你可以执行你想 // 执行的任何代码 } if (Cont & KEY_PLUS) // 如果“加”按键被按着不放 { cnt_plus++; // 计时 if (cnt_plus > 100) // 20ms*100 = 2S 如果时间到 { Func(); // 你需要的执行的程序 } } } 不知道各位感觉如何?我觉得还是挺简单的完成了任务, 当然, 作为演示用代码。
PDF 文件使用 "pdfFactory Pro" 试用版本创建
if (Intrcnt>20) // 一直在等,直到 20ms 时间到 { Intrcnt="0"; break; // 返回主循环 } } } } 貌似扯远了,回到我们刚才的问题,也就是怎么做按键消抖处理。我们将读按键 的程序放在了主循环,也就是说,每 20ms 我们会执行一次 KeyRead()函数来得 到新的 Trg 和 Cont 值。好了,下面是我的消抖部分,很简单,基本架构如上,我 自己比较喜欢的, 一直在用。 当然, 和这个配合, 每个子程序必须执行时间不长, 更加不能死循环,一般采用有限状态机的办法来实现,具体参考其它资料咯。 懂得基本原理之后, 至于怎么用就大家慢慢思考了,我想也难不到聪明的工程师 们。例如还有一些处理,怎么判断按键释放?很简单,Trg 和 Cont 都为 0 则肯 定已经释放了。在这个基础上再增加一个按键释放检测功能,程序如下: volatile unsigned char Trg; volatile unsigned char Cont; volatile unsigned char Release; // 再增加新功能! void KeyRead( void ) { unsigned char ReadData = PINB^0xff; // 1 读键值 Trg = ReadData & (ReadData ^ Cont); // 2 得到按下触发值 Release= (ReadData ^ Trg ^ Cont); // 3 得到释放触发值 Cont = ReadData; // 4 得到所有未释放的键值 }
PDF 文件使用 "pdfFactory Pro" 试用版本创建
应用 3:点触型按键和开关型按键的混合使用 点触形按键估计用的最多,特别是单片机。开关型其实也很常见,例如家里的电 灯,那些按下就不松开,除非关。这是两种按键形式的处理原理也没啥特别,但 是你有没有想过, 如果一个系统里面这两种按键是怎么处理的?我想起了我以前 的处理,分开两个非常类似的处理程序,现在看起来真的是笨的不行了,但是也 没有办法啊,结构决定了程序。不过现在好了,用上面介绍的办法,很轻松就可 以搞定。原理么?可能你也会想到,对于点触开关,按照上面的办法处理一次按 下和长按,对于开关型,我们只需要处理 Cont 就 OK 了,为什么?很简单嘛, 把它当成是一个长按键,这样就找到了共同点,屏蔽了所有的细节。程序就不给 了,完全就是应用 2 的内容,在这里提为了就是说明原理~~ 好了,这个好用的按键处理算是说完了。可能会有朋友会问,为什么不说延时消 抖问题?哈哈,被看穿了。果然不能偷懒。下面谈谈这个问题,顺便也就非常简 单的谈谈我自己用时间片轮办法,以及是如何消抖的。延时消抖的办法是非常传 统,也就是 第一次判断有按键,延时一定的时间(一般习惯是 20ms)再读端口, 如果两次读到的数据一样,说明了是真正的按键,而不是抖动,则进入按键处理 程序。 当然,不要跟我说你 delay(20)那样去死循环去,真是那样的话,我衷心的建议 你先放下手上所有的东西, 好好的去了解一下操作系统的分时工作原理,大概知 道思想就可以,不需要详细看原理,否则你永远逃不出“菜鸟”这个圈子。当然我 也是菜鸟。我的意思是,真正的单片机入门,是从学会处理多任务开始的,这个 也是学校程序跟公司程序的最大差别。当然,本文不是专门说这个的,所以也不 献丑了。 我的主程序架构是这样的: volatile unsigned char Intrcnt; void InterruptHandle() // 中断服务程序 { Intrcnt++; // 1ms 中断 1 次,可变 } void main(void) { SysInit(); while(1) // 每 20ms 执行一次大循环 { KeyRead(); // 将每个子程序都扫描一遍 KeyProc(); Func1(); Funt2(); … … while(1) {
PDF 文件使用 "pdfFactory Pro" 试用版本创建
Trg = 0x01;Trg 只会在这个时候对应位的值为 1,其它时候都为 0 Cont = 0x01; (3)PB0 按着不松(长按键)的情况 端口数据为 0xfe,ReadData 读端口并且取反是 0x01 了。 Trg = ReadData & (ReadData ^ Cont); 因为这是连续按下, 所以 Cont 是上 次的值,应为为 0x01。那么这个式子就变成了 Trg = 0x01 & (0x01^0x01) = 0x00 Cont = ReadData = 0x01; 结果就是: ReadData = 0x01; Trg = 0x00; Cont = 0x01; 因为现在按键是长按着,所以 MCU 会每个一定时间(20ms 左右)不断的执行这 个函数,那么下次执行的时候情况会是怎么样的呢? ReadData = 0x01;这个不会变,因为按键没有松开 Trg = ReadData & (ReadData ^ Cont) = 0x01 & (0x01 ^ 0x01) = 0 ,只要按键没有松开,这个 Trg 值永远为 0 !!! Cont = 0x01;只要按键没有松开,这个值永远是 0x01!! (4)按键松开的情况 端口数据为 0xff,ReadData 读端口并且取反是 0x00 了。 Trg = ReadData & (ReadData ^ Cont) = 0x00 & (0x00^0x01) = 0x00 Cont = ReadData = 0x00; 结果就是: ReadData = 0x00; Trg = 0x00; Cont = 0x00; 很显然,这个回到了初始状态,也就是没有按键按下的状态。 总结一下,不知道想懂了没有?其实很简单,答案如下: Trg 表示的就是触发的意思,也就是跳变,只要有按键按下(电平从 1 到 0 的跳 变),那么 Trg 在对应按键的位上面会置一,我们用了 PB0 则 Trg 的值为 0x01, 类似,如果我们 PB7 按下的话,Trg 的值就应该为 0x80 ,这个很好理解,还 有,最关键的地方,Trg 的值每次按下只会出现一次,然后立刻被清除,完全不 需要人工去干预。 所以按键功能处理程序不会重复执行,省下了一大堆的条件判 断,这个可是精粹哦!!Cont 代表的是长按键,如果 PB0 按着不放,那么 Con t 的值就为 0x01,相对应,PB7 按着不放,那么 Cont 的值应该为 0x80,同样 很好理解。 如果还是想不懂的话,可以自己演算一下那两个表达式,应该不难理解的。因为 有了这个支持,那么按键处理就变得很爽了,下面看应用: 应用一:一次触发的按键处理 假设 PB0 为蜂鸣器按键,按一下,蜂鸣器 beep 的响一声。这个很简单,但是