小按键,大学问按键是最常用的人机交互的输入方式,但是按键有很多学问,你知道吗?问:你知道按键怎么获取键值吗?
我:按键就是获取按下的键值,一般电路下,没按下的时候是高电平,按下就是低电平,获取到低电平就触发。
问:那我要松手触发呢?
我:...
问:长按呢?
我:就按下的时候延时呗
问:那怎么保证其他程序的实时性,不被延时打断?
我:...
问:双击呢?
我:...
问:按下连续触发呢?
我:...
问:组合按键呢?
我:...
问:组合长按呢?
我:...
没错,这就是我第一次出来找工作的时候被问到的问题,那时候我刚毕业,以年少轻狂,桀骜不驯的心态去找工作,也是第一次被问得无地自容,一个最常用的按键,竟然有这么大的学问,那时候也看到了自己的不足,一个小小的按键都有这么大的学问,我需要学的地方还很多啊。
按键的处理方式,以及滤波处理用过按键都知道,按下的时候会有抖动,需要加滤波,但是绝大部分人都只处理按下的时候的抖动,而忘记了松手的抖动,这个松手抖动也是我工作中遇到的问题,特此分享一下,处理按键滤波需要处理按下抖动和松手抖动!
单击,也分按下触发和抬起触发,不同的场景需要不同的处理方式
长按,单击不松开,并计数到长按的时间,触发长按
双击,本篇没有添加双击,但实现思路不难,检测到单击松手后,开始计数,在100ms内如果再次检测到单击,则判断为双击,如果超时没有检测到单击,则此次为单击
连发,连发机制为按下后开始计时,当超过长按时间后执行连发
组合,其实就把组合当做一个按键来处理即可,只要你传组合的键值给处理代码,代码就处理组合的键值
1.如果让你设计一个按键模块,你会怎么设计?初学者可能会这样设计
- <span role="presentation"><span class="cm-keyword">if</span>(<span class="cm-variable">readkey_pin</span> <span class="cm-operator">==</span> <span class="cm-number">0</span>)</span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>{</span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-variable">delay</span>(<span class="cm-number">10</span>);</span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-keyword">if</span>(<span class="cm-variable">readkey_pin</span> <span class="cm-operator">==</span> <span class="cm-number">0</span>)</span>
- <span role="presentation"> {</span>
- <span role="presentation"> <span class="cm-comment">//do somthing</span></span>
- <span role="presentation"> }</span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>}</span>
复制代码
有的人会用考虑到实时性,采用中断的方式。
还有的人会使用定时器扫描的方式,也就是优化第一种里面的延时,在主循环里面获取键值。
但是遇到按键多的时候,处理起来比较麻烦,用延时方式肯定是会堵塞其他程序运行,用中断的方式,可能会占用比较多的中断源,所以采用扫描的方式比较合适一般的工程。
2.本框架的实现思路和特点本框架采用扫描的方式,对每一个按键注册相应的功能,对每一个按键进行扫描,如果扫描到某个按键,则进入处理程序处理
采用软件滤波机制,滤波时间可调,长按时间可调,连发加速时间可调,移植方便,通用性强
简单的说就是,你给什么键值过来,我就处理什么键值的按键,然后根据注册的功能返回相应的执行键值(如:A键按下的值是1,那么经过处理,返回A短按键值是0,长按是1,连发是2...)
本框架使用的是读取GPIO高低电平扫描的方式,但是开发板上3个按键都是接入GPIO5,但只有一个是可以直接读取电压,其他两个是需要读取AD值来判断按键,所以本教程需要自己外接按键,也比较符合实际项目中的按键设计处理
3.重点移植代码讲解
程序模块放在key_driver.c 和 key_driver.h 里边
key_driver.c里的枚举设置经过处理的键值,在主程序中根据这些键值进行逻辑处理
- <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n44" mdtype="fences"><span role="presentation">typedef enum</span>
- <span role="presentation">{</span>
- <span role="presentation"><span cm-text=""></span></span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>KEY_DOWN_POWER=1,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* POWER键按下 */</span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>KEY_UP_POWER,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> /* POWER键弹起 */</span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>KEY_LONG_POWER,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> <span class="cm-tab" role="presentation" cm-text=" "> </span>/* POWER键长按 */</span>
- <span role="presentation" class="cm-tab-wrap-hack"><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>KEY_DOWN_ADD,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* ADD键按下 */</span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>KEY_LONG_ADD,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* ADD键长按 */</span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>KEY_DOWN_DEC,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* DEC键按下 */</span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>KEY_LONG_DEC,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* ADD键长按 */</span><span role="presentation" class="cm-tab-wrap-hack"><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>Couple_down,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>//组合按键按下</span>
- <span role="presentation" class="cm-tab-wrap-hack"><span class="cm-tab" role="presentation" cm-text=" "> </span>Couple_long,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span><span role="presentation"><span cm-text=""></span></span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>KEY_REPEAT_POWER,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> /* POWER键连发 */</span>
- <span role="presentation">}KEY_ENUM;</span></pre><p cid="n45" mdtype="paragraph" class="md-end-block md-p"><span md-inline="plain" class="md-plain">头文件宏定义</span></p><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n46" mdtype="fences"><span role="presentation">/* 按键滤波时间50ms, 单位10ms(按键扫描函数要放在10ms定时器或者任务中)</span>
- <span role="presentation"> 只有连续检测到50ms状态不变才认为有效,包括弹起和按下两种事件</span>
- <span role="presentation">*/</span>
- <span role="presentation">#define BUTTON_FILTER_TIME <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>5</span>
- <span role="presentation">#define BUTTON_LONG_TIME <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>200<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* 持续2秒,认为长按事件 */</span>
- <span role="presentation">#define BUTTON_REPEAT_TIME<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>30<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* 300ms 重复按键 */</span>
- <span role="presentation">#define BUTTON_DOWN_TIME<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>10 /* 100ms 按下后20ms执行 */</span>
- <span role="presentation">#define KEY_NONE 0<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* 0 表示按键事件 */</span>
- <span role="presentation"><span cm-text=""></span></span>
- <span role="presentation">#define REPEAT_SPEED_UP_EN 1<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* 重复按键加速,由默认的300ms重复->200ms->100ms->50ms 重复速度越来越快 */</span>
- <span role="presentation">#define SpeedUp_Period<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>3000<span class="cm-tab" role="presentation" cm-text=" "> </span>/* 重复按键切换速度的周期,设定3秒后切换 */</span>
- <span role="presentation"><span cm-text=""></span></span></pre><p cid="n47" mdtype="paragraph" class="md-end-block md-p"></p><p cid="n48" mdtype="paragraph" class="md-end-block md-p"><span md-inline="plain" class="md-plain">BUTTON_T这个结构体是定义一个按键的功能</span></p><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n49" mdtype="fences"><span role="presentation">typedef struct</span>
- <span role="presentation">{</span>
- <span role="presentation">/* 下面是一个函数指针,指向判断按键手否按下的函数 */</span>
- <span role="presentation">uint8_t (*IsKeyDownFunc)(uint8_t buffer); /* 按键按下的判断函数,1表示按下 */</span>
- <span role="presentation">uint8_t Count;<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* 滤波器计数器 */</span>
- <span role="presentation">uint8_t FilterTime;<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* 滤波时间(最大255,表示2550ms) */</span>
- <span role="presentation">uint16_t ShortCount;<span class="cm-tab" role="presentation" cm-text=" "> </span>/* 短按计数器 */</span>
- <span role="presentation">uint16_t LongCount;<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* 长按计数器 */</span>
- <span role="presentation">uint16_t LongTime;<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* 按键按下持续时间, 0表示不检测长按 */</span>
- <span role="presentation">uint8_t State;<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* 按键当前状态(按下还是弹起) */</span>
- <span role="presentation">uint8_t KeyCodeUp;<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* 按键弹起的键值代码, 0表示不检测按键弹起 */</span>
- <span role="presentation">uint8_t KeyCodeDown;<span class="cm-tab" role="presentation" cm-text=" "> </span>/* 按键按下的键值代码, 0表示不检测按键按下 */</span>
- <span role="presentation">uint8_t KeyCodeLong;<span class="cm-tab" role="presentation" cm-text=" "> </span>/* 按键长按的键值代码, 0表示不检测长按 */</span>
- <span role="presentation">uint8_t RepeatSpeed;<span class="cm-tab" role="presentation" cm-text=" "> </span>/* 连续按键周期 */</span>
- <span role="presentation">uint8_t RepeatCount;<span class="cm-tab" role="presentation" cm-text=" "> </span>/* 连续按键计数器 */</span>
- <span role="presentation">uint8_t SpeedUpCount;<span class="cm-tab" role="presentation" cm-text=" "> </span>/* 连发加速计数器 */</span>
- <span role="presentation">}BUTTON_T;</span></pre><p cid="n50" mdtype="paragraph" class="md-end-block md-p"><span md-inline="plain" class="md-plain">使用的时候根据按键的多少来创建多大的结构体数组,本例程使用了4个按键,故设置按键功能的结构体数组如下</span></p><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n51" mdtype="fences"><span role="presentation">BUTTON_T ButtonType[4]={</span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>{</span>
- <span role="presentation"> IsKeyDownPower, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>/* 按键按下的判断函数,1表示按下 */</span>
- <span role="presentation"> BUTTON_FILTER_TIME/2, <span class="cm-tab" role="presentation" cm-text=" "> </span>//单次扫描为10ms</span>
- <span role="presentation"> BUTTON_FILTER_TIME, <span class="cm-tab" role="presentation" cm-text=" "> </span>//滤波时间 0~255 最大2550ms</span>
- <span role="presentation"> 0, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> /* 短按计数器初始值设为0 */</span>
- <span role="presentation"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> /* 长按计数器初始值设为0 */</span>
- <span role="presentation"> BUTTON_LONG_TIME, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>//长按时间 在宏定义设置,这里使用连发或者长按都要设置</span>
- <span role="presentation"> 0, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> //当前按键的状态,初始化为0</span>
- <span role="presentation"> 0, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> //按键抬起的键值,</span>
- <span role="presentation"> KEY_REPEAT_POWER,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>//按键按下的键值,</span>
- <span role="presentation"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> //按键长按键值,设为0则不使能长按<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> </span>
- <span role="presentation"> BUTTON_REPEAT_TIME, <span class="cm-tab" role="presentation" cm-text=" "> </span>//连发周期,也就是隔多久按一下,宏定义修改,这里设置不为0,则使能连发</span>
- <span role="presentation"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span> <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> //连发计数器 </span>
- <span role="presentation"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> //连发加速计数器</span>
- <span role="presentation"> },</span>
- <span role="presentation"> </span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>{</span>
- <span role="presentation"> IsKeyDownAdd, </span>
- <span role="presentation"> BUTTON_FILTER_TIME/2, </span>
- <span role="presentation"> BUTTON_FILTER_TIME, </span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> BUTTON_LONG_TIME, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span> </span>
- <span role="presentation" class="cm-tab-wrap-hack"> KEY_DOWN_ADD, <span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> KEY_LONG_ADD,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation"> 0</span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>},</span>
- <span role="presentation" class="cm-tab-wrap-hack"><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>{</span>
- <span role="presentation"> IsKeyDownDec, </span>
- <span role="presentation"> BUTTON_FILTER_TIME/2, </span>
- <span role="presentation"> BUTTON_FILTER_TIME, </span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> BUTTON_LONG_TIME, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> KEY_DOWN_DEC, <span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> KEY_LONG_DEC, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation"> 0</span>
- <span role="presentation"> },</span>
- <span role="presentation" class="cm-tab-wrap-hack"><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>{</span>
- <span role="presentation"> IsKeyDownDecADD, </span>
- <span role="presentation"> BUTTON_FILTER_TIME/2, </span>
- <span role="presentation"> BUTTON_FILTER_TIME, </span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> BUTTON_LONG_TIME, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> Couple_down, <span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> Couple_long, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0, <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation" class="cm-tab-wrap-hack"> 0,<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span></span>
- <span role="presentation"> 0</span>
- <span role="presentation"><span class="cm-tab" role="presentation" cm-text=" "> </span>},</span>
- <span role="presentation">};</span>
- <span role="presentation"><span cm-text=""></span></span>
- <span role="presentation"><span cm-text=""></span></span>
- <span role="presentation">//获取执行按键是否按下函数 </span>
- <span role="presentation">uint8_t IsKeyDownPower(uint8_t buffer) <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>{if ((buffer == 0x01)) return 1; return 0;} </span>
- <span role="presentation">uint8_t IsKeyDownAdd(uint8_t buffer) <span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>{if ((buffer == 0x02)) return 1; return 0;}<span class="cm-tab" role="presentation" cm-text=" "> </span> </span>
- <span role="presentation">uint8_t IsKeyDownDec(uint8_t buffer) {if ((buffer == 0x04)) return 1; return 0;} </span>
- <span role="presentation">uint8_t IsKeyDownDecADD(uint8_t buffer)<span class="cm-tab" role="presentation" cm-text=" "> </span><span class="cm-tab" role="presentation" cm-text=" "> </span>{if ((buffer == 0x03)) return 1; return 0;}</span></pre><p cid="n52" mdtype="paragraph" class="md-end-block md-p"></p><p cid="n53" mdtype="paragraph" class="md-end-block md-p"></p>
复制代码
注意:
在设置读取键值的时候,应和此处判断是否按下的键值一致
如 uint8_t IsKeyDownPower(uint8_t buffer) {if ((buffer == 0x01)) return 1; return 0;}
此处函数键值设为1,则读取到的某个按键键值应设置为 1
1.在设置按键功能的时候应注意逻辑冲突,如按键抬起的键值,不建议和其他功能一起使用,比如同时设置了按下触发和抬起触发,那么就会返回两个值,一个是按下的一个是抬起的,除非你的项目真的需要这样的处理。
2.设置连发应注意不要使能长按,连发的机制是超过了长按的时间就会触发,如果你使能了长按的键值,那么就会先返回长按的键值,再触发连发
3.使能连发需把连发触发周期值设置,和按下的键值,连发就是返回你多次按下的键值,所以需要设置
4.使能连发加速 需要在宏定义使能 REPEAT_SPEED_UP_EN 设为 1
当构建完按键功能函数之后,只需要在定时器中或者任务中调用 bsp_KeyPro(uint8_t _KeyCode); KeyCode为读取到IO口的键值,周期为10ms
获取经过处理的键值函数为 uint8_t bsp_GetKey(void),就可以获取经过处理的键值了
在Hi3861上移植步骤1.创建按键组合创建一个.c文件用来处理执行扫描函数
先定义处理一下按键组合,此处定义了3个按键,但是处理函数那里初始化了4个,因为有判断函数,如果没有获取到那个键按下,是不会处理相应的功能的,这里是为了演示,实际项目中应注意节省空间
#define G_SET_BIT(a,b) (a |= (1 << b))
#define G_CLEAR_BIT(a,b) (a &= ~(1 << b))
#define KEY_NUM 3
//这里定义的按键IO口为GPIO0 1 2
WifiIotGpioIdx key_io_array[KEY_NUM] = {WIFI_IOT_IO_NAME_GPIO_0, WIFI_IOT_IO_NAME_GPIO_1, WIFI_IOT_IO_NAME_GPIO_2}; //IO口数组
WifiIotGpioValue singlekey_value_array[KEY_NUM] = {1, 1, 1}; //设置上拉输入,没有按下的时候是1
创建一个任务,初始化按键IO口,并执行
void Key_Function_Init(void)
{
osThreadAttr_t attr;
GpioInit();
//复用引脚为GPIO
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_0, WIFI_IOT_IO_FUNC_GPIO_0_GPIO);
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_1, WIFI_IOT_IO_FUNC_GPIO_1_GPIO);
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_GPIO);
//设置为输入
GpioSetDir(WIFI_IOT_IO_NAME_GPIO_0, WIFI_IOT_GPIO_DIR_IN);
GpioSetDir(WIFI_IOT_IO_NAME_GPIO_1, WIFI_IOT_GPIO_DIR_IN);
GpioSetDir(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_GPIO_DIR_IN);
//设置上拉输入
IoSetPull(WIFI_IOT_IO_NAME_GPIO_0, WIFI_IOT_IO_PULL_UP);
IoSetPull(WIFI_IOT_IO_NAME_GPIO_1, WIFI_IOT_IO_PULL_UP);
IoSetPull(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_PULL_UP);
attr.name = "Key_Scan_Task";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024;
attr.priority = 26;
if (osThreadNew((osThreadFunc_t)Key_Scan_Task, NULL, &attr) == NULL) {
printf("[Key_Scan] Falied to create Key_Scan_Task!n");
}
printf("Key scan task init succes!rn");
}
SYS_RUN(Key_Function_Init);
然后在任务函数中扫描按键,并把键值放进按键处理函数
void *Key_Scan_Task(const char arg[])
{
(void)arg;
bsp_InitButtonQueqe();
uint8_t Key_Value = 0;
while (1)
{
for (uint8_t i = 0; i < KEY_NUM; i++) //这样处理就可以比较方便的获得组合按键的键值
{
GpioGetInputVal(key_io_array
, &singlekey_value_array);
if (singlekey_value_array == 0)
{
G_SET_BIT(Key_Value, i);
}
else
{
G_CLEAR_BIT(Key_Value, i);
}
}
bsp_KeyPro(Key_Value);
// printf("Keyvalue is %d!rn", Key_Value);
usleep(10000); //10ms
}
return NULL;
}
外部文件调用按键模块既然按键模块做好了,那实际应用应该是在主函数中调用的,对吧,那么我们只需把这个按键模块包含到你的主函数中,再包含头文件,再获取按键就行了。
1.先把按键模块编进系统,在application/sample/wifi-iot/app/BUILD.gn 中添加编译指令
我的主函数是mainapp,所以需要另外创建一个app(小白可以直接用官方教程Hi3861开发板第二个示例程序(my_first_app))作为主函数调用各个模块
然后修改你的主函数下的BUILD.gn,包含按键模块的路径
最后可以在主函数中调用按键模块啦
先包含头文件
#include "key_driver.h"
然后创建一个任务,在任务函数的while(1)里面添加
- <span role="presentation"> if(bsp_GetKey() > 0)</span>
- <span role="presentation"> {</span>
- <span role="presentation"> printf("key value is %d rn",bsp_GetKey()); </span>
- <span role="presentation"> }</span>
复制代码
打印的数字即为你设定的返回的键值
总结实话说,这个框架不是特别好,主要还是在使能按键功能这里,需要设置的参数比较多,另外没有加入双击,下一版本优化一下吧。
打算下个教程把这个AD检测的按键处理方式给加进去,方便更多人使用