ESP32 LVGL8.1 ——Input devices 输入设备 (Input devices 18)

提示:本博客作为学习笔记,有错误的地方希望指正

一、Input devices 简介

1.1概述 Overview

  输入设备通常意味着:
•像触控板或鼠标这样的指针式输入设备
•小键盘像一个普通的键盘或简单的数字小键盘
•编码器与左/右转和推选项
•外部硬件按钮,分配给屏幕上的特定点
在进一步阅读之前,请阅读输入设备的移植(/移植/indev)部分,

1.2 指针 Pointers

  指针输入设备可以有光标。(通常为鼠标)

lv_indev_t * mouse_indev = lv_indev_drv_register(&indev_drv);
LV_IMG_DECLARE(mouse_cursor_icon); 							/*Declare the image file.*/
lv_obj_t * cursor_obj = lv_img_create(lv_scr_act(), NULL); 	/*Create an image object␣
/*for the cursor */
lv_img_set_src(cursor_obj, &mouse_cursor_icon); /*Set the image source*/
lv_indev_set_cursor(mouse_indev, cursor_obj); 	/*Connect the image ␣
,→object to the driver*/

  注意,游标对象应该有lv_obj_set_click(cursor_obj, false)。对于图像,默认情况下禁用单击。

1.3 按键和编码器 Keypad and encoder

  您可以完全控制用户界面无需触摸板或鼠标使用一个小键盘或编码器(s)。它的工作原理类似于PC上的TAB键来选择应用程序或网页中的元素。

1.3.1 组 Groups

  需要将要用键盘或编码器控制的对象添加到组中。在每一组中,都有一个被聚焦的对象接收按下的键或编码器的动作。例如,如果一个文本区域是集中的,您按键盘上的某个字母,键将被发送并插入到文本区域。类似地,如果一个滑块被聚焦,并且你按下向左或向右的箭头,滑块的值将会改变。您需要将输入设备与组关联起来。一个输入设备只能将密钥发送给一个组,但是,一个组也可以接收来自多个输入设备的数据。要创建组,请使用lv_group_t * g = lv_group_create();要向组添加对象,请使用lv_group_add_obj(g, obj)。使用lv_indev_set_group(indev, g)将组与输入设备关联,其中indev是lv_indev_drv_register()的返回值。

1.3.1.1 按键 Keys

  有一些预定义的键有特殊的含义:
• LV_KEY_NEXT 下一个对象
• LV_KEY_PREV 关注前一个对象
• LV_KEY_ENTER 触发LV_EVENT_PRESSED/CLICKED/LONG_PRESSED等事件
• LV_KEY_UP 增加价值或向上移动
• LV_KEY_DOWN 降低价值或向下移动
• LV_KEY_RIGHT 增加价值或向右移动
• LV_KEY_LEFT 减少数值或向左移动
• LV_KEY_ESC 关闭或退出(例如关闭下拉列表)
• LV_KEY_DEL 删除(例如文本区域右边的一个字符)
• LV_KEY_BACKSPACE 删除左边的字符(例如在文本区域)
• LV_KEY_HOME 转到开始/顶部(例如在文本区域)
• LV_KEY_END 转到最后(例如在文本区域))
最重要的特殊键是LV_KEY_NEXT/PREV、LV_KEY_ENTER和LV_KEY_UP/DOWN/LEFT/RIGHT。在
read_cb函数中,您应该将一些键转换为这些特殊的键,以便在组中导航并与所选对象交互。只使用LV_KEY_LEFT/RIGHT就足够了,因为大多数对象都可以用它们完全控制。对于编码器,您应该只使用LV_KEY_LEFT、LV_KEY_RIGHT和LV_KEY_ENTER。

