13315|42

7815

帖子

57

TA的资源

裸片初长成(中级)

楼主
 

你是怎么写 (底层)读键程序的(最多可有150个芯币奉送) [复制链接]

 
我在发上一个帖子的时候

[原创文章] 底层读键 的 两种简单思路 的 空间 时间 开销 简单测试
https://bbs.eeworld.com.cn/thread-487709-1-1.html

忽然在想,我一直以来习惯的读键程序的写法,是如此这般,但我不知道你们一般是怎么写的。

是单纯在定时器中周期性扫描,还是利用外部中断,在检测到有按键按下时,才开始扫描,还是怎样?

欢迎你详细说说你的 读键/按键扫描 程序思路。

要特别注意的是,除了底层的实现方案,更重要的是如何调用,和程序的其他部分如何配合。

欢迎回帖,每个描述完整的方案 版主送 50个芯币,如果有带(演示性的)简单程序(即可)
再另外加100个芯币。

总额1000个芯币,送完即止。
此帖出自编程基础论坛

最新回复

本帖最后由 damiaa 于 2017-9-18 11:49 编辑 打土豪,分田地!!! 定时器里一次处理,定时器响应时间可以拉长点。比如10MS, 20MS 看情况来。    防抖动,键盘扫描。得出建值,还有是按下,还是弹起,长按,短按等。这里不要浪费时间。特别不能有延时之类的东西。快进快出。 主程序只要查看是否有键按下,键值多少,是长按还是短按就可以随意处理了。具体的在下面: https://bbs.eeworld.com.cn/thread-501060-1-1.html   详情 回复 发表于 2017-9-18 11:43
点赞 关注(7)
个人签名

强者为尊,弱者,死无葬身之地

 

回复
举报

6040

帖子

204

TA的资源

版主

沙发
 
土豪啊,啥时候又攒了8000多芯币了!
此帖出自编程基础论坛
 
 
 

回复

855

帖子

5

TA的资源

一粒金砂(高级)

板凳
 
FIFO
此帖出自编程基础论坛
 
个人签名作为一个菜逼,干货并没有多少。唯一会的就是水,所以回帖水分大。望见谅!
 
 

回复

85

帖子

0

TA的资源

一粒金砂(中级)

4
 
打土豪! 习惯用定时器,每1-10ms扫描行并读取列,时间根据按键数目选择,如果键少扫描时间就可以长点,里面包括去抖动。 也用过FPGA自动扫描并通过编码产生中断读取键值编码。至于用专门的IC,没用过毕竟浪费资源
此帖出自编程基础论坛
 
 
 

回复

650

帖子

8

TA的资源

纯净的硅(初级)

5
 
首先按键硬件接法有两种,一种就是普通IO口矩阵方式,这种我用定时扫描;另一种就是AD采样,最近在用这种,感觉这种方式比较好,就根据AD值判断按键即可。
此帖出自编程基础论坛
 
 
 

回复

1234

帖子

4

TA的资源

纯净的硅(高级)

6
 
写底层按键有过几次变化
最开始学习编程的时候在主程序里 扫描按键--延时消抖--扫描按键(确认按键)--键值处理--循环下去
渐渐的发现,只要外设稍微多一点,加上这种按键程序,时间就像是卡住了一样,整体下来效率不高

后来用了定时器,这一个转折,定时100ms,扫描按键直接加上键值处理,将键值交给主程序,效率也提升了不少

再到后来看来别人的三段代码

    unsigned char ReadData = PINB^0xff;   // 1
    Trg = ReadData & (ReadData ^ Cont);      // 2
    Cont = ReadData;                                // 3

当时心里很激动 我决定要加入到我的单片机里去与是就出现了(stm32f1)

void Key_scan(void)                                               //按键扫描并做出状态的改变
{
    u16 ReadData = (GPIO_ReadInputData(GPIOB)&0x0220);      //9脚和5脚 //
    ReadData = ReadData^0xffff;                                                // 1 对按键状态
   Trg = ReadData&(ReadData^Cont);                                      // 2 有触发为1,无触发以及久按为0
   Cont = ReadData;                                                                 // 3 保存按键状态
   if((Trg&0x0200)&&(Cont&0x0220)){                                   //当9脚按下就可以直接处理
    ....                                                                                   
  }
}

至此 我还一直保持这种方式,很轻松 很愉快
此帖出自编程基础论坛
 
个人签名天地庄周马;江湖范蠡船。
个性签名还是放QQ号吧,2060347305,添加说明EEworld好友
 
 

回复

366

帖子

1

TA的资源

一粒金砂(高级)

7
 
我一般是设置一个队列存放键值,然后在主函数中查询。扫描的话按键数量少就用中断,按键数量多就开一个定时器来扫描。如果有键按下就把相应的键值入队。主函数中出队,如果是非零键值,则调用相应的按键服务函数。队列我是用数组实现的循环队列。

