关于使用FlexButton这个按键驱动库兼容矩阵键盘

具体怎么使用FlexButton这个组件起始很简单。毕竟只要把引脚绑定过去,然后读取一下引脚就好了。其他的部分就更加不用注意了。

这篇文章主要介绍的还是对于这个组件对于矩阵按键的支持。

矩阵按键一共有两种比较常用的方法。行列扫描式以及线反转式

行列扫描式

  • 此方法主要是先把行或者列进行轮流的给高低电平这样就可以先判断出是哪个行或者列被按了下去。之后还会进行读取相反的行列进行具体到按下了哪个按键。此方法中的引脚设置一般行如果设置是输出那么列就是读取设置。

线反转式

  • 此方法是先把行列一个设置为输入另外一个设置为输出然后读取一下,之后循环线反。
本次采用的是行列扫描方式,获取的代码如下所示:
/**
 * @function: scan_key_x_y
 * @brief: 行列式扫描按键
 * @param {*}
 * @return {*}
 * @author: 
 */
int scan_key_x_y(void)
{
    char key_x_num = 1;     //x轴
    char key_press_num = 0; //按下的按键,从k2开始
    int CC = 0; //用于标记按键信息
    /*X轴提供高电平*/
    while (1)
    {
        switch (key_x_num)
        {
        case 1:
            rt_pin_write(KEY_SCAN_Y1, PIN_LOW);
            rt_pin_write(KEY_SCAN_Y2, PIN_HIGH);
            break;
        case 2:
            rt_pin_write(KEY_SCAN_Y1, PIN_HIGH);
            rt_pin_write(KEY_SCAN_Y2, PIN_LOW);
            break;
        default:
            break;
        }
        for (int i = 0; i < 10; i++) {}
        /*read the state of Y1*/
        if (rt_pin_read(KEY_SCAN_X1) == 1)
        {
            CC |= 0x1 << key_press_num;
        }
        key_press_num++;
        if (rt_pin_read(KEY_SCAN_X2) == 1)
        {
            CC |= 0x1 << key_press_num;
        }
        key_press_num++;
        if (rt_pin_read(KEY_SCAN_X3) == 1)
        {
            CC |= 0x1 << key_press_num;
        }
        key_x_num++;
        key_press_num++;
        if (key_x_num >= 3)
        {
            rt_pin_write(KEY_SCAN_Y1, PIN_LOW);
            rt_pin_write(KEY_SCAN_Y2, PIN_LOW);
            return CC;
        }
    }
}

上面的代码主要用于获取以及确定键值,具体的处理还是得需要在后面的回调函数中进行,如下所示。

int Key_Value = 0;
static uint8_t common_btn_read(void *arg)
{
    uint8_t value = 0;
    flex_button_t *btn = (flex_button_t *)arg;
    Key_Value = 0;
    switch (btn->id)
    {
    case USER_BUTTON_0:
        // 如果是矩阵键盘
#if Matrix_keyboard_Enable
        Key_Value = scan_key_x_y();
        if (Key_Value == USER_MATRIX_BUTTON_0_Val)
            value = 1;
        else
            value = 0;
        // 普通按键
#else
        value =  rt_pin_read(KEY_0);
        Key_Value = value;
#endif
        break;

    case USER_BUTTON_1:
        // 如果是矩阵键盘
#if Matrix_keyboard_Enable
        Key_Value = scan_key_x_y();
        if (Key_Value == USER_MATRIX_BUTTON_1_Val)
            value = 1;
        else
            value = 0;
        // 普通按键
#else
        value = rt_pin_read(KEY_1);
        Key_Value = value;
#endif
        break;

    case USER_BUTTON_2:
        // 如果是矩阵键盘
#if Matrix_keyboard_Enable
        Key_Value = scan_key_x_y();
        if (Key_Value == USER_MATRIX_BUTTON_2_Val)
            value = 1;
        else
            value = 0;
        // 普通按键
#else
        value = rt_pin_read(KEY_2);
        Key_Value = value;
#endif
        break;

    case USER_BUTTON_3:
        // 如果是矩阵键盘
#if Matrix_keyboard_Enable
        Key_Value = scan_key_x_y();
        if (Key_Value == USER_MATRIX_BUTTON_3_Val)
            value = 1;
        else
            value = 0;
        // 普通按键
#else
        value = rt_pin_read(KEY_UP);
        Key_Value = value;
#endif
        break;
    default:
        RT_ASSERT(0);
    }
    return value;
}

