key_board介绍
key_board是用于单片机中的一个小巧多功能按键支持库。该软件采用了分层的设计思想,并且与平台无关,用户只需要提供按键的基本信息和读写IO电平的函数即可进行移植,非常方便。同时,key_board支持多个矩阵键盘和多个单IO控制键盘。
目前,key_board已经实现了多种按键触发功能,包括按下触发、弹起触发、长按自动触发、长按弹起触发、多击触发、连续触发等,并且可以随意组合使用(支持同一时间轴和非同一时间轴的状态)。在未来,还将添加更多功能。
使用说明
-
初始化相关的硬件资源。 -
提供一个1毫秒的定时器,用于周期性调用’key_check’函数。 -
提供按键的描述和读写IO的函数。 -
将键盘注册到系统。 -
参考提供的STM32例程来进行具体操作。 -
注意,该程序默认使用堆内存。如果发现程序运行结果异常,请尝试增大程序的堆空间,或者注册调试接口来查看原因。 -
获取更详细的使用教程,请参阅详细的使用说明或提供的STM32例程。
已支持的键盘
-
矩阵键盘
矩阵键盘
-
单io按键
单io按键
详细使用说明
将key_board.c
,key_board.h
,key_board_config.h
放进key_board
文件夹中并包含进你的工程,添加头文件路径。
基础功能移植(以stm32
矩阵键盘为例)
首先需要一个可使用的定时器(如果不想使用定时器也可直接放到主循环中,但不推荐,会导致时基不准确),固定为1ms
触发一次;
准备待检测的按键的基本信息,可参考key_board_sample.c
文件中的struct key_pin_t
结构体,如:
struct key_pin_t {
GPIO_TypeDef *port; //按键端口号
uint16_t pin; //按键的引脚号
GPIO_PinState valid; //按键的有效电平(即按键按下时的电平)
GPIO_PinState invalid; //按键的无效电平(即按键空闲时的电平)
/*
可添加你的其它参数
*/
};
定义待检测的按键信息,可参考key_board_sample.c
文件中的const struct key_pin_t key_pin_sig[]
结构体数组,对应头文件为key_board_sample.h
,如:
//全局变量
const struct key_pin_t key_pin_sig[] = {
{
.port = KEY_PORT_J12,
.pin = KEY_PIN_J12,
.valid = KEY_PRESS_LEVEL_J12,
.invalid = KEY_RELEASE_LEVEL_J12
},
{
.port = KEY_PORT_J34,
.pin = KEY_PIN_J34,
.valid = KEY_PRESS_LEVEL_J34,
.invalid = KEY_RELEASE_LEVEL_J34
},
{
.port = KEY_PORT_J56,
.pin = KEY_PIN_J56,
.valid = KEY_PRESS_LEVEL_J56,
.invalid = KEY_RELEASE_LEVEL_J56
},
};
如果为矩阵键盘还需要定义控制io的相关信息,可参考key_board_sample.c
文件中的const struct key_pin_t key_pin_ctrl[]
结构体数组,对应头文件为key_board_sample.h
,如:
const struct key_pin_t key_pin_ctrl[] = {
{
.port = KEY_PORT_J135,
.pin = KEY_PIN_J135,
.valid = KEY_CTL_LINE_ENABLE,
.invalid = KEY_CTL_LINE_DISABLE
},
{
.port = KEY_PORT_J246,
.pin = KEY_PIN_J246,
.valid = KEY_CTL_LINE_ENABLE,
.invalid = KEY_CTL_LINE_DISABLE
},
};
实现按键io的电平读取函数,可参考key_board_sample.c
文件中的pin_level_get
函数,如:
static inline bool pin_level_get(const void *desc)
{
struct key_pin_t *pdesc;
pdesc = (struct key_pin_t *)desc;
return HAL_GPIO_ReadPin(pdesc->port, pdesc->pin) == pdesc->valid;
}
如果为矩阵键盘还需要实现按键io的电平写入函数,可参考key_board_sample.c
文件中的pin_level_set
函数,如:
static inline void pin_level_set(const void *desc, bool flag)
{
struct key_pin_t *pdesc;
pdesc = (struct key_pin_t *)desc;
HAL_GPIO_WritePin(pdesc->port, pdesc->pin, flag ? pdesc->valid : pdesc->invalid);
}
定义按键的id及功能结构体struct key_public_sig_t
,可参考key_board_sample.c
文件中的const struct key_public_sig_t key_public_sig[]
结构体数组,对应头文件key_board.h
,如:
const struct key_public_sig_t key_public_sig[] = {
KEY_PUBLIC_SIG_DEF(KEY_UP, &key_pin_sig[0], pin_level_get, KEY_FLAG_NONE),
KEY_PUBLIC_SIG_DEF(KEY_LEFT, &key_pin_sig[1], pin_level_get, KEY_FLAG_NONE),
KEY_PUBLIC_SIG_DEF(KEY_DOWN, &key_pin_sig[2], pin_level_get, KEY_FLAG_NONE),
//下面的是因为使用的矩阵键盘而扩展出来的三个按键
KEY_PUBLIC_SIG_DEF(KEY_ENTER, &key_pin_sig[0], pin_level_get, KEY_FLAG_NONE),
KEY_PUBLIC_SIG_DEF(KEY_RIGHT, &key_pin_sig[1], pin_level_get, KEY_FLAG_NONE),
KEY_PUBLIC_SIG_DEF(KEY_EXIT, &key_pin_sig[2], pin_level_get, KEY_FLAG_NONE),
};
如果为矩阵键盘还需要定义控制io的id及功能结构体struct key_public_ctrl_t
,可参考key_board_sample.c
文件中的const struct key_public_ctrl_t key_public_ctrl[]
结构体数组,对应头文件key_board.h
,如:
const struct key_public_ctrl_t key_public_ctrl[] = {
KEY_PUBLIC_CTRL_DEF(&key_pin_ctrl[0], pin_level_set),
KEY_PUBLIC_CTRL_DEF(&key_pin_ctrl[1], pin_level_set),
};
初始化键盘,可参考key_board_sample.c
文件中的GPIO_Key_Board_Init
函数,如:
void GPIO_Key_Board_Init(void)
{
//硬件io的初始化
GPIO_InitTypeDef GPIO_InitStruct;
unsigned int i;
RCC_KEY_BOARD_CLK_ENABLE();
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
for(i = 0;i for(i = 0;i
主流程伪代码框架,更多例子参考main_test.c
文件:
int main(void)
{
//初始化硬件io,并注册键盘
GPIO_Key_Board_Init();
//初始化定时器,用于按键扫描(1ms)
init_tmr();
for(;;)
{
if(key_check_state(KEY_UP, KEY_RELEASE))
{
PRINTF("KEY_UP KEY_RELEASE\r\n");
}
if(key_check_state(KEY_UP, KEY_PRESS))
{
PRINTF("KEY_UP KEY_PRESS\r\n");
}
}
}
//定时器到期回调处理函数
void tmr_irq_callback(void)
{
//调用按键扫描核心函数
key_check();
}
扩展功能长按的使用
首先确保key_board_config.h
文件中宏KEY_LONG_SUPPORT
已处于使能状态,并且正确设置了宏KEY_DEFAULT_LONG_TRRIGER_TIME
的值;
设置按键功能需要对长按进行检测,如:
KEY_PUBLIC_SIG_DEF(KEY_UP, &key_pin_sig[0], pin_level_get, KEY_FLAG_PRESS_LONG | KEY_FLAG_RELEASE_LONG)
使用例程:
if(key_check_state(KEY_UP, KEY_PRESS_LONG))
{
PRINTF("KEY_UP KEY_PRESS_LONG\r\n");
}
if(key_check_state(KEY_UP, KEY_RELEASE_LONG))
{
PRINTF("KEY_UP KEY_RELEASE_LONG\r\n");
}
扩展功能连按的使用
首先确保key_board_config.h
文件中宏KEY_CONTINUOUS_SUPPORT
已处于使能状态,并且正确设置了宏KEY_DEFAULT_CONTINUOUS_INIT_TRRIGER_TIME
和KEY_DEFAULT_CONTINUOUS_PERIOD_TRRIGER_TIME
的值;
设置按键功能需要对连按进行检测,如:
KEY_PUBLIC_SIG_DEF(KEY_UP, &key_pin_sig[0], pin_level_get, KEY_FLAG_PRESS_CONTINUOUS)
使用例程:
if(key_check_state(KEY_UP, KEY_PRESS_CONTINUOUS))
{
PRINTF("KEY_UP KEY_PRESS_CONTINUOUS\r\n");
}
扩展功能多击的使用
首先确保key_board_config.h
文件中宏KEY_MULTI_SUPPORT
已处于使能状态,并且正确设置了宏KEY_DEFAULT_MULTI_INTERVAL_TIME
的值;
设置按键功能需要多击进行检测,如:
KEY_PUBLIC_SIG_DEF(KEY_UP, &key_pin_sig[0], pin_level_get, KEY_FLAG_PRESS_MULTI | KEY_FLAG_RELEASE_MULTI)
使用例程:
unsigned int res;
res = key_check_state(KEY_UP, KEY_PRESS_MULTI);
if(res)
{
PRINTF("KEY_UP KEY_PRESS_MULTI:%d\r\n", res);
}
res = key_check_state(KEY_UP, KEY_RELEASE_MULTI);
if(res)
{
PRINTF("KEY_UP KEY_RELEASE_MULTI:%d\r\n", res);
}
扩展功能组合状态(同一时间轴)
感谢网友:石玉虎[@shi-yuhu]的反馈,已更正之前错误的使用案例。
使用例程:
unsigned int key_down_release_long, key_up_release_long;
key_down_release_long = key_check_state(KEY_DOWN, KEY_RELEASE_LONG);
key_up_release_long = key_check_state(KEY_UP, KEY_RELEASE_LONG);
if(key_down_release_long && key_up_release_long)
{
PRINTF("KEY_DOWN KEY_RELEASE_LONG && KEY_UP KEY_RELEASE_LONG\n");
}
扩展功能组合状态(非同一时间轴)
首先确保key_board_config.h
文件中宏KEY_COMBINE_SUPPORT
已处于使能状态,并且正确设置了宏KEY_DEFAULT_COMBINE_INTERVAL_TIME
的值;
使用例程:
//用于保存注册后的组合状态id
static unsigned int test_id1, test_id2;
//定义要检测的状态
const struct key_combine_t test_combine1[] = {
{ .id = KEY_UP, .state = KEY_PRESS },
{ .id = KEY_DOWN, .state = KEY_PRESS_LONG },
{ .id = KEY_UP, .state = KEY_PRESS },
};
//注册组合状态
test_id1 = key_combine_register(test_combine1, ARRAY_SIZE(test_combine1));
const struct key_combine_t test_combine2[] = {
{ .id = KEY_UP, .state = KEY_PRESS },
{ .id = KEY_DOWN, .state = KEY_PRESS },
{ .id = KEY_UP, .state = KEY_PRESS },
{ .id = KEY_DOWN, .state = KEY_PRESS },
};
test_id2 = key_combine_register(test_combine2, ARRAY_SIZE(test_combine2));
if(key_check_combine_state(test_id1))
{
PRINTF("combine test_id1\r\n");
}
if(key_check_combine_state(test_id2))
{
PRINTF("combine test_id2\r\n");
}
以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !