一、说明
通过按键来读取按下按键信息,可以实现单机、双击和长按的状态
二、硬件电路
1.开机电路设计
三、软件设计
1.按键初始化略过
/**按键通道数以及数据读取*/
#define PIOS_KEY_NUMBERS 2 //通道数量
#define PIOS_KEY_POWER 0 //电源键
#define PIOS_KEY_FUNCTION 1 //多功能按键
//按键更新时各个状态
typedef enum
{
KEY_STATE_RELEASE = 0, /**< enum 0 状态--释放按键. */
KEY_STATE_PRESS, /**< enum 1 状态--按下按键. */
KEY_STATE_PRESS_FILTER, /**< enum 2 状态--消抖后仍按下. */
KEY_STATE_HOLD, /**< enum 3 状态--长按按键. */
KEY_STATE_DOUBLE, /**< enum 4 状态--双击按键. */
} KeyStateType;
//按键编码动作
typedef enum
{
KEY_NONE = 0, /**< enum 0 按键空. */
KEY_TOGGLE, /**< enum 1 按键短按. */
KEY_HOLD, /**< enum 2 按键长按. */
KEY_DOUBLE, /**< enum 3 按键双击. */
} KeyCodeType;
2.读取具体引脚的高低电平数据
/**
* @brief 读取按键状态
* @param channal
* @retval 相对应通道的按键状态
*/
uint8_t PIOS_KEY_GPIO_Read(uint8_t channal)
{
switch(channal)
{
case PIOS_KEY_POWER:
return (uint8_t)GPIO_ReadInputDataBit(KEY_POWER_GPIO,KEY_POWER_GPIO_PIN);
case PIOS_KEY_FUNCTION:
return (uint8_t)GPIO_ReadInputDataBit(KEY_FUNCTION_GPIO,KEY_FUNCTION_GPIO_PIN);
default:
return 0;
}
}
3.按键状态更新
/*按键值*/
static KeyCodeType key_code[PIOS_KEY_NUMBERS];
static KeyStateType state[PIOS_KEY_NUMBERS];
static uint32_t timeNowMs[PIOS_KEY_NUMBERS] ;
/**
* @brief 获取当前的时间,返回Ms
* @param None
* @retval sys_tick / 10
*/
uint32_t Get_sysTime(void)
{
return sys_tick / 10;
}
/**
* @brief 按键更新函数
* @param\[in] channal 传入所要更新的按键序号
* @retval None
*/
void PIOS_KEY_Update_Key(uint8_t channal)
{
if (channal >= PIOS_KEY_NUMBERS){
return;
}
switch (state[channal] ){
case KEY_STATE_RELEASE:
if (!PIOS_KEY_GPIO_Read(channal)){ //检测按键是否按下
state[channal] = KEY_STATE_PRESS;
}
break;
case KEY_STATE_PRESS:
if (!PIOS_KEY_GPIO_Read(channal)){ //再次检测按键是否按下 100ms去抖动
timeNowMs[channal] = Get_sysTime();
state[channal] = KEY_STATE_PRESS_FILTER;
}
break;
case KEY_STATE_PRESS_FILTER:
if (!PIOS_KEY_GPIO_Read(channal)){ //检测消抖后按键是否仍按下
if (((Get_sysTime()) - timeNowMs[channal] ) > PIOS_KEY_HOLD_TIME){ //按键按下是否超过2秒
//长按按键
state[channal] = KEY_STATE_HOLD;
key_code[channal] = KEY_HOLD;
}
}else{
timeNowMs[channal] = Get_sysTime();
state[channal] = KEY_STATE_DOUBLE;
}
break;
case KEY_STATE_DOUBLE:
if (((Get_sysTime()) - timeNowMs[channal] ) > PIOS_KEY_DOUBLE_TIME){
//释放按键 短按键
key_code[channal] = KEY_TOGGLE;
state[channal] = KEY_STATE_HOLD;
}else{
//400ms内又按下
if (!PIOS_KEY_GPIO_Read(channal)){
key_code[channal] = KEY_DOUBLE;
state[channal] = KEY_STATE_HOLD;
}
}
break;
case KEY_STATE_HOLD:
if (PIOS_KEY_GPIO_Read(channal)){ //检测按键释放
state[channal] = KEY_STATE_RELEASE;
}
break;
default:
break;
}
}
4.定时1ms去扫描各按键数据
/**
* @brief 按键更新函数
* @param\[in] num 按键个数
* @retval None
*/
void PIOS_KEY_Update_Keys(void)
{
uint8_t i = 0;
for (; i < PIOS_KEY_NUMBERS; ++i){
PIOS_KEY_Update_Key(i);
}
}
5.在每次使用完一次之后对按键状态进行清除
/**
* @brief 清除按键键值
* @param None
* @retval None
*/
void PIOS_KEY_Reset(void)
{
uint8_t i = 0;
for (; i < PIOS_KEY_NUMBERS; i++){
key_code[i] = KEY_NONE;
}
}
/**
* @brief 获取单个按键键值
* @param\[in] channal 按键序号
* @return 返回键值
*/
KeyCodeType PIOS_KEY_GetKey(uint8_t channal)
{
return key_code[channal];
}
6.通过不断扫描按键可以达到去识别那个按键按下和按下的状态
/**
* @brief 按键处理 (在定时器每1ms中断一次中运行)
* @param None
* @retval None
*/
void key_handle()
{
// 长按电源按键进入
if((PIOS_KEY_GetKey(PIOS_KEY_POWER) == KEY_HOLD)){
//在此写需要执行的程序
PIOS_KEY_Reset();//执行完恢复按键状态,防止一直扫描进入
}
//短按电源按键进入
if((!PIOS_KEY_GPIO_Read(PIOS_KEY_POWER)) && Get_sysTime() < 2000){
PIOS_KEY_Reset();
}
//多功能按键-短按进入
if(PIOS_KEY_GetKey(PIOS_KEY_FUNCTION) == KEY_TOGGLE){
PIOS_KEY_Reset();
}
}