按键通常有: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);// 记录按键按下标志,等待释放
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』