1.3.1.2 编辑和导航模式 Edit and navigate mode

  因为小键盘有很多键,所以很容易在对象之间导航并使用小键盘编辑它们。但是,编码器的“密钥”数量有限,因此很难使用默认选项进行导航。创建导航和编辑是为了避免编码器的这个问题。
  在导航模式下,编码器LV_KEY_LEFT/RIGHT被转换为LV_KEY_NEXT/PREV。因此,将通过旋转编码器选择下一个或上一个对象。按LV_KEY_ENTER将切换到编辑模式。
  在编辑模式下,通常使用LV_KEY_NEXT/PREV来编辑对象。根据对象的类型,短按或长按LV_KEY_ENTER将更改回导航模式。通常,一个对象不能按下(如滑块)在短点击离开编辑模式。但是对于那些短点击具有意义的对象(如按钮),就需要长时间的按压。
  通常使用这个函数进行切换导航模式和编辑模式 lv_group_set_editing(group,false);

1.3.2 样式 Styling

  如果一个对象通过触摸板点击聚焦,或者通过编码器或键盘聚焦,它就会转到LV_STATE_FOCUSED。因此,重点样式将应用于它。
  如果对象进入编辑模式,它将进入LV_STATE_FOCUSED | LV_STATE_EDITED状态,因此这些样式属性将被显示。
  有关更详细的描述,请阅读样式部分。

二、输入设备接口 Input device interface

2.1 输入设备类型 Types of input devices

  注:文章中的内容大部分从 lv_port_indev_template.c模板中修改而来的。
  要注册输入设备,必须初始化lv_indev_drv_t变量:: 以初始化KeyPad为例子

2.1.1 触摸板,鼠标或任何指针 Touchpad, mouse or any pointer

    static lv_indev_drv_t indev_drv;
    /*Initialize your keypad or keyboard if you have*/
    keypad_init();                                  //初始化硬件
    /*Register a keypad input device*/
    lv_indev_drv_init(&indev_drv);                  //初始化注册
    indev_drv.type = LV_INDEV_TYPE_KEYPAD;          //初始化注册类型
    indev_drv.read_cb = keypad_read;                //初始化读取回调
    indev_keypad_or_encoder = lv_indev_drv_register(&indev_drv);    //初始化回调实现

  indev_drv.type 可以是以下一种情况。
• LV_INDEV_TYPE_POINTER 触摸板或鼠标
• LV_INDEV_TYPE_KEYPAD 键盘
• LV_INDEV_TYPE_ENCODER编码器与左/右转和推选项
• LV_INDEV_TYPE_BUTTON外部按键几乎在按屏幕
read_cb是一个函数指针,它将被定期调用以报告输入设备的当前状态。
  可以点击屏幕点的输入设备属于这一类。

indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_input_read;

void my_input_read(lv_indev_drv_t * drv, lv_indev_data_t*data)
{
	if(touchpad_pressed) {
		data->point.x = touchpad_x;
		data->point.y = touchpad_y;
		data->state = LV_INDEV_STATE_PRESSED;
	} else {
		data->state = LV_INDEV_STATE_RELEASED;
	}
}

  要设置鼠标光标,请使用lv_indev_set_cursor(my_indev, &img_cursor)。(my_indev是lv_indev_drv_register的返回值)

2.1.1 键盘或键盘 Keypad or keyboard

  包含所有字母的全键盘或带有几个导航按钮的简单键盘都属于这里。
使用键盘/小键盘:
•用LV_INDEV_TYPE_KEYPAD类型注册一个read_cb函数。
•必须创建一个对象组:lv_group_t * g = lv_group_create(),并且必须使用lv_group_add_obj(g, obj)向其添加对象
•创建的组必须分配给输入设备:lv_indev_set_group(my_indev, g) (my_indev是lv_indev_drv_register的返回值)
• 使用LV_KEY_……在组中的对象之间导航。有关可用的键,请参阅lv_core/lv_group.h。

indev_drv.type = LV_INDEV_TYPE_KEYPAD;
indev_drv.read_cb = keyboard_read;
void keyboard_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
	data->key = last_key(); /*Get the last pressed or released key*/
	if(key_pressed()) data->state = LV_INDEV_STATE_PRESSED;
		else data->state = LV_INDEV_STATE_RELEASED;
}

2.1.1 编码器 Encoder

  使用编码器你可以做4件事:
