按键实现单击、双击、长按

前言一、硬件原理图二、构造按键结构体三、在定时器中断回调函数中检测四、按键处理函数五、现象

前言

基于蓝桥杯嵌入式开发板实现按键的单击,双击,长按检测与处理,使用定时器后台检测,防止占用前台资源,可以随便移植到任何单片机上。

一、硬件原理图

CubeMX配置,使用定时器3来检测按键

二、构造按键结构体

看注释

#define KEY_B1 HAL_GPIO_ReadPin(KEY_B1_GPIO_Port, KEY_B1_Pin)

#define KEY_B2 HAL_GPIO_ReadPin(KEY_B2_GPIO_Port, KEY_B2_Pin)

#define KEY_B3 HAL_GPIO_ReadPin(KEY_B3_GPIO_Port, KEY_B3_Pin)

#define KEY_B4 HAL_GPIO_ReadPin(KEY_B4_GPIO_Port, KEY_B4_Pin)

/* 按键长按检测时间(单位:次数) 一次为定时器扫描一次的时间 */

#define KEY_LONG_PRESS_TIME 80

/* 按键双击间隔时间(单位:次数) 一次为定时器扫描一次的时间 */

#define KEY_DOUBLE_GAP_TIME 40

enum KEY_STATE

{

key_state_0 = 0,

key_state_1 = 1,

key_state_2 = 2,

key_state_3 = 3

};

enum KEY_EVENT

{

key_no = 0, /* 无按键按下 */

key_click = 1, /* 单击 */

key_double = 2, /* 双击 */

key_long = 3 /* 长按 */

};

struct key{

bool key_input_val;

enum KEY_STATE key_state_buff1; /* 按键执行状态1 */

enum KEY_STATE key_state_buff2; /* 按键执行状态2 */

enum KEY_EVENT key_real_result; /* 最终判断结果 */

unsigned char key_time_cnt1; /* 定时器1 */

unsigned char key_time_cnt2; /* 定时器2 */

};

三、在定时器中断回调函数中检测

我的按键是检测到0为有效,1为无效看注释

static enum KEY_EVENT key_driver(int key_num)

{

enum KEY_EVENT key_result = key_no;

switch (key[key_num].key_state_buff1)

{

case key_state_0:

if (key[key_num].key_input_val == 0)

{

key[key_num].key_state_buff1 = key_state_1;

/* 如果按键被按下,状态切换到按键消抖和确认状态 */

}

break;

case key_state_1:

if (key[key_num].key_input_val == 0)

{

key[key_num].key_time_cnt1 = 0;

key[key_num].key_state_buff1 = key_state_2;

/* 按键仍处于按下状态 */

/* 消抖完成,计时器key_time_cnt1 开始计时 */

/* 状态切换到计时状态 */

}

else

key[key_num].key_state_buff1 = key_state_0;

break;

case key_state_2:

if (key[key_num].key_input_val == 1)

{

key_result = key_click; /* 按键抬起,产生一次click操作 */

key[key_num].key_state_buff1 = key_state_0;

}

else if (++key[key_num].key_time_cnt1 >= KEY_LONG_PRESS_TIME)

{ /* 按键继续按下超过1000ms */

key_result = key_long; /* 返回长按操作 */

key[key_num].key_state_buff1 = key_state_3; /* 状态切换到按键释放状态 */

}

break;

case key_state_3:

if (key[key_num].key_input_val == 1)

/* 没按键按下了,回正常状态,防止按一次检测出两次单击 */

key[key_num].key_state_buff1 = key_state_0;

break;

}

return key_result;

}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

if (htim->Instance == TIM3)

{

enum KEY_EVENT key_result;

key[0].key_input_val = KEY_B1;/* 读取按键值 */

key[1].key_input_val = KEY_B2;

key[2].key_input_val = KEY_B3;

key[3].key_input_val = KEY_B4;

for (int i = 0; i < 4; i++)

{

key_result = key_driver(i);

switch (key[i].key_state_buff2)

{

case key_state_0:

if (key_result == key_click)

{

key[i].key_time_cnt2 = 0;

key[i].key_state_buff2 = key_state_1;

/* 第一次单击,不返回,到下一个状态判断是否有双击 */

}

else

key[i].key_real_result = key_result;

/* 对于无键,长按,返回原事件 */

break;

case key_state_1:

if (key_result == key_click) /* 又一次单击,时间间隔小于500ms */

{

key[i].key_real_result = key_double; /* 返回双击事件 */

key[i].key_state_buff2 = key_state_0;

}

else if (++key[i].key_time_cnt2 >= KEY_DOUBLE_GAP_TIME)

{

key[i].key_real_result = key_click;

/* 500ms内没有再次出现单击事件,返回单击事件 */

key[i].key_state_buff2 = key_state_0;

}

break;

}

}

}

}

四、按键处理函数

记得处理完按键后清除按键事件,置为无键事件记得开定时器3

void key_proc()

{

if (key[0].key_real_result == key_click)

{

LCD_ClearLine(Line1);

LCD_DisplayStringLine(Line1, (uint8_t *)" key0_click ");

key[0].key_real_result = key_no;/* 清除按键事件,置为无键事件 */

}

else if (key[0].key_real_result == key_double)

{

LCD_ClearLine(Line1);

LCD_DisplayStringLine(Line1, (uint8_t *)" key0_double ");

key[0].key_real_result = key_no;

}

else if (key[0].key_real_result == key_long)

{

LCD_ClearLine(Line1);

LCD_DisplayStringLine(Line1, (uint8_t *)" key0_long ");

key[0].key_real_result = key_no;

}

if (key[1].key_real_result == key_click)

{

LCD_ClearLine(Line2);

LCD_DisplayStringLine(Line2, (uint8_t *)" key1_click ");

key[1].key_real_result = key_no;

}

else if (key[1].key_real_result == key_double)

{

LCD_ClearLine(Line2);

LCD_DisplayStringLine(Line2, (uint8_t *)" key1_double ");

key[1].key_real_result = key_no;

}

else if (key[1].key_real_result == key_long)

{

LCD_ClearLine(Line2);

LCD_DisplayStringLine(Line2, (uint8_t *)" key1_long ");

key[1].key_real_result = key_no;

}

}

五、现象

参考文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。