static unsigned char MatKey_Buff[ MAT_KEYBUFF_SIZE ]; //定义键盘缓冲队列数组(FIFO)
static unsigned char MatKey_IndexW = 0;          //键盘缓冲队列写入指针(头指针)
static unsigned char MatKey_IndexR = 0;          //键盘缓冲队列读取指针(尾指针)
static unsigned char MatKey_Count = 0;           //键盘缓冲队列内记录的按键次数

/****************************************************************************
* 名    称:Key_InBuff()
* 功    能:将一次键值压入键盘缓冲队列
* 入口参数:Key:被压入缓冲队列的键值
* 出口参数:无
****************************************************************************/
static void Key_InBuff(unsigned char Key){
    if( MatKey_Count >= MAT_KEYBUFF_SIZE ) return;//若缓冲区已满,放弃本次按键
    MatKey_Count++;                       //按键次数计数增加
    MatKey_Buff[ MatKey_IndexW ] = Key;         //从队列头部追加新的数据
    if ( ++MatKey_IndexW >=  MAT_KEYBUFF_SIZE ){//循环队列,如果队列头指针越界
        MatKey_IndexW = 0;                  //队列头指针回到数组起始位置
    }
}

/****************************************************************************
* 名    称:Key_GetKey()
* 功    能:从键盘缓冲队列内读取一次键值
* 入口参数:无
* 出口参数:若无按键,返回0,否则返回一次按键键值。
* 说    明: 调用一次该函数,会自动删除缓冲队列里一次按键键值。
****************************************************************************/
unsigned char Key_GetKey(void){
    unsigned char key_key;
    if(MatKey_Count==0)  return(0); //若无按键,返回0
    _DINT();
    MatKey_Count--;              //按键次数计数减1
    key_key = MatKey_Buff[ MatKey_IndexR ];    //从缓冲区尾部读取一个按键值
    if ( ++MatKey_IndexR >= MAT_KEYBUFF_SIZE ){//循环队列,如果队列尾指针越界
        MatKey_IndexR = 0;       //队列尾指针回到数组起始位置
    }
    _EINT();
    return( key_key );
}
此帖出自编程基础论坛
 
 
 

回复

137

帖子

0

TA的资源

一粒金砂(中级)

8
 
我的思路估计是最大路货的  但是也是最简单实用的 .

定时器,置位时标,如果10ms 或者20ms的时间标记.

但是确保后台是个近乎于没有延时的大循环,

在这个大循环中,  keyscan模块不断的在时间标记的引导下,对按键所在io 进行扫描,

然后有一定的状态机对按键键值的情况,进行记录,

与keyscan模块对应的是KeyProc按键处理循环,对按键的扫描结果有一个消息机制, 一旦有有效按键,则启用对应按键类型和兼职的事件处理函数 .
此帖出自编程基础论坛
 
个人签名 与时间赛跑
 
 

回复

1658

帖子

1

TA的资源

纯净的硅(高级)

9
 
如果按键比较少,或者有些按键优先级比较高,我直接用中断处理

另外,就是采用状态机了(分 READY,MIDDLE,DOWN,RELEASE四个状态)
因为系统轮转有个时间,每次轮转扫描一次,每次扫描不使用延时,具体延时由轮转时间的次数决定,自认为效率比较高

        switch(Key_State[0])                //按键 K1 扫描
        {
                case        READY:          // 确认按下,检测到键位变化
                                        if(HAL_GPIO_ReadPin(GPIO_S1,S1)==0){Key_State[0]=MIDDLE;key_num[0]=1;}
                                        break;
                case        MIDDLE:                // 中间状态,软件延时,时长 KEY_Period = 20ms
                                        key_num[0]=key_num[0]+1;
                                        if(key_num[0]>=KEY_Period)
                                                {
                                                        if(HAL_GPIO_ReadPin(GPIO_S1,S1)==0)Key_State[0]=DOWN;
                                                                else Key_State[0]=READY;
                                                        key_num[0]=0;
                                                }
                                        break;
                case        DOWN:                // 确认按下,如需要可添加响应动作
                                        if(HAL_GPIO_ReadPin(GPIO_S1,S1)==1)Key_State[0]=RELEASE;
                                        break;
                case        RELEASE:// 确认按键释放,如需要可添加响应动作       
                                        HAL_GPIO_TogglePin(GPIO_K,K1);       
                                        Last_key=0;
                                        Key_State[0]=READY;
                                        break;
                default:
                                        Key_State[0]=READY;
                                        break;
        }


此帖出自编程基础论坛
 
 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

10
 
好,我会给钱的~~不过现在还没看,我是来回 水饺 的帖子 的~~~~~~~
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

6423

帖子

16

TA的资源

版主

11
 