1.按下的按钮
2.长按该按钮
3.向左转
4.向右转
简而言之,Encoder输入设备是这样工作的:
•通过旋转编码器,你可以关注下一个/上一个对象。
•当您在一个简单的对象(如按钮)上按下编码器时,它将被单击。.
• 如果你在一个复杂的对象(如列表,消息框等)上按下编码器,该对象将进入编辑模式,通过这种方式,你可以在对象内部导航。
•要离开编辑模式,请长按按钮。
要使用编码器(类似于小键盘),对象应该添加到组中。

indev_drv.type = LV_INDEV_TYPE_ENCODER;
indev_drv.read_cb = encoder_read;
void encoder_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
	data->enc_diff = enc_get_new_moves();if(enc_pressed()) data->state = LV_INDEV_STATE_PRESSED;
	else data->state = LV_INDEV_STATE_RELEASED;
}

  使用按钮与编码器逻辑 Using buttons with Encoder logic 除了标准的编码器行为,您还可以利用它的逻辑来导航(焦点)和使用按钮编辑小部件。如果您只有几个可用的按钮,或者您想使用除编码器轮之外的其他按钮,这是特别方便的。
你需要3个按钮:
• LV_KEY_ENTER 模拟按下或按下编码器按钮
• LV_KEY_LEFT 模拟编码器向左移
• LV_KEY_RIGHT模拟编码器向右移
•其他键将被传递给聚焦的小部件
如果你按住这些键,它将模拟编码器点击并指定周期为indev_drv.long_press_rep_time.

2.1.1 按钮 Button

  按钮是指屏幕旁边的外部“硬件”按钮,它们被分配给屏幕的特定坐标。如果一个按钮被按下,它将模拟在指定坐标上的按下。(类似于触摸板)将按钮分配给坐标使用lv_indev_set_button_points(my_indev,points_array).points_array应该像这样const lv_point_t points_array[] = {{12,30},{60,90}, …}

indev_drv.type = LV_INDEV_TYPE_BUTTON;
indev_drv.read_cb = button_read;
void button_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
	static uint32_t last_btn = 0;				/*Store the last pressed button*/
	int btn_pr = my_btn_read(); 				/*Get the ID (0,1,2...) of the pressed button*/
	if(btn_pr >= 0) { 							/*Is there a button press? (E.g. -1 indicated no button was pressed)*/
		last_btn = btn_pr; 						/*Save the ID of the pressed button*/
		data->state = LV_INDEV_STATE_PRESSED; 	/*Set the pressed state*/
	} else {
		data->state = LV_INDEV_STATE_RELEASED; 	/*Set the released state*/
	}
	data->btn = last_btn; 						/*Save the last button*/
}

2.2 其他特点 Other features

2.2.1 参数 Parameters

  以下参数的默认值可以在lv_indev_drv_t:
• scroll_limit在实际滚动对象之前要滑动的像素数。
• scroll_throw滚动投掷(动量)减速在[%]。值越大,减速速度越快。
• long_press_time按下发送LV_EVENT_LONG_PRESSED的时间(毫秒)
• long_press_rep_timeLV_EVENT_LONG_PRESSED_REPEAT发送间隔(毫秒)
• read_timer指向lv_rimer的指针,用于读取输入设备。它的参数可以通过lv_timer_…()函数来更改。
lv_conf.h中的LV_INDEV_DEF_READ_PERIOD设置默认的读周期。

2.2.1 反馈 Feedback

  除了read_cb,还可以在lv_indev_drv_t中指定feedback_cb回调。当输入设备发送任何类型的事件时,调用Feedback_cb。(与类型无关)。它允许为用户提供反馈,例如在LV_EVENT_CLICKED上播放声音。

2.2.1 与显示器关联 Associating with a display

  每个输入设备都与一个显示器相关联。默认情况下,新输入设备会添加到最后创建的或显式选择的(使用lv_disp_set_default())显示中。相关的显示存储,并可以在驱动器的disp字段更改。

