历史上的今天
返回首页

历史上的今天

今天是:2025年03月06日(星期四)

正在发生

2020年03月06日 | MCU实战经验:多种的按键处理

2020-03-06 来源:eefocus

按键通常有:IO口按键(BUTTON),AD按键(通过AD采样电压),IR(遥控器)

按按键功能分:有短按键,长按键,连续按键。打个比方,遥控电视机,按一下音量键,音量增加1,这个就是短按键。按住音量键不放,音量连续加,这个就是连续按键。按住一个按键5s,系统会复位,这个是长按键。


1、IO口按键,就是我们比较常见的一个IO接一个按键,或者是一个矩阵键盘。很多新人的处理方法可能是采样延时的方法,当年我也是这样的,如下


   if(GETIO==low)

    { 

      delay_10ms()

      if(GETIO==low)

      {

        //得到按键值

      }

    }


这种方法虽然简单,但是有很大弊端。首先 Delay浪费很多时间,影响系统。第二,无法判断长短按键,连续按键。第三,如果这个按键是开关机按键系统在低功耗状态下,需要中断唤醒,这种方法比较容易出问题,如STM8S系列的 halt 模式。


所以我们一般在产品开发的过程中,采用扫描的方法,就是每隔10ms 去检测IO的状态,看是否有按键,然后去抖动,判断按键功能。参考代码如下,这段代码是之前在一个论坛看到的比我自己写的更加优秀,所以拿出来和大家分享一下,也顺便感谢一下作者。这段代码,容易修改,可以根据自己的时间需要,进行长短按键,连续按键,还有组合按键的判断。

   

/* 按键滤波时间50ms, 单位10ms

 *只有连续检测到50ms状态不变才认为有效,包括弹起和按下两种事件

 */

#define BUTTON_FILTER_TIME         5

#define BUTTON_LONG_TIME         300                /* 持续1秒,认为长按事件 */

 

/*

        每个按键对应1个全局的结构体变量。

        其成员变量是实现滤波和多种按键状态所必须的

*/

typedef struct

{

        /* 下面是一个函数指针,指向判断按键手否按下的函数 */

        unsigned char  (*IsKeyDownFunc)(void); /* 按键按下的判断函数,1表示按下 */

 

        unsigned char  Count;                        /* 滤波器计数器 */

        unsigned char  FilterTime;                /* 滤波时间(最大255,表示2550ms) */

        unsigned short LongCount;                /* 长按计数器 */

        unsigned short LongTime;      /* 按键按下持续时间, 0表示不检测长按 */

        unsigned char   State;        /* 按键当前状态(按下还是弹起) */

        unsigned char  KeyCodeUp; /* 按键弹起的键值代码, 0表示不检测按键弹起 */

        unsigned char  KeyCodeDown;   /* 按键按下的键值代码, 0表示不检测按键按下 */

        unsigned char  KeyCodeLong;  /* 按键长按的键值代码, 0表示不检测长按 */

        unsigned char  RepeatSpeed;        /* 连续按键周期 */

        unsigned char  RepeatCount;        /* 连续按键计数器 */

}BUTTON_T;

 

typedef enum

{

        KEY_NONE = 0,                        /* 0 表示按键事件 */

 

        KEY_DOWN_Power,                        /* 按键键按下 */

        KEY_UP_Power,                        /* 按键键弹起 */

        KEY_LONG_Power,                        /* 按键键长按 */

        

        KEY_DOWN_Power_TAMPER        /* 组合键,Power键和WAKEUP键同时按下 */

}KEY_ENUM;

 

BUTTON_T s_Powerkey;                

//是否有按键按下接口函数

unsigned char  IsKeyDownUser(void)                 

{if (0==GPIO_ReadInputPin(POWER_KEY_PORT, POWER_KEY_PIN) ) return 1;return 0;}

 

 

 void  PanakeyHard_Init(void)

{

   GPIO_Init (POWER_KEY_PORT, POWER_KEY_PIN, GPIO_MODE_IN_FL_NO_IT);//power key

}

 void  PanakeyVar_Init(void)

