0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

jf_pJlTbmA9 2023-10-24 16:28 次阅读

key_board介绍

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

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

使用说明

1、初始化相关的硬件资源。

2、提供一个1ms的定时器,用于周期性的调用'key_check'函数。

3、提供按键的描述及读写io的函数。

4、将键盘注册到系统。

5、具体的操作参考提供的stm32例程。

6、因为程序默认使用了堆内存,当发现程序运行结果不正常时,尝试增大你的程序堆空间,或者注册调试接口查看原因。

7、更详细的使用教程见详细使用说明或者提供的stm32例程。

已支持的键盘

1、矩阵键盘

wKgaomUDyWSAFCHeAABkcpo29Ug109.jpg

矩阵键盘

2、单io按键

wKgaomUDyWWALK1hAABd50azyE4774.jpg

单io按键

详细使用说明

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

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

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

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

structkey_pin_t{
GPIO_TypeDef*port;//按键端口号
uint16_tpin;//按键的引脚号
GPIO_PinStatevalid;//按键的有效电平(即按键按下时的电平)
GPIO_PinStateinvalid;//按键的无效电平(即按键空闲时的电平)
/*
可添加你的其它参数
*/
};

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

//全局变量
conststructkey_pin_tkey_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,如:

conststructkey_pin_tkey_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函数,如:

staticinlineboolpin_level_get(constvoid*desc)
{
structkey_pin_t*pdesc;

pdesc=(structkey_pin_t*)desc;
returnHAL_GPIO_ReadPin(pdesc->port,pdesc->pin)==pdesc->valid;
}

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

staticinlinevoidpin_level_set(constvoid*desc,boolflag)
{
structkey_pin_t*pdesc;

pdesc=(structkey_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,如:

conststructkey_public_sig_tkey_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,如:

conststructkey_public_ctrl_tkey_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函数,如:

voidGPIO_Key_Board_Init(void)
{
//硬件io的初始化
GPIO_InitTypeDefGPIO_InitStruct;
unsignedinti;

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文件:

intmain(void)
{
//初始化硬件io,并注册键盘
GPIO_Key_Board_Init();
//初始化定时器,用于按键扫描(1ms)
init_tmr();

for(;;)
{
if(key_check_state(KEY_UP,KEY_RELEASE))
{
PRINTF("KEY_UPKEY_RELEASErn");
}
if(key_check_state(KEY_UP,KEY_PRESS))
{
PRINTF("KEY_UPKEY_PRESSrn");
}
}
}

//定时器到期回调处理函数
voidtmr_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_UPKEY_PRESS_LONGrn");
}
if(key_check_state(KEY_UP,KEY_RELEASE_LONG))
{
PRINTF("KEY_UPKEY_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_UPKEY_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)

使用例程:

unsignedintres;
res=key_check_state(KEY_UP,KEY_PRESS_MULTI);
if(res)
{
PRINTF("KEY_UPKEY_PRESS_MULTI:%drn",res);
}
res=key_check_state(KEY_UP,KEY_RELEASE_MULTI);
if(res)
{
PRINTF("KEY_UPKEY_RELEASE_MULTI:%drn",res);
}

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

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

使用例程:

unsignedintkey_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_DOWNKEY_RELEASE_LONG  KEY_UPKEY_RELEASE_LONGn");
}

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

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

使用例程:

//用于保存注册后的组合状态id
staticunsignedinttest_id1,test_id2;

//定义要检测的状态
conststructkey_combine_ttest_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));

conststructkey_combine_ttest_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("combinetest_id1rn");
}

if(key_check_combine_state(test_id2))
{
PRINTF("combinetest_id2rn");
}

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6001

    文章

    43978

    浏览量

    620871
  • 定时器
    +关注

    关注

    23

    文章

    3148

    浏览量

    112043
收藏 人收藏

    评论

    相关推荐

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

    目前已实现按下触发、弹起触发、长按自动触发、长按弹起触发、多击触发、连续触发等功能,并且能够随意组合(支持状态的同一时间轴和非同一时间轴),后续还会添加更多的功能。
    的头像 发表于 02-17 09:37 1200次阅读
    一个<b class='flag-5'>应用于</b><b class='flag-5'>单片机</b>的<b class='flag-5'>按键</b><b class='flag-5'>处理</b><b class='flag-5'>模块</b>

    单片机按键的问题(转)

    在网上看到这篇心得,感觉还是很实用的小问题,转来希望大家共同学习,在网上看了《单片机按键处理的优化方法》这篇文章,很有点启发,不过我疑惑的是第二
    发表于 08-11 11:03

    用于网络处理单片机选型

    我在做一个基于单片机的网络控制系统,要处理100兆的网络速度,单片机处理速度要多快呢?强人推荐
    发表于 12-22 17:47

    单片机按键处理的优化方法介绍

    以前做单片机的时候总会遇到问题就是:在单片机的键盘输入的键盘处理时,原来的做法通常是通
    发表于 07-19 03:02

    单片机按键设计的四方案详解

    。第种是最简单和最基础的,对于单片机初学者很容易理解和使用,但是缺点是,需要在主循环中不断检测按键是否按下,并且需要做消抖处理。若主循环中某个函数任务占用时间较长,则
    发表于 09-05 15:32

    单片机独立按键使用程序

    单片机独立按键使用程序 (51单片机)独立按键单片机中很重要的
    发表于 11-18 08:32

    51单片机按键输入

    按键,每个按键对应IO口,通过循环或者中断去检测,这种方法常用于按键个数较少得时候。如果
    发表于 11-18 07:39

    独立按键处理思路

    模块题目二、原理简述1、独立按键处理思路(转载)般情况下,独立按键有两
    发表于 01-11 07:36

    如何使用单片机接入按键遥感

    文章目录1 简介2 主要器件2.1 双轴摇杆模块2.2 电路原理图3 实现效果4 测试代码6 最后1 简介Hi,大家好,这里是丹成学长,今天向大家介绍如何使用单片机接入按键遥感单片机
    发表于 01-19 08:31

    如何制作单片机独立按键扫描的模块

    如何制作单片机独立按键扫描的模块
    发表于 02-17 06:38

    单片机按键处理总结——含程序详解

    讲述几种常用的按键的应用及程序处理方法,帮助大家掌握单片机处理按键的方法。
    发表于 11-10 10:55 11次下载

    基于单片机的彩屏模块(1.8寸彩屏程序-2)4X3按键检测

    基于单片机的彩屏模块(1.8寸彩屏程序-2)4X3按键检测
    发表于 01-12 14:41 7次下载

    单片机按键使用程序 (51单片机

    单片机独立按键使用程序 (51单片机)独立按键单片机中很重要的一个器件,在这篇文章里,通过这个用独立
    发表于 11-11 18:36 105次下载
    <b class='flag-5'>单片机</b><b class='flag-5'>按键</b>使用程序 (51<b class='flag-5'>单片机</b>)

    一个实用的、可应用于单片机的内存管理模块

    关注+星标公众号,不错过精彩内容转自 |嵌入式大杂烩本次给大家分享一位大佬写的应用于单片机内存管理模块mem_malloc,这个mem_malloc的使用不会产生内存碎片,可以高效利用单...
    发表于 12-22 19:50 7次下载
    一个实用的、可<b class='flag-5'>应用于</b><b class='flag-5'>单片机</b>的内存管理<b class='flag-5'>模块</b>

    单片机按键切换模式怎么设置

    单片机:选择一款合适的单片机型号,例如常见的8051、STM32等。 按键模块用于实现按键
    的头像 发表于 12-13 11:07 1618次阅读