一个应用于单片机的按键处理模块!

key_board介绍
key_board用于单片机中的小巧多功能按键支持,软件采用了分层的思想,并且做到了与平台无关,用户只需要提供按键的基本信息和读写io电平的函数即可,非常方便移植,同时支持多个矩阵键盘及多个单io控制键盘。
目前已实现按下触发、弹起触发、长按自动触发、长按弹起触发、多击触发、连续触发等功能,并且能够随意组合(支持状态的同一时间轴和非同一时间轴),后续还会添加更多的功能。
使用说明
1、初始化相关的硬件资源。
2、提供一个1ms的定时器,用于周期性的调用'key_check'函数。
3、提供按键的描述及读写io的函数。
4、将键盘注册到系统。
5、具体的操作参考提供的stm32例程。
6、因为程序默认使用了堆内存,当发现程序运行结果不正常时,尝试增大你的程序堆空间,或者注册调试接口查看原因。
7、更详细的使用教程见详细使用说明或者提供的stm32例程。
已支持的键盘
1、矩阵键盘
矩阵键盘
2、单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 < array_size(key_pin_sig);i++)   {      gpio_initstruct.pin   = key_pin_sig[i].pin;      hal_gpio_init(key_pin_sig[i].port,  gpio_initstruct);   }   gpio_initstruct.speed = gpio_speed_freq_low;   gpio_initstruct.pull  = gpio_nopull;   gpio_initstruct.mode  = gpio_mode_output_pp;   for(i = 0;i < array_size(key_pin_ctrl);i++)   {      gpio_initstruct.pin   = key_pin_ctrl[i].pin;      hal_gpio_init(key_pin_ctrl[i].port,  gpio_initstruct);   }   //初始化键盘   key_board_init();   //注册键盘到系统中(矩阵键盘)   key_board_register(key_board_matrix, key_public_sig, array_size(key_public_sig), key_public_ctrl, array_size(key_public_ctrl));}  
主流程伪代码框架,更多例子参考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_releasern);        }        if(key_check_state(key_up, key_press))        {            printf(key_up key_pressrn);        }    }}//定时器到期回调处理函数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_longrn);}if(key_check_state(key_up, key_release_long)){    printf(key_up key_release_longrn);}  
扩展功能连按的使用
首先确保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_continuousrn);}  
扩展功能多击的使用
首先确保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:%drn, res);}res = key_check_state(key_up, key_release_multi);if(res){    printf(key_up key_release_multi:%drn, 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_longn);}  
扩展功能组合状态(非同一时间轴)
首先确保key_board_config.h文件中宏key_combine_support已处于使能状态,并且正确设置了宏key_default_combine_interval_time的值;
使用例程:
//用于保存注册后的组合状态idstatic 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_id1rn);}if(key_check_combine_state(test_id2)){    printf(combine test_id2rn);}  
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理


重磅!中国北斗导航系统可取代美国GPS
stm32看门狗的特点是什么
芯片短缺考验来袭,AI新势力们热心助拳
容声“双净”冰箱,再造下一代除菌养鲜技术的行业高峰!
适用于高速无线通信系统的FPGA基带验证平台的设计
一个应用于单片机的按键处理模块!
华为鸿蒙OS系统单挑谷歌安卓系统表现如何
直接耦合放大电路的零点漂移
三星10nm级DDR4 SoDIMM内存,容量达到32GB单条
女友让翻译化妆品标签 看大佬如何用Python轻松解决
浅谈齿轮的分类及模数计算方式
如何设计开发新支付系统模式
群同步,群同步是什么意思
centos在线安装docker详细说明
中微半导推出新一代车规级SoC芯片BAT32A6300
什么蓝牙耳机好用?盘点2021年最值得入手的蓝牙耳机
超能云终端创领先机 英特尔超能云终端解决方案峰会来袭
运算放大器,运算放大器是什么意思
苹果新款MacBook Air/Pro加8GB内存需要200美元
关于IO单元环设计的学习(2)