• 注册 / 登录
  • 切换到窄版
  • 查看: 1845|回复: 0

    常用单片机的按键处理程序

    [复制链接]

    676

    主题

    690

    帖子

    6808

    积分

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    6808
    发表于 2023-5-6 13:06:13 | 显示全部楼层 |阅读模式

    路线栈欢迎您!

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    key_board介绍

    key_board用于单片机中的小巧多功能按键支持,软件采用了分层的思想,并且做到了与平台无关,用户只需要提供按键的基本信息和读写io电平的函数即可,非常方便移植,同时支持多个矩阵键盘及多个单io控制键盘。

    目前已实现按下触发、弹起触发、长按自动触发、长按弹起触发、多击触发、连续触发等功能,并且能够随意组合(支持状态的同一时间轴和非同一时间轴),后续还会添加更多的功能。

    使用说明

    1.初始化相关的硬件资源。
    2.提供一个1ms的定时器,用于周期性的调用'key_check'函数。
    3.提供按键的描述及读写io的函数。
    4.将键盘注册到系统。
    5.具体的操作参考提供的stm32例程。
    6.因为程序默认使用了堆内存,当发现程序运行结果不正常时,尝试增大你的程序堆空间,或者注册调试接口查看原因。
    7.更详细的使用教程见详细使用说明或者提供的stm32例程。

    已支持的键盘

    1.矩阵键盘

    矩阵键盘.jpg
    矩阵键盘

    2.单io按键

    单io按键.jpg
    单io按键

    详细使用说明

    将key_board.c,key_board.h,key_board_config.h放进key_board文件夹中并包含进你的工程,添加头文件路径。

    基础功能移植(以stm32矩阵键盘为例)

    首先需要一个可使用的定时器(如果不想使用定时器也可直接放到主循环中,但不推荐,会导致时基不准确),固定为1ms触发一次;

    准备待检测的按键的基本信息,可参考key_board_sample.c文件中的struct key_pin_t结构体,如:

    1. struct key_pin_t
    复制代码

    定义待检测的按键信息,可参考key_board_sample.c文件中的const struct key_pin_t key_pin_sig[]结构体数组,对应头文件为key_board_sample.h,如:

    1. //全局变量

    2. const struct key_pin_t key_pin_sig[] = {
    3.     {
    4.         .port = KEY_PORT_J12,
    5.         .pin = KEY_PIN_J12,
    6.         .valid = KEY_PRESS_LEVEL_J12,
    7.         .invalid = KEY_RELEASE_LEVEL_J12
    8.     },
    9.     {
    10.         .port = KEY_PORT_J34,
    11.         .pin = KEY_PIN_J34,
    12.         .valid = KEY_PRESS_LEVEL_J34,
    13.         .invalid = KEY_RELEASE_LEVEL_J34
    14.     },
    15.     {
    16.         .port = KEY_PORT_J56,
    17.         .pin = KEY_PIN_J56,
    18.         .valid = KEY_PRESS_LEVEL_J56,
    19.         .invalid = KEY_RELEASE_LEVEL_J56
    20.     },
    21. };
    复制代码

    如果为矩阵键盘还需要定义控制io的相关信息,可参考key_board_sample.c文件中的const struct key_pin_t key_pin_ctrl[]结构体数组,对应头文件为key_board_sample.h,如:

    1. const struct key_pin_t key_pin_ctrl[] = {
    2.     {
    3.         .port = KEY_PORT_J135,
    4.         .pin = KEY_PIN_J135,
    5.         .valid = KEY_CTL_LINE_ENABLE,
    6.         .invalid = KEY_CTL_LINE_DISABLE
    7.     },
    8.     {
    9.         .port = KEY_PORT_J246,
    10.         .pin = KEY_PIN_J246,
    11.         .valid = KEY_CTL_LINE_ENABLE,
    12.         .invalid = KEY_CTL_LINE_DISABLE
    13.     },
    14. };
    复制代码

    实现按键io的电平读取函数,可参考key_board_sample.c文件中的pin_level_get函数,如:

    1. static inline bool pin_level_get(const void *desc)
    2. {
    3.     struct key_pin_t *pdesc;
    复制代码

    如果为矩阵键盘还需要实现按键io的电平写入函数,可参考key_board_sample.c文件中的pin_level_set函数,如:

    1. static inline void pin_level_set(const void *desc, bool flag)
    2. {
    3.     struct key_pin_t *pdesc;
    复制代码

    定义按键的id及功能结构体struct key_public_sig_t,可参考key_board_sample.c文件中的const struct key_public_sig_t key_public_sig[]结构体数组,对应头文件key_board.h,如:

    1. const struct key_public_sig_t key_public_sig[] = {
    2.     KEY_PUBLIC_SIG_DEF(KEY_UP, &key_pin_sig[0], pin_level_get, KEY_FLAG_NONE),
    3.     KEY_PUBLIC_SIG_DEF(KEY_LEFT, &key_pin_sig[1], pin_level_get, KEY_FLAG_NONE),
    4.     KEY_PUBLIC_SIG_DEF(KEY_DOWN, &key_pin_sig[2], pin_level_get, KEY_FLAG_NONE),
    5.     //下面的是因为使用的矩阵键盘而扩展出来的三个按键
    6.     KEY_PUBLIC_SIG_DEF(KEY_ENTER, &key_pin_sig[0], pin_level_get, KEY_FLAG_NONE),
    7.     KEY_PUBLIC_SIG_DEF(KEY_RIGHT, &key_pin_sig[1], pin_level_get, KEY_FLAG_NONE),
    8.     KEY_PUBLIC_SIG_DEF(KEY_EXIT, &key_pin_sig[2], pin_level_get, KEY_FLAG_NONE),
    9. };
    复制代码

    如果为矩阵键盘还需要定义控制io的id及功能结构体struct key_public_ctrl_t,可参考key_board_sample.c文件中的const struct key_public_ctrl_t key_public_ctrl[]结构体数组,对应头文件key_board.h,如:

    1. const struct key_public_ctrl_t key_public_ctrl[] =
    复制代码

    初始化键盘,可参考key_board_sample.c文件中的GPIO_Key_Board_Init函数,如:

    1. void GPIO_Key_Board_Init(void)
    2. {
    3.     //硬件io的初始化
    4.     GPIO_InitTypeDef GPIO_InitStruct;
    5.     unsigned int i;

    6.     RCC_KEY_BOARD_CLK_ENABLE();

    7.     GPIO_InitStruct.Pull  = GPIO_PULLUP;
    8.     GPIO_InitStruct.Mode  = GPIO_MODE_INPUT;
    9.     for(i = 0;i < ARRAY_SIZE(key_pin_sig);i++)
    10.     {
    11.         GPIO_InitStruct.Pin   = key_pin_sig[i].pin;
    12.         HAL_GPIO_Init(key_pin_sig[i].port, &GPIO_InitStruct);
    13.     }

    14.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    15.     GPIO_InitStruct.Pull  = GPIO_NOPULL;
    16.     GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;
    17.     for(i = 0;i < ARRAY_SIZE(key_pin_ctrl);i++)
    18.     {
    19.         GPIO_InitStruct.Pin   = key_pin_ctrl[i].pin;
    20.         HAL_GPIO_Init(key_pin_ctrl[i].port, &GPIO_InitStruct);
    21.     }

    22.     //初始化键盘
    23.     key_board_init();
    24.     //注册键盘到系统中(矩阵键盘)
    25.     key_board_register(KEY_BOARD_MATRIX, key_public_sig, ARRAY_SIZE(key_public_sig), key_public_ctrl, ARRAY_SIZE(key_public_ctrl));
    26. }
    复制代码

    主流程伪代码框架,更多例子参考main_test.c文件:

    1. int main(void)
    2. {
    3.     //初始化硬件io,并注册键盘
    4.     GPIO_Key_Board_Init();
    5.     //初始化定时器,用于按键扫描(1ms)
    6.     init_tmr();

    7.     for(;;)
    8.     {
    9.         if(key_check_state(KEY_UP, KEY_RELEASE))
    10.         {
    11.             PRINTF("KEY_UP KEY_RELEASE\r\n");
    12.         }
    13.         if(key_check_state(KEY_UP, KEY_PRESS))
    14.         {
    15.             PRINTF("KEY_UP KEY_PRESS\r\n");
    16.         }
    17.     }
    18. }

    19. //定时器到期回调处理函数
    20. void tmr_irq_callback(void)
    21. {
    22.     //调用按键扫描核心函数
    23.     key_check();
    24. }
    复制代码

    扩展功能长按的使用

    首先确保key_board_config.h文件中宏KEY_LONG_SUPPORT已处于使能状态,并且正确设置了宏KEY_DEFAULT_LONG_TRRIGER_TIME的值;

    设置按键功能需要对长按进行检测,如:

    1. KEY_PUBLIC_SIG_DEF(KEY_UP, &key_pin_sig[0], pin_level_get, KEY_FLAG_PRESS_LONG | KEY_FLAG_RELEASE_LONG)
    复制代码

    使用例程:

    1. if(key_check_state(KEY_UP, KEY_PRESS_LONG))
    2. {
    3.     PRINTF("KEY_UP KEY_PRESS_LONG\r\n");
    4. }
    5. if(key_check_state(KEY_UP, KEY_RELEASE_LONG))
    6. {
    7.     PRINTF("KEY_UP KEY_RELEASE_LONG\r\n");
    8. }
    复制代码

    扩展功能连按的使用

    首先确保key_board_config.h文件中宏KEY_CONTINUOUS_SUPPORT已处于使能状态,并且正确设置了宏KEY_DEFAULT_CONTINUOUS_INIT_TRRIGER_TIME和KEY_DEFAULT_CONTINUOUS_PERIOD_TRRIGER_TIME的值;

    设置按键功能需要对连按进行检测,如:

    1. KEY_PUBLIC_SIG_DEF(KEY_UP, &key_pin_sig[0], pin_level_get, KEY_FLAG_PRESS_CONTINUOUS)
    复制代码

    使用例程:

    1. if(key_check_state(KEY_UP, KEY_PRESS_CONTINUOUS))
    2. {
    3.     PRINTF("KEY_UP KEY_PRESS_CONTINUOUS\r\n");
    4. }
    复制代码

    扩展功能多击的使用

    首先确保key_board_config.h文件中宏KEY_MULTI_SUPPORT已处于使能状态,并且正确设置了宏KEY_DEFAULT_MULTI_INTERVAL_TIME的值;

    设置按键功能需要多击进行检测,如:

    1. KEY_PUBLIC_SIG_DEF(KEY_UP, &key_pin_sig[0], pin_level_get, KEY_FLAG_PRESS_MULTI | KEY_FLAG_RELEASE_MULTI)
    复制代码

    使用例程:

    1. unsigned int res;
    2. res = key_check_state(KEY_UP, KEY_PRESS_MULTI);
    3. if(res)
    4. {
    5.     PRINTF("KEY_UP KEY_PRESS_MULTI:%d\r\n", res);
    6. }
    7. res = key_check_state(KEY_UP, KEY_RELEASE_MULTI);
    8. if(res)
    9. {
    10.     PRINTF("KEY_UP KEY_RELEASE_MULTI:%d\r\n", res);
    11. }
    复制代码

    扩展功能组合状态(同一时间轴)

    感谢网友:石玉虎[@shi-yuhu]的反馈,已更正之前错误的使用案例。

    使用例程:

    1. unsigned int key_down_release_long, key_up_release_long;
    2. key_down_release_long = key_check_state(KEY_DOWN, KEY_RELEASE_LONG);
    3. key_up_release_long = key_check_state(KEY_UP, KEY_RELEASE_LONG);
    4. if(key_down_release_long && key_up_release_long)
    5. {
    6.     PRINTF("KEY_DOWN KEY_RELEASE_LONG && KEY_UP KEY_RELEASE_LONG\n");
    7. }
    复制代码

    扩展功能组合状态(非同一时间轴)

    首先确保key_board_config.h文件中宏KEY_COMBINE_SUPPORT已处于使能状态,并且正确设置了宏KEY_DEFAULT_COMBINE_INTERVAL_TIME的值;

    使用例程:

    1. //用于保存注册后的组合状态id
    2. static unsigned int test_id1, test_id2;

    3. //定义要检测的状态
    4. const struct key_combine_t test_combine1[] = {
    5.     { .id = KEY_UP,     .state = KEY_PRESS },
    6.     { .id = KEY_DOWN,   .state = KEY_PRESS_LONG },
    7.     { .id = KEY_UP,     .state = KEY_PRESS },
    8. };
    9. //注册组合状态
    10. test_id1 = key_combine_register(test_combine1, ARRAY_SIZE(test_combine1));

    11. const struct key_combine_t test_combine2[] = {
    12.     { .id = KEY_UP,     .state = KEY_PRESS },
    13.     { .id = KEY_DOWN,   .state = KEY_PRESS },
    14.     { .id = KEY_UP,     .state = KEY_PRESS },
    15.     { .id = KEY_DOWN,   .state = KEY_PRESS },
    16. };
    17. test_id2 = key_combine_register(test_combine2, ARRAY_SIZE(test_combine2));

    18. if(key_check_combine_state(test_id1))
    19. {
    20.     PRINTF("combine test_id1\r\n");
    21. }

    22. if(key_check_combine_state(test_id2))
    23. {
    24.     PRINTF("combine test_id2\r\n");
    25. }
    复制代码

    END

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    小黑屋|路丝栈 ( 粤ICP备2021053448号 )

    GMT+8, 2024-12-22 15:02 , Processed in 0.048793 second(s), 22 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表