开发板一般都是带的轮询扫描,但是这个实在效率太低,改中断加扫描,再有就是使用编码芯片
此帖出自编程基础论坛
 
个人签名training
 
 

回复

2721

帖子

0

TA的资源

纯净的硅(中级)

12
 
中断扫描
此帖出自编程基础论坛
 
 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

13
 
lr_xgm 发表于 2016-4-13 09:06
打土豪! 习惯用定时器,每1-10ms扫描行并读取列,时间根据按键数目选择,如果键少扫描时间就可以长点,里 ...

你这个,应该是惯用了矩阵按键的组织方式?
我只是有一点小疑问:那你这样不是每次去抖的效果不一样?毕竟延迟的时间不一样。
至于用特定硬件,我的想法和你一样。
没必要,这么简单的东西,另外增加硬件,比起软件,代价太大,这里说的不只是器件的费用。

不过不管如何,你是第一个,50个芯币是你的了。
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

14
 
29447945 发表于 2016-4-13 09:12
首先按键硬件接法有两种,一种就是普通IO口矩阵方式,这种我用定时扫描;另一种就是AD采样,最近在用这种, ...

AD那种方式我听说过,但自己没做过。
我就想知道,是不是通过开关改变电阻网络的阻值,来实现效果的。
我就不知道一般你们是怎么具体做的,需要给他多大的电流,会不会功耗大了些?

至于说用AD高射炮打蚊子这种事情我倒是不怎么在意,毕竟资源富足的情况下,不用白不用。
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

15
 
29447945 发表于 2016-4-13 09:12
首先按键硬件接法有两种,一种就是普通IO口矩阵方式,这种我用定时扫描;另一种就是AD采样,最近在用这种, ...

哦,还有,第二个50个芯币,是你的了
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

16
 
ywlzh 发表于 2016-4-13 13:02
写底层按键有过几次变化
最开始学习编程的时候在主程序里 扫描按键--延时消抖--扫描按键(确认按键)--键 ...

我和你的思路过程类似。
说到你最后提到这种思路,不知道是不是在我们版块里一个老帖子看过的,我当时还专门好好看了他那个帖子并发了一个帖子。

说实在的,那个操作确实写得非常精彩,也让我激动了好一阵子。

可惜的是,如同 @freebsder说的,这个 位操作虽然精彩,但是却没有处理按键的一些根本性的问题,所以只是局部很精彩,对读键思路产生了多大的冲击。
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

17
 
ywlzh 发表于 2016-4-13 13:02
写底层按键有过几次变化
最开始学习编程的时候在主程序里 扫描按键--延时消抖--扫描按键(确认按键)--键 ...

哦,对了,第三个50个芯币
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

18
 
本帖最后由 辛昕 于 2016-4-17 20:49 编辑
飞翔荷兰人号 发表于 2016-4-13 13:54
我一般是设置一个队列存放键值,然后在主函数中查询。扫描的话按键数量少就用中断,按键数量多就开一个定时 ...

不好意思,我又认真看了你的思路,发现你这个方案其实只是处理读键。并没有神马和其他的混合勾搭在一起。
不过,我就是不太明白,是什么样的调用机制,需要让你采用队列来存储键值?
毕竟,一个纯粹的数组,也就是一个普通的线性表,比起一个队列,还是要更小开销更简单?

这个思路,对于我来说,略有点新鲜。
说新鲜是因为,在单独的按键处理这么底层的位置,我很少采取这种方法。
但是也算不上陌生,因为在做UI的输入处理时,我其实采用的就是这种思路。
不过我只是提供了一个键值缓冲,还不需要动用队列。

不过虽然我没用过这种思路,但可以预见的是,这种思路下组织的读键函数可以轻易处理连键和长短键等复合操作。另外就是这个模块稍作扩展,已经可以作为一个最基本的 消息机制 了。
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

19
 
飞翔荷兰人号 发表于 2016-4-13 13:54
我一般是设置一个队列存放键值,然后在主函数中查询。扫描的话按键数量少就用中断,按键数量多就开一个定时 ...

思路+代码,而且很完整,还颇有新意
150,u got it。
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

20
 
xinxiaojun 发表于 2016-4-13 19:28
我的思路估计是最大路货的  但是也是最简单实用的 .

定时器,置位时标,如果10ms 或者20ms的时间标记.

...

这个思路,从描述来看,属于一般的扫描 和 上述 那种采用键值对列的 思路中间。
比前者要完善一些,比后者还欠缺一些。

不过说真的,我个人认为,这样不上不下还不如,要么彻底简单到不涉及任何其他应用的处理方式,比如状态机。要么就干脆一步到位,融合到整体的一部分,就像上面那个键值对列的思路。

当然,这个采取各人的想法,只是说说看法而已,并无优劣之分。

50个芯币u got it
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表