2.2.1 缓冲阅读 Buffered reading

  默认情况下,LVGL会定期调用read_cb。由于这种断断续续的轮询,有可能某些用户姿态是错过了。
  为了解决这个问题,你可以为你的输入设备编写一个事件驱动的驱动程序来缓冲测量数据。在read_cb中,你可以设置缓冲数据,而不是读取输入设备。你可以设置data-> continue_reading标志来告诉LVGL有更多的数据要读,它应该再次调用read_cb。

2.1 API

  有关于分组的API如下所示

lv_group_t * lv_group_create(void)					//创建一个新的对象组
void lv_group_del(lv_group_t * group)				//删除组对象
void lv_group_set_default(lv_group_t * group)		//设置默认组。如果在类中使用' add_to_def_group = true '启用该组,则新对象将被添加到该组中。
lv_group_t * lv_group_get_default(void)				//获取默认组
void lv_group_add_obj(lv_group_t * group, struct _lv_obj_t * obj)	//添加一个对象到组
void lv_group_remove_obj(struct _lv_obj_t * obj)	//从组中移除一个对象
void lv_group_remove_all_objs(lv_group_t * group)	//移除组中的所有对象
void lv_group_focus_obj(struct _lv_obj_t * obj)		//聚焦一个对象(离焦当前)
void lv_group_focus_next(lv_group_t * group)		//聚焦组中的下一个对象(离焦当前对象)
void lv_group_focus_prev(lv_group_t * group)		//对一组中的前一个对象进行焦点化(对当前对象进行散焦)
void lv_group_focus_freeze(lv_group_t * group, bool en)				//不要改变当前对象的焦点
lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c)			//发送一个控制字符到组的焦点对象
void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb)			//为一个组设置一个函数,当一个新对象被聚焦时,该函数将被调用
void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy)	//设置组中的下一项还是前一项是焦点,如果当前的焦点对象被删除。
struct _lv_obj_t * lv_group_get_focused(const lv_group_t * group)	//获取焦点对象,如果没有的话获取NULL
lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group)	//获取一个组的焦点回调函数
void lv_group_set_editing(lv_group_t * group, bool edit)			//手动设置当前模式(编辑或导航)。
bool lv_group_get_editing(const lv_group_t * group)					//获取当前模式(编辑或导航)。
void lv_group_set_wrap(lv_group_t * group, bool en)					//设置焦点next/prev是否允许从first->last或last->first对象进行包装。
bool lv_group_get_wrap(lv_group_t * group)							//获取焦点next/prev是否允许从first->last或last->first对象进行包装。
uint32_t lv_group_get_obj_count(lv_group_t * group)					//获取组中对象的数量

  有关于输入设备的API如下所示

void lv_indev_read_timer_cb(lv_timer_t * timer)						//周期性调用以读取输入设备
void lv_indev_enable(lv_indev_t * indev, bool en)					//输入设备使能
lv_indev_t * lv_indev_get_act(void)									//获取当前处理的输入设备。也可以用于动作函数中。
lv_indev_type_t lv_indev_get_type(const lv_indev_t * indev)			//获取一个输入设备的类型
void lv_indev_reset(lv_indev_t * indev, lv_obj_t * obj)				//重置一个或所有输入设备
void lv_indev_reset_long_press(lv_indev_t * indev)					//重置输入设备的长按状态
void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj)	//为指针输入设备(LV_INPUT_TYPE_POINTER和LV_INPUT_TYPE_BUTTON)设置游标
void lv_indev_set_group(lv_indev_t * indev, lv_group_t * group)		//为键盘输入设备设置目标组(为LV_INDEV_TYPE_KEYPAD)
void lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t points[])	//为LV_INDEV_TYPE_BUTTON设置一个点数组。
void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point)//获取一个输入设备的最后一点(对于LV_INDEV_TYPE_POINTER和LV_INDEV_TYPE_BUTTON)
lv_dir_t lv_indev_get_gesture_dir(const lv_indev_t * indev)			//直接获取当前的手势
uint32_t lv_indev_get_key(const lv_indev_t * indev)					//获取一个输入设备的最后一个按下的键(LV_INDEV_TYPE_KEYPAD)
lv_dir_t lv_indev_get_scroll_dir(const lv_indev_t * indev)			//检查当前输入设备的滚动方向(对于LV_INDEV_TYPE_POINTER和LV_INDEV_TYPE_BUTTON)
lv_obj_t * lv_indev_get_scroll_obj(const lv_indev_t * indev)		//获取当前滚动的对象(LV_INDEV_TYPE_POINTER和LV_INDEV_TYPE_BUTTON)
void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point)//获取一个输入设备的移动向量(对于LV_INDEV_TYPE_POINTER和LV_INDEV_TYPE_BUTTON)
void lv_indev_wait_release(lv_indev_t * indev)						//在下一个s释放之前什么都不要做
lv_obj_t * lv_indev_get_obj_act(void)								//获取一个指向当前处理的输入设备中当前活动对象的指针。
lv_timer_t * lv_indev_get_read_timer(lv_disp_t * indev)				//获取一个indev读定时器的指针修改它的参数' lv_timer_…的功能。
lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point)	//搜索最顶部,可点击的对象点

