马老师能否编一个 一个按键支持单击,双击的程序?
马老师能否编一个 一个按键支持单击,双击的,N击的程序论坛上面貌似没有这样的。 你是什么鸟? 你是什么鸟? 在检测到一次单击后,设定一个定时器,再次单击时检测这个定时器,如果时间没有到,就算双击,否则算单击。N击有意义吗? 估计实际做过单片机程序的都会写,不至于找专人。。 回复【2楼】110112110
---------------------------------------------------------------------
多少钱啊
你没有见过钱啊 回复【1楼】bill
-----------------------------------------------------------------------
什么话吗 回复【4楼】whhityang小样一
-----------------------------------------------------------------------
老兄能帮下小弟吗 回复【3楼】xiaobendan仲跻东
-----------------------------------------------------------------------
你好。能说详细点吗, 回复【楼主位】jacky82512
马老师能否编一个 一个按键支持单击,双击的,n击的程序
论坛上面貌似没有这样的。
-----------------------------------------------------------------------
这个值得让马老师给你写吗 ?
自己动动脑子吧 回复【9楼】avr-qq高级工程叁
-----------------------------------------------------------------------
写不出来,否则也不必请教。弱势群体啊 前排围观!!!此帖必火。 这里虽号称电子桃花源,但仍是武林风俗,哪有徒子徒孙求师祖代扫院子的啊。 //4。***342页,按键扫描函数代码
//原代码不理想,请改成如下:
#define key_input PIND // 按键输入口
#define key_mask 0b11000000 // 按键输入屏蔽码
#define key_no 0
#define key_k1 1
#define key_k2 2
#define key_state_0 0
#define key_state_1 1
#define key_state_2 2
unsigned char read_key(void)
{
static unsigned char key_state = 0,key_old,key_time,key_cnt,key_time_start=0;
unsigned char key_press,key_return = key_no;
key_press = key_input & key_mask; // 读按键I/O电平
if(key_time_start) //双击判断计时开始
{
key_time++;//
}
switch (key_state)
{
case key_state_0: // 按键初始态
if (key_press != key_mask)
{
key_old = key_press; // 记录原电平
key_state = key_state_1; // 键被按下,状态转换到键确认态
}
break;
case key_state_1: // 按键确认态
if (key_press == key_old) // 与原电平比较(消抖处理)
{
if (key_press == 0b01000000)
{
key_time_start=0xff; //计时标志置位
if(key_time>50) //>500ms做什么
{
//key_cnt=0;
key_time=0;
key_time_start=0x00; //计时停止
key_return = key_k1;
}
else//<=500ms做什么
{
key_cnt++;
if(key_cnt>=8)//
{
key_cnt=0;
key_time=0;
key_time_start=0x00;//计时停止
key_return = key_double_k1;
}
}
//key_return = key_k1;
}
else if (key_press == 0b10000000) key_return = key_k2;
key_state = key_state_2; // 状态转换到键释放态
}
else
key_state = key_state_0; // 按键已抬起,转换到按键初始态
break;
case key_state_2:
if (key_press == key_mask) key_state = key_state_0;//按键已释放,转换到按键初始态
break;
}
return key_return;
}
//在此附上我在马老师程序基础上面改的程序。
但是和我要实现的东西不一样。
必须按2下才可以实现单击的目的。
摆脱大家看看怎么才能实现 一个按键 单击 双击 的目的。
被这个问题困扰了很久。
希望大侠给出自己的意见,怎么样才可以实现单击,双击在一个按键上面 的目的。
想骂人的请闭嘴。 别说让马老师 随便叫个人都没人给你写 闲的蛋疼了?你说大家讨论下思路 还差不多 LZ 典型自我为中心。。 我以前实现过的,长按,短按,单击,双击,等,理解好那个状态机就行了。 双击只不过是两次相隔时间很短的单击,因此利用定时器记录两次单击之间的时间,如果超过一个限度就算是两次单击,否则算是一次双击,这个应该不难。最简单的按键接入捕捉的引脚,中断里面读取定时器数值。 回复【14楼】nome物净
-----------------------------------------------------------------------
以自我为中心,你何不站在苦难中的我考虑下。 回复【16楼】tiancaigao7天才杨威利
-----------------------------------------------------------------------
你好,天才 看了一下程序,感觉这程序你只是对单击和双击的时间上做了处理,对于单击和双击的点击数没有处理,不知道你调用后的程序上有没有处理好,因为你说只有击两次才实现单击功能,所以我觉得你的点击数上没处理好,都需要双击,只是时间延迟长了是单击,延时短就是双击 师父领进门,修行在个人!说句不好听得,就你这样的学习态度,劝你不要搞技术,没多大前途 ./emotion/em084.gif 这种按键双击有意义吗?要单击之后是不是要等到定时过后才执行双击的功能呢?那样反应也太慢了点吧。 回复【22楼】xiaobendan仲跻东
这种按键双击有意义吗?要单击之后是不是要等到定时过后才执行双击的功能呢?那样反应也太慢了点吧。
-----------------------------------------------------------------------
你天天都在用这个双击! 回复【23楼】linghu2令狐二中
回复【22楼】xiaobendan仲跻东
这种按键双击有意义吗?要单击之后是不是要等到定时过后才执行双击的功能呢?那样反应也太慢了点吧。
-----------------------------------------------------------------------
你天天都在用这个双击!
-----------------------------------------------------------------------
顶 1.先理解马老师这个使用状态机的按键程序,再把马老师书里这个章节的题目做出来。。。
2.分析一下你的需求,单击和双击----其实是多了第一次按键释放至第二次按下弹起的延时时间。。。
3.结合状态机,在写程序测试。。。尤其要理解的是状态机,是一次干一件事情的。。。 给个程序自己移值一下,之前在网上找的,调通OK的(没有太多的注示)。
点击此处下载 ourdev_668590AHCNHE.txt(文件大小:12K) (原文件名:老化测试治具程序(12864显示按键长短功能).txt) 回复【楼主位】jacky82512
马老师能否编一个 一个按键支持单击,双击的,n击的程序
论坛上面貌似没有这样的。
-----------------------------------------------------------------------
你自己连按键的过程都不清楚,编什么程序?已经说过首先是理解多功能按件的操作过程和判别,分析出有几个稳定的状态,相互之间的转换条件,然后才是程序。
对于一个多功能按键,在操作中,只能出现:单击、长按(属于连_发类)、双击(属于N击类,但当N>2时,需要额外规定。比如5次连击,那么你击的次数大于1,但小于5,此时算什么?)三个复用情况。定义有双击动作,就不存在什么N击动作了。
你自己先在脑子里搞清楚,对着PC的一个按键多体会,把这个多功能按键的过程定义用文字表述出来(包括重要的时间定义),然后才是考虑编写程序的问题。
在实际的产品中,可能会用到n击的情况。我设计的一个控制器上,就是在正常检测工作状态下,连续短促的按一个键10次,就把设定检测时间间隔的功能锁掉/打开,防止一般人员误操作,进入设置状态,把参数搞乱。这样的程序并不复杂,关键是你的理解。 这个DD就作为一个训练的题目吧,不是马上要“全国大学生电子设计大赛”吗,看看这些“精英”们有谁能给出漂亮的答案。
题目就是一个I/O口,接一个按键,实现多功能操作:
功能为:单击+双击+长按。
用在时钟时间设置上。比如设置时钟时间有时、分、秒。
假定开始设置秒位:单击一次,秒的个位加1,长按(按下时间超过1秒)一次,秒的十位加1。如果是双击,表示秒设置完,转到分位设置了。。。。。
只要分析按键的操作过程和区分判别的条件,给出一个读一个按键的低层代码,能返回:
1。无按键
2。单击
3。长按
4。双击 首先要保证精英们都来这里看到这个题目 晕,参加电设的也有很多强人,虽然不一定是精英,但还是很有实力的,这种题目很多人都很早就会做了,没必要当作电设的训练题。 眼高手低的人,大把存在....... 回复【26楼】hnzhy870215
-----------------------------------------------------------------------
看了下 ,代码很长。
需要的时候参考下! 回复【28楼】machao
-----------------------------------------------------------------------
“全国大学生电子设计大赛”在哪里举办?在网上公布情况吗?
那就静静的期待吧,一边在继续我的工作。 回复【20楼】xingguangyouxi
-----------------------------------------------------------------------
怎么样才算好的学习态度?不防说说看看。看看你境界有多高。随随便便指指点点态度,态度还是不要指指点点好。 回复【25楼】hetiger
-----------------------------------------------------------------------
感谢你,你说的很到点。
不想论坛上面的某些人,要不骂人,要不就装,要不---。
大家,就应该有大家的风度。 回复【23楼】linghu2令狐二中
-----------------------------------------------------------------------
你想说什么,表达什么。
你说说天天都在用双击?是意思 回复【27楼】machao
-----------------------------------------------------------------------
试问当1个写软件的人,写不出来,也没有什么好的思路的时候,该做点什么。
或者是遇到困难的时候。在此感谢马老师。真的感谢了。 回复【17楼】jacky82512
-----------------------------------------------------------------------
以自我为中心,你何不站在苦难中的我考虑下。
-----------------------------------------------------------------------
写不出程序来,说明你对这个按键本身没有太多的了解,甚至不了解它的工作原理,别说就一个开关,如果你把它工作在单击、双击、N连击、长按的各种状态下的分解动作好好理解一番,那么程序自然就出来了。除非你连写代码都成问题,那就没法帮你了。建议你练练太极,好好把浮躁的性子克服一下,然后找只按键,用慢动作按几次,这个事情是需要悟的。
本来想给你贴个程序来着,罢了罢了,写了这么多字,也啰嗦得差不多了,唉…… 楼主需要看一看一篇很多论坛上都有的帖子《提问的智慧》
在这个论坛里谁都不欠谁的,所以首先要自己努力去解决,然后才是提问,在提问前也要多问自己几次,“真的就没办法了吗?”
解答马老师的问题,不一定对,还请大家拍砖。
http://cache.amobbs.com/bbs_upload782111/files_44/ourdev_668999BSZ2LD.jpg
(原文件名:key.jpg) 今天上午想了办法总算实现了目的。虽然不是很好的状态机。目的实现了。
还是感谢各位了。特别是给出很多建议的朋友。 回复【39楼】igoal
-----------------------------------------------------------------------
你这个状态图用什么【软件】分析的,那么好的软件可否分享下。 分析【软件】叫大脑
实现软件很多,word,visio,matlab,fpga
我最喜欢用纸和铅笔 【32楼】 duxingkei 独行客
-------------------------------
下面是单双击程序,上面的是带12864串口驱动,很好用的程序
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
#include<intrins.h>
#include<stdlib.h>
#define LCD_data P0
sbit cs=P2^4;
sbit sid=P2^5;
sbit sclk=P2^6;
sbit PSB=P2^1;
//根据按键硬件连接定义按键键值
#define KEY_VALUE_1 0x0e
#define KEY_VALUE_2 0x0d
#define KEY_VALUE_3 0x0b
#define KEY_VALUE_4 0x07
#define KEY_NULL 0x0f
//定义长按键的TICK数,以及连_发间隔的TICK数
#define KEY_LONG_PERIOD 300
#define KEY_CONTINUE_PERIOD 150
//定义按键返回值状态(按下,长按,连_发,释放)
#define KEY_DOWN 0x80
#define KEY_LONG 0x40
#define KEY_CONTINUE 0x20
#define KEY_UP 0x10
//定义按键状态
#define KEY_STATE_INIT 0
#define KEY_STATE_WOBBLE 1
#define KEY_STATE_PRESS 2
#define KEY_STATE_LONG 3
#define KEY_STATE_CONTINUE 4
#define KEY_STATE_RELEASE 5
//其中io_key_1等是我们按键端口的定义,如下所示:
sbit io_key_1 = P3^0 ;
sbit io_key_2 = P3^1 ;
sbit io_key_3 = P3^2 ;
sbit io_key_4 = P3^3 ;
sbit led1=P1^0;
sbit led2=P1^1;
sbit led3=P1^2;
sbit led4=P1^3;
static uint KeyScan(void)
{
if(io_key_1 == 0)return KEY_VALUE_1 ;
if(io_key_2 == 0)return KEY_VALUE_2 ;
if(io_key_3 == 0)return KEY_VALUE_3 ;
if(io_key_4 == 0)return KEY_VALUE_4 ;
return KEY_NULL ;
}
uint GetKey()
{
static uint s_u8KeyState = KEY_STATE_INIT ;
static uint s_u8KeyTimeCount = 0 ;
static uint s_u8LastKey = KEY_NULL ; //保存按键释放时候的键值
uint KeyTemp = KEY_NULL ;
KeyTemp = KeyScan() ; //获取键值
switch(s_u8KeyState)
{
case KEY_STATE_INIT :
{
if(KEY_NULL != (KeyTemp))
{
s_u8KeyState = KEY_STATE_WOBBLE ;
}
}
break ;
case KEY_STATE_WOBBLE : //消抖
{
s_u8KeyState = KEY_STATE_PRESS ;
}
break ;
case KEY_STATE_PRESS :
{
if(KEY_NULL != (KeyTemp))
{
s_u8LastKey = KeyTemp ; //保存键值,以便在释放按键状态返回键值
KeyTemp |= KEY_DOWN ; //按键按下
s_u8KeyState = KEY_STATE_LONG ;
}
else
{
s_u8KeyState = KEY_STATE_INIT ;
}
}
break ;
case KEY_STATE_LONG :
{
if(KEY_NULL != (KeyTemp))
{
if(++s_u8KeyTimeCount > KEY_LONG_PERIOD)
{
s_u8KeyTimeCount = 0 ;
KeyTemp |= KEY_LONG ; //长按键事件发生
s_u8KeyState = KEY_STATE_CONTINUE ;
}
}
else
{
s_u8KeyState = KEY_STATE_RELEASE ;
}
}
break ;
case KEY_STATE_CONTINUE :
{
if(KEY_NULL != (KeyTemp))
{
if(++s_u8KeyTimeCount > KEY_CONTINUE_PERIOD)
{
s_u8KeyTimeCount = 0 ;
KeyTemp |= KEY_CONTINUE ;
}
}
else
{
s_u8KeyState = KEY_STATE_RELEASE ;
}
}
break ;
case KEY_STATE_RELEASE :
{
s_u8LastKey |= KEY_UP ;
KeyTemp = s_u8LastKey ;
s_u8KeyState = KEY_STATE_INIT ;
}
break ;
default : break ;
}
return KeyTemp ; //返回键值
}
delay(uint a)
{
uint x,y;
for(x=a;x>0;x--)
for(y=110;y>0;y--);
}
void main(void)
{
uint KeyValue = KEY_NULL;
uint temp = 0 ;
while(1)
{
delay(50);
KeyValue=GetKey();
KeyValue&=KeyValue;
if(KeyValue == (KEY_VALUE_1 | KEY_DOWN)) P1=0xfe ;
if(KeyValue == (KEY_VALUE_1 | KEY_LONG))P1=0xef ;
if(KeyValue == (KEY_VALUE_1 | KEY_CONTINUE)) P1=0xf0;
//if(KeyValue == (KEY_VALUE_1 | KEY_UP))P1=0x0f;
KeyValue=0;
}
} ls的,没看出能实现双击啊,只不过持续按能响应2次
今天太晚,先给出波形图
http://cache.amobbs.com/bbs_upload782111/files_44/ourdev_668984G9JD5Y.jpg
3种按键情况 (原文件名:按键.jpg) 简单说明下
1、长按:1秒以上,且只响应一次,除非松手
2、双击:1秒内(要小于长按时间,否则容易引起混乱)按下2次,有且仅有2次
3、可以看出,第一次按下时并不能知道是单击还是双击,必须等到1秒才能做出判断 我给你个思路:
记录4个时间量
T3:上次按下
T2:上次抬起
T1:本次按下
T0:本次抬起
设置4个时间长度判断值
1:按键最长有效间隔时间
2:按键最短有效间隔时间
3:最长按键时间长度
4:最短按键时间长度
这样通过T3~T0的各种比较可以判断出
1 ___-___________ 单击
2 ___---_________ 长单击
3 ___-_-_________ 短间隔 短双击
4 ___-___-_______ 长间隔 短双击
5 ___---_---_____ 短间隔 长双击
6 ___---___---___ 长间隔 长双击
7 ___-_---_______ 短间隔 短长击
8 ___-___---_____ 长间隔 短长击
9 ___---_-_______ 短间隔 长短击
10___---___-_____ 长间隔 长短击
11_______________ 没按
12--------------- 一直在按,可以连_发
一共12种状态
楼下的再多记录次按键时间,看看一共能拼出来几种状态 哇,一个按键出这么多状态,那么再加上扫键法,可以用极少的IO实现无限的功能了,厉害厉害! 嗯。。。。
不止。。。
LS,我想要是算上上升沿和下降沿的判断,估计组合还多。。。 搞这么多组合有意义吗?用户能搞清楚哪个是长按哪个是短按?这要是在产品上用估计要被客户骂死。 回复【46楼】madara
-----------------------------------------------------------------------
强悍啊,慢慢去实现。 回复【44楼】packer
-----------------------------------------------------------------------
用啥剪的这个图?示波器测引脚的电平吗? 回复【47楼】xiaobendan 仲跻东
哇,一个按键出这么多状态,那么再加上扫键法,可以用极少的io实现无限的功能了,厉害厉害!
-----------------------------------------------------------------------
他那是莫尔斯电码 楼主是个狗东西,大家不要理他 回复【51楼】jacky82512
回复【44楼】packer
-----------------------------------------------------------------------
用啥剪的这个图?示波器测引脚的电平吗?
-----------------------------------------------------------------------
用示波器自带上位机软件截图,测的按键引脚
+5
|
--
||
|| 10K
--
|------->示波器
|
\
\ 按键
|
GND 回复【53楼】xcodes
-----------------------------------------------------------------------
不想理你,你还做什么 回复【53楼】xcodes
-----------------------------------------------------------------------
别污染马老师论坛的空气 回复【54楼】packer
-----------------------------------------------------------------------
示波器这个功能不错,我还没有用过。有机会试试 回复【46楼】madara
我给你个思路:
记录4个时间量
t3:上次按下
t2:上次抬起
t1:本次按下
t0:本次抬起
设置4个时间长度判断值
1:按键最长有效间隔时间
2:按键最短有效间隔时间
3:最长按键时间长度
4:最短按键时间长度
这样通过t3~t0的各种比较可以判断出
1 ___-___________ 单击
2 ___---_________ 长单击
3 ___-_-_________ 短间隔 短双击
4 ___-___-_______ 长间隔 短双击
5 ___---_---_____ 短间隔 长双击
6 ___---___---___ 长间隔 长双击
7 ___-_---_______ 短间隔 短长击
8 ___-___---_____ 长间隔 短长击
9 ___---_-_______ 短间隔 长短击
10___---___-_____ 长间隔 长短击
11_______________ 没按
......
-----------------------------------------------------------------------
按的人估计也很累一会就晕了我到底要按啥了? 浮躁、浮夸、纸上谈兵、好高务远。。。。。
当前电子工程师和学校学生所具备的毛病在这里曝露出来了。
以上所有对于这个三功能“简单”按键的回帖,目前没有一个能到60分。
劝那些想真正提高自己本事的朋友,要静下心,仔细全面做练习设计,贴上点有价值的东西,大家讨论。
测试环境如下:
main(viod)
{
.........
while
{
if (time_10ms_ok) //每10ms执行一次,
{
time_10ms_ok =0;
key = read_key(); //《====== 10ms读按键程序,根据返回键值,点亮不同的LED灯,测试按键操作是否正常
if (key == k1)
//点亮A_LED,关闭C_LED和D_LED
else if(key == k2)
//点亮A_LED,关闭C_LED和D_LED
else if(key == k3)
//点亮A_LED,关闭C_LED和D_LED
}
}
}
有兴趣的朋友,补上read_key()函数。该函数读一个按键,返回单击、双击、长按、无按键4种情况。
} 浮躁、浮夸、纸上谈兵、好高务远。。。。。
当前电子工程师和学校学生所具备的毛病在这里曝露出来了。
以上所有对于这个三功能“简单”按键的回帖,目前没有一个能到60分。
劝那些想真正提高自己本事的朋友,要静下心,仔细全面做练习设计,贴上点有价值的东西,大家讨论。
测试环境如下:
main(viod)
{
.........
while
{
if (time_10ms_ok) //每10ms执行一次,
{
time_10ms_ok =0;
key = read_key(); //《====== 10ms读按键程序,根据返回键值,点亮不同的LED灯,测试按键操作是否正常
if (key == k1)
//点亮A_LED,关闭C_LED和D_LED
else if(key == k2)
//点亮A_LED,关闭C_LED和D_LED
else if(key == k3)
//点亮A_LED,关闭C_LED和D_LED
}
}
}
有兴趣的朋友,补上read_key()函数。该函数读一个按键,返回单击、双击、长按、无按键4种情况。
} 首先请考虑和定义:单击、双击、长按、无按键4种情况的分类。比如,第一次短按后,马上按下键不放,这个情况算什么按键?
另外,每次按键过程中,按键按下和释放,都要考虑消抖,否则你的按键就会经常出现误动(读)。
最后,程序要简捷,合理,优化,方便调试。 “第一次短按后,马上按下键不放,这个情况算什么按键?”按我的理解应该算按两次键,第一次算单击,第二次算长按。 回复【61楼】machao
-----------------------------------------------------------------------
小小按键,竟有那么多道道。可见---我深思去 回复【62楼】igoal
“第一次短按后,马上按下键不放,这个情况算什么按键?”按我的理解应该算按两次键,第一次算单击,第二次算长按。
-----------------------------------------------------------------------
短按被取消了执行长按啊呵呵 mark 回复【62楼】igoal
“第一次短按后,马上按下键不放,这个情况算什么按键?”按我的理解应该算按两次键,第一次算单击,第二次算长按。
-----------------------------------------------------------------------
我认为是次双击
不过,做乙方习惯了,在现实中我会说
“甲方,你说算什么我就怎么做” #define LONG_KEY_UP 1//长按键松开500ms
#define LONG_KEY_DOWN 2//长按键进行中
#define SINGLE_KEY 3 //单击完成(500ms无按键)
#define DOUBLE_KEY4 //双击完成(可扩展N击)
#define NO_KEY 5 //无按键
#define KEYDOWN 1
#define KEYUP 0
//每10ms调用一次该函数
unsigned char ReadKey()
{
static unsigned char flag=0;
static unsigned int keydowncount=0;
static unsigned int keyupcount=0;
unsigned char keystat;
keystat=ReadKey(); //读按键状态
if(keystat==KEYDOWN) //按下状态
{
if(keyupcount!=0) // 松开有计数 说明正在等待的时候按下
{
keyupcount=0;
flag=1; //等待连击
}
keydowncount++;
if(keydowncount>100) //长按状态
return LONG_KEY_DOWN;
}
else //松开状态
{
if(keydowncount>=5) //有按下计数的时候才会启动
keyupcount++;
if(keydowncount<5)//防抖
{
keydowncount=0;
return NO_KEY;
}
else if (keydowncount>=5&&keydowncount<100) //防抖成功而且 按下小于1s
{
if(keyupcount>50) //松开大于500ms
{
keydowncount=0;
keyupcount=0;
if(flag) //等待双击标志位
return DOUBLE_KEY; //双击
else
{
flag=0;//等待双击失败
return SINGLE_KEY; //单击
}
}
else //松开不到500ms
{
return NO_KEY;
}
}
else if (keydowncount>=100)//按下大于1S
{
if(keyupcount>50) //松开500ms
{
keydowncount=0;
keyupcount=0;
flag=0;
return LONG_KEY;
}
else
{
return NO_KEY;
}
}
}
}
readkey.courdev_669474TM6GRU.txt(文件大小:1K) (原文件名:ReadKey.txt)
粗略的写了一下 上来接受板砖“当前电子工程师和学校学生所具备的毛病在这里曝露出来了。”受教了 “第一次短按后,马上按下键不放,这个情况算什么按键?”这里面其实隐含了什么情况才算一次按键触发事件的判断,有些人把按键按下去作为一次按键事件发生,有些人把按键抬起作为一次按键事件发生。我一般都是把按键抬起当做一次按键发生的。 回复【67楼】nome物净
-----------------------------------------------------------------------
我试验下。谢了朋友 围观一下
楼主是坛子里为数不多的牛人,想必是过多了衣来伸手,饭来张口的生活 回复【70楼】max232X工
-----------------------------------------------------------------------
什么意思这个是? 回复【68楼】igoal
“第一次短按后,马上按下键不放,这个情况算什么按键?”这里面其实隐含了什么情况才算一次按键触发事件的判断,有些人把按键按下去作为一次按键事件发生,有些人把按键抬起作为一次按键事件发生。我一般都是把按键抬起当做一次按键发生的。
-----------------------------------------------------------------------
一次按键的事件发生在按下还是释放,应该考虑实际应用的需要。但不关如何选择,按键事件的发生,在整个按键过程中(包括按下和释放削抖的过程)只能定义出现一次。
对于一个普通的单次按键,还是定义在按下为好,通常在削抖后就可以作为按键事件发生了。
这样系统的反映及时,一旦系统有反映了,操作者会马上释放,而不会按更长的时间。在一些特殊的应用中,比如测试人的反映时间(8个LED随机亮一个,测试者马上按下对应的按键,测试反映的时间),如果是释放按键才算按键发生的话,测试时间就不准确了,因为包含了按下去的时间长短,而不是马上按下的时间。在此类的需求时,按键发生可以定义在按下削抖之前的。
而对于多功能的按键操作,比如长/短按键、连击等,第一次的按键发生只能定义在释放,但第2次的按键发生也需要根据情况定。比如一个只支持单次和双击的按键,第1次按键发生必需在按键释放,而第2次双击按键发生,则放在按键按下为好。
以上采用状态机的按键设计方法,都是很方便的。
========================================================
把按键抬起当做一次按键发生,也不是不可以。但对于有些操作者,会造成系统不必要的延误,如果系统本身编写不完善会导致崩溃出问题。
这些操作者往往是按下键后,看到反映(比如是设置时间过程,时间位加了1了),或听到按键提示音后,才释放按键。如果按键发生定义在释放,那么操作者就看(听)不到按键的反映,可能会一直按着按键不放,此时你的系统就惨了! 回复【72楼】machao
-----------------------------------------------------------------------
受教了。 题目:多功能按键设计。利用一个I/O口,接一个按键,实现3功能操作:单击 + 双击 + 长按。
============================================================================
用户基本操作定义:
1。短按操作:按键按下,按下时间<1s,属于一次短按操作
2。长按操作:按键按下,按下时间>1s,属于一次长按操作
在正常0.5s内无按键操作为启始按键扫描条件下,扫描按键将产生以下3种按键事件:
1。长按事件:任何1次出现的长按操作都属于长按事件
2。单击事件:1次短按操作后,间隔0.5内没有短按操作
3。双击事件:2次短按操作间隔时间<0.5s,则2次短按操作为1次双击事件,且2次短按都取消
特别操作情况定义:
1。短按操作和长按操作间隔<0.5s,以及,长按操作和短按操作间隔<0.5s,均不产生双击事件
2。连续n次(n为奇数)短按操作,且间隔均<0.5s,产生(n-1)/2次双击事件+1次单击事件
3。连续n次(n为偶数)短按操作,且间隔均<0.5s,产生n/2次双击事件
对按键操作者的建议:
由于按键的多功能性质,建议操作者每次在单击/长按/双击按键事件发生后,隔0.5s后再进行下一次的按键操作。因为在特别操作情况下,程序是保证按定义进行判断和处理的,主要是怕操作者自己记不清楚导致操作失误。
对软件设计者的要求:
1。应该全面进行分析,给出严格定义和判断条件,如上所示。如果自己都不清楚,你的设计出的系统就不稳定,不可靠。
2。在1的基础上,编写出符合要求的程序,并进行全面测试。
/*=============
低层按键(I/0)扫描函数,即低层按键设备驱动,只返回无键、短按和长按。具体双击不在此处判断。参考本人教材的例9-1,稍微有变化。教材中为连_发。
===============*/
#define key_input PIND.7 // 按键输入口
#define N_key 0 //无键
#define S_key 1 //单键
#define D_key 2 //双键
#define L_key 3 //长键
#define key_state_0 0
#define key_state_1 1
#define key_state_2 2
unsigned char key_driver(void)
{
static unsigned char key_state = key_state_0, key_time = 0;
unsigned char key_press, key_return = N_key;
key_press = key_input; // 读按键I/O电平
switch (key_state)
{
case key_state_0: // 按键初始态
if (!key_press) key_state = key_state_1; // 键被按下,状态转换到按键消抖和确认状态
break;
case key_state_1: // 按键消抖与确认态
if (!key_press)
{
key_time = 0; //
key_state = key_state_2; // 按键仍然处于按下,消抖完成,状态转换到按下键时间的计时状态,但返回的还是无键事件
}
else
key_state = key_state_0; // 按键已抬起,转换到按键初始态。此处完成和实现软件消抖,其实按键的按下和释放都在此消抖的。
break;
case key_state_2:
if(key_press)
{
key_return = S_key; // 此时按键释放,说明是产生一次短操作,回送S_key
key_state = key_state_0; // 转换到按键初始态
}
else if (++key_time >= 100) // 继续按下,计时加10ms(10ms为本函数循环执行间隔)
{
key_return = L_key; // 按下时间>1000ms,此按键为长按操作,返回长键事件
key_state = key_state_3; // 转换到等待按键释放状态
}
break;
case key_state_3: // 等待按键释放状态,此状态只返回无按键事件
if (key_press) key_state = key_state_0; //按键已释放,转换到按键初始态
break;
}
return key_return;
}
/*=============
中间层按键处理函数,调用低层函数一次,处理双击事件的判断,返回上层正确的无键、单键、双键、长键4个按键事件。
本函数由上层循环调用,间隔10ms
===============*/
unsigned char key_read(void)
{
static unsigned char key_m = key_state_0, key_time_1 = 0;
unsigned char key_return = N_key,key_temp;
key_temp = key_driver();
switch(key_m)
{
case key_state_0:
if (key_temp == S_key )
{
key_time_1 = 0; // 第1次单击,不返回,到下个状态判断后面是否出现双击
key_m = key_state_1;
}
else
key_return = key_temp; // 对于无键、长键,返回原事件
break;
case key_state_1:
if (key_temp == S_key) // 又一次单击(间隔肯定<500ms)
{
key_return = D_key; // 返回双击键事件,回初始状态
key_m = key_state_0;
}
else
{ // 这里500ms内肯定读到的都是无键事件,因为长键>1000ms,在1s前低层返回的都是无键
if(++key_time_1 >= 50)
{
key_return = S_key; // 500ms内没有再次出现单键事件,返回上一次的单键事件
key_m = key_state_0; // 返回初始状态
}
}
break;
}
return key_return;
}
下面,根据程序分析按键事件的反映时间:
1。对于长键,按下超过1s马上响应,反映最快
2。对于双键,第2次按键释放后马上得到反映。
3。对于单键,释放后延时拖后500ms才能响应,反映最慢。这个与需要判断后面是否有双击操作有关,只能这样。实际应用中,可以调整两次单击间隔时间定义,比如为300ms,这样单击的响应回快一点,单按键操作人员需要加快按键的操作过程。如果产品是针对老年人的,这个时间不易太短,因为年纪大的人,反映和动作都比较慢。
当然,上面两段可以合在一起。我这样做的目的,是为了可以方便的扩展为N击(当然,需要做修改)。可是最底层的就是最基本的操作处理短按和长按,不用改动的。至于双击,还是N击,在中间层处理。这就是程序设计中分层结构的优点。
测试代码环境如下:
interrupt void timer0_comp_isr(void) // 定时器10ms中断服务
{
time_10ms_ok = 1;
}
main(viod)
{
.........
while
{
if (time_10ms_ok) //每10ms执行一次,
{
time_10ms_ok =0;
key = key_read(); //《====== 10ms一次调用按键中间层函数,根据返回键值,点亮不同的LED灯,全面测试按键操作是否正常
if (key == L_key)
........//点亮A_LED,关闭B_LED和C_LED
else if(key == D_key)
........//点亮B_LED,关闭A_LED和C_LED
else if(key == S_key)
........//点亮C_LED,关闭A_LED和B_LED
}
}
}
=================================================
通过以上这个看似简单的按键,看在应用中如何变化,以及如何在实际产品中全面、可靠的进行设计。
=========================================================
lz,我这个老家伙完成你的作业,还行吗?
大家给打个分数,100分太满了,90分有吧?
========================================================= 回复【74楼】machao
-----------------------------------------------------------------------
多谢马老师了。仔细研读下。 是不是要加这个?return key_return;我在琢磨下
/*=============
中间层按键处理函数,调用低层函数一次,处理双击事件的判断,返回上层正确的无键、单键、双键、长键4个按键事件。
本函数由上层循环调用,间隔10ms
===============*/
unsigned char key_read(void)
{
static unsigned char key_m = key_state_0, key_time_1 = 0;
unsigned char key_return = N_key,key_temp;
key_temp = key_driver();
switch(key_m)
{
case key_state_0:
if (key_temp == S_key )
{
key_time_1 = 0; // 第1次单击,不返回,到下个状态判断后面是否出现双击
key_m = key_state_1;
}
else
key_return = key_temp; // 对于无键、长键,返回原事件
break;
case key_state_1:
if (key_temp == S_key) // 又一次单击(间隔肯定<500ms)
{
key_return = D_key; // 返回双击键事件,回初始状态
key_m = key_state_0;
}
else
{ // 这里500ms内肯定读到的都是无键事件,因为长键>1000ms,在1s前低层返回的都是无键
if(++key_time_1 >= 50)
{
key_return = S_key; // 500ms内没有再次出现单键事件,返回上一次的单键事件
key_m = key_state_0; // 返回初始状态
}
}
break;
}
return key_return; //这里是不是要加上这句,因为不加这个,key = key_read();没有返回值吧,是不是这样
}
==================================================================
是漏掉了返回语句,谢谢提醒。
已经补上了。 __machao__
================================================================== 回复【36楼】jacky82512
回复【23楼】linghu2 令狐二中
-----------------------------------------------------------------------
你想说什么,表达什么。
你说说天天都在用双击?是意思
-----------------------------------------------------------------------
鼠标双击,你没有用? 慢慢的理解“真谛” machao 发表于 2011-8-23 14:36 static/image/common/back.gif
题目:多功能按键设计。利用一个I/O口,接一个按键,实现3功能操作:单击 + 双击 + 长按。
============== ...
这个如何改成软件延时扫描,不用定时器中断? 楼主好象是不不爱动脑筋的人! 对象分析很重要啊!!! machao 发表于 2011-8-18 01:28 static/image/common/back.gif
这个DD就作为一个训练的题目吧,不是马上要“全国大学生电子设计大赛”吗,看看这些“精英”们有谁能给出漂 ...
马老师,您好,在百度文库看到你写的一个按键的单击、双击和长按功能的程序,觉得写的很好,用状态机的思想以前没用过。这个按键扫描程序是不是只可以实现扫描一个按键?如果要扫描两个按键,应该怎么写呢? jacky82512 发表于 2011-8-18 08:31 static/image/common/back.gif
回复【23楼】linghu2令狐二中
---------------------------------------------------------------------- ...
左右互搏,击小弟弟,猜的,应该是这个意思吧 machao 发表于 2011-8-19 18:42
浮躁、浮夸、纸上谈兵、好高务远。。。。。
当前电子工程师和学校学生所具备的毛病在这里曝露出来了。
马老师,若是把按键处理放在外部中断里,那么,利用定时器定时10ms来延时就做不到了吧
页:
[1]