这个函数主要是处理按键的回调函数,处理的也大部分是按键相关的回调函数。主要还是适配对这个按键驱动的框架。针对按键还需要对具体的键值要有一定的认知,知道什么情况下键值对应的按键。有些外部电路会影响到我们设置的电平,也会影响到键值。

全部的按键处理文件key_deal.c的代码如下所示:

/*
 * @Description:
 * @Version: 1.0
 * @Autor: 
 * @Date: 2021-06-28 14:17:27
 * @LastEditors:  
 * @LastEditTime: 2021-07-21 13:10:56
 */

#include "GUI.h"
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_gpio.h"
#include "key_deal.h"
#include "startup.h"
#include "flexible_button.h"

/* 单独按键定义方式 */
#define     KEY_0       GET_PIN(1,5)
#define     KEY_1       GET_PIN(5,1)
#define     KEY_2       GET_PIN(3,26)

#define     KEY_UP      GET_PIN(5,0)

/* 矩阵键盘定义方式 */
#define     KEY_SCAN_X1     GET_PIN(3,14)
#define     KEY_SCAN_X2     GET_PIN(3,12)
#define     KEY_SCAN_X3     GET_PIN(3,15)

#define     KEY_SCAN_Y1     GET_PIN(3,17)
#define     KEY_SCAN_Y2     GET_PIN(3,16)

#define     WM_Enable                   0
#define     Matrix_keyboard_Enable      1

extern WM_Status_t WM_Status;
//flex button
// 优点:支持组合按键,支持多次按键的按下的检测。多按键的情况下的实施比较方便
// 缺点:复杂,而且由于是回调类型的可能比较不方便。单个回调。
flex_button/
#define ENUM_TO_STR(e) (#e)
typedef enum
{
    USER_BUTTON_0 = 0, // 对应  的 PIN_KEY0
    USER_BUTTON_1,     // 对应  的 PIN_KEY1
    USER_BUTTON_2,     // 对应  的 PIN_KEY2
    USER_BUTTON_3,     // 对应  的 PIN_WK_UP
    USER_BUTTON_MAX
} user_button_t;

typedef enum
{
    USER_MATRIX_BUTTON_0_Val = 31,           // 对应  的 PIN0
    USER_MATRIX_BUTTON_1_Val = 47,           // 对应  的 PIN1
    USER_MATRIX_BUTTON_2_Val = 55,           // 对应  的 PIN2
    USER_MATRIX_BUTTON_3_Val = 59,           // 对应  的 PIN3
    USER_MATRIX_BUTTON_4_Val = 61,           // 对应  的 PIN4
    USER_MATRIX_BUTTON_5_Val = 62,           // 对应  的 PIN5
    USER_MATRIX_BUTTON_DEFULT_Val = 63  // 对应  的 PIN5
} user_Matrix_button_val_t;

static char *enum_event_string[] =
{
    ENUM_TO_STR(FLEX_BTN_PRESS_DOWN),
    ENUM_TO_STR(FLEX_BTN_PRESS_CLICK),
    ENUM_TO_STR(FLEX_BTN_PRESS_DOUBLE_CLICK),
    ENUM_TO_STR(FLEX_BTN_PRESS_REPEAT_CLICK),
    ENUM_TO_STR(FLEX_BTN_PRESS_SHORT_START),
    ENUM_TO_STR(FLEX_BTN_PRESS_SHORT_UP),
    ENUM_TO_STR(FLEX_BTN_PRESS_LONG_START),
    ENUM_TO_STR(FLEX_BTN_PRESS_LONG_UP),
    ENUM_TO_STR(FLEX_BTN_PRESS_LONG_HOLD),
    ENUM_TO_STR(FLEX_BTN_PRESS_LONG_HOLD_UP),
    ENUM_TO_STR(FLEX_BTN_PRESS_MAX),
    ENUM_TO_STR(FLEX_BTN_PRESS_NONE),
};

static char *enum_btn_id_string[] =
{
    ENUM_TO_STR(USER_BUTTON_0),
    ENUM_TO_STR(USER_BUTTON_1),
    ENUM_TO_STR(USER_BUTTON_2),
    ENUM_TO_STR(USER_BUTTON_3),
    ENUM_TO_STR(USER_BUTTON_MAX),
};

