具体怎么使用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的部分使得其他部分也可以正常运行