回复: 122
按键处理模块,实现短按、长按、连击判断,附源码与图...
[复制链接]
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
电梯直达
1楼
发表于 2018-9-24 17:29:32
|
只看该作者
|倒序浏览
|阅读模式
本帖最后由 dxgdsx 于 2018-9-24 19:41 编辑
论坛已有几位大神发布了关于按键处理的C代码,写的都非常好,本人很受启发。
比如https://www.amobbs.com/forum.php ... =%E6%8C%89%E9%94%AE
中秋闲来无事,我也自己动手写一写。
事先声明:本代码参考了论坛里面几位大神的开源代码,以及STM32库函数代码风格,此外也加入了个人的一点想法,欢迎批评指正!
首先简单单片机系统中,常见的按键操作有短按(点击)、长按、连击。
个人对“连击”操作的定义并不是很清晰,个人理解是在长按基础上继续按着,然后超过一段时间视为连击1次,...,直到弹起。
下图是个人对按键操作的理解:
那么源代码中定义一些操作判定用的时间常数:
//建议10ms扫描一次
//这些常数大小,可以根据项目实际需求进行修改
//按键按下消抖计数
#define KEY_PRESS_DB_CNT 3
//判断按键长按计数
#define KEY_LONG_PRESS_CNT 150
//判断按键连击计数
#define KEY_REPEAT_PRESS_CNT 50
//按键释放消抖计数
#define KEY_RELEASE_DB_CNT 3复制代码
设计了一个按键扫描处理状态机,共有5个状态编码:
//按键扫描状态机状态编码
typedef enum
{
//按键状态机:“按键等待被按下”处理
KEY_FSM_WAIT_PRESS = 0,
//按键状态机:“按键短按”处理
KEY_FSM_SHORT_PRESS,
//按键状态机:“按键长按”处理
KEY_FSM_LONG_PRESS,
//按键状态机:“按键连击”处理
KEY_FSM_REPEAT_PRESS,
//按键状态机:“按键释放”处理
KEY_FSM_RELEASE
}KEY_FsmTypeDef;复制代码
定义按键的不同,共有6个状态编码:
//按键状态编码
typedef enum
{
//按键状态:释放状态
KEY_RELEASED = 0,
//按键状态:短按状态
KEY_SHORT_PRESSED,
//按键状态:等待长按状态
KEY_LONG_PRESS_WAIT,
//按键状态:长按状态
KEY_LONG_PRESSED,
//按键状态:等待连击状态
KEY_REPEAT_PRESS_WAIT,
//按键状态:一次连击状态
KEY_REPEAT_PRESSED
}KEY_StateTypeDef;复制代码
定义一个独立按键的按键句柄结构体:
//按键句柄结构体
typedef struct
{
uint8_t KeyId; //按键编号
KEY_StateTypeDef KeyState; //按键当前状态(高4bit为上一个状态,低4bit为当前状态)
uint16_t KeyCnt; //内部计数器(高2bit给按下/弹出计数用,低14bit给长按/连击计数用)
KEY_FsmTypeDef KeyFsmState; //状态机状态
}KEY_HandleTypeDef;复制代码
声明一些函数:
//按键端口读取函数声明,需要用户根据硬件情况自行实现
uint8_t KEY_Read_Port(uint8_t KeyId);
//按键初始化函数声明
void KEY_Init(void);
//按键扫描函数声明
void KEY_Scan(KEY_HandleTypeDef* keyHandle);
//按键状态获取函数声明
KEY_StateTypeDef KEY_Get_State(KEY_HandleTypeDef* keyHandle);复制代码
其中,关键函数是KEY_Scan函数,事实上其它几个函数无关紧要,存在更多只是为了形式上的完整
KEY_Scan函数就是一个状态机处理函数,源代码如下:
/**
* @brief 单个按键处理函数,需要被周期性调用,建议10ms扫描一次
* @param 指定单个按键的句柄
* @retval None
*/
void KEY_Scan(KEY_HandleTypeDef* keyHandle)
{
//读取按键端口电平
uint8_t IsKeyDown = KEY_Read_Port(keyHandle->KeyId);
//获取状态机的当前状态
switch(keyHandle->KeyFsmState)
{
case KEY_FSM_WAIT_PRESS:
if(IsKeyDown) //检测到按键按下
{
keyHandle->KeyCnt = KEY_FULL_CNT(KEY_HIGH_CNT(keyHandle->KeyCnt)+1, 0);
//按键按下消抖:连续几次检测到按键按下,可以确认按键按下
if(KEY_HIGH_CNT(keyHandle->KeyCnt) >= KEY_PRESS_DB_CNT)
{
keyHandle->KeyCnt = 0; //复位计数器,状态跳转
keyHandle->KeyFsmState = KEY_FSM_SHORT_PRESS;
keyHandle->KeyState = KEY_FULL_STATE(KEY_RELEASED, KEY_SHORT_PRESSED);
}
}
else
keyHandle->KeyCnt = 0; //检测到按键释放,复位计数器
break;
case KEY_FSM_SHORT_PRESS:
keyHandle->KeyState = KEY_FULL_STATE(KEY_SHORT_PRESSED, KEY_LONG_PRESS_WAIT);
if(!IsKeyDown) //检测到按键释放
{
keyHandle->KeyCnt = KEY_FULL_CNT(KEY_HIGH_CNT(keyHandle->KeyCnt)+1, 0);
//按键释放消抖:连续几次检测到按键释放,可以确认按键释放
if(KEY_HIGH_CNT(keyHandle->KeyCnt) >= KEY_RELEASE_DB_CNT)
{
keyHandle->KeyCnt = 0; //复位计数器,状态跳转
keyHandle->KeyFsmState = KEY_FSM_RELEASE;
keyHandle->KeyState = KEY_FULL_STATE(KEY_SHORT_PRESSED, KEY_RELEASED);
}
}
else
{
keyHandle->KeyCnt = KEY_FULL_CNT(0, KEY_LOW_CNT(keyHandle->KeyCnt)+1);
if(KEY_LOW_CNT(keyHandle->KeyCnt) >= KEY_LONG_PRESS_CNT) //可以确认按键长按
{
keyHandle->KeyCnt = 0; //复位计数器,状态跳转
keyHandle->KeyFsmState = KEY_FSM_LONG_PRESS;
keyHandle->KeyState = KEY_FULL_STATE(KEY_LONG_PRESS_WAIT, KEY_LONG_PRESSED);
}
}
break;
case KEY_FSM_LONG_PRESS:
keyHandle->KeyState = KEY_FULL_STATE(KEY_LONG_PRESSED, KEY_REPEAT_PRESS_WAIT);
if(!IsKeyDown) //检测到按键释放
{
keyHandle->KeyCnt = KEY_FULL_CNT(KEY_HIGH_CNT(keyHandle->KeyCnt)+1, 0);
//按键释放消抖:连续几次检测到按键释放,可以确认按键释放
if(KEY_HIGH_CNT(keyHandle->KeyCnt) >= KEY_RELEASE_DB_CNT)
{
keyHandle->KeyCnt = 0; //复位计数器,状态跳转
keyHandle->KeyFsmState = KEY_FSM_RELEASE;
keyHandle->KeyState = KEY_FULL_STATE(KEY_LONG_PRESSED, KEY_RELEASED);
}
}
else
{
keyHandle->KeyCnt = KEY_FULL_CNT(0, KEY_LOW_CNT(keyHandle->KeyCnt)+1);
if(KEY_LOW_CNT(keyHandle->KeyCnt) >= KEY_REPEAT_PRESS_CNT) //可以确认按键连击
{
keyHandle->KeyCnt = 0; //复位计数器,状态跳转
keyHandle->KeyFsmState = KEY_FSM_REPEAT_PRESS;
keyHandle->KeyState = KEY_FULL_STATE(KEY_REPEAT_PRESS_WAIT, KEY_REPEAT_PRESSED);
}
}
break;
case KEY_FSM_REPEAT_PRESS:
keyHandle->KeyState = KEY_FULL_STATE(KEY_REPEAT_PRESSED, KEY_REPEAT_PRESS_WAIT);
if(!IsKeyDown) //检测到按键释放
{
keyHandle->KeyCnt = KEY_FULL_CNT(KEY_HIGH_CNT(keyHandle->KeyCnt)+1, 0);
//按键释放消抖:连续几次检测到按键释放,可以确认按键释放
if(KEY_HIGH_CNT(keyHandle->KeyCnt) >= KEY_RELEASE_DB_CNT)
{
keyHandle->KeyCnt = 0; //复位计数器,状态跳转
keyHandle->KeyFsmState = KEY_FSM_RELEASE;
keyHandle->KeyState = KEY_FULL_STATE(KEY_REPEAT_PRESS_WAIT, KEY_RELEASED);
}
}
else
{
keyHandle->KeyCnt = KEY_FULL_CNT(0, KEY_LOW_CNT(keyHandle->KeyCnt)+1);
if(KEY_LOW_CNT(keyHandle->KeyCnt) >= KEY_REPEAT_PRESS_CNT) //可以确认按键连击
{
keyHandle->KeyCnt = 0; //复位计数器,状态跳转
keyHandle->KeyFsmState = KEY_FSM_REPEAT_PRESS;
keyHandle->KeyState = KEY_FULL_STATE(KEY_REPEAT_PRESS_WAIT, KEY_REPEAT_PRESSED);
}
}
break;
case KEY_FSM_RELEASE:
keyHandle->KeyCnt = 0; //复位计数器,状态跳转
keyHandle->KeyFsmState = KEY_FSM_WAIT_PRESS;
keyHandle->KeyState = KEY_FULL_STATE(KEY_RELEASED, KEY_RELEASED);
break;
default:
break;
}
}
复制代码
状态迁移图如下(部分默认分支没有画出):
KEY_Init函数是用于初始化按键对应的IO,若已有类似功能函数,则该函数就不需要再实现。
KEY_Read_Port函数是读取指定按键对应的IO口电平值,不需要消抖,一次读取即可,该函数需要用户根据硬件自行实现。
/**
* @brief 按键初始化操作,如端口配置、按键句柄结构体初始化等
* @param None
* @retval None
*/
__weak void KEY_Init(void)
{
/*
hkey.KeyId = KEY_ID_1;
hkey.KeyReadFuncPtr = KeyReadFunc;
hkey.KeyState = KEY_RELEASED;
hkey.KeyCnt = 0;
hkey.KeyFsmState = KEY_FSM_FSTATE(KEY_FSM_WAIT_PRESS, KEY_FSM_WAIT_PRESS);
*/
}
/**
* @brief 读取指定按键对应的IO口电平值,不需要消抖,一次读取即可,该函数需要用户根据硬件自行实现
* @param 按键的ID值,用户自行编码
* @retval IO口电平值,本实现中1:按键按下,0:按键按下,
*/
__weak uint8_t KEY_Read_Port(uint8_t KeyId)
{
/*
//根据KeyId读取指定IO口电平值
switch(KeyId)
{
case KEY_ID_1:
return (HAL_GPIO_ReadPin(USEKEY_GPIO_Port, USEKEY_Pin));
break;
default:
return 0;
break;
}
*/
return 0;
}复制代码
另外,本代码中最重要的,或者说与其他实现方式不同的地方在于,按键动作识别。
关键在于按键句柄结构体中的KeyState成员,其高4bit为上一个状态,低4bit为当前状态,通过对这个组合字可以识别出按键的具体动作。
定义了短按、长按、连击的组合识别码:
//按键状态组合字(8位),ls为上一个状态(高4位),cs为当前状态(低4位)
#define KEY_FULL_STATE(ls, cs) (KEY_StateTypeDef)(((ls)<<4)|(cs))
//按键的当前状态值,取按键状态组合字的低4位
#define KEY_CURT_STATE(s) (KEY_StateTypeDef)((s)&0x0F)
//按键上一个状态值,取按键状态组合字的高4位
#define KEY_LAST_STATE(s) (KEY_StateTypeDef)(((s)&0xF0)>>4)
//按键内部计数组合字(16位),h2用于按下/释放消抖计数(高2位),l14用于长按/连击计数(低14位)
#define KEY_FULL_CNT(h2, l14) ((((h2)&0x0003)<<14)|((l14)&0x3FFF))
//按键按下/释放消抖计数值
#define KEY_LOW_CNT(c) ((c)&0x3FFF)
//按键长按/连击计数值
#define KEY_HIGH_CNT(c) (((c)&0xC000)>>14)
//按键短按动作识别字
#define KEY_SHORT_ACTION() KEY_FULL_STATE(KEY_SHORT_PRESSED, KEY_RELEASED)
//按键长按动作识别字
#define KEY_LONG_ACTION() KEY_FULL_STATE(KEY_LONG_PRESSED, KEY_RELEASED)
//按键连击动作识别字
#define KEY_REPEAT_ACTION() KEY_FULL_STATE(KEY_REPEAT_PRESS_WAIT, KEY_REPEAT_PRESSED)复制代码
上述代码最后形成两个文件:key_driver.c和key_driver.h
如何使用该模块:
/**
* @brief main.c--以单个按键以例,仅把与本模块相关的代码写出,其余代码未写
* @param
* @retval
*/
//包含其他头文件
//包含按键处理模块头文件
#include "key_driver.h"
//定义一个按键句柄结构体,并进行初始化
#define KEY_ID_1 1
KEY_HandleTypeDef hkey = {KEY_ID_1, KEY_FULL_STATE(KEY_RELEASED, KEY_RELEASED), 0, KEY_FSM_WAIT_PRESS};
/*若有多个按键,可以定义按键句柄结构体数组
#define KEY_ID_1 1
#define KEY_ID_2 2
#define KEY_ID_3 3
KEY_HandleTypeDef hkey[3] = {{KEY_ID_1, KEY_FULL_STATE(KEY_RELEASED, KEY_RELEASED), 0, KEY_FSM_WAIT_PRESS},
{KEY_ID_2, KEY_FULL_STATE(KEY_RELEASED, KEY_RELEASED), 0, KEY_FSM_WAIT_PRESS},
{KEY_ID_3, KEY_FULL_STATE(KEY_RELEASED, KEY_RELEASED), 0, KEY_FSM_WAIT_PRESS}};
*/
//用户根据硬件情况自行实现指定按键的IO电平读取,该函数将覆盖模块中的同名函数
uint8_t KEY_Read_Port(uint8_t KeyId)
{
switch(KeyId)
{
case KEY_ID_1:
return (HAL_GPIO_ReadPin(USEKEY_GPIO_Port, USEKEY_Pin));
break;
default:
return 0;
break;
}
}
//main函数
int main(void)
{
//按键端口配置,若其他代码已对其进行了配置,则可忽略
KEY_Init();
//其余代码
while(1)
{
//其余代码
//周期性调用按键扫描
KEY_Scan(&hkey);
//按键动作识别
if(KEY_SHORT_ACTION() == KEY_Get_State(&hkey)) //短按,点亮led
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
if(KEY_LONG_ACTION() == KEY_Get_State(&hkey)) //长按,熄灭led
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET);
if(KEY_REPEAT_ACTION() == KEY_Get_State(&hkey)) //连击1次,led翻转1下
HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
//扫描间隔10ms
HAL_Delay(10);
}
return 0;
}
复制代码
本按键代码模块在STM32L152 Discovery硬件上进行了验证,附源码供参考,欢迎批评指正!
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛21周年了!感谢大家的支持与爱护!!
当你觉得为时已晚的时候,恰恰是最早的时候。
收藏235
回复
举报本楼层
了无
了无
当前离线
积分1829
1829
积分
精华
汤圆VIP++ {*}
出0入8汤圆
2楼
发表于 2018-9-24 18:32:26
来自手机
|
只看该作者
非常不错,有机会试一下
回复
举报本楼层
wlmwwx
wlmwwx
当前离线
积分195
195
积分
精华
汤圆VIP- {*}
出0入0汤圆
3楼
发表于 2018-9-24 18:35:40
|
只看该作者
谢谢分享,收藏备用。
回复
举报本楼层
haohai
haohai
当前离线
积分220
220
积分
精华
汤圆VIP- {*}
出0入0汤圆
4楼
发表于 2018-9-24 18:51:10
|
只看该作者
楼主的图用什么画的,很不错,说明很清楚!
回复
举报本楼层
arndei
arndei
当前离线
积分876
876
积分
精华
汤圆VIP- {*}
出0入0汤圆
5楼
发表于 2018-9-24 18:53:24
|
只看该作者
写的很清楚,记得论坛之前也有一个类似的,程序写的也很不错
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
6楼
楼主|
发表于 2018-9-24 19:14:18
|
只看该作者
haohai 发表于 2018-9-24 18:51
楼主的图用什么画的,很不错,说明很清楚!
是用Visio画的。
回复
举报本楼层
shenwrt
shenwrt
当前离线
积分115
115
积分
精华
汤圆VIP- {*}
出0入0汤圆
7楼
发表于 2018-9-24 19:30:28
来自手机
|
只看该作者
收藏收藏
回复
举报本楼层
机器人天空
机器人天空
当前离线
积分2195
2195
积分
精华
汤圆VIP++ {*}
出0入0汤圆
8楼
发表于 2018-9-24 19:55:54
来自手机
|
只看该作者
没有组合键吗
回复
举报本楼层
zcllom
zcllom
当前离线
积分3020
3020
积分
精华
汤圆VIP++ {*}
出330入0汤圆
9楼
发表于 2018-9-24 20:06:00
来自手机
|
只看该作者
希望你这个模块站在前人的肩膀上,博采众长,成为集大成者。
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
10楼
楼主|
发表于 2018-9-24 20:09:49
|
只看该作者
机器人天空 发表于 2018-9-24 19:55
没有组合键吗
可以的,定义多个按键,然后对多个键进行组合判断即可(因为手头板子只有一个按键,多键组合未加验证)。
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
11楼
楼主|
发表于 2018-9-24 20:15:57
|
只看该作者
zcllom 发表于 2018-9-24 20:06
希望你这个模块站在前人的肩膀上,博采众长,成为集大成者。
惭愧惭愧,这个是自己练习用到。
回复
举报本楼层
makesoft
makesoft
当前离线
积分5343
5343
积分
精华
汤圆VIP- {*}
出10入120汤圆
12楼
发表于 2018-9-24 20:27:39
来自手机
|
只看该作者
很多场合不能等到按键释放再响应,那样人机交互感受不好。
回复
举报本楼层
andy93762
andy93762
当前离线
积分1037
1037
积分
精华
汤圆VIP++ {*}
出0入0汤圆
13楼
发表于 2018-9-24 20:50:48
来自手机
|
只看该作者
非常不错,学习下,了解下
回复
举报本楼层
elecfun
elecfun
当前离线
积分3471
3471
积分
精华
汤圆VIP- {*}
出0入134汤圆
14楼
发表于 2018-9-24 21:02:44
|
只看该作者
看起来不错,多谢分享
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
15楼
楼主|
发表于 2018-9-24 21:07:03
|
只看该作者
makesoft 发表于 2018-9-24 20:27
很多场合不能等到按键释放再响应,那样人机交互感受不好。
关于这一点,我也很疑问,个人觉得要看实际项目的需求来定。
事实上,这里的代码是可以获取每一个10ms检测时的按键上一次状态和当前状态,通过设置不同的组合状态字来进行判断,不一定要非等到按键释放以后再操作。
另外,代码只能检测过去,不可能预测未来。
就拿短按来看:
所以,下面几个动作识别字都是用来识别一个独立的操作,短按就是短按,长按就是长按。不能先认为短按,然后继续按着,就认为是长按
//按键短按动作识别字
#define KEY_SHORT_ACTION() KEY_FULL_STATE(KEY_SHORT_PRESSED, KEY_RELEASED)
//按键长按动作识别字
#define KEY_LONG_ACTION() KEY_FULL_STATE(KEY_LONG_PRESSED, KEY_RELEASED)
//按键连击动作识别字
#define KEY_REPEAT_ACTION() KEY_FULL_STATE(KEY_REPEAT_PRESS_WAIT, KEY_REPEAT_PRESSED)复制代码
当然,说到底,还是根据实际项目需求来定。
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
回复
举报本楼层
sjf
sjf
当前离线
积分355
355
积分
精华
汤圆VIP- {*}
出0入0汤圆
16楼
发表于 2018-9-24 21:18:58
|
只看该作者
楼主不错,共享精神,值得肯定!
回复
举报本楼层
lisingch
lisingch
当前离线
积分1023
1023
积分
精华
汤圆高级会员 {*}
出0入0汤圆
17楼
发表于 2018-9-24 21:21:53
|
只看该作者
这个帖子得好好学习一下。
回复
举报本楼层
BS_good200xy
BS_good200xy
当前离线
积分424
424
积分
精华
汤圆VIP- {*}
出0入4汤圆
18楼
发表于 2018-9-24 21:32:13
|
只看该作者
正想好好研究一下按键。
回复
举报本楼层
wthzack
wthzack
当前离线
积分347
347
积分
精华
汤圆VIP- {*}
出0入0汤圆
19楼
发表于 2018-9-24 23:52:54
|
只看该作者
多谢分享 有机会试一下
回复
举报本楼层
wajlh
wajlh
当前离线
积分9385
9385
积分
精华
汤圆VIP- {*}
出0入4汤圆
20楼
发表于 2018-9-25 02:08:24
|
只看该作者
收藏一下
回复
举报本楼层
dory_m
dory_m
当前离线
积分1376
1376
积分
精华
汤圆VIP- {*}
出0入0汤圆
21楼
发表于 2018-9-25 07:41:37
|
只看该作者
学习,谢谢!!!
回复
举报本楼层
daicp
daicp
当前离线
积分1314
1314
积分
精华
汤圆VIP- {*}
出0入0汤圆
22楼
发表于 2018-9-25 08:31:30
|
只看该作者
感谢楼主无私分享
回复
举报本楼层
eliterxzgxu
eliterxzgxu
当前离线
积分1015
1015
积分
精华
汤圆VIP- {*}
出0入0汤圆
23楼
发表于 2018-9-25 08:33:05
来自手机
|
只看该作者
感谢楼主分享
回复
举报本楼层
337zhang
337zhang
当前离线
积分1559
1559
积分
精华
汤圆VIP++ {*}
出0入0汤圆
24楼
发表于 2018-9-25 08:34:26
|
只看该作者
好久没见干货了,帮顶一下
回复
举报本楼层
peteryzm
peteryzm
当前离线
积分683
683
积分
精华
汤圆VIP- {*}
出250入17汤圆
25楼
发表于 2018-9-25 08:52:30
|
只看该作者
mark,按键程序
感谢无私分享
回复
举报本楼层
AlertTao
AlertTao
当前离线
积分412
412
积分
精华
汤圆VIP {*}
出0入0汤圆
26楼
发表于 2018-9-25 08:52:41
|
只看该作者
回复
举报本楼层
zengyi703
zengyi703
当前离线
积分542
542
积分
精华
汤圆VIP- {*}
出0入0汤圆
27楼
发表于 2018-9-25 08:58:38
|
只看该作者
收藏备用
回复
举报本楼层
2012Ehome
2012Ehome
当前离线
积分716
716
积分
精华
汤圆VIP- {*}
出0入0汤圆
28楼
发表于 2018-9-25 09:08:20
|
只看该作者
谢谢分享,收藏备用+1
回复
举报本楼层
mculjf
mculjf
当前离线
积分1063
1063
积分
精华
汤圆VIP- {*}
出0入13汤圆
29楼
发表于 2018-9-25 09:11:47
|
只看该作者
感谢楼主分享
回复
举报本楼层
a105
a105
当前离线
积分897
897
积分
精华
汤圆VIP- {*}
出0入0汤圆
30楼
发表于 2018-9-25 09:40:38
|
只看该作者
收藏备用
回复
举报本楼层
asbzhang
asbzhang
当前离线
积分215
215
积分
精华
汤圆VIP- {*}
出0入0汤圆
31楼
发表于 2018-9-25 10:01:16
|
只看该作者
很详细,不错。
回复
举报本楼层
dreambox
dreambox
当前离线
积分927
927
积分
精华
汤圆高级会员 {*}
出0入0汤圆
32楼
发表于 2018-9-25 10:01:43
|
只看该作者
感谢楼主分享
回复
举报本楼层
yangbo18416
yangbo18416
当前离线
积分190
190
积分
精华
汤圆VIP- {*}
出0入0汤圆
33楼
发表于 2018-9-25 10:18:43
|
只看该作者
感谢分享,收藏备用
回复
举报本楼层
Aslm
Aslm
当前离线
积分98
98
积分
精华
汤圆VIP- {*}
出0入0汤圆
34楼
发表于 2018-9-25 10:22:10
|
只看该作者
按键处理模块,实现短按、长按、连击判断,附源码与图
回复
举报本楼层
bbsview
bbsview
当前离线
积分2887
2887
积分
精华
汤圆VIP- {*}
出0入0汤圆
35楼
发表于 2018-9-25 10:26:05
|
只看该作者
不错,值得好好的学习一下!
回复
举报本楼层
stevensun80
stevensun80
当前离线
积分10
10
积分
精华
汤圆VIP++ {*}
出0入0汤圆
36楼
发表于 2018-9-25 10:30:37
|
只看该作者
状态机流程图画的很用心,学习了
回复
举报本楼层
jackjiao
jackjiao
当前离线
积分443
443
积分
精华
汤圆VIP- {*}
出0入0汤圆
37楼
发表于 2018-9-25 10:32:42
|
只看该作者
之前也写过按键的模块,不过有一定的局限性,学习下
回复
举报本楼层
pjdu
pjdu
当前离线
积分533
533
积分
精华
汤圆中级会员 {*}
出0入0汤圆
38楼
发表于 2018-9-25 10:44:56
|
只看该作者
谢谢分享,收藏备用。
回复
举报本楼层
l.htlht
l.htlht
当前离线
积分906
906
积分
精华
汤圆VIP- {*}
出0入0汤圆
39楼
发表于 2018-9-25 10:52:46
|
只看该作者
谢谢分享
回复
举报本楼层
Excellence
Excellence
当前离线
积分7035
7035
积分
精华
汤圆VIP- {*}
出0入0汤圆
40楼
发表于 2018-9-25 10:58:41
|
只看该作者
谢谢楼主无私分享。
最近用矩阵键盘,有时间试试。
回复
举报本楼层
Excellence
Excellence
当前离线
积分7035
7035
积分
精华
汤圆VIP- {*}
出0入0汤圆
41楼
发表于 2018-9-25 10:59:02
|
只看该作者
4*5矩阵键盘,而且GPIO不是连续的,不知道楼主代码支持吗?
回复
举报本楼层
阿豪博士
阿豪博士
当前离线
积分3023
3023
积分
精华
汤圆VIP++ {*}
出0入0汤圆
42楼
发表于 2018-9-25 11:17:15
|
只看该作者
MRARK:按键状态机!
回复
举报本楼层
fsmcu
fsmcu
当前离线
积分729
729
积分
精华
汤圆VIP- {*}
出0入0汤圆
43楼
发表于 2018-9-25 11:21:12
|
只看该作者
有些应用场合很变态,比如长按,还要区分长按不同的时间,需要根据按键释放来测算按下的时间,然后进入相应的动作
回复
举报本楼层
yangxizhong
yangxizhong
当前离线
积分513
513
积分
精华
汤圆中级会员 {*}
出0入0汤圆
44楼
发表于 2018-9-25 11:22:37
|
只看该作者
学习,谢谢!!!
回复
举报本楼层
qinshiysb
qinshiysb
当前离线
积分1144
1144
积分
精华
汤圆VIP- {*}
出0入0汤圆
45楼
发表于 2018-9-25 11:22:41
|
只看该作者
楼主给力,按键处理
回复
举报本楼层
linccfzu
linccfzu
当前离线
积分792
792
积分
精华
汤圆VIP+++ {*}
出100入976汤圆
46楼
发表于 2018-9-25 11:23:00
|
只看该作者
收藏学习!!
回复
举报本楼层
linux-0405209
linux-0405209
当前离线
积分388
388
积分
精华
汤圆中级会员 {*}
出0入0汤圆
47楼
发表于 2018-9-25 11:28:37
|
只看该作者
很详细,很好的资料,谢谢楼主
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
48楼
楼主|
发表于 2018-9-25 12:05:44
|
只看该作者
Excellence 发表于 2018-9-25 10:59
4*5矩阵键盘,而且GPIO不是连续的,不知道楼主代码支持吗?
暂时没有看过矩阵键盘,但是个人觉得实现思路基本差不多的。
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
49楼
楼主|
发表于 2018-9-25 12:07:02
|
只看该作者
fsmcu 发表于 2018-9-25 11:21
有些应用场合很变态,比如长按,还要区分长按不同的时间,需要根据按键释放来测算按下的时间,然后进入相应 ...
对的,所以要根据实际情况来实现。
可以在这个代码基础上增加时间常数与按键状态来拓展。
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
50楼
楼主|
发表于 2018-9-25 12:08:59
|
只看该作者
Excellence 发表于 2018-9-25 10:59
4*5矩阵键盘,而且GPIO不是连续的,不知道楼主代码支持吗?
个人觉得不管什么类型的键盘,只要根据具体硬件把KEY_Read_Port函数实现了,就可以直接使用。
回复
举报本楼层
yanzhiwei
yanzhiwei
当前离线
积分645
645
积分
精华
汤圆VIP++ {*}
出0入0汤圆
51楼
发表于 2018-9-25 13:54:53
|
只看该作者
谢谢分享,收藏备用
回复
举报本楼层
OOXX110
OOXX110
当前离线
积分2162
2162
积分
精华
汤圆VIP++ {*}
出0入12汤圆
52楼
发表于 2018-9-25 14:05:14
|
只看该作者
谢谢分享,收藏备用
回复
举报本楼层
qq335702318
qq335702318
当前离线
积分1306
1306
积分
精华
汤圆VIP- {*}
出0入0汤圆
53楼
发表于 2018-9-25 14:23:19
|
只看该作者
本帖最后由 qq335702318 于 2018-9-25 14:37 编辑
不错!楼主是花了心思做流程分析的!
我认为的"连击"是短时间内按键 ”按下-弹起-再次按下-再次弹起”,也就是Double-Click
另外,每个按键都占用一个结构体的思路,虽然用起来灵活方便,但不适合RAM空间极小的8位机
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
54楼
楼主|
发表于 2018-9-25 15:01:28
|
只看该作者
qq335702318 发表于 2018-9-25 14:23
不错!楼主是花了心思做流程分析的!
我认为的"连击"是短时间内按键 ”按下-弹起-再次按下-再次弹起”,也 ...
“双击”确实如你所说,但是“连击”我确实没怎么搞明白定义。
比如一些设备上,先长按按键,屏幕上对应的数字闪烁(意味着进入修改状态),继续按着按键,该数字每隔一定时间加1。
结构体的使用,确实对于资源极小的单片机系统不够友好。
回复
举报本楼层
oaixuw
oaixuw
当前离线
积分1167
1167
积分
精华
汤圆VIP- {*}
出0入0汤圆
55楼
发表于 2018-9-25 15:13:01
|
只看该作者
很好,先收藏了,谢谢!
回复
举报本楼层
1785345205
1785345205
当前离线
积分461
461
积分
精华
汤圆VIP++ {*}
出180入0汤圆
56楼
发表于 2018-9-25 15:13:15
|
只看该作者
谢谢分享
回复
举报本楼层
Pjm2008
Pjm2008
当前离线
积分2205
2205
积分
精华
汤圆VIP- {*}
出0入14汤圆
57楼
发表于 2018-9-25 15:27:52
|
只看该作者
很好,先收藏
回复
举报本楼层
雨中的风铃
雨中的风铃
当前离线
积分376
376
积分
精华
汤圆VIP++ {*}
出0入0汤圆
58楼
发表于 2018-9-25 15:32:02
|
只看该作者
谢谢分享!!!!!!!!!
回复
举报本楼层
LK9286
LK9286
当前离线
积分1287
1287
积分
精华
汤圆VIP- {*}
出0入0汤圆
59楼
发表于 2018-9-25 15:35:12
|
只看该作者
感谢,收藏学习
回复
举报本楼层
pisgah
pisgah
当前离线
积分465
465
积分
精华
汤圆中级会员 {*}
出0入0汤圆
60楼
发表于 2018-9-25 15:35:47
|
只看该作者
多谢楼主的分享和详细的图文解说
回复
举报本楼层
_yuming
_yuming
当前离线
积分2447
2447
积分
精华
汤圆VIP- {*}
出0入0汤圆
61楼
发表于 2018-9-25 18:58:27
|
只看该作者
收藏,备用。。。虽然目前还用不到。
回复
举报本楼层
fuu
fuu
当前离线
积分267
267
积分
精华
汤圆VIP- {*}
出0入0汤圆
62楼
发表于 2018-9-25 22:44:47
|
只看该作者
思路挺好,支持
回复
举报本楼层
cc1987
cc1987
当前离线
积分722
722
积分
精华
汤圆VIP++ {*}
出0入81汤圆
63楼
发表于 2018-9-26 08:31:58
|
只看该作者
谢谢分享
回复
举报本楼层
yuguoliang
yuguoliang
当前离线
积分747
747
积分
精华
汤圆VIP- {*}
出0入0汤圆
64楼
发表于 2018-9-26 08:33:54
|
只看该作者
谢谢分享,收藏备用。
回复
举报本楼层
a312835782
a312835782
当前离线
积分1282
1282
积分
精华
汤圆VIP- {*}
出0入0汤圆
65楼
发表于 2018-9-26 08:37:19
|
只看该作者
看起来很麻烦
回复
举报本楼层
iqxt88
iqxt88
当前离线
积分871
871
积分
精华
汤圆VIP- {*}
出0入0汤圆
66楼
发表于 2018-9-26 08:46:51
|
只看该作者
不错思路清晰,谢谢分享。
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
67楼
楼主|
发表于 2018-9-26 08:47:27
|
只看该作者
a312835782 发表于 2018-9-26 08:37
看起来很麻烦
之前我看傻孩子老师工作室发布的通用按键模块,源码里面多个状态机loop,然后又是双队列,觉得麻烦,所以精简了一下,只剩下一个状态机loop。队列直接舍去。
当然如果只是读取按键的话,确实没必要这样写。但是毕竟还是想把按键这块做成一个相对独立的模块,所以稍微写的多一点。
你觉得上面代码还有哪部分可以精简一下?
回复
举报本楼层
Jmhh247
Jmhh247
当前离线
积分1245
1245
积分
精华
汤圆VIP- {*}
出0入8汤圆
68楼
发表于 2018-9-26 10:26:20
|
只看该作者
dxgdsx 发表于 2018-9-26 08:47
之前我看傻孩子老师工作室发布的通用按键模块,源码里面多个状态机loop,然后又是双队列,觉得麻烦,所以 ...
不能一味的精简。
即然都在前人的基础上重写成了“模块”,就把队列加上吧,一步到位。
回复
举报本楼层
wushifeng
wushifeng
当前离线
积分367
367
积分
精华
汤圆VIP- {*}
出0入0汤圆
69楼
发表于 2018-9-26 10:27:01
|
只看该作者
MARK
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
70楼
楼主|
发表于 2018-9-26 10:31:22
|
只看该作者
Jmhh247 发表于 2018-9-26 10:26
不能一味的精简。
即然都在前人的基础上重写成了“模块”,就把队列加上吧,一步到位。 ...
队列并不是刚需。
回复
举报本楼层
jack_yu
jack_yu
当前离线
积分822
822
积分
精华
汤圆VIP- {*}
出0入0汤圆
71楼
发表于 2018-9-26 13:23:06
来自手机
|
只看该作者
谢谢楼主分享。学习了
回复
举报本楼层
xingjianpeng
xingjianpeng
当前离线
积分838
838
积分
精华
汤圆VIP- {*}
出0入0汤圆
72楼
发表于 2018-9-26 13:54:46
|
只看该作者
谢谢楼主分享。学习了
回复
举报本楼层
TigerFish
TigerFish
当前离线
积分4411
4411
积分
精华
汤圆VIP- {*}
出0入16汤圆
73楼
发表于 2018-9-27 08:31:44
|
只看该作者
这种资料真正有用,感谢
回复
举报本楼层
Gorgon_Meducer
Gorgon_Meducer
当前离线
积分9894
9894
积分
精华
汤圆VIP+++ {*}
出0入296汤圆
74楼
发表于 2018-9-27 23:06:47
|
只看该作者
本帖最后由 Gorgon_Meducer 于 2018-9-27 23:37 编辑
dxgdsx 发表于 2018-9-26 10:31
队列并不是刚需。
首先,非常,非常,非常开心楼主认真的阅读了代码,并根据自己的理解做出了自己的实现,甚至花费宝贵的时间发到我的板块来分享。非常感谢。
其次,关于队列的问题,我想说:“等我书出来,你就知道打脸的感觉了。” 卖个关子。
为了避免被人带节奏催书的问题,这里先放一点原理图,聪明的人应该可以看出使用两个队列的其中一个原因(是的还有别的原因):
结论:通过替换数据处理的前端(Frontend)可以在不改写后续处理和APP的情况下,实现按键模块对不同类型键盘的支持(这是好处之一)。
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
75楼
楼主|
发表于 2018-9-28 08:58:51
|
只看该作者
Gorgon_Meducer 发表于 2018-9-27 23:06
首先,非常,非常,非常开心楼主认真的阅读了代码,并根据自己的理解做出了自己的实现,甚至花费宝贵的时 ...
终于看到大神前来指导了!激动,感谢感谢!
既然逮到大神了,我就抓住机会请教下:
我觉得双FIFO的存在,最好的作用是:用户从FIFO中获取的结果是已经处理好的最终结果,不需要用户进行再次判断。
而我写的里面,用户得到的结果是:上一次扫描到的按键状态 与 本次扫描到的按键状态 的组合状态,这个组合状态字自带了很多有用信息,用它来判断“短按”、“长按”、“连击”的操作是可以的。
但是如果要判断更多动作,可能需要用户二次处理。
所以,我这个严格来讲不能算是独立的模块,只能算是一段可供参考的代码。
回复
举报本楼层
ilikemcu
ilikemcu
当前离线
积分8910
8910
积分
精华
汤圆VIP- {*}
出0入50汤圆
76楼
发表于 2018-9-28 09:43:25
|
只看该作者
makesoft 发表于 2018-9-24 20:27
很多场合不能等到按键释放再响应,那样人机交互感受不好。
有短按键和长按键同时使用的时候,只能取消短按键的这个功能了,也就是短按键必须等待按键释放才能响应,但是长按键可以在时间到达后立即响应,而无需等待按键释放。
在按键数量极其有限的情况下,楼主的方法是很有效律的,我的设计里用2个按键,也是实现了类似的长按,短按,连击等等功能,不过由于按键功能是逐步添加的,整个按键的处理代码都是分散加载的。
回复
举报本楼层
makesoft
makesoft
当前离线
积分5343
5343
积分
精华
汤圆VIP- {*}
出10入120汤圆
77楼
发表于 2018-9-28 10:48:23
|
只看该作者
Gorgon_Meducer 发表于 2018-9-27 23:06
首先,非常,非常,非常开心楼主认真的阅读了代码,并根据自己的理解做出了自己的实现,甚至花费宝贵的时 ...
一直按键处理使用类似方法,最大的好处是做好按键识别和按键使用分离,增加了系统的可靠性和灵活性。
回复
举报本楼层
lrzxc
lrzxc
当前离线
积分1698
1698
积分
精华
汤圆VIP- {*}
出0入0汤圆
78楼
发表于 2018-9-28 11:17:10
|
只看该作者
嗯,收藏了
回复
举报本楼层
Gorgon_Meducer
Gorgon_Meducer
当前离线
积分9894
9894
积分
精华
汤圆VIP+++ {*}
出0入296汤圆
79楼
发表于 2018-9-28 21:20:38
|
只看该作者
dxgdsx 发表于 2018-9-28 08:58
终于看到大神前来指导了!激动,感谢感谢!
既然逮到大神了,我就抓住机会请教下:
我注意到了你在提供给客户的内容中加入了状态信息,但是这里有个问题,就是你没有办法
携带时间信息。而时间信息是很多用户行为识别的关键。另外,如果你仔细看我提供的图,
你会明白,这里队列存在的目的主要是两点:隔离和接口去耦。
我的理解是,队列先进先出的特性已经实际上保留了事件之间的前后状态,所以不必在一个
按键report中包含前后的相邻状态。同样,如果真的考虑应用可能需要这些信息,只保存一级
恐怕是不够的……最后用户还是要根据实际情况去队列里挖掘,而这个挖掘的过程还是离不开
使用状态机。
为了解决这个问题,我的处理方法实际上是,在保留各原始的按键事件的前提下,通过逐级
追加数据处理,根据已有的案件事件来进行模式识别,提取出更有用的按键事件,并追加到
事件流里面——比如,双击的处理就是根据单击的事件配合时间信息来实现的。
这里我想强调的是,逐级处理信息,由简单到抽象,这正是人类大脑进行信息处理的方式。
比如,视网膜第一级,简单的对光线和颜色敏感,第二级神经网络将第一集的点信息处理成
线条信息,第三极则对将点和线的信息处理成运动的矢量信息。你可以看出这里明显的逐级
处理,逐级追加有用信息,逐级抽象的过程。
我觉得你现在最大的问题是,太专注于按键扫描本身了。从技术的角度说需要适当扩大一点
思考的范围。
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
80楼
楼主|
发表于 2018-9-29 09:50:39
|
只看该作者
Gorgon_Meducer 发表于 2018-9-28 21:20
我注意到了你在提供给客户的内容中加入了状态信息,但是这里有个问题,就是你没有办法
携带时间信息。而 ...
真的非常受教,感谢!
逐级增加信息,逐级进行处理,确实是人类大脑认知、处理事务最有效的方式。大脑虽然厉害,但是一下子面对复杂事务却很难有效处理,经过分层逐级处理,可以将复杂问题分解成若干简单问题,然后逐步处理,最后解决复杂问题。
太受教了!
回复
举报本楼层
hubinghuandi
hubinghuandi
当前离线
积分530
530
积分
精华
汤圆VIP- {*}
出0入0汤圆
81楼
发表于 2018-9-29 11:58:11
|
只看该作者
学习,谢谢!!!
回复
举报本楼层
gongngei
gongngei
当前离线
积分404
404
积分
精华
汤圆VIP- {*}
出0入0汤圆
82楼
发表于 2018-9-29 12:05:36
|
只看该作者
学习了,谢谢
回复
举报本楼层
bitter_rain
bitter_rain
当前离线
积分1086
1086
积分
精华
汤圆VIP++ (2年){*}
出0入0汤圆
83楼
发表于 2018-9-29 14:22:45
|
只看该作者
不错,赞赞赞!
回复
举报本楼层
liaihua1997
liaihua1997
当前离线
积分1070
1070
积分
精华
汤圆VIP- {*}
出0入8汤圆
84楼
发表于 2018-9-29 16:11:37
|
只看该作者
这个程序长按的时候会有响应短按的时间窗口吗?
回复
举报本楼层
dxgdsx
dxgdsx
当前离线
积分468
468
积分
精华
汤圆VIP- {*}
出0入0汤圆
85楼
楼主|
发表于 2018-9-29 16:13:07
|
只看该作者
liaihua1997 发表于 2018-9-29 16:11
这个程序长按的时候会有响应短按的时间窗口吗?
不会。
但是可以很容易实现这个功能。
回复
举报本楼层
zd0305
zd0305
当前离线
积分119
119
积分
精华
汤圆VIP- {*}
出0入0汤圆
86楼
发表于 2018-10-15 10:27:26
|
只看该作者
值得学习!!!!!!!好贴
回复
举报本楼层
sandeant
sandeant
当前离线
积分135
135
积分
精华
汤圆VIP- {*}
出0入0汤圆
87楼
发表于 2018-10-16 14:49:57
|
只看该作者
好贴!!!!!!!!
回复
举报本楼层
a673261839
a673261839
当前离线
积分105
105
积分
精华
汤圆VIP- {*}
出0入0汤圆
88楼
发表于 2018-11-1 10:05:15
|
只看该作者
学习,谢谢!!!
回复
举报本楼层
HJMB
HJMB
当前离线
积分112
112
积分
精华
汤圆VIP++ {*}
出0入0汤圆
89楼
发表于 2018-11-2 08:37:40
|
只看该作者
好帖子,非常实用!谢谢!
回复
举报本楼层
minier
minier
当前离线
积分831
831
积分
精华
汤圆VIP- {*}
出0入0汤圆
90楼
发表于 2018-11-2 09:40:06
|
只看该作者
嗯!借助实践触发和状态机,二合一就既有FSM思想好理解,又有时间控制,实现不同的击键要求
回复
举报本楼层
四川李工
四川李工
当前离线
积分674
674
积分
精华
汤圆中级会员 {*}
出0入0汤圆
91楼
发表于 2018-11-2 10:07:25
|
只看该作者
mark、以下!!!!!!!!!
回复
举报本楼层
TKZXJ
TKZXJ
当前离线
积分987
987
积分
精华
汤圆VIP++ {*}
出0入0汤圆
92楼
发表于 2019-1-23 12:08:27
|
只看该作者
收藏一下
回复
举报本楼层
jackjiao
jackjiao
当前离线
积分443
443
积分
精华
汤圆VIP- {*}
出0入0汤圆
93楼
发表于 2019-1-23 12:16:34
|
只看该作者
也写过一个类似的key queue驱动,学习学习
回复
举报本楼层
bsz84
bsz84
当前离线
积分770
770
积分
精华
汤圆VIP- {*}
出0入0汤圆
94楼
发表于 2019-1-23 12:44:38
|
只看该作者
不错,值得学习一下!
回复
举报本楼层
zbx6020
zbx6020
当前离线
积分67
67
积分
精华
汤圆VIP {*}
出0入0汤圆
95楼
发表于 2019-1-23 12:46:28
来自手机
|
只看该作者
不错,值得学习一下!
回复
举报本楼层
d314361768
d314361768
当前离线
积分313
313
积分
精华
汤圆VIP- {*}
出0入0汤圆
96楼
发表于 2019-1-23 12:55:44
|
只看该作者
收藏下!!!
回复
举报本楼层
zhongsandaoren
zhongsandaoren
当前离线
积分2105
2105
积分
精华
汤圆VIP++ (2年){*}
出0入0汤圆
97楼
发表于 2019-1-23 13:23:53
|
只看该作者
按键处理程序 Mark
回复
举报本楼层
片羽之神
片羽之神
当前离线
积分698
698
积分
精华
汤圆中级会员 {*}
出0入0汤圆
98楼
发表于 2019-6-6 22:20:47
|
只看该作者
mark~~有机会研究一下~
回复
举报本楼层
lizuqing
lizuqing
当前离线
积分305
305
积分
精华
汤圆VIP- {*}
出0入0汤圆
99楼
发表于 2019-6-7 09:35:31
|
只看该作者
按键处理程序 Mark
回复
举报本楼层
waymcu
waymcu
当前离线
积分378
378
积分
精华
汤圆VIP++ {*}
出0入0汤圆
100楼
发表于 2019-6-7 17:00:12
|
只看该作者
按键处理程序 Mark
回复
举报本楼层