static flex_button_t user_button[USER_BUTTON_MAX];

volatile static rt_thread_t tid1 = RT_NULL;

// 此函数需要实现,采用Emwin的KEY部分的发送
extern void WM_Send_Key_Msg(int Screen_Num, int Key, int Pressed, char Focus);
// example:
// void WM_Send_Key_Msg(char Screen_Num,int Key, int Pressed, char Focus)
// {
//     GUI_SendKeyMsg(Key, Pressed);
//     if (!Focus)
//         WM_SendMessageNoPara(WM_GetDialogItem(my_hWin, Screen_Num), WM_KEY_USER_DEAL);
// }

static void common_btn_evt_cb(void *arg)
{
    flex_button_t *btn = (flex_button_t *)arg;

    rt_kprintf("id: [%d - %s]  event: [%d - %30s]  repeat: %d\n",
               btn->id, enum_btn_id_string[btn->id],
               btn->event, enum_event_string[btn->event],
               btn->click_cnt);
    switch (btn->id)
    {
    case  USER_BUTTON_0:
        switch (btn->event)
        {
        case FLEX_BTN_PRESS_CLICK:
            rt_kprintf("Button 0 is click!!\r\n");
#if WM_Enable
            WM_Send_Key_Msg(WM_Status.Current_Screen, GUI_KEY_RIGHT, 1, 0);
#endif
            break;

        default:
            break;
        }
        break;
    case  USER_BUTTON_1:
        switch (btn->event)
        {
        case FLEX_BTN_PRESS_CLICK:
            rt_kprintf("Button 1 is click!!\r\n");
#if WM_Enable
            WM_Send_Key_Msg(WM_Status.Current_Screen, GUI_KEY_DOWN, 1, 0);
#endif
            break;

        default:
            break;
        }
        break;
    case  USER_BUTTON_2:
        switch (btn->event)
        {
        case FLEX_BTN_PRESS_CLICK:
            rt_kprintf("Button 2 is click!!\r\n");
#if WM_Enable
            WM_Send_Key_Msg(WM_Status.Current_Screen, GUI_KEY_LEFT, 1, 0);
#endif
            break;

        default:
            break;
        }
        break;
    case  USER_BUTTON_3:
        switch (btn->event)
        {
        case FLEX_BTN_PRESS_CLICK:
            rt_kprintf("Button 3 is click!!\r\n");
            break;

        default:
            break;
        }
        break;
    default:
        break;
    }
    if ((flex_button_event_read(&user_button[USER_BUTTON_0]) == FLEX_BTN_PRESS_CLICK) && \
            (flex_button_event_read(&user_button[USER_BUTTON_1]) == FLEX_BTN_PRESS_CLICK))
    {
        rt_kprintf("[combination]: button 0 and button 1\n");
    }
}

/**
 * @function: scan_key_x_y
 * @brief: 行列式扫描按键
 * @param {*}
 * @return {*}
 * @author: lzc
 */
int scan_key_x_y(void)
{
    char key_x_num = 1;     //x轴
    char key_press_num = 0; //按下的按键,从k2开始
    int CC = 0; //用于标记按键信息
    /*X轴提供高电平*/
    while (1)
    {
        switch (key_x_num)
        {
        case 1:
            rt_pin_write(KEY_SCAN_Y1, PIN_LOW);
            rt_pin_write(KEY_SCAN_Y2, PIN_HIGH);
            break;
        case 2:
            rt_pin_write(KEY_SCAN_Y1, PIN_HIGH);
            rt_pin_write(KEY_SCAN_Y2, PIN_LOW);
            break;
        default:
            break;
        }
        for (int i = 0; i < 10; i++) {}
        /*read the state of Y1*/
        if (rt_pin_read(KEY_SCAN_X1) == 1)
        {
            CC |= 0x1 << key_press_num;
        }
        key_press_num++;
        if (rt_pin_read(KEY_SCAN_X2) == 1)
        {
            CC |= 0x1 << key_press_num;
        }
        key_press_num++;
        if (rt_pin_read(KEY_SCAN_X3) == 1)
        {
            CC |= 0x1 << key_press_num;
        }
        key_x_num++;
        key_press_num++;
        if (key_x_num >= 3)
        {
            rt_pin_write(KEY_SCAN_Y1, PIN_LOW);
            rt_pin_write(KEY_SCAN_Y2, PIN_LOW);
            return CC;
        }
    }
}