{

        /* 初始化USER按键变量,支持按下、弹起、长按 */

        s_Powerkey.IsKeyDownFunc = IsKeyDownUser;                /* 判断按键按下的函数 */

        s_Powerkey.FilterTime = BUTTON_FILTER_TIME;                /* 按键滤波时间 */

        s_Powerkey.LongTime = BUTTON_LONG_TIME;                        /* 长按时间 */

        s_Powerkey.Count = s_Powerkey.FilterTime / 2;                /* 计数器设置为滤波时间的一半 */

        s_Powerkey.State = 0;                                                        /* 按键缺省状态,0为未按下 */

        s_Powerkey.KeyCodeDown = KEY_DOWN_Power;                        /* 按键按下的键值代码 */

        s_Powerkey.KeyCodeUp =KEY_UP_Power;                                /* 按键弹起的键值代码 */

        s_Powerkey.KeyCodeLong = KEY_LONG_Power;                        /* 按键被持续按下的键值代码 */

        s_Powerkey.RepeatSpeed = 0;                                                /* 按键连发的速度,0表示不支持连发 */

        s_Powerkey.RepeatCount = 0;                                                /* 连发计数器 */                

}

void Panakey_Init(void)

{

        PanakeyHard_Init();                /* 初始化按键变量 */

        PanakeyVar_Init();                /* 初始化按键硬件 */

}

/*

*********************************************************************************************************

*        函 数 名: bsp_DetectButton

*        功能说明: 检测一个按键。非阻塞状态,必须被周期性的调用。

*        形    参:按键结构变量指针

*        返 回 值: 无

*********************************************************************************************************

*/

 void Button_Detect(BUTTON_T *_pBtn)