void lv_indev_drv_init(struct _lv_indev_drv_t * driver)				//用默认值初始化一个输入设备驱动程序。它被用来确定字段中已知的值,而不是内存垃圾。在它之后你可以设置字段。
lv_indev_t * lv_indev_drv_register(struct _lv_indev_drv_t * driver)	//注册一个初始化的输入设备驱动程序。
void lv_indev_drv_update(lv_indev_t * indev, struct _lv_indev_drv_t * new_drv)//在运行时更新驱动程序。
lv_indev_t * lv_indev_get_next(lv_indev_t * indev)					//获取下一个输入设备。
void _lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data)		//从输入设备读取数据。

三、示例

  需要使用外部的输入设备就需要对外设备的初始化,我这里对外部设备keypad和使用encoder修改使用编码器模式,我这里并没有使用真正的编码器,而是使用陀螺仪作为输入控制,以陀螺仪的俯仰角和横滚角来作为输入的变化参数(按键),横滚角实现编码器的左右旋转,俯仰角实现编码器的按压和释放。
  初始化lv_port_indev_Key.c文件

#include "lv_port_indev_Key.h"

static const char *TAG = "lv_port_indev";

static void keypad_init(void);
static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static uint32_t keypad_get_key(void);

static void encoder_init(void);
static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static void encoder_handler(void);

lv_indev_t * indev_keypad_or_encoder;

static int32_t encoder_diff;
static lv_indev_state_t encoder_state;

void keypad_lv_port_indev_init(void)
{
    static lv_indev_drv_t indev_drv;
    /*Initialize your keypad or keyboard if you have*/
    keypad_init();                                  //初始化硬件
    /*Register a keypad input device*/
    lv_indev_drv_init(&indev_drv);                  //初始化注册
    indev_drv.type = LV_INDEV_TYPE_KEYPAD;          //初始化注册类型
    indev_drv.read_cb = keypad_read;                //初始化读取回调
    indev_keypad_or_encoder = lv_indev_drv_register(&indev_drv);    //初始化回调实现
}

/*------------------
 * Keypad
 * -----------------*/

/*Initialize your keypad*/
static void keypad_init(void)
{
    /*Your code comes here*/
    key_init();
}

/*Will be called by the library to read the mouse*/
static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static uint32_t last_key = 0;
    /*Get whether the a key is pressed and save the pressed key*/
    uint32_t act_key = keypad_get_key();
    if(act_key != 0) {
        data->state = LV_INDEV_STATE_PR;
        /*Translate the keys to LVGL control characters according to your key definitions*/
        switch(act_key) {
        case 1:
            act_key = LV_KEY_NEXT;
            break;
        case 2:
            act_key = LV_KEY_PREV;
            break;
        case 3:
            act_key = LV_KEY_LEFT;
            break;
        case 4:
            act_key = LV_KEY_RIGHT;
            break;
        case 5:
            act_key = LV_KEY_ENTER;
            break;
        }

        last_key = act_key;
    } else {
        data->state = LV_INDEV_STATE_REL;
    }
    data->key = last_key;
}