int Key_Value = 0;
static uint8_t common_btn_read(void *arg)
{
    uint8_t value = 0;
    flex_button_t *btn = (flex_button_t *)arg;
    Key_Value = 0;
    switch (btn->id)
    {
    case USER_BUTTON_0:
        // 如果是矩阵键盘
#if Matrix_keyboard_Enable
        Key_Value = scan_key_x_y();
        if (Key_Value == USER_MATRIX_BUTTON_0_Val)
            value = 1;
        else
            value = 0;
        // 普通按键
#else
        value =  rt_pin_read(KEY_0);
        Key_Value = value;
#endif
        break;

    case USER_BUTTON_1:
        // 如果是矩阵键盘
#if Matrix_keyboard_Enable
        Key_Value = scan_key_x_y();
        if (Key_Value == USER_MATRIX_BUTTON_1_Val)
            value = 1;
        else
            value = 0;
        // 普通按键
#else
        value = rt_pin_read(KEY_1);
        Key_Value = value;
#endif
        break;

    case USER_BUTTON_2:
        // 如果是矩阵键盘
#if Matrix_keyboard_Enable
        Key_Value = scan_key_x_y();
        if (Key_Value == USER_MATRIX_BUTTON_2_Val)
            value = 1;
        else
            value = 0;
        // 普通按键
#else
        value = rt_pin_read(KEY_2);
        Key_Value = value;
#endif
        break;

    case USER_BUTTON_3:
        // 如果是矩阵键盘
#if Matrix_keyboard_Enable
        Key_Value = scan_key_x_y();
        if (Key_Value == USER_MATRIX_BUTTON_3_Val)
            value = 1;
        else
            value = 0;
        // 普通按键
#else
        value = rt_pin_read(KEY_UP);
        Key_Value = value;
#endif
        break;
    default:
        RT_ASSERT(0);
    }
    return value;
}

static void user_button_init(void)
{
    int i;

    /* 初始化按键数据结构 */
    rt_memset(&user_button[0], 0x0, sizeof(user_button));

    rt_pin_mode(KEY_0, PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(KEY_1, PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(KEY_2, PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(KEY_UP, PIN_MODE_INPUT_PULLUP);

    rt_pin_mode(KEY_SCAN_X1, PIN_MODE_INPUT);
    rt_pin_mode(KEY_SCAN_X2, PIN_MODE_INPUT);
    rt_pin_mode(KEY_SCAN_X3, PIN_MODE_INPUT);

    rt_pin_mode(KEY_SCAN_Y1, PIN_MODE_OUTPUT);
    rt_pin_mode(KEY_SCAN_Y2, PIN_MODE_OUTPUT);


    for (i = 0; i < USER_BUTTON_MAX; i ++)
    {
        user_button[i].id = i;
        user_button[i].usr_button_read = common_btn_read;
        user_button[i].cb = common_btn_evt_cb;
        user_button[i].pressed_logic_level = 1;
        user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500);
        user_button[i].long_press_start_tick = FLEX_MS_TO_SCAN_CNT(3000);
        user_button[i].long_hold_start_tick = FLEX_MS_TO_SCAN_CNT(4500);

        if (i == USER_BUTTON_3)
        {
            user_button[USER_BUTTON_3].pressed_logic_level = 1;
        }

        flex_button_register(&user_button[i]);
    }
}

static void button_scan(void *arg)
{
    while (1)
    {
        flex_button_scan();
        rt_thread_mdelay(20); // 20 ms
    }
}

int flex_button_main(void)
{
    rt_thread_t tid = RT_NULL;
    user_button_init();
    /* 创建按键扫描线程 flex_btn,线程栈 1024 byte,优先级 10 */
    tid = rt_thread_create("flex_btn", button_scan, RT_NULL, 1024, 10, 10);
    if (tid != RT_NULL)
    {
        rt_thread_startup(tid);
    }
    return 0;
}

/* 使用 RT-Thread 的自动初始化 */
INIT_APP_EXPORT(flex_button_main);

如果不采用Emwin可以去掉我代码中关于emwin的部分使得其他部分也可以正常运行

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值