按键
按键作为人机交互使用最多的一种交互方式,有时候一个按键有多个功能,有时候需要多个按键组合,实现复杂的功能,比如CTRL+C和CTRL+V,有的时候需要按下去使调节量一直持续变化,有的时候单击和双击也在功能上做区分.......
实现方法
通过定时器同步,根据实际需要调整不同动作的按键定时更新个数,区分各动作,并作出响应
关键代码
定时器初始化
[复制]()
void timer_base_set(u16 per,u16 psc)
{
timer_parameter_struct base_timer_structure;
rcu_periph_clock_enable(RCU_TIMER6);
base_timer_structure.alignedmode=TIMER_COUNTER_EDGE;
base_timer_structure.clockdivision=TIMER_CKDIV_DIV1;
base_timer_structure.counterdirection=TIMER_COUNTER_UP;
base_timer_structure.period=per;
base_timer_structure.prescaler=psc;
base_timer_structure.repetitioncounter=0;
timer_init(TIMER6,&base_timer_structure);
timer_interrupt_enable(TIMER6,TIMER_INT_UP);
nvic_irq_enable(TIMER6_IRQn,2,2);
timer_enable(TIMER6);
}
各按键动作占用定时器周期数
[复制]()
#define SHORT_KEY_DELAY 2 // 短按延时
#define LONG_KEY_DELAY 200 // 长按延时
#define DOUBLE_KEY_DELAY 30 // 双击两次触发之间的最大延时
#define CNTINUS_KEY_DELAY 20 // 连续触发延时
#define HW_KEYS_NUM 5 // 支持按键数量(包括独立按键+组合按键)
#define NOKEY_INPUT_VALUE 0x00 // 没有按键按下时get_key_input()的返回值
#define KEY1_INPUT_VALUE 0x01
#define KEY2_INPUT_VALUE 0x02
#define KEY3_INPUT_VALUE 0x04
#define KEY4_INPUT_VALUE 0x05
#define KEY1_2_INPUT_VALUE (KEY1_INPUT_VALUE | KEY2_INPUT_VALUE) // KEY1+KE2组合键
按键按下和释放的处理
[复制]()
/**
- @brief: 处于按下状态的处理:检测长按键,连续按是否有效
- @author: lusd
- [url=home.php?mod=space&uid=3142012]@param[/url] [in] new_input,当前的按键输入
- [url=home.php?mod=space&uid=266161]@return[/url] 按键有效则返回相应键值,无效则返回KEY_NONE
*/
static uint8_t key_pressed_handle(uint16_t new_input)
{
uint8_t res = KEY_NONE;
if (key.id < HW_KEYS_NUM)
{
key.cnt++;
if (new_input == key.last_input)
{
if (SHORT_KEY_DELAY == key.cnt)
{
key.pressed = 1; // 标记按键按下生效
}
else if (keys_info[key.id].long_cnt == key.cnt)
{ // 长按达到2秒钟
res = keys_info[key.id].long_key_val; // 长按键值
}
else if ((keys_info[key.id].long_cnt + CNTINUS_KEY_DELAY) == key.cnt)
{
// 长按2秒之后,每持续0.2秒返回一次键值
key.cnt = keys_info[key.id].long_cnt;
res = keys_info[key.id].cntinus_key_val; // 一直按,连续触发的键值
}
}
}
return res;
}
/**
- @brief: 按键释放时,判定是否返回短按值或双击键值
- @author: lusd
- @param none.
- [url=home.php?mod=space&uid=266161]@return[/url] 可能返回短按值(对不支持双击的按键),
-
或双击键值(对支持双击的按键),
-
无效则返回KEY_NONE
*/
static uint8_t key_release_handle(void)
{
uint8_t res = KEY_NONE;
if (key.pressed)
{
if (key.id < HW_KEYS_NUM)
{
if (key.cnt < keys_info[key.id].long_cnt)
{ // 按下的时长,小于长按判定时间
res = keys_info[key.id].short_key_val; // 短按键值.
// 如果当前按键支持双击
if (KEY_NONE != keys_info[key.id].double_key_val)
{
if (key.wait_double[key.id])
{
key.wait_double[key.id] = 0; // 清除等待双击标志
key.double_timeout[key.id] = 0;
res = keys_info[key.id].double_key_val; // 双击键值
}
else
{
key.wait_double[key.id] = 1; // 设置等待双击标志
key.double_timeout[key.id] = DOUBLE_KEY_DELAY; // 设置超时时间
key.wait_double_flag = 1;
res = KEY_NONE;
}
}
}
}
}
key.cnt = 0;
key.pressed = 0;
key.last_input = NOKEY_INPUT_VALUE;
return res;
}
双击
[复制]()
/**
- @brief: 判定等待双击是否超时,超时则返回短按值
- @author: lusd
- @param none.
- [url=home.php?mod=space&uid=1141835]@Return[/url] 等待双击超时则返回短按键值,无效则返回KEY_NONE
*/
static uint8_t key_wait_double_timeout_handle(void)
{
uint8_t res = KEY_NONE;
uint8_t i;
key.wait_double_flag = 0;
for (i = 0; i < HW_KEYS_NUM; i++)
{
if (key.double_timeout[i])
{ // 如果按键正在等待双击
key.double_timeout[i]--;
key.wait_double_flag = 1;
if (0 == key.double_timeout[i])
{ // 减到0的时刻,表示等待超时了
key.wait_double[i] = 0; // 清除等待双击标志
return (keys_info[i].short_key_val); // 返回该键的短按值
}
}
}
return res;
}
主函数
#include "bitband.h"
#include "systick.h"
#include "usart.h"
#include "key.h"
#include "timer.h"
int main(void)
{
u8 key_val;
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
systick_set(96);
usart_init(9600);
gpio_port_set();
timer_base_set(960-1,1000-1);
while (1)
{
if (key.scan_flag)
{
key_val = key_scan();
if (KEY_NONE != key_val)
{
printf("KEY VALUE = %d.\r\n", key_val);
}
}
}
}
开源地址
开源地址:https://gitee.com/zhang_en/beauty_key.git
视频地址:【一个开源的按键处理程序-可以实现短按、长按、双击、组合】 https://www.bilibili.com/video/BV1uK411D7cq?share_source=copy_web&vd_source=7f0cb9c0f09b768583faf157910eb515