LVGL学习(4):输入设备的四种类型及物理按键的实现

在有一些场合中,如野外情况,可能我们会选择使用物理按键来控制LVGL,而不是使用触摸屏。所以本篇文章就以物理键盘为例来介绍一下如何自定义输入设备与LVGL进行交互。

1 输入设备类型

对于键盘、触摸屏、编码器等输入设备,都可以与LVGL进行交互。我们只需要将输入设备注册到LVGL的输入设备结构体lv_indev_drv_t中即可。输入设备的类型,有以下几种选择:

typedef enum {
    LV_INDEV_TYPE_NONE,    /**< Uninitialized state*/
    LV_INDEV_TYPE_POINTER, /**< Touch pad, mouse, external button*/
    LV_INDEV_TYPE_KEYPAD,  /**< Keypad or keyboard*/
    LV_INDEV_TYPE_BUTTON,  /**< External (hardware button) which is assigned to a specific point of the screen*/
    LV_INDEV_TYPE_ENCODER, /**< Encoder with only Left, Right turn and a Button*/
} lv_indev_type_t;

先来分析一下这四种输入设备有什么区别,具体源码请参考lv_indev_read_timer_cb函数:
(1)LV_INDEV_TYPE_POINTER
主要用于触摸屏、鼠标,所以它的输入处理函数indev_pointer_proc就是判断当前触摸屏返回的位置处是不是有组件存在,若有且触摸释放了,则会执行对应组件的Clicked动作。
(2)LV_INDEV_TYPE_KEYPAD
它的输入处理函数indev_keypad_proc中,就根据输入的不同按键(Prev,Next,ESC,Enter等)对Keypad所绑定的group内的组件进行操作,如焦点的切换、进度条的滑动。比如说对于一个Table来说,里面的数据很多,有一个滑动条,这个滑动条就受LV_KEY_UPLV_KEY_Down键控制;而对于一个Tabview来说,Tab的切换则是受LV_KEY_LEFTLV_KEY_RIGHT键控制。而Group中的组件之间的焦点切换则是通过LV_KEY_PREVLV_KEY_NEXT键切换。
(3)LV_INDEV_TYPE_BUTTON
就是一个按键,适用于GUI中焦点永远在某一个组件上的情况。按下物理按键就代表GUI中的按键按下。
(4)LV_INDEV_TYPE_ENCODER
一个编码器应该只能左右旋转,也就是支持LV_KEY_LEFTLV_KEY_RIGHT。但在LVGL的源码中,编码器除了左右外,还保留了LV_KEY_ENTERLV_KEY_ESC两个按键触发的代码,用户可以根据自己的情况触发这两个按键,适用于编码器和按键的组合情况。

2 物理键盘实现

经过上面的分析,我们知道对于物理键盘应该选择LV_INDEV_TYPE_KEYPAD,这样我们就可以完成各个组件焦点的切换、滑动条上下移动等操作。

2.1 输入设备驱动注册

在函数lv_port_indev_init中,默认有触摸设备LV_INDEV_TYPE_POINTER的注册代码,这里我们仿照触摸设备,写一个物理按键的注册代码:

static lv_indev_drv_t keypad_drv;
lv_indev_drv_init(&keypad_drv);
keypad_drv.type    = LV_INDEV_TYPE_KEYPAD;
/* 回调函数:通过这个函数读取输入设备的值 */
keypad_drv.read_cb = keypad_read;
indev_keypad = lv_indev_drv_register(&keypad_drv);

通过前面的分析,我们知道LV_KEY_PREVLV_KEY_NEXT两个按键可以切换焦点,而焦点是基于组中的组件进行切换的,最后还需要绑定Keypad输入设备对应的组。

group = lv_group_create();
lv_indev_set_group(indev_keypad, group); 
lv_group_set_default(group);

2.2 按键驱动的实现

首先我们要实现按键的驱动,比如物理按键有四个,左、右、退出和确定,分别对应LV_KEY_LEFTLV_KEY_RIGHTLV_KEY_ESCLV_KEY_ENTER

对于硬件上来说,在按键处接了电容,所以不用消抖。我们就打开硬件上按键所对应引脚的上升沿/下降沿中断,然后在中断中返回我们的按键即可。这里我们默认数字0为没有任何按键按下,数字1~4分别对应物理按键的四种,在中断中将这个数字赋值给curKey变量。然后定义一个按键读取函数,代码如下所示:

static uint8_t curKey
uint8_t button_read()
{
	uint8_t tmp = curKey;
	curKey = 0;
	return tmp;
}

我们注意到前面注册输入设备驱动的时候,还有一个回调函数:keypad_drv.read_cb = keypad_read,LVGL就会周期性调用这个函数来判断是否有按键按下,按键的扫描频率可以通过修改下面的宏定义改变。

#define LV_INDEV_DEF_READ_PERIOD       10

现在我们需要通过keypad_read函数将我们的物理按键和与LVGL中的左、右、退出和确定对应起来,代码如下:

static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static uint32_t last_key = 0;
    uint32_t act_key = button_read();
    if(act_key != 0) {
        data->state = LV_INDEV_STATE_PR;
        switch(act_key)
        {
	        case 1:
	            act_key = LV_KEY_LEFT;
	            break;
	        case 2:
	            act_key = LV_KEY_RIGHT;
	            break;
	        case 3:
	            act_key = LV_KEY_ESC;
	            break;
	        case 4:
	        	act_key = LV_KEY_ENTER;
	        default:
	        	break;
        }
        last_key = act_key;
    } else {
        data->state = LV_INDEV_STATE_REL;
    }
    data->key = last_key;
}

上面的函数就是在有按键按下时,赋值对应的LVGL按键宏给data->key,而在没有按键按下时,data->key就等于上一次按下的键。而data->state变量则是判断按键按下后是否松开,比如对于按键的回调函数来说,可以设置ClickedReleased时触发GUI中的按键,对于Clicked来说,按下不松开就触发按键回调函数,而Released则需要按下后放开才会触发按键回调函数。

猜你喜欢

转载自blog.csdn.net/tilblackout/article/details/131097596