/*Get the currently being pressed key.  0 if no key is pressed*/
static uint32_t keypad_get_key(void)
{
    uint8_t key_value = 0;              //按键返回值
#if UserGyroscope   
    short aacx = 0, aacy = 0, aacz = 0; //加速度传感器原始数
    float pitch, roll;
    Get_Accelerometer(&aacx, &aacy, &aacz);         //获取数据
    LIS3DH_get_angleXY(aacx,aacy,aacz,&pitch,&roll);//处理欧拉角
    // ESP_LOGI(TAG,"angle: x=%.3f, y=%.3f,\r\n",pitch,roll);
    if (pitch > 66){
        key_value = LV_KEY_ENTER;       
        // ESP_LOGI(TAG,"LV_KEY_ENTER\r\n");
    }
    else if(pitch < -66){
        key_value = LV_KEY_NEXT;
        // ESP_LOGI(TAG,"LV_KEY_NEXT\r\n");
    }
    else if(roll > 66){
        key_value = LV_KEY_LEFT;
        // ESP_LOGI(TAG,"LV_KEY_LEFT\r\n");
    }
    else if(roll < -66){
        key_value = LV_KEY_RIGHT;
        // ESP_LOGI(TAG,"LV_KEY_RIGHT\r\n");
    }
#else
    //按键触发 方式
    if(gpio_get_level(KEY_LEFT)==1)
        key_value = LV_KEY_LEFT;
    else if(gpio_get_level(KEY_CENTER)==1)
        key_value = LV_KEY_ENTER;
    else if(gpio_get_level(KEY_RIGHT)==1)
        key_value = LV_KEY_RIGHT;
    else if(gpio_get_level(KEY_RIGHT_ADD)==1)
        key_value = LV_KEY_NEXT;
#endif
    return key_value;
}

void encoder_lv_port_indev_init(void)
{
    static lv_indev_drv_t indev_drv;
    /*Initialize your encoder if you have*/
    encoder_init();

    /*Register a encoder input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_ENCODER;
    indev_drv.read_cb = encoder_read;
    indev_keypad_or_encoder = lv_indev_drv_register(&indev_drv);
}

/*------------------
 * Encoder
 * -----------------*/

/*Initialize your keypad*/
static void encoder_init(void)
{
    /*Your code comes here*/
    key_init();
}

/*Will be called by the library to read the encoder*/
static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    encoder_handler();              //状态检测
    data->enc_diff = encoder_diff;  //获取按键值
    data->state = encoder_state;    //获取按键状态值

    encoder_diff = 0;               //增量设置位0
}

/*Call this function in an interrupt to process encoder events (turn, press)*/
static void encoder_handler(void)
{
#if UserGyroscope   
    /*Your code comes here*/
    short aacx = 0, aacy = 0, aacz = 0; //加速度传感器原始数
    float pitch, roll;
    Get_Accelerometer(&aacx, &aacy, &aacz);         //获取数据
    LIS3DH_get_angleXY(aacx,aacy,aacz,&pitch,&roll);//处理欧拉角
	// ESP_LOGI(TAG,"angle: x=%.3f, y=%.3f,\r\n",pitch,roll);

    if (pitch > 66){
        encoder_state = LV_INDEV_STATE_PR;      //按压状态
        // ESP_LOGI(TAG,"LV_INDEV_STATE_PR\r\n");
    }
    else { 
        encoder_state = LV_INDEV_STATE_REL;     //释放状态
        // ESP_LOGI(TAG,"LV_INDEV_STATE_REL\r\n");
    }
    if(roll > 66 && pre_flag){
        encoder_diff ++;                        //增大方向旋转
        pre_flag = 0;
        // ESP_LOGI(TAG,"encoder_diff ++\r\n");
        vTaskDelay(10 / portTICK_PERIOD_MS);    //延时消抖
    }
    else if(roll < -66 && pre_flag){            //减小方向旋转
        encoder_diff --;
        pre_flag = 0;
        // ESP_LOGI(TAG,"encoder_diff --\r\n");
        vTaskDelay(10 / portTICK_PERIOD_MS);    //延时消抖
    }else{
		pre_flag = 1;                           //按压标志位
    }
#else
    //按键触发 方式
    if(gpio_get_level(KEY_LEFT)==1){
        encoder_diff ++;                        //增大方向旋转
        pre_flag = 0;
    }else if(gpio_get_level(KEY_RIGHT)==1){
        encoder_diff ++;                        //增大方向旋转
        pre_flag = 0;
    }
    if(gpio_get_level(KEY_CENTER)==1){
        encoder_state = LV_INDEV_STATE_PR;      //按压状态
    }
    else{
        encoder_state = LV_INDEV_STATE_REL;     //释放状态
    }
#endif
}

