1. ESP开发之实体按键(KEYPAD&BUTTON)控制LVGL控件

  • 说明
  • LV_INDEV_TYPE_BUTTON的使用
  • LV_INDEV_TYPE_KEYPAD的使用

说明

本实验使用LVGL版本为v9.2

LVGL中有四种输入设备,如下

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_KEYPAD和LV_INDEV_TYPE_BUTTON的使用。因为这两个输入设备都可以用实体按键实现。当然,这两个输入设备掌握了,LV_INDEV_TYPE_ENCODER也是很容易类推的。

LV_INDEV_TYPE_BUTTON的使用

此输入设备其实是模拟的 LV_INDEV_TYPE_POINTER设备相应坐标被按下。使用它之前,应该有明确UI的布局,特别屏幕上按钮的坐标是明确的。

  1. 实体按键初始化
c 复制代码
void key_init(void)
{
	// 配置 GPIO
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << KEY1)|(1ULL << KEY2)|(1ULL << KEY3),   // 选择 GPIO
        .mode = GPIO_MODE_INPUT,              // 设置为输出模式
        .pull_up_en = GPIO_PULLUP_ENABLE,     // 启用上拉
        .pull_down_en = GPIO_PULLDOWN_DISABLE, // 不启用下拉
        .intr_type = GPIO_INTR_DISABLE         // 不启用中断
    };
    gpio_config(&io_conf);
}
  1. 按键匹配键值

此键值将对应一个数组的序号,此数组是由BUTTON控件的坐标构成。

源码如下:

c 复制代码
static int read_key(void)
{
	if(gpio_get_level(KEY1)==0){
		 return 0;
	}
	if(gpio_get_level(KEY2)==0){
		 return 1;
	}
    if(gpio_get_level(KEY3)==0){
		 return 2;
	}	
    return -1;	
}
  1. 读取键值并保存到lv_indev_data_t数据结构中

目的是将实体按键与LVGL建立联系,后面通过创建输入设备相关API完成建立

c 复制代码
void button_read(lv_indev_t * drv, lv_indev_data_t*data){
    static uint32_t last_btn = 0;   /*Store the last pressed button*/
    int btn_pr = read_key();     /*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)*/
	   data->state = LV_INDEV_STATE_PRESSED;  /*Set the pressed state*/
       last_btn = btn_pr;   /*Save the ID of the pressed button*/
    } else {
       data->state = LV_INDEV_STATE_RELEASED; /*Set the released state*/
    }

   data->btn_id = last_btn;            /*Save the last button*/
}
  1. 创建输入设备
c 复制代码
lv_indev_t * button_indev_drv;
button_indev_drv=lv_indev_create();
lv_indev_set_type(button_indev_drv,LV_INDEV_TYPE_BUTTON);//将输入设备设置为BUTTON模式
lv_indev_set_read_cb(button_indev_drv, button_read);//注册回调函数,即上一步实现的函数,这样就完成了硬件和LVGL的联系
//配置坐标点
static const lv_point_t btn_points[5] = {
    {0, 0},   /*当键值为0时模拟点击的坐标*/
    {80, 0},   /*当键值为1时模拟点击的坐标*/
    {160, 1},   /*当键值为2时模拟点击的坐标*/
    {320, 120},   /*当键值为3时模拟点击的坐标*/
    {160, 240},   /*当键值为4时模拟点击的坐标*/
};
lv_indev_set_button_points(button_indev_drv, btn_points);//将按键与坐标连接
  1. 使用LVGL的API在界面上创建三个BUTTON控件
c 复制代码
	lv_obj_t * btn1;
    btn1 = lv_button_create(scr);
	lv_obj_set_width(btn1,80);
	lv_obj_set_height(btn1,35);
	lv_obj_set_pos(btn1,0,0);
	 /*Button event*/
    lv_obj_add_event_cb(btn1, btn_event_handler, LV_EVENT_ALL, NULL);
	lv_obj_add_flag(btn1, LV_OBJ_FLAG_CHECKABLE);

    lv_obj_t * lbl1 = lv_label_create(btn1);
    lv_label_set_text_static(lbl1, "LEFT");
    lv_obj_align(lbl1, LV_ALIGN_CENTER,0, 0);

	lv_obj_t * btn2;
    btn2 = lv_button_create(scr);
	lv_obj_set_width(btn2,80);
	lv_obj_set_height(btn2,35);
	lv_obj_set_pos(btn2,80,0);
    /*Button event*/
    lv_obj_add_event_cb(btn2, btn_event_handler, LV_EVENT_ALL, NULL);
	lv_obj_add_flag(btn2, LV_OBJ_FLAG_CHECKABLE);

    lv_obj_t * lbl2 = lv_label_create(btn2);
    lv_label_set_text_static(lbl2, "RIGHT");

	lv_obj_t * btn3;
    btn3 = lv_button_create(scr);
	lv_obj_set_width(btn3,80);
	lv_obj_set_height(btn3,35);
	lv_obj_set_pos(btn3,0,70);
	  /*Button event*/
    lv_obj_add_event_cb(btn3, btn_event_handler, LV_EVENT_ALL, NULL);
	lv_obj_add_flag(btn3, LV_OBJ_FLAG_CHECKABLE);

    lv_obj_t * lbl3 = lv_label_create(btn3);
    lv_label_set_text_static(lbl3, "DOWN");
	lv_obj_align(lbl3, LV_ALIGN_CENTER,0, 0);
  1. 创建群组,并将输入设备绑定到群组且将以上三个BUTTON加入
c 复制代码
	lv_group_t *g = lv_group_create();
	lv_indev_set_group(button_indev_drv, g); //绑定定义的lv_indev_t 
	lv_group_add_obj(g ,btn1);
	lv_group_add_obj(g ,btn2);
	lv_group_add_obj(g ,btn3);

此时按下实体按键将会控制对应BUTTON控件按下。

  1. 此时可以创建BUTTON回调函数了
c 复制代码
void btn_event_handler(lv_event_t *e)//按键回调函数
{
    lv_event_code_t code = lv_event_get_code(e);
	if(code == LV_EVENT_CLICKED) {
        ESP_LOGI(TAG,"Clicked");
    }
}

LV_INDEV_TYPE_KEYPAD的使用

LV_INDEV_TYPE_KEYPAD的键值LVGL已经有实现,固定死了。

c 复制代码
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_INDEV_TYPE_KEYPAD按键分两个状态,导航态和编辑态。导航态就是在同组中选择相关控件,编辑态就是对控件数值上的增加/减少。LV_KEY_NEXT/PREV、LV_KEY_ENTER则是作为导航态。LV_KEY_UP/DOWN/LEFT/RIGHT则可以对控件进行数值上的编辑,一般而言LEFT/RIGHT就足够使用了。

LV_INDEV_TYPE_KEYPAD只需要对上面的代码做一些简单的调整,如下:

  1. 键值匹配
c 复制代码
static int read_key(void)
{
	if(gpio_get_level(KEY1)==0){
		 return LV_KEY_NEXT;
	}
	if(gpio_get_level(KEY2)==0){
		 return LV_KEY_RIGHT;
	}
    if(gpio_get_level(KEY3)==0){
		 return LV_KEY_LEFT;
	}	
    return -1;	
}
  1. 输入设备的回调函数
c 复制代码
void button_read(lv_indev_t * drv, lv_indev_data_t*data){
    static uint32_t last_btn = 0;   /*Store the last pressed button*/
    int btn_pr = read_key();     /*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)*/
	   data->state = LV_INDEV_STATE_PRESSED;  /*Set the pressed state*/
       last_btn = btn_pr;   /*Save the ID of the pressed button*/
    } else {
       data->state = LV_INDEV_STATE_RELEASED; /*Set the released state*/
    }
//注意这个地方做了修改
   data->key = last_btn;            /*Save the last button*/
}
  1. 创建输入设备
c 复制代码
lv_indev_t * button_indev_drv;
button_indev_drv=lv_indev_create();
lv_indev_set_type(button_indev_drv,LV_INDEV_TYPE_KEYPAD);//将输入设备设置为KEYPAD模式
lv_indev_set_read_cb(button_indev_drv, button_read);//注册回调函数,即上一步实现的函数,这样就完成了硬件和LVGL的联系
  1. 按键回调函数

既然编辑态会有值的变化,那自然会触发相关事件,所以有了下面的改变

c 复制代码
void btn_event_handler(lv_event_t *e)//按键回调函数
{
    lv_event_code_t code = lv_event_get_code(e);
//LV_EVENT_CLICKED这个事件在KEYPAD中只有ENTER才会触发
	if(code == LV_EVENT_CLICKED) {
        ESP_LOGI(TAG,"Clicked");
    }else if(code == LV_EVENT_VALUE_CHANGED) {
		ESP_LOGI(TAG,"BUTTUN");
    }
}
  1. 只是按键不太能看到效果,可以创建一个slider加入组中,通过导航按键选中后,用LEFT/RIGHT进行编辑
c 复制代码
	lv_obj_t *slider1;
	slider1=lv_slider_create(scr);
	lv_obj_set_pos(slider1,0,140);

	lv_group_add_obj(g ,slider1);

总结

经过以上编程后,其实LV_INDEV_TYPE_ENCODER也是很容易实现的,只要将左右旋转和按下动作对应LV_KEY_LEFT/RIGHT以及LV_KEY_ENTER,剩下的代码基本都差不多了。

相关推荐
sakabu4 小时前
ESP32 外设驱动开发指南 (ESP-IDF框架)——GPIO篇:基础配置、外部中断与PWM(LEDC模块)应用
笔记·单片机·学习·esp32
Ronin-Lotus3 天前
嵌入式硬件篇---ESP32驱动异常
嵌入式硬件·esp32
Ronin-Lotus3 天前
程序代码篇---数据包解析
python·esp32·数据包解析
努力做小白4 天前
Linux驱动20 --- FFMPEG视频API
linux·驱动开发·单片机·嵌入式硬件·ffmpeg·lvgl
IT项目分享4 天前
ESP32 BLE开发快速入门:用MicroPython实现手机与硬件通信
esp32·micropython·it项目网
Ronin-Lotus4 天前
嵌入式硬件篇---驱动板
单片机·嵌入式硬件·esp32·驱动板
flashier5 天前
ESP32学习笔记_Components(1)——使用LED Strip组件点亮LED灯带
学习·esp32·led·led灯带·esp32组件
flashier6 天前
ESP32学习笔记_Peripherals(4)——MCPWM基础使用
单片机·学习·esp32·pwm·mcpwm
努力做小白7 天前
Linux驱动18 --- LCD 屏
linux·驱动开发·单片机·嵌入式硬件·lvgl·屏幕