单片机一个按键的多次击键组合判别技巧
基于单片机的快速按键识别方法
基于单片机的快速按键识别方法基于单片机的快速按键识别方法快速按键识别技术是信息处理方面的一个重要领域,应用于各种设备与系统。
在现代电子产品中,按键控制是常用的操作方式之一。
而基于单片机的快速按键识别方法,是目前较为常见的实现方式之一。
一、快速按键识别原理快速按键识别是通过按键接通时,产生的电信号来判断你所按的按键类型及次数,进而执行对应的操作。
单片机通过外部中断或定时器来进行按键事件的处理和识别,实现快速的数据处理与反馈。
二、快速按键识别系统设计1.硬件设计硬件设计主要包括单片机、键盘、蜂鸣器和LED等模块。
其中,单片机为整个系统的核心部件,键盘是输入信号的来源,蜂鸣器是输出信号的反馈,LED则为系统的指示灯。
2.软件设计软件设计则需要通过编程实现按键事件的处理、识别及反馈,其中主要包括定时器、外部中断、键盘扫描和矩阵按键扫描等方式。
三、快速按键识别方法1.定时器扫描法通过定时器来设定扫描周期,通过中断来响应按下事件,实现按键的检测。
相比其他方法,定时器扫描法的扫描速度较快,适用于对响应速度有要求的场合。
2.(硬件)按键编码法每个按键使用一个编码计数器的,通过单片机译码器来解码,实现按键的响应。
这种方法根据不同的按键引脚电平来区分每个按键,适合于按键比较多的场合。
3.矩阵按键扫描法矩阵扫描是常用的键盘扫描方法,遵循矩阵思想,通过行列交叉检测来检测按键的按下,比较简单可靠,适合于按键数量较多的场合。
四、总结基于单片机的快速按键识别方法应用广泛,可以有效提高按键的响应速度和灵敏度,实现更加智能化的操作。
实现这种技术需要考虑系统的硬件和软件设计,但是相比其他识别方式,它更加高效和快速,更容易向各个方向进行扩展。
单片机按键单击双击长按功能实现
单片机按键单击双击长按功能实现在很多嵌入式系统中,都需要对按键进行检测和处理,以实现不同的功能。
常见的按键功能包括单击、双击和长按。
在这篇文章中,我们将介绍如何使用单片机实现这些按键功能。
首先,我们需要连接一个按键到单片机的I/O口。
按键通常是一个开关,有两个接触点。
当按键按下时,两个接触点会闭合,导致I/O口的电平发生变化。
我们可以利用这个变化来检测按键的状态。
为了实现按键功能,我们需要编写一段程序来监测按键的状态。
以下是一个简单的流程:1.初始化I/O口:将按键连接到I/O口上,并将I/O口设置为输入模式。
2.监测按键状态:定时读取I/O口的电平状态,以检测按键是否按下。
如果I/O口电平发生变化,则按键被按下或松开。
3.单击功能:当按键被按下时,记录当前时间,并等待一段时间,如果超过这段时间,说明按键已松开,则触发单击功能。
4.双击功能:如果在两次按键之间的时间间隔内再次检测到按键按下,则触发双击功能。
5.长按功能:当按键被按下一段较长的时间后,触发长按功能。
下面我们来具体介绍如何实现这些功能。
首先,我们需要初始化单片机的I/O口。
这个过程可以通过配置相应的寄存器实现。
具体的方法和步骤依赖于你使用的单片机型号和开发环境。
在这里,我们不具体展开,而是假设我们已经成功初始化了I/O口。
接下来,我们需要设置一个计时器用于定时检测按键的状态。
计时器的定时周期决定了我们可以检测的最短按键时间间隔。
通常,我们使用一个定时器来实现单击和双击功能,使用另一个定时器来检测长按功能。
一旦我们完成了计时器的配置,我们就可以开启定时器中断,并启动计时器。
每当定时器溢出时,中断函数会被触发,我们可以在这个函数中检测按键的状态。
在中断函数中,我们读取I/O口的电平状态,并根据当前的按键状态做出相应的处理。
首先,我们需要检测按键是否按下。
为了防止按键的抖动和误触发,我们使用一个状态机来确定按键的状态。
状态机的状态可以分为按下和松开两种。
占用较少的单片机IO口就能够实现较多的按键功能
本文介绍两种方法解决"如何占用较少的单片机I/O口就能够实现较多的按键功能?"
方法一:二进制编码法
这个方法我在好几个产品上都用过,适合需要的按键不是太多的情况下使用.如果单片机有n 个I/O口,那么在理论上就可以实现2n—1个按键, 下面的电路图是利用3个I/O口实现6个按键的功能,每个按键代表1个二进制编码,如[ENT]键的编码是[0 0 1],其他按键以此类推。
方法二:A/D值判断法
这个方法只占用单片机的1个A/D输入口,就可以实现较多的按键功能.通过采样A/D值的大小就可以判断是哪个按键被按下,缺点是当多个按键同时按下时,容易判断出错.
本文简单介绍“低边与高边电流检测”的主要区别。
图B低边电流检测方案简单而且便宜,一般的运放器都可以实现此功能。
但是很多应用无法接受检测电阻Rs引入的地线干扰问题,负载电流较大时更会加剧这个问题,因为系统中一部分电路的地电位由于低边检流电阻而产生偏移,而这部分电路可能与另一部分地电位没有改变的电路相互联系。
所以当需要大电流检测时,必须重视这个问题。
图A在负载的高端进行电流检测的简易电路,不仅消除了地线干扰,而且能够检测到短路故障,需要注意的是高边检测要求放大器能够处理接近电源电压的共模电压。
本文介绍无源滤波电路的频率计算公式
1. 常用的RC滤波电路
f 0 = 1/(2πRC)
例:R = 16K ,C =10nF
f 0 = 1/(2πRC) = 1/(2π×16×103×10×10-9 ) =1000Hz
2. LC滤波电路
下期介绍。
单片机按键处理方式(一)——典型的按键处理方式
单⽚机按键处理⽅式(⼀)——典型的按键处理⽅式前⾔ 按键处理是学习单⽚机的必修课之⼀。
⼀次按键的过程,并⾮是⼀个理想的有⼀定宽度的电平脉冲,⽽是在按下、弹起过程中存在抖动,只有在中间阶段电平信号是稳定的。
⼀次典型的按键过程是酱紫的: 在抖动过程中,电平信号⾼低反复变化,如果你的按键检测是检测下降沿或上升沿或者是⽤外部中断检测按键,都可能在抖动时重复检测到多次按键。
这就是在未消抖的按⼀次键显⽰值加1的程序中,出现按⼀次键显⽰值+2、+3甚⾄加更多的原因。
对于按键消抖,常⽤的有硬件消抖和软件消抖。
本⽂是我个⼈对按键处理的⼀些常见⽅法的总结,由于我本⼈不太懂硬件,所以这⾥只讨论独⽴按键的软件消抖实现。
⽔平有限,如有错误请不吝指正。
硬件环境 本⽂代码均在单⽚机STC90C516RD+、晶振12.0MHz硬件环境下试验通过。
带消抖的简单的按键处理 最简单的消抖处理就是在⾸次检测到电平变化后加⼀个延时,等待抖动停⽌后再次检测电平信号。
这也是⼤多数单⽚机教程讲述的消抖⽅式。
但在实际应⽤中基本不⽤这种⽅式,原因后⾯讲,先看代码://⽅法⼀:带消抖的简单的按键处理#include <reg52.h>#define GPIO_KEY P1 //8个独⽴按键IO⼝#define GPIO_LED P0 //8个LED灯,⽤于显⽰键值unsigned char ScanKey();void DelayXms(unsigned char x);void main(){unsigned char key;GPIO_LED = 0x00; //初始化LEDwhile (1){key = ScanKey(); //读取键值// if (0xff != key) //若有键按下,则更新LED的状态GPIO_LED = ~key; //点亮LED}}unsigned char ScanKey(){unsigned char keyValue = 0xff; //赋初值,0xff表⽰没有键按下GPIO_KEY = 0xff; //给按键IO⼝置位if (0xff != GPIO_KEY) //检查按键IO⼝的电平,如有键按下则不为0xff{DelayXms(15); //延时15ms,滤掉抖动。
单片机按键单击、双击、长按功能实现
单片机按键单击、双击、长按功能实现由于项目产品的需要,只能设置一个按键,但是需要实现短按(即单击)切换工作模式、长按开关机、双击暂停等复用功能。
下图是三种情况下的按键波形。
按键未按下时是高电平,按下去是低电平。
按键单击时,判断时间门槛设置为50~2000ms;长按门槛为持续按下2000ms。
双击可以视为时间间隔很短的俩次有效单击,从第一次单击上升沿到第二次单击上升沿延时门槛为100~500ms。
按键单击按键长按按键双击在STM8单片机上面实现代码为://按键按下去会出现下降沿,设置按键IO口GPIOB4所在的外部端口B下降沿触发中断void exit_init(void){EXTI_DeInit();EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOB,EXTI_SENSITIVITY_FALL_ONLY);}//按键按下中断服务程序INTERRUPT_HANDLER(EXTI_PORTB_IRQHandler, 4){if(GPIO_ReadInputPin(GPIOB,GPIO_PIN_4)==0)//是按键下降沿{key_fall_flag = 1;//生成按键按下标志}}//周期1ms的定时器中断服务程序INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23){if(key_fall_flag==1)//发生按键按下事件{if(GPIO_ReadInputPin(GPIOB,GPIO_PIN_4)==0)//按键持续按下{if(key_holdon_ms <= 2000){key_holdon_ms++;}else //按键按下到2000ms就判断长按时间成立,生成长按标志{key_holdon_ms = 0;short_key_flag=0;//清短按键标志key_long_down = 1;//长按键标志置位key_fall_flag = 0;//清按键按下标志}}else //按键抬起{if(key_holdon_ms>50)//按下时间大于50ms,生成单击标志{key_holdon_ms=0;short_key_flag=1;key_long_down =0;key_fall_flag=0;//距离上次单击时间在100~500ms之间,则认为发生连击事件if(keyupCnt>100 && keyupCnt<500){doubleClick = TRUE;short_key_flag=0;}keyUpFlag = TRUE;//单击抬起按键后,生成按键抬起标志}else //按键持续时间小于50ms,忽略{key_holdon_ms=0;short_key_flag=0;long_key_flag=0;key_fall_flag=0;}}}if(keyUpFlag)//单击抬起后,启动计数,计数到500ms keyupCnt++;if(keyupCnt>500){keyupCnt = 0;keyUpFlag = FALSE;}}。
基于单片机的快速按键识别方法
基于单片机的快速按键识别方法摘要:在使用单片机实现的智能控制系统中,快速、可靠的按键识别控制非常关键,一定程度上决定了整个系统的高效运行。
本文在分析传统的按键扫描或识别方法的基础上,对比各种方法的优缺点,重点讨论一种高效的按键识别方法,并给出该方法对应的程序设计思路,它可快速识别对按键的一次响应,解决多次冗余响应的缺陷。
关键词:单片机按键识别一次响应中图分类号:tp368.12 文献标识码:a 文章编号:1007-9416(2012)08-0175-021、引言在以单片机为核心控制的应用系统中,键盘按键能实现向单片机输入数据、传送命令等功能,是单片机应用系统中人工干预单片机的主要手段。
而单片机对按键闭合与否的判断,主要是通过其引脚上的电压高低进行的。
本文以51单片机为例说明,所述键盘按键的硬件电路设计也非常简单——轻触开关的一端接地,另一端连接单片机引脚,该引脚同时接10k上拉电阻[1]。
很明显,单片机引脚呈现高电平表示按键开关断开;反之,引脚电压呈现低电平表示按键开关闭合。
因此,对单片机的按键识别只要通过对其引脚电平的高低状态的检测,即可确认按键按下与否[2]。
众所周知,按键为机械弹性开关,加之按键按下或抬起瞬间均会产生抖动现象,因此消除按键抖动也是整个系统的关键。
为更突出本文的讨论重点,这里不再重点讨论按键去抖的方法。
2、传统按键识别方法2.1 简单的按键识别该按键识别方法虽然简单,但当按下按键的瞬间,却可能让系统多次循环处理同一按键事件,造成cpu资源的浪费。
以下为该方法的程序设计思路,下述中的“按键确实按下”表示延迟10ms后,按键仍处于按下状态。
(1)初始化按键;(2)if(按下按键){延迟10ms去抖;if(按键确实按下){事件处理,退出}}else {未按按键,退出}单片机程序可能是一个循环执行的过程,当按键按下闭合,程序进入按键事件,执行完该事件,若按键仍未被抬起,则程序循环又再一次进入同样的按键事件执行。
单片机按键识别篇---单击---双击----长按
单⽚机按键识别篇---单击---双击----长按 最近做⼀任务需要使⽤⼀个按键实现三种功能,分别是按键单击功能,按键双击功能和按键长按功能,可能之前没有接触过这类按键复⽤情况,顶多也只是简单识别单击和长按,没有想过双击以上按键功能,也是绞尽脑汁,想了半天,⼜上⽹看了些例程,算是对于按键的识别有点⼩⼩的了解,感觉这个功能挺实⽤,在此做个随笔。
⼀、思路 1.识别长按操作思路:我们使⽤系统定时器定时,然后让系统每过⼀段时间去扫描按键I/O⼝状态,当扫描到按键按下I/O⼝状态超过设定长按时间的阀值,就判定这次按键操作为“长按”操作; 2.识别单击操作思路:当系统扫描按键按下的I/O⼝时间⼩于我们设定的长按阀值,这时就可能出现两种情况,情况1.可能是单击;情况2.可能是双击;⾸先我们来说情况1,单击操作,这时我们可以检测按键按下后,按键弹起的时间到下次按键按下的时间间隔,当按键按下弹起到下次按键按下的时间超过某个值,则我们判定这次操作为“单击”操作; 3.识别双击操作思路:上⾯刚说的情况1,这次来说情况2,:双击操作,当我们检测按键按弹起后在⼀定时间阀值内,⼜检测到按键I/O⼝有电平变化,则我们判断这次操作为“双击”操作⼆、程序部分unsigned char scan_key(){/*值key_return如下:1---------单击2---------双击3---------长按*/static unsigned char key_state=0; //按键状态static unsigned char state=0;static unsigned char time,time1,time2;static unsigned char key_up_flag=0; //按键弹起标志位static unsigned char key_return;if(Key==0) //按键按下消抖{delay(50);if(Key==0){key_state=0;}}else{delay(50); //按键松开消抖if(Key==1){key_state=1;key_up_flag=0;}}if((state==0)&&(key_state==0)&&(key_up_flag==0)) //这⾥主要防⽌,按键在识别长按后,⼜会执⾏⼀遍单击操作{state=1;time=key_time; //记录按键按下的时间为多少,做标记}if(state==1){time1=key_time;time2=time1-time; //计算按键按下时长if(time2>50) //长按判断{state=2;}if(key_state==1) //按键弹起{state=3;time=key_time; //标志什么时间按键弹起的}}if(state==2) //长按{state=0; //重置状态key_up_flag=1;key_return=3;}if((state==3)&&(key_up_flag==0)){time1=key_time;time2=time1-time; //计算按键弹起后时间if(time2>6) //判断按键弹起后的时间,超过300ms,则说明为单击 {state=0;key_return=1;}else if(key_state==0) //按键弹起后,300ms内⼜有按键按下{state=4;}}if(state==4){if(key_state==1) //按键弹起{state=0;key_return=2;}}return key_return;}void timer0() interrupt 1//定时器T0中断函数⼊⼝{TH0=0X9E; //初值重载TL0=0X57; //定时50ms=50000us; 50000/2=25000key_time++; //50MS++}。
简谈单片机检测按键原理和中断按键检测的办法
简谈单片机检测按键原理和中断按键检测的办法单片机检测按键原理首先说一下独立键盘检测,在单片机外围电路中,通常用到的按键都是机械弹性开关,当开关闭合时,线路导通,开关断开时,线路断开。
单片机检测按键的原理:按键的一端接地,另一端与单片机的某个I/O口相连,开始先给I/O赋一高电平,然后让单片机不断检测该I/O口是否变为低电平,当按键闭合时,相当于I/O口与地相连,就会变为低电平。
在单片机检测按键是否被按下时,电压的实际波形与理想波形时有一点=定差别的,波形在按下和释放瞬间都有抖动现象,抖动时间的长短和按键的机械特性有关。
所以单片机在检测键盘是否被按下都要加上去抖操作,所以在编写单片机的键盘检测程序时,一般在检测按下时加入去抖延时。
独立键盘与单片机连接时每一个按键都需要一个I/O口,会过多占用I/O口资源。
所以就引出了矩阵键盘。
矩阵键盘的连接方式,每一行将每个按键的一端连接在一起构成行线,每一列将按键的另一端连接在一起构成列线。
这样的话,16个按键排成4行4列就只要8根线。
它的按键检测,简单点说,就是先送一列低电平,其余均为高电平,然后轮流检测,确认行列。
这里就要提到另外一个东西,switch-case语句又称开关语句,它是一个专门用于处理多分支结构的条件选择语句。
使用switch语句可直接处理多个分支。
按键检测是初学单片机的同学玩的前几个例程,按键的种类有许多(普通按钮,矩阵键盘等等),按键检测的方法也有许多。
对于普通按钮当然你会说设计一个外围电路通过GPIO 口读一下还不简单,或许你说通过外部中断做边沿检测,对于矩阵键盘来说,往往你会通过行列分别扫描的方法做按键检测,通常我们会加一个按键防抖(经典的方法是通过延时二次确认的方法进行按键防抖,还有就是按键释放的时候你可能会通过while语句去防抖,也就是按键如果一直按下,让程序一直死在while里),这些都是初学者常用的方法,但是如果是一个大的程序,往往是不允许你有这么多延时和死循环的。
单个按键多次击键的检测方法
宝箱》。
网址: 《匠人手记》之十二单个按键多次击键的检测方法作者:程序匠人 出处:《匠人的百宝箱》1.前言匠人早年曾经写过一篇关于单个按键多次击键的检测方法。
现抽空重新整理一下。
(这“重新整理”的另一种说法就是“炒冷饭”,呵呵)在某些设计中,我们可能要用一个按键来输入多种信息。
如:单击/双击/三击、短击/长击、还有各种组合击键方式。
为了实现这种需要,匠人设计了这个读键子程序。
本文的正式发布版本为PDF格式,欢迎转载。
匠人唯一的要求是,转载者不可对文件中的任何内容(包括作者和出处信息)进行修改。
转载者有义务保证此文档的完整性。
2.设计思路在这个读键子程序中,定义了三个常数。
1)长击时间常数=500ms用于识别短击/长击。
如果按键闭合时间<500ms,判断为一次短击(用“0”代表);如果按键闭合时间>500ms,判断为一次长击(用“1”代表)。
2)两次击键时间间隔常数=700ms用于判别击键动作是否完成。
两次击键时间间隔应<700ms,如果按键释放后700ms内无键按下,则结束读键。
3)最多击键次数(ZHBIT)本程序可以识别的击键次数为1~7次。
由于每次击键都可以是短击或长击,所以最多可以识别254种组合。
但并非每个程序中用得上这么多次击键。
在大多数程序中,能判断双击即可以了,这时可将程序中的ZHBIT常数定义为2。
同理,如果要判断3次按键,将ZHBIT 常数定义为3即可。
当ZHBIT=1时,程序仅能识别1次击键,那么就有2种不同的组合:短击、长击 当ZHBIT=2时,程序还能识别最多2次击键,那么就有6(2+4)种不同的组合:短击、长击、短击+短击、短击+长击、长击+短击、长击+长击宝箱》。
网址:当ZHBIT=3时,程序能识别最多3次击键,包括14(2+4+8)种组合。
以此类推,就可以得到以下这张表格:最多击键次数(ZHBIT)组合种类1 22 2+4=63 2+4+8=144 2+4+8+16=305 2+4+8+16+32=626 2+4+8+16+32+64=1267 2+4+8+16+32+64+128=254通过上面的表格,我们可以看到,这个子程序的潜力巨大,最多可以识别254种击键组合序列。
单片机一键多功能按键识别设计
安徽电子信息职业技术学院《单片机应用技术》课程设计报告书题目:一键多功能按键识别设计姓名:xxx专业:电子信息工程技术班级:电信097学号:090301704设计成绩:指导教师:李炎设计完成日期2010年12月26日前言单片机的应用介绍单片机具有体积小、可靠性高、功能强、灵活方便等许多优点,广泛应用于国民经济的各个领域。
智能仪器的应用单片机用于各种仪器仪表,是仪器仪表智能化,可以提高测量的自动化程度和精度;简化仪器仪表的硬件结构,减小体积,提高其性价比。
例如:温度智能控制仪表、医用仪表、数字示波器等。
通信设备的应用单片机与通信技术相结合促使通信设备的智能控制水平大大提高,广泛应用于通信的各个领域。
例如:调制解调器、传真机、复印机、打印机、移动电话、固定电话机等。
(3)家用电器的应用传统的家电配上单片机以后,提高了智能化程度,增加了功能,倍受人们的喜爱;单片机使人类生活更加方便、舒适、丰富多彩。
例如:洗衣机、电冰箱、电子玩具、收录机、微波炉、电视机、录像机、音响设备、程控玩具、游戏机等。
工业控制的应用机电一体化是机械工业发展的方向。
机电一体化产品是集机械技术、微电子技术、计算机技术于一体,具有智能化特征的机电产品,例如微机控制的车床、钻床等。
单片机广泛用于导弹的导航装置、飞机上各种仪表的控制、计算机的网络通信与数据传输、机器人、工业自动化过程的实时控制和数据处理。
在比较复杂的系统中,常采用分布式多机系统。
多机系统一般由若干功能各异的单片机组成,各自完成特定的任务,它们通过串行通信相互联系。
协调工作。
单片机的高可靠性和强抗干扰能力,使它可以置于恶劣课程设计的目的和意义1、目的:(1)掌握单片机中有关指令的使用方法。
(2)掌握循环程序的设计方法。
(3)掌握子程序的应用方法。
(4)掌握延时时间的计算、应用。
课题设计意义计算机与计算机或计算机与终端之间的数据传送可以采用串行通讯和并行通讯二种方式。
由于串行通讯方式具有使用线路少、成本低,特别是在远程传输时,避免了多条线路特性的不一致而被广泛采用。
按键操作的识别
按键是电子产品中常见的一个小部件,它的电路很简单,如下图
按键信号接到单片机一个IO,并且打开内部上拉,这样空闲时按键信号是高电平,按下时按键信号是低电平。
一个按键常用的事件有:按下、弹起、单击、长按、双击、多次连击等。
如何识别出这些动作呢?下面给大家分享下
当按键按下时,我们记录按下的时间T0;当按键弹起时,记录弹起的时间T1.
单击:按下后保持较短时间就松开了,按键按下的时间小于一定值,比如0.5秒,也就是T1-T0小于0.5秒。
长按:从按下的那一刻,开始计时,当持续按下状态的时间超过一定值时,判定为长按。
双击和多次连击:
连击的定义:约束上一次按键弹起到本次按下的时间间隔,如果过长,则认为连击终止。
如上图,假如我们定义连击的间隔时间不超过0.5秒,那么T2-T1<0.5秒时,两次单击就可以判定为双击,多次连击是同样地。
搭建个简单的测试电路(按键信号接到P04,内部上拉)
软件实现:
按下时间不超过0.5秒为一次点击,按下时间超过1秒为长按,两次相邻的点击间隔不超过0.5秒为连击。
根据这个规则识别出按键的动作。
独立按键连按和长按处理技巧
单片机按键处理技巧及编程方式2010-10-23 15:01从这一章开始,我们步入按键程序设计的殿堂。
在基于单片机为核心构成的应用系统中,用户输入是必不可少的一部分。
输入可以分很多种情况,譬如有的系统支持PS2键盘的接口,有的系统输入是基于编码器,有的系统输入是基于串口或者USB或者其它输入通道等等。
在各种输入途径中,更常见的是,基于单个按键或者由单个键盘按照一定排列构成的矩阵键盘(行列键盘)。
我们这一篇章主要讨论的对象就是基于单个按键的程序设计,以及矩阵键盘的程序编写。
◎按键检测的原理常见的独立按键的外观如下,相信大家并不陌生,各种常见的开发板学习板上随处可以看到他们的身影。
(原文件名:1.jpg)引用图片总共有四个引脚,一般情况下,处于同一边的两个引脚内部是连接在一起的,如何分辨两个引脚是否处在同一边呢?可以将按键翻转过来,处于同一边的两个引脚,有一条突起的线将他们连接一起,以标示它们俩是相连的。
如果无法观察得到,用数字万用表的二极管挡位检测一下即可。
搞清楚这点非常重要,对于我们画PCB的时候的封装很有益。
它们和我们的单片机系统的I/O口连接一般如下:(原文件名:2.jpg)引用图片对于单片机I/O内部有上拉电阻的微控制器而言,还可以省掉外部的那个上拉电阻。
简单分析一下按键检测的原理。
当按键没有按下的时候,单片机I/O通过上拉电阻R接到VCC,我们在程序中读取该I/O的电平的时候,其值为1(高电平); 当按键S按下的时候,该I/O被短接到GND,在程序中读取该I/O 的电平的时候,其值为0(低电平) 。
这样,按键的按下与否,就和与该按键相连的I/O的电平的变化相对应起来。
结论:我们在程序中通过检测到该I/O口电平的变化与否,即可以知道按键是否被按下,从而做出相应的响应。
一切看起来很美好,是这样的吗?◎现实并非理想在我们通过上面的按键检测原理得出上述的结论的时候,其实忽略了一个重要的问题,那就是现实中按键按下时候的电平变化状态。
单片机一键多功能按键识别技术
单片机一键多功能按键识别技术在一些单片机系统中,有时候需要采用一些一键多功能的技术,这里我给大家介绍一下。
开关SP1 接在P3.7/RD 管脚上,在AT89S51 单片机的P1 端口接有四个发光二极管,上电的时候,L1 接在P1.0 管脚上的发光二极管在闪烁,当每一次按下开关SP1 的时候,L2 接在P1.1 管脚上的发光二极管在闪烁,再按下开关SP1 的时候,L3 接在P1.2 管脚上的发光二极管在闪烁,再按下开关SP1 的时候,L4 接在P1.3 管脚上的发光二极管在闪烁,再按下开关SP1 的时候,又轮到L1 在闪烁了,如此轮流下去。
这样就实现了具有一键多功能的按键识别技术。
简单吧单片机系统板上硬件连线把“单片机系统”区域中的P3.7/RD 端口连接到“独立式键盘”区域中的SP1 端口上把“单片机系统”区域中的P1.0-P1.4 端口用8 芯排线连接到“八路发光二极管指示模块”区域中的“L1-L8”端口上;要求,P1.0 连接到L1,P1.1 连接到L2,P1.2 连接到L3,P1.3 连接到L4 上。
具体的电路图在单片机论坛51hei51区上有。
欢迎发表您的高见。
本文为郭子喻先生原创作品希望大家支持。
汇编源程序ID EQU 30H SP1 BIT P3.7 L1 BIT P1.0 L2 BIT P1.1 L3 BIT P1.2 L4 BIT P1.3 ORG 0 MOV ID,#00H START: JB K1,REL LCALL DELAY10MS JB K1,REL INC ID MOV A,ID CJNE A,#04,REL MOV ID,#00H REL: JNB K1,$ MOV A,ID CJNE A,#00H,IS0 CPL L1 LCALL DELAY SJMP START IS0: CJNE A,#01H,IS1 CPL L2 LCALL DELAY SJMP START IS1: CJNE A,#02H,IS2 CPL L3 LCALL DELAY SJMP START IS2: CJNE A,#03H,IS3 CPL L4 LCALL DELAY SJMP START IS3: LJMP START DELAY10MS: MOV R6,#20 LOOP1: MOV R7,#248 DJNZ R7,$ DJNZ。
一种实用的单片机按键检测方式
一种实用的单片机按键检测方式《手把手教你学51单片机》第八课讲解按键相关内容的时候,介绍了一种状态检测扫描按键的办法,既可以检测按键,又可以有效消抖。
但是部分同学以前没有接触过类似的思想和方式,所以可能接受起来有点难度,这里我再详细给讲解分析一下,如果教程第八课你已经彻底明白,那么这里可以不用再学习了,如果还模模糊糊,可以再巩固一下。
1、独立按键常用的按键电路有两种形式,独立式按键和矩阵式按键,独立式按键比较简单,它们各自与独立的输入线相连接,如下图所示。
4条输入KeyIn1、KeyIn2、KeyIn3、KeyIn4接到单片机的IO口上,当按键K1按下时,+5V通过电阻R1然后再通过按键K1最终进入GND形成一条通路,那么这条线路的全部电压都加到了R1这个电阻上,KeyIn1这个引脚就和GND等电位,是个低电平。
当松开按键后,线路断开,就不会有电流通过,那么KeyIn1和+5V就应该是等电位,是一个高电平。
我们就可以读取通过KeyIn1这个IO口的高低电平来判断是否有按键按下,独立按键的原理还是很简单的。
2、矩阵按键在某一个系统设计中,如果需要使用很多的按键时,做成独立按键会大量占用IO口,因此我们引入了矩阵按键的设计方式,如下图所示,用了8个IO口实现了16个按键检测的电路。
上图,一共有4组按键,我们只看其中一组,如下图所示。
大家认真看一下,如果KeyOut1输出一个低电平,KeyOut1就相当于是GND,是否相当于4个独立按键呢。
当然这时候KeyOut2、KeyOut3、KeyOut4都必须输出高电平,它们都输出高电平才能保证与它们相连的三路按键不会对这一路产生干扰,大家可以对照两张原理图分析一下。
同理,可以将KeyOut1,KeyOut3,KeyOut4都拉高,把KeyOut2拉低,来读取KEY5到KEY8的值。
关于按键扫描的具体程序部分,大家可以去参考教程,我这里只把一段摘出来给大家讲一下,部分同学对其中一条语句有所疑问。
8051按键处理程序:单击、长按、连击、组合
最近参考大神的按键处理程序,写了下面这个程序,希望大家指点一下硬件为8051,采用8255扩展接口,功能上,实现单击K1、K2、K3分别使时、分、秒递增;长按K1、K2、K3分别使时、分、秒递减;K1、K2、K3连击使第二个横杠处变为0;组合键K1、K2使第一个横杠处变为0,组合键K2、K3使第一个横杠处变为横杠;组合键K1、K3使第二个横杠处变为横杠。
下图为proteus仿真电路完整程序如下://-----------------------------------------------------------------// 8255实现接口扩展//-----------------------------------------------------------------// PA、PB为输出分别控制段码和位码,PC为输入////-----------------------------------------------------------------#include <reg51.h>#include <absacc.h>#define INT8U unsigned char#define INT16U unsigned int//8255 PA、PB、PC的端口和命令端口定义#define PA XBYTE[0x0000]#define PB XBYTE[0x0001]#define PC XBYTE[0x0002]#define COM XBYTE[0x0003]//上述定义可以这么写//#define PA *(XBYTE + 0x0000)//#define PB *(XBYTE + 0x0001)//#define PC *(XBYTE + 0x0002)//#define COM *(XBYTE + 0x0003)//根据硬件定义按键值#define KEY_V ALUE_1 0x0e#define KEY_V ALUE_2 0x0d#define KEY_V ALUE_3 0x0b#define KEY_NULL 0x0f//按键状态标志#define N_KEY 0x80#define S_KEY 0x40#define D_KEY 0x20#define L_KEY 0x10//状态机状态#define KEY_STATE_INIT 0 //初始状态#define KEY_STATE_WOBBLE 1 //电平抖动状态#define KEY_STATE_PRESS 2 //按键按下状态#define KEY_STATE_CONTINUE 3 //连击状态#define KEY_STATE_LONG 4 //长按状态#define KEY_STATE_RELEASE 5 //释放按键状态INT8U key_JL; //存储单击按键值code INT8U SEG_CODE[] ={ 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xBF }; //共阳数码管编码,最后一位为横杠//初始显示的数字12-39-59INT8U Disp_Buf[] = {1,2,10,3,9,10,5,9};//-----------------------------------------------------------------// 8255端口按键处理//-----------------------------------------------------------------//按键底层处理,这里只识别单击和长按static INT8U Key_driver(){static INT8U key_time=0,key_state=KEY_STATE_INIT;INT8U key_temp,key_return=N_KEY;key_temp=PC&0x0f;switch(key_state){case KEY_STA TE_INIT:if(key_temp!=KEY_NULL) key_state=KEY_STATE_PRESS;break;// caseKEY_STA TE_WOBBLE://按键消抖处理,由于是仿真,为了加快按键灵敏度,减短延时时间// key_state=KEY_STA TE_PRESS;break;case KEY_STA TE_PRESS: //按键下,此处不返回值if(key_temp!=KEY_NULL) {key_state=KEY_STA TE_LONG; key_JL=key_temp;}else key_state=KEY_STA TE_INIT;break;case KEY_STA TE_LONG:if(key_temp==KEY_NULL) //单击确认{key_return=S_KEY|key_JL;key_state=KEY_STATE_INIT;}else if(++key_time>=100) //长按等待1s{key_return=L_KEY|key_temp; //返回长按值key_time=0;// key_state=KEY_STATE_RELEASE;key_state=KEY_STATE_INIT;}break;// case KEY_STA TE_RELEASE ://此处如果加上这段程序,长按不会不断递减// if(key_temp==KEY_NULL) key_state=KEY_STA TE_INIT;// break;}return key_return;}//按键处理中层按键判定单击、双击static INT8U Key_Read(){static INT8U key_time_1=0,key_m=KEY_STA TE_INIT;INT8U key_return=N_KEY,key_temp;key_temp=Key_driver();switch(key_m){case KEY_STA TE_INIT:if(key_temp&S_KEY){key_time_1=0;key_m=KEY_STA TE_CONTINUE;}elsekey_return=key_temp;break;case KEY_STA TE_CONTINUE:if(key_temp&S_KEY){key_return=key_temp|D_KEY;key_m=KEY_STATE_INIT;}else{if(++key_time_1>=30){key_return=key_JL|S_KEY;key_time_1=0;key_m=KEY_STA TE_INIT;}}break;}return key_return;}//按键处理顶层static void Key_Process(){INT8U key_temp;INT8U shi,fen,miao;key_temp=Key_Read();switch(key_temp){case 0x4e:shi=Disp_Buf[0]*10+Disp_Buf[1];shi++;if(shi==24) shi=0;Disp_Buf[0]=shi/10;Disp_Buf[1]=shi%10;break;case 0x1e:shi=Disp_Buf[0]*10+Disp_Buf[1];shi--;if(shi==255) shi=23;Disp_Buf[0]=shi/10;Disp_Buf[1]=shi%10;break;case 0x6e:Disp_Buf[5]=0x00; break;case 0x4d:fen=Disp_Buf[3]*10+Disp_Buf[4];fen++;if(fen==60) fen=0;Disp_Buf[3]=fen/10;Disp_Buf[4]=fen%10;break;case 0x1d:fen=Disp_Buf[3]*10+Disp_Buf[4];fen--;if(fen==255) fen=59;Disp_Buf[3]=fen/10;Disp_Buf[4]=fen%10;break;case 0x6d:Disp_Buf[5]=0x00; break;case 0x4b:miao=Disp_Buf[6]*10+Disp_Buf[7];miao++;if(miao==60) miao=0;Disp_Buf[6]=miao/10;Disp_Buf[7]=miao%10;break;case 0x1b:miao=Disp_Buf[6]*10+Disp_Buf[7];miao--;if(miao==255) miao=59;Disp_Buf[6]=miao/10;Disp_Buf[7]=miao%10;break;case 0x6b:Disp_Buf[5]=0x00; break;case 0x1c:Disp_Buf[2]=0x00;break;case 0x1a:Disp_Buf[5]=10; break;case 0x19:Disp_Buf[2]=10; break;default: break;}}INT8U time_scan=0;//-----------------------------------------------------------------// Ö÷³ÌÐò//-----------------------------------------------------------------void main(){INT8U i; //初始化定时中断TMOD=0x01; //定时器T0中断EA=1;ET0=1;TH0=(-1000)/256;TL0=(-1000)%256;TR0=1;COM=0x89; //初始化8255接口while(1){for(i=0;i<8;i++) //数码管显示{PA=0xff;PB=(1<<i);PA=SEG_CODE[Disp_Buf[i]];}if(time_scan==10) //每隔10ms进行一次扫描按键{Key_Process();time_scan=0;}}}//1ms定时中断void T0_time() interrupt 1{TH0=(65536-1000)/256;TL0=(65536-1000)%256;time_scan++;}。
单片机按键长短按得识别原理
单⽚机按键长短按得识别原理stm32f103按键长短按得识别原理需要⼀个定时器,⽤来计算按键按下的时间,可以⼀秒钟检测100次, 设置初始化为10ms的中断,⽐如使⽤定时4作为按键时间计算的定时器⽐如我们需要4种模式,轻触,短按,长按,超级长按#define clickTypeTouch 1 //轻触#define clickTypeShort 2 //短按#define clickTypeLong 3 //长按#define clickTypeVeryLong 4 //⾮常长的长按#define timeCntClickTouch 500 //ms内为短按#define timeCntClickShort 1000 //ms内为短按#define timeCntClickLong 2000//ms内,且⼤于短按时间为长按#define timeCntClickVeryLong 5000//ms的按键时间为⾮常长,⽤于进⼊⾼级模式//这⾥时钟选择为APB1的2倍,⽽APB1为36M//arr:⾃动重装值。
//psc:时钟预分频数//这⾥使⽤的是定时器7void TIM4_Init(u16 arr,u16 psc){TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能TIM_TimeBaseStructure.TIM_Period = arr; //设置在下⼀个更新事件装⼊活动的⾃动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置⽤来作为TIMx时钟频率除数的预分频值 10Khz的计数频率TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位TIM_ITConfig( //使能或者失能指定的TIM中断TIM4,TIM_IT_Update ,ENABLE //使能);NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器TIM_Cmd(TIM4, ENABLE); //使能TIMx外设}定时器的初始化然后设置⼀个变量⽤来累计按键按下的时间,没按键按下的时候, ⼀直循环累计时间,从0到溢出,有按键按下的时候,⽴即清空,重新开始累计⾸先初始化按键端⼝void keyIOInit(void){GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PAGPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11; //LED0-->PA.8 端⼝配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA}u16 timeKeyPressed; //按键按下的时间 10ms 步进设置两个常量,⽤来区别按键的状态,是按下还是释放#define keyStatusPressed 0#define keyStatusReleased 1定时器的中断,累计时间void TIM4_IRQHandler(void) //中断{if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //检查指定的TIM中断发⽣与否:TIM 中断源 {TIM_ClearITPendingBit(TIM4, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源timeKeyPressed+=10; //10ms的中断}}这个键,我叫做设置键,什么时候开始给设置键开始计算按下时间呢?设置键被按下⽽且按键状态还是释放需要⼏个常量标志和⼏个变量u8 statusCntingKeyTime; //是否开始计算按键时间#define statusCnting 1#define statusNotCnting 0//设置键按下,且之前没开始计时的时候,开始计算按下时间if(keySet==keyStatusPressed && statusCntingKeyTime==statusNotCnting ){timeKeyPressed=0; //设置键按下后,重新开始计时statusCntingKeyTime=statusCnting;//开始计算按下时间}当按键松开后,统计⼀下,按下的时间为多长//松⼿后统计按下时间if(keySet==keyStatusReleased && statusCntingKeyTime==statusCnting){statusCntingKeyTime=statusNotCnting;//停⽌计时//轻触if(timeKeyPressed<=timeCntClickTouch ){}//短按else if(timeKeyPressed>=timeCntClickShort &&timeKeyPressed<timeCntClickLong ){}//长按else if(timeKeyPressed>=timeCntClickLong &&timeKeyPressed<timeCntClickVeryLong){}//超级长按else if(timeKeyPressed>=timeCntClickVeryLong){}}。
单片机键盘扫描
单片机键盘扫描在单片机设计过程中,有时需要依靠键盘输入的支持。
这就需要进行识别按键技术,在本文当中,将为大家介绍识别键盘的常见方法、盘的编码、以及单片机系统中键盘系统的工作方式。
感兴趣的朋友快来看一看吧。
在实际应用中,识别按键的方法是非常多的,其中最常见的方法是扫描法。
当按键按下,与此键相连的行线与列线导通,行线在无键按下时处在高电平。
如果让所有的列线也处在高电平,那么按键按下与否不会引起行线电平的变化,因此必须使所有列线处在低电平。
只有这样,在有键按下时该键所在的行电平才会由高电平变为低电平。
CPU 根据行电平的变化,便能判定相应的行有键按下。
键盘的编码对于独立式按键键盘,因按键数量少,可根据实际需要灵活编码。
对于矩阵式键盘,按键的位置由行号和列号惟一确定,因此可分别对行号和列号进行二进制编码,然后将两值合成一个字节,高4位是行号,低4位是列号。
键盘的工作方式对键盘的响应取决于键盘的工作方式,键盘的工作方式应根据实际应用系统中CPU的工作状况而定,其选取的原则是既要保证CPU能及时响应按键操作,又不要过多占用CPU的工作时间。
通常键盘的工作方式有三种,即编程扫描、定时扫描和中断扫描。
1、编程扫描方式编程扫描方式是利用CPU完成其它工作的空余时间,调用键盘扫描子程序来响应键盘输入的要求。
在执行键功能程序时,CPU不再响应键输入要求,直到CPU重新扫描键盘为止。
2、定时扫描方式定时扫描方式就是每隔一段时间对键盘扫描一次,它利用单片机内部的定时器产生一定时间(例如10ms)的定时,当定时时间到就产生定时器溢出中断。
CPU响应中断后对键盘进行扫描,并在有键按下时识别出该键,再执行该键的功能程序。
3、中断扫描方式采用上述两种键盘扫描方式时,无论是否按键,CPU都要定时扫描键盘,而单片机应用系统工作时,并非经常需要键盘输入,因此,CPU 经常处于空扫描状态。
中断模式适合在需要提升工作效率最大化的情况中使用,当采用中断模式时,如果没有按键按下,那么CPU会针对自己的工作进行处理,但如果按键被按下,则产生了中断请求,此时CPU就会主动执行针对键盘的子程序扫描,并对键号进行键盘识别。
独立按键判断单机、长击、双击、复合击
自己琢磨着写了一个按键判单击、双击、长击、复合击的程序不太完善求指教#include "reg52.h"#include "key.h" //子文件code uint8 shuzhu[]={0x03f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //断码int16 time,num,flag,kiss,state,same,repeat,tabl1,tabl2;/***********************************延时函***********************************/ void delay(){uint16 i=10000;while(i--);}/*****************************************************************************//**********************************主函数************************************/ void main(){P0 =0xFF;tabl1=0;tabl2=0; //p0初始化ADDR0 = 0; ADDR1 = 0; ADDR2 = 0; //位码TMOD=0x01;TH0=(65536-50000)/256; //50msTL0=(65536-50000)%256;EA=1;ET0=1;TR0=0; //中断初始化P0=shuzhu[0]; //p0断码初始化while(1){if(!KeyIn1){delay();if(!KeyIn1) //判按键KeyIn1是否按下{TR0=1;while(!KeyIn1) //判按键弹起{tabl1=1;repeat=1;if((time==1)&&(KeyIn2)) //判长击{TR0=0;time=0;same=0;num=0;repeat=0;kiss=3;flag=0;}}state++; //判按下次数}}/*****************************************************************************/ if(KeyIn2==0) //判复合击{delay();if(KeyIn2==0){while(!KeyIn2){tabl2=1;}}}if(tabl1&&tabl2==1){kiss=4;}/*************************************************************************/if((num>=7)&&(KeyIn2)) //1s内如果计数时间>击键间隔时间(0.5~1s)为单击,反之为长击{num=0;if(state==1) //单击判定{TR0=0;state=0;kiss=1;}else //双击判定{if(state==2){TR0=0;state=0;kiss=2;}}}switch (kiss){case 1: P0=shuzhu[1];break;case 2: P0=shuzhu[2];break;case 3: P0=shuzhu[3];break;case 4: P0=shuzhu[4];break;}}kiss=0;state=0;}/***********************************定时器中断函数***********************/ void timer0()interrupt 1{TH0=(65536-50000)/256;TL0=(65536-50000)%256;num++;if(num>=10){num=0;flag=1;if(repeat==1){same++;if(same>=3){same=0;time=1;}}}}。
51单片机C语言实验及实践教程_8.按键识别方法之一
3. 系统板上硬件连线
图 4.8.1
(1. 把“单片机系统”区域中的 P3.7/RD 端 口连接到“独立式键盘”区域中的 SP1 端口上;
(2. 把“单片机系统”区域中的 P1.0-P1.4 端口用 8 芯排线连接到“八路 发光二极管指示模块”区域中的“L1-L8”端口上;要求,P1.0 连接到 L1,P1.1 连接到 L2,P1.2 连接到 L3,P1.3 连接到 L4 上。
4. 程序设计方法
(1. 其实,作为一个按键从没有按下到按下以及释放是一个完整的过程,
也就是说,当我们按下一个按键时,总希望某个命令只执行一次,而
在按键按下的 过程中,不要有干扰进来,因为,在按下的过程中,
一旦有干扰过来,可能造成误触发过程,这并不是我们所想要的。因
此在按键按下的时候,
图 4.8.2
void main(void) {
while(1) { if(P3_7==0) { delay10ms(); if(P3_7==0) { count++; if(count==16) { count=0; } P1=~count; while(P3_7==0); } } }
}
(2. 但对程序设计过程中按键识别过程的框图如右图所示:
5. 程序框图
6. 汇编源程序
ORG 00H
START: 0,表示从 0 开始计数
MOV R1,#00H
MOV A,R1
CPL A
;初始化 R7 为 ;
;取反指
令
MOV P1,A
;送出 P1 端口由发光二极管显示
REL:
JNB P3.7,REL
51 单片机 C 语言实验及实践教程_8.按键识别方法之一
关于单片机独立按键的详解
关于单片机独立按键的详解
键的闭合与否,反应在口线的电平上,即口线的电平是呈现高电平还是低
电平状态。
因此,可以通过口线电平高、低状态的检测,来确认按键是否按下。
但如果在触点抖动期间检测按键的通与断状态,可能导致判断出错,即按键一
次按下或释放被错误地认为是多次操作,这种情况是不允许出现的。
为了克服
按键触点机械抖动所致的检测误判,确保CPU 对一次按键动作只确认一次按
键,必须采取去抖动措施。
消除按键抖动的措施:
具体措施可从硬件、软件两方面予以考虑。
在键数较少时,可采用硬件去
抖,而当键数较多时,采用软件去抖。
软件措施:
在第一次检测到有键按下时,执行一段延时10ms 的子程序,之后,
再次检测该键的电平状态,如果该键电平仍保持闭合状态电平,
则确认为真正有键按下。
否则,认为无键按下;
同理,在检测到该键释放后,也应采用相同的步骤进行确认,从而可消除抖
动的影响。
code:/*独立按键,采用共阳极数码管*/#include#include#define uint unsigned int#define uchar unsigned charsbit key1=P2;sb it ledA=P1;uchar num;void delay(uint z);
uchar code dutable[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//段选0~9
void main(){while(1){if(key1==0){delay(10);//去按下抖动延时if(key1==0)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《一个按键的多次击键组合判别技巧》大话篇
小匠自从上次在旧社区发表了一篇《<程序编写规范倡议书>大话篇》后,好久没有发表"高"论了.急坏了一帮MM,以为小匠退隐江湖了。
(斑竹在旁问道:“MM”不是“Mie Mie”,而是“Ma Ma”吧?)
论坛内外谣言四起,有人说小匠改行了,不做程序匠,改做泥水匠了;还有人说小匠上阿富汗反恐怖去了;其实非也,只因新板论坛启用后,小匠一直用不惯......
(斑竹在旁笑道:是“用不来”吧?)
今天,小匠再次隆重登坛献演。
贴一个小程序段.....
(斑竹道:我看是“蹬痰现眼”吧?)
(程序匠人贴完帖子,下到后台,一边洗着手上残余的浆糊,一边哼着小曲:“如果你的‘芯’是一座作坊,我愿作那不知疲倦的程序匠,……”)
(一黑客悄悄贴近匠人,将一个废弃的浆糊桶扣到匠人头上......)
(匠人忙问:“斑竹,谁把灯给关了?”)
(众人哈哈大笑!......)
一个按键的多次击键组合判别技巧
有时在设计中,往往要用一个按键来输入多种信息。
如:单击/双击/三击、短击/长击、还有各种组合击键方式。
可以用以下程序来做。
如果按键闭合时间<500MS,判断为一次短击(0);
如果按键闭合时间>500MS,判断为一次长击(1);
两次击键时间间隔应<700MS,如果按键释放后700MS内无键按下,则结束读键。
读键完毕返回一个键号值KEY_NUM。
其意义如下:
KEY_NUM 意义
00000000 无键按下过
00000001 无意义
00000010 单次短击
00000011 单次长击
00000100 短击+ 短击
00000101 短击+ 长击
00000110 长击+ 短击
00000111 长击+ 长击
…………
10000000 7次短击
11111111 7次长击
上表中的KEY_NUM值的规律是,从左向右看,第一个"1"后面的每一位代表一次击键;"0"代表短击,"1"代表长击。
掌握该规律后,我们可将任何一个8位的二进制数"翻译"成一种击键组合。
例如:01010101,代表的是:短+长+短+长+短+长。
该程序最多可识别7次连续击键,共254种组合。
但并非每个程序中用得上。
在大多数程序中,能判断双击即可以了,这时可将程序中的ZHBIT定义为2。
同理,如果要判断3次按键,将ZHBIT定义为3即可。
当ZHBIT=1时,程序仅能判断一次击键,包括2种组合(短击/长击);当ZHBIT=2时,程序还能判断两次击键,包括6(2+4)种组合(短击/长击/(短+短)/(短+长)/(长+短)/(长+长));以次类推,当ZHBIT=3时,程序能判断三次击键,包括14(2+4+8)种组合。
ZHBIT 组合种类
1 2
2 2+4=6
3 2+4+8=14
4 2+4+8+16=30
5 2+4+8+16+32=62
6 2+4+8+16+32+64=126
7 2+4+8+16+32+64+128=254
下面这段程序摘自小匠的一个智能充电器程序(MCU是EM78P458),如下:
;********************************
;读键子程序
;出口: KEY_NUM =键号值
;中间: KEY_DL =计数器
;说明:
/*
短击:键按下时间<500MS
长击:键按下时间>500MS
两次按键间隔时间<700MS
键号定义:
KEY_NUM=00000000: 无键按下
KEY_NUM=00000001: 无意义
KEY_NUM=00000010: 单次短击
KEY_NUM=00000011: 单次长击
KEY_NUM=00000100: 短击+ 短击
KEY_NUM=00000101: 短击+ 长击
KEY_NUM=00000110: 长击+ 短击
KEY_NUM=00000111: 长击+ 长击
...
...
KEY_NUM=11111110: 长击+ 长击+ 长击+ 长击+ 长击+ 长击+ 短击
KEY_NUM=11111111: 长击+ 长击+ 长击+ 长击+ 长击+ 长击+ 长击
*/
ZHBIT EQU 2 ;按键组合位(选择范围1~7)
;********************************
READKEY:
CLR KEY_NUM ;清键号
JKOFF READKEYF ;键未按下跳
BS KEY_NUM,0 ;"1" -> 键号低位
;=================
READKEYA:
CLR KEY_DL ;清计数器
READKEYB:
INC KEY_DL
MOV A,@50
SUB A,KEY_DL
JBC R3,C
JMP READKEYC ;计数器溢出跳
JKON READKEYB ;键未释放跳
BC R3,C ;C=0
JMP READKEYD
;=================
READKEYC:
WDTC ;喂狗
JKON READKEYC ;键未释放跳
BS R3,C ;C=1
READKEYD:
RLLC KEY_NUM ;键号左移一位,C -> 键号低位JBC KEY_NUM,ZHBIT ;按键检测未完成继续
RET
;=================
CLR KEY_DL ;清计数器
READKEYE:
CALL DL10MS
MOV A,@70
SUB A,KEY_DL
JBC R3,C
READKEYF:
RET ;计数器溢出返回
JKOFF READKEYE ;键未按下跳
JMP READKEYA ;再次检测
;=================
;键闭合跳(宏)
;=================
JKON MACRO ADDRESS
JBS R5,KEY ;键断开跳
FJMP ADDRESS ;键闭合跳
CALL DL10MS ;延时去抖动JBS R5,KEY ;键断开跳
FJMP ADDRESS ;键闭合跳ENDM
;=================
;键断开跳(宏)
;=================
JKOFF MACRO ADDRESS
JBC R5,KEY ;键闭合跳
FJMP ADDRESS ;键断开跳
CALL DL10MS ;延时去抖动JBC R5,KEY ;键闭合跳
FJMP ADDRESS ;键断开跳ENDM。