void my_lv_port_indev_init(void)
{
#if Encoder
    encoder_lv_port_indev_init();               //初始化编码器
    ESP_LOGI(TAG,"init_encoder_indev\r\n");
#else
    keypad_lv_port_indev_init();                //初始化按键kaypad
    ESP_LOGI(TAG,"init_keypad_indev\r\n");
#endif
}

  初始化lv_port_indev_Key.h文件

#ifndef LV_PORT_INDEV_Key_H
#define LV_PORT_INDEV_Key_H

#include "../components/lvgl/lvgl.h"
#include "my_key.h"
#include "lis3dh.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"

#include <stdio.h>
#include "esp_log.h"

#define Encoder       1     //定义使用编码器模式还是Keypad模式
#define UserGyroscope 0     //定义使用陀螺仪模式还是普通按键输入模式

int pre_flag;               //按压标志位

extern lv_indev_t *  indev_keypad_or_encoder;
void my_lv_port_indev_init(void);
#endif /*LV_PORT_INDEV_TEMPL_H*/

  测试程序

/*************************************************
 *  函数名称 :  key_pad_event_cb
 *  参    数 : lv_event_t * e 回调事件
 *  函数功能 : 事件回调显示
 *************************************************/
static void key_pad_event_cb(lv_event_t * e)
{
   lv_event_code_t code = lv_event_get_code(e);			    //获取事件代码
   lv_obj_t * target = lv_event_get_target(e);			   	//获取事件发送到的对象
   lv_obj_t * cur_target = lv_event_get_current_target(e);  //获取事件最初发送到的对象(与启用事件冒泡时的lv_event_get_target不同)
   lv_obj_t * label = lv_event_get_user_data(e);	        //获取作为lv_obj_add_event_cb的最后一个参数传递的指针
   lv_obj_t * btn = lv_event_get_param(e);			        //获取作为lv_event_send的最后一个参数传递的参数
   if(code==LV_EVENT_KEY){
      uint32_t key=lv_event_get_key(e);                     //获取按键事件
      if(key == LV_KEY_ENTER){
         printf("\r\n *ENTER_key=%d,code=%d",key,(uint32_t)code);
      }else if(key == LV_KEY_NEXT){
         printf("\r\n *NEXT_key=%d,code=%d",key,(uint32_t)code);
      }else if(key == LV_KEY_LEFT){
         printf("\r\n *LEFT_key=%d,code=%d",key,(uint32_t)code);
      }else if(key == LV_KEY_RIGHT){
         printf("\r\n *RIGHT_key=%d,code=%d",key,(uint32_t)code);
      }
   }
}
/*************************************************
 *  函数名称 :  Key_pad_test
 *  参    数 : 无
 *  函数功能 : 事件输入测试
 *************************************************/
void Key_pad_test()
{
   lv_group_t * group = lv_group_create();            //创建分组变量
   lv_indev_set_group(indev_keypad_or_encoder,group); //为键盘输入设备设置目标组

   static lv_style_t style;                           //创建样式
   lv_style_init(&style);                             //初始化样式

   lv_style_set_radius(&style,3);                     //设置圆角
   lv_style_set_bg_color(&style,lv_palette_main(LV_PALETTE_RED)); //设置背景颜色
   lv_style_set_bg_opa(&style,LV_OPA_COVER);          //设置背景透明度

   lv_style_set_border_color(&style,lv_palette_darken(LV_PALETTE_RED,2));//设置变宽
   lv_style_set_border_opa(&style,LV_OPA_80);         //设置变宽透明度

   lv_obj_t * btn1 = lv_btn_create(lv_scr_act());     //创建btn对象
   // lv_obj_add_flag(btn1,LV_OBJ_FLAG_HIDDEN);       //添加标志位
   lv_obj_add_style(btn1,&style,LV_STATE_PRESSED);    //将样式添加到按键对象
   lv_obj_add_event_cb(btn1,key_pad_event_cb,LV_EVENT_KEY,NULL);  //添加按键回调函数
   lv_obj_align(btn1,LV_ALIGN_CENTER,-40,0);          //居中显示

   lv_obj_t * label1 = lv_label_create(btn1);         //创建label
   lv_label_set_text(label1,"Btn1");                  //显示label字内容
   
   lv_obj_t * btn2 = lv_btn_create(lv_scr_act());     //创建btn对象
   // lv_obj_add_flag(btn2,LV_OBJ_FLAG_CHECKABLE);    //添加标志位
   lv_obj_add_style(btn2,&style,LV_STATE_PRESSED);    //将样式添加到按键对象
   lv_obj_add_event_cb(btn2,key_pad_event_cb,LV_EVENT_KEY,NULL);  //添加按键回调函数
   lv_obj_align(btn2,LV_ALIGN_CENTER,40,0);           //居中显示

   lv_obj_t * label2 = lv_label_create(btn2);         //创建label
   lv_label_set_text(label2,"Btn2");                  //显示label字内容

   lv_group_add_obj(group,btn1);                      //添加组
   lv_group_add_obj(group,btn2);                      //添加组
}

  值得注意的是在使用的时候需要初始化外部驱动,初始化位置需要放置在屏幕初始化结束之后。
在这里插入图片描述
测试显示视频:LVGL8外部输入按键输入

要下载ESP32 LVGL 8.2,首先需要进入官方网站(www.lvgl.io)并找到ESP32 LVGL库的下载页面。然后,可以在该页面上找到与ESP32兼容的LVGL版本。确保选择8.2版本。 一旦找到正确的版本,就可以下载ESP32 LVGL 8.2库的ZIP文件。点击下载按钮后,文件将被保存到计算机本地的指定位置。 下载完成后,解压缩ZIP文件,并将解压缩后的文件夹重命名为“ESP32 LVGL 8.2”或其他有意义的名称。 现在,打开Arduino IDE(如果尚未安装,请先安装)。在Arduino IDE中,打开“文件”菜单,然后选择“首选项”。在首选项对话框中,复制并粘贴以下链接到“附加开发板管理器网址”中: https://dl.espressif.com/dl/package_esp32_index.json 保存设置并关闭对话框。接下来,打开“工具”菜单,然后选择“开发板”下的“开发板管理器”选项。 在开发板管理器中,使用搜索栏查找并安装“esp32”开发板支持。找到“esp32 by Espressif Systems”并点击“安装”按钮。 安装完成后,选择“工具”菜单下的“开发板”选项,在开发板列表中找到“ESP32 Dev Module”并选择。 现在,打开“文件”菜单,然后选择“示例”,在下拉菜单中找到“ESP32 LVGL 8.2”文件夹。可以在这个文件夹中找到不同的示例。 选择要运行的示例,并点击“上传”按钮。此时,编译和上传过程将开始。 如果一切正常,示例将成功上传到ESP32开发板上,并且在串行监视器中可以看到示例运行的输出。 这样,我们就完成了ESP32 LVGL 8.2的下载和运行。现在可以开始使用这个强大的图形库来开发各种精美的用户界面了。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值