{

        if (_pBtn->IsKeyDownFunc())

        {

                if (_pBtn->Count < _pBtn->FilterTime)

                {

                        _pBtn->Count = _pBtn->FilterTime;

                }

                else if(_pBtn->Count < 2 * _pBtn->FilterTime)

                {

                        _pBtn->Count++;

                }

                else

                {

                        if (_pBtn->State == 0)

                        {

                                _pBtn->State = 1;

 

                                /* 发送按钮按下的消息 */

                                if (_pBtn->KeyCodeDown > 0)

                                {

                                        /* 键值放入按键FIFO */

                                        Pannelkey_Put(_pBtn->KeyCodeDown);// 记录按键按下标志,等待释放

 

                                }

                        }

 

                        if (_pBtn->LongTime > 0)

                        {

                                if (_pBtn->LongCount < _pBtn->LongTime)

                                {

                                        /* 发送按钮持续按下的消息 */

                                        if (++_pBtn->LongCount == _pBtn->LongTime)

                                        {

                                                /* 键值放入按键FIFO */

                                                Pannelkey_Put(_pBtn->KeyCodeLong);        

                                

                                        }

推荐阅读

史海拾趣

EMBEST公司的发展小趣事

EMBEST公司成立于XXXX年,早期便专注于ARM嵌入式软件的开发。在XXXX年,EMBEST发布了国内首个具有自主知识产权的ARM嵌入式软件开发工具Embest IDE For ARM,这一里程碑式的产品不仅填补了国内市场的空白,也为EMBEST在嵌入式领域的地位奠定了基础。通过持续的创新和研发,EMBEST逐步建立了自己的技术壁垒,为公司的长远发展奠定了坚实基础。

Grayhill公司的发展小趣事
如汽车音响、车载充电器等需要稳定电压和电流的电子设备。
AF International公司的发展小趣事

随着公司业务规模的不断扩大,AF International意识到建立完善的质量管理体系至关重要。公司引进了先进的质量管理理念和方法,建立了严格的质量控制流程,确保从原材料采购到产品生产的每一个环节都符合质量标准。同时,AF International还加强了对员工的培训和教育,提高员工的质量意识和操作技能。这些措施使得公司的产品质量得到了有效保障,赢得了客户的广泛赞誉。

Acutechnology公司的发展小趣事

随着国内市场的逐渐饱和,Acutechnology公司开始将目光投向国际市场。公司制定了国际化发展战略,通过在海外设立分支机构、参加国际展会等方式拓展海外业务。同时,公司还积极引进国际先进技术和管理经验,提升企业的整体竞争力。这些举措为公司的长远发展注入了新的活力。

APC (APC by Schneider Electric)公司的发展小趣事

在电子行业的早期,电源的稳定性是许多企业和个人用户面临的一大难题。正是在这样的背景下,APC公司凭借其敏锐的市场洞察力,将重心放在小型桌面不中断电力供应(UPS)系统的电源保护及开发上。1984年,APC推出了公司的首个UPS产品,为PC、PC服务器及其网络提供了可靠的电力保障。这一创新举措不仅解决了当时的电力供应问题,更为APC在UPS电源保护领域奠定了坚实的基础。

富士康(FOXCONN)公司的发展小趣事

随着技术的不断积累与突破,FMS在二极管及MOSFET等产品的设计与制造上取得了显著成就。公司不仅成功研发出多款高性能产品,还通过了ISO9001、ISO14001、IATF16949等品质认证,以及AEC-Q101等车规元件验证程序。这些认证不仅证明了FMS产品的卓越品质,也为其进一步拓展汽车、工业、通信等高端市场提供了有力保障。

问答坊 | AI 解惑

USB控制器芯片按功能分类的特性比较

引   言         通用串行总线USB是以主机为中心的分层星型总线拓扑结构实现与外设的连接,软件比较复杂,对功率要求也比较高,所以在推出后的一段时期内,USB在基于PC的系统中得到了广泛应用,而在嵌入 ...…

查看全部问答>

基于KEELOQ跳码技术的密码发生器设计

基于密码的访问控制系统应用在当今是非常普遍的,但人们对其提供的安全等级经常估计过高。通信传输速度和系统计算能力的提高使得系统受到恶意攻击或“密码扫描”的风险增加。在使用不安全的传送方式时,可能发生密码被盗取的现象。例如典型的通过电 ...…

查看全部问答>

PLATFORM BUILD 和IAR5.2的关系

各位大虾好,有个问题向大家请教:小弟正在搞wince 5.0的开发工作,现在刚作好SBOOT,生成了SBOOT.bin,SBOOT.nb0,SBOOT.exe,现在我又装好了IAR5.2,并把SBOOT下的startup.s及.c文件和需要的.h文件加入到工程之中,但发现有好多问题 1:在PB5.0下编译通过 ...…

查看全部问答>

添加记录问题

Imports System.Data.SqlServerCe Imports System.IO Public Class Form2     Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load        &nbs ...…

查看全部问答>

诚心请教open at 开发问题,请各位大侠进来看看。

     小女子刚接触无线通信,用Q24PL模块,做一些应用程序,手里有一本书,。在open at 的开发环境下编程,以前只会纯粹的C,现在想用VC编,生成目标文件下载到模块里实现,打电话、发短信、GPRS上网,等一些常用功能。   ...…

查看全部问答>

AVR中怎么象51那样把不变的数据存到代码段?

最近 做东西需要很多数据的存储但是空间有限啊就是要把一些不变的制度数据存到其他的地方中去,以免占用太多的数据存储空间。。…

查看全部问答>

Nand Flash 分区只得到一半的容量?

wince5.0 下 flash是 1G bytes 的,型号K9K8G08U0M 分号区后,我在存储管理器中看到,容量:960M,未分配的:896M,我只分到64M. 问题: 1、怎样我才能将未分配的容量加分出来呢? 2、OS是通过哪个函数分得64M的呢,FMD_ReadSector()?我驱 ...…

查看全部问答>

CAB安装包修改注册表问题

各位大虾,       小弟需要一个将一个.dll文件打包安装到设备,同时修改注册表.我的.inf文件已经写好了,能正确生成.cab文件, 现在就是不知道怎么才能修改注册表,那位兄弟能指点以下?谢了。…

查看全部问答>

自己做板子终于能连上DSP

自己做板子终于能连上DSP了。 先冷静下,再load程序,希望一切顺利。 这的代价是毁了一个DSP加两块板子。 …

查看全部问答>

创意盲文手机:接通的不仅仅是电话

创意盲文电话:接通的不仅仅是电话最近热播的中国移动最新广告,打动了无数人的情绪,就像安静水面掉入的一个小石块,激起层层涟漪,让我们的内心久久不能安静,这样的创意应当受到感谢的掌声。同样,这款创意盲文手机,也是一个巨大的创意,也许它 ...…

查看全部问答>