MCU实战经验:多种的按键处理

2020-03-06来源: eefocus关键字:MCU  IO口  按键处理

按键通常有: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);// 记录按键按下标志,等待释放

 

[1] [2] [3]
关键字:MCU  IO口  按键处理 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic490675.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM8S触摸按键固件库详解
下一篇:STM8L052定时器1配置30S

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

瑞萨蓝牙5 32位MCU助力工程师快速着手开发
全球领先的半导体解决方案供应商瑞萨电子株式会社推出首款集成了蓝牙5(Bluetooth® 5)的RA微控制器(MCU)产品RA4W1,支持低功耗蓝牙。在单芯片56引脚QFN封装内集成了48 MHz 32位Arm® Cortex®-M4内核和蓝牙5内核。RA4W1 MCU与易用的灵活配置软件包(FSP)相结合,加上Arm生态系统中支持RA MCU开箱即用的软硬件模块,可帮助工程师即刻启动开发。 RA4W1 MCU可帮助嵌入式设计人员轻松地为工业4.0、楼宇自动化、计量、医疗、消费类可穿戴设备及家电等应用开发安全可靠的物联网终端设备。此款MCU还非常适合构建用于无线传感网络的IoT边缘设备、IoT集中器、网关附加
发表于 2020-05-07
瑞萨蓝牙5 32位MCU助力工程师快速着手开发
【PIC32MZ】点亮LED
MCU开发第一步都是点亮LED,就跟软件的Hello World一样,先开始第一步吧。新建一个项目,参考开发环境搭建,具体我就不写了。1、配置时钟,这个在Clock Diagram中配置,点击Auto-Calculate,输入系统主频即可,最高可达252MHz,这里没有涉及到其他外设,仅设置主频即可。2、选择服务,由于GPIO只能使用Static,并且系统已经默认配好,那么就不需要自己配置Driver了。在System Services中勾选Clock和Ports即可。3、配置端口,在PinSetting配置区,我们配置RH0,RH1,RH2三个LED,Order设为Ports,找到RH进行配置,Direction为Out
发表于 2020-04-28
【PIC32MZ】点亮LED
RTX51 tiny——51MCU上的多任务操作系统
软件设计工作。2、MCU的利用率更高,系统的响应性更好。程序里通常需要延时程序,不用RTX51(tiny)的话,通常的做法是让CPU不断循环执行一段无用的代码来消耗时间,在执行延时函数时,MCU无法执行其他代码,而使用了RTX51后,不再需要自己编写延时函数,使用RTX51(tiny)内核提供的os_wait函数可以更加精确地进行延时,而且在等待延时完毕的过程中,MCU是在执行其他任务,一旦延时时间到达,MCU会跳回原任务继续往下执行代码。3、对防破解防盗版有一定作用。使用了操作系统后,编译出来的二进制代码包括了操作系统的代码,其中有大量的跳转、中断切换、堆栈操作指令,很难跟踪执行。盗版者能复制出一样功能的软硬件,但很难对软件进行
发表于 2020-04-28
基于于HMR3000和MCU实现车辆模拟驾驶动感数据采集系统的设计
按照指定的工作模式发送数据,一般会选择连续工作方式。需要查询当前的数据状态和具体数值时需要使用查询指令。HPR格式的查询指令为$PTNT,HPR*78 ∥查询HPR格式的数据状态3.1.6 HMR3000与MCU的接口连接由于HMR3000与外界的串行通信采用的是自身所带的RS-232接口,与MCU串行数据传输的TTL电平不匹配,所以需要MAX232型电平转换器,如图1所示。3.2 动感数据无线收发系统动感数据无线收发系统采用nRF905型无线收发模块,该模块具有以下突出特点:●三频段收发合一,工作频率为国际通用的ISM频段433/868/915 MHz;●GMSK调制,抗干扰能力强,特别适合工业控制领域;●采用DSS+PLL频率
发表于 2020-04-26
基于于HMR3000和MCU实现车辆模拟驾驶动感数据采集系统的设计
CAN BUS的架构特点、应用优势与实例分析
由于汽车产业不断追求安全可靠、极致性能、舒适方便以及低成本等目标,但汽车内高复杂的系统网络,使得线束过于庞大,导致成本提高且网络架构也难以持续提升,与前者形成冲突。于是德国Bosch在1985年提出CAN BUS(Controller Area Network),不但解决了车内线束持续增加的问题,还为日后可靠且有效率的网络系统垫定了基础。1993年,CAN BUS更制定为标准化(ISO-11898),由于具有高可靠性和错误检测能力,也被广泛应用在船舶、航空电子、大众交通、农用设备、医疗设备、工业控制中。CAN BUS的架构与特色CAN BUS是一种串行双线式差分传输的技术规格(见图1),MCU负责运算数据,CAN
发表于 2020-04-17
CAN BUS的架构特点、应用优势与实例分析
Flash、MCU、DRAM,兆易创新三驾马车并驾齐驱
;根据最新财报显示,2019财年,兆易创新营收约32亿,比去年同期增长42.62%;归属于上市公司股东的扣除非经常性损益的净利润5.65亿,比去年同期增长56.7%。其中,存储芯片毛利提升贡献了超7成营收,微控制器(MCU)业务营收持续提升,传感器业务也开始崭露头角。                                                兆易创新代理总经理何卫表示,过去
发表于 2020-04-15
Flash、MCU、DRAM,兆易创新三驾马车并驾齐驱
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved