当前位置: 首页 > news >正文

1. ESP开发之实体按键(KEYPADBUTTON)控制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. 实体按键初始化
void key_init(void)
{// 配置 GPIOgpio_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控件的坐标构成。

源码如下:

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完成建立

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. 创建输入设备
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控件
	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加入
	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回调函数了
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已经有实现,固定死了。

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. 键值匹配
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. 输入设备的回调函数
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. 创建输入设备
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. 按键回调函数

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

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进行编辑
	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,剩下的代码基本都差不多了。

http://www.lryc.cn/news/605222.html

相关文章:

  • 一文掌握最新版本Monocle3单细胞轨迹(拟时序)分析
  • 【Unity】在构建好的项目里创建自定义文件夹
  • Thales靶机
  • Redis知识点(1)
  • 【力扣热题100】哈希——字母异位词分组
  • 【c++】leetcode763 划分字母区间
  • LeetCode热题100--148. 排序链表--中等
  • 限流算法详解:固定窗口、滑动窗口、令牌桶与漏桶算法全面对比
  • 力扣-543.二叉树的直径
  • 【LeetCode】链表反转实现与测试
  • (补题)小塔的饭
  • sqLite 数据库 (3):以编程方式使用 sqLite,4 个函数,以及 sqLite 移植,合并编译
  • linux 执行sh脚本,提示$‘\r‘: command not found
  • C语言:函数指针、二级指针、常量指针常量、野指针
  • 【Kubernetes 指南】基础入门——Kubernetes 201(二)
  • Vite 模块动态导入之Glob导入
  • Cursor MCP搭建入门
  • 力扣热题100---------35.搜索插入为位置
  • jQuery UI Tabs切换功能实例
  • Python在自动化与运维领域的核心角色:工具化、平台化与智能化
  • Jaeger理论、实战、问题记录
  • TikTok 视频审核模型:用逻辑回归找出特殊类型的视频
  • Elasticsearch 文档操作管理:从增删改查到批量操作与数据类型
  • 硬性巩膜镜市场报告:深度解析行业现状与未来趋势
  • Java项目:基于SSM框架实现的济南旅游网站管理系统【ssm+B/S架构+源码+数据库+毕业论文+远程部署】
  • 同一雷达不同样式的pdw数据
  • FFmpeg:因码流采集与封装不同步导致录制出来的MP4文件会出现黑屏、绿屏的问题
  • 达梦数据库(DM Database)角色管理详解|了解DM预定义的各种角色,掌握角色创建、角色的分配和回收
  • 实现了加载 正向 碰撞 雅可比 仿真
  • 第十九周-文档数据库MongoDB、消息队列和微服务