LittleVGL (LVGL)干货入门教程二之LVGL的输入设备(indev)API对接。
LittleVGL (LVGL)干货入门教程二之LVGL的输入设备(indev)API对接
前言:
阅读前,请确保你拥有以下条件:
- 你已经完成“显示API”的移植。
- 你已经实现了一个屏幕的触摸驱动 (如果你使用外部物理按键进行操作,那么请确保你实现了读按键状态的驱动)。
LVGL有三大种需要对接的API
- 显示API(教程一已实现, 链接:LittleVGL (LVGL)入门教程一之移植到stm32芯片)
- 输入设备API(比如触摸屏、按键 等, 此篇教程实现)
- 文件系统API(如FatFs等)
这篇文章讲“输入设备API”的移植,默认你已经移植好了“显示API”。
(重要) 编译LVGL至少需要c99标准
目录:
- LittleVGL (LVGL)干货入门教程二之LVGL的输入设备(indev)API对接
- 前言:
- 一、indev输入设备的种类介绍
- (一)输入设备的种类
- 二、lv_port_indev更改
- (一)使能indev的port文件
- (二)优化indev的port文件(重要)
- 三、移植输入设备API
- (一)以touchpad为例:
- (二)以keypad为例:
- 1.移植keypad API
- 2.使用keypad的方法
- 四、使用示例
- 五、启动LVGL
- 本篇完
- 其他:
- 下一篇
一、indev输入设备的种类介绍
(一)输入设备的种类
LVGL有5种输入设备接口:
- Touchpad (触摸板,例如电容屏、电阻屏等)
- Mouse (鼠标)
- Keypad (键盘)
- Encoder (编码器)
- Button (外部按键)
我们常用的是“Touchpad、Keypad”,这篇文章基于这两种,其他类似,可以根据目录第三章看你想看的接口API对接。
二、lv_port_indev更改
(一)使能indev的port文件
- 方法很简单,在lv_port_indev文件中把“#if 0”改为“#if 1”,c文件和h文件都要改。
- 在lv_port_indev.h中添加声明void lv_port_indev_init(void);
(二)优化indev的port文件(重要)
提醒,这里的修改很冗长和枯燥,主要原因,原port文件非常混乱,各种indev的API混在一起,如果你不实现就会报错或警告,而实际上我们的项目往往只会用上一两个indev,比如我同时使用键盘和鼠标或同时使用touchpad和button。为了代码的精简和易于管理,这个部分以添加预处理语句为主,以后你要用什么类型的indev,修改预处理语句和宏定义即可。
/************************************************* 一、我们在文件"lv_port_indev.c"顶部定义宏定义************************************************/
#define LV_USE_INDEV_TOUCHPAD 0x1u
#define LV_USE_INDEV_MOUSE 0x2u
#define LV_USE_INDEV_KEYPAD 0x4u
#define LV_USE_INDEV_ENCODER 0x8u
#define LV_USE_INDEV_BUTTON 0x10u
#define LV_USE_INDEV LV_USE_INDEV_TOUCHPAD | \LV_USE_INDEV_KEYPAD // 使用Touchpad 和 keypad/************************************************* 二、根据注释 我们找到 STATIC PROTOTYPES,按类型* 添加预处理语句************************************************/
#if ( LV_USE_INDEV & LV_USE_INDEV_TOUCHPAD ) == LV_USE_INDEV_TOUCHPAD
static void touchpad_init(void);
static bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool touchpad_is_pressed(void);
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y);
#endif#if ( LV_USE_INDEV & LV_USE_INDEV_MOUSE ) == LV_USE_INDEV_MOUSE
static void mouse_init(void);
static bool mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool mouse_is_pressed(void);
static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y);
#endif#if ( LV_USE_INDEV & LV_USE_INDEV_KEYPAD ) == LV_USE_INDEV_KEYPAD
static void keypad_init(void);
static bool keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static uint32_t keypad_get_key(void);
#endif#if ( LV_USE_INDEV & LV_USE_INDEV_ENCODER ) == LV_USE_INDEV_ENCODER
static void encoder_init(void);
static bool encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static void encoder_handler(void);
#endif#if ( LV_USE_INDEV & LV_USE_INDEV_BUTTON ) == LV_USE_INDEV_BUTTON
static void button_init(void);
static bool button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static int8_t button_get_pressed_id(void);
static bool button_is_pressed(uint8_t id);
#endif/************************************************* 我们继续往下看是indev的初始化函数实现,官方注释* 很贴心,大家看着添加预处理语句就行************************************************/
void lv_port_indev_init(void)
{/* Here you will find example implementation of input devices supported by LittelvGL:* - Touchpad* - Mouse (with cursor support)* - Keypad (supports GUI usage only with key)* - Encoder (supports GUI usage only with: left, right, push)* - Button (external buttons to press points on the screen)** The `..._read()` function are only examples.* You should shape them according to your hardware*/// 不动lv_indev_drv_t indev_drv;#if ( LV_USE_INDEV & LV_USE_INDEV_TOUCHPAD ) == LV_USE_INDEV_TOUCHPAD/*------------------* Touchpad* -----------------*//*Initialize your touchpad if you have*/touchpad_init();/*Register a touchpad input device*/lv_indev_drv_init(&indev_drv);indev_drv.type = LV_INDEV_TYPE_POINTER;indev_drv.read_cb = touchpad_read;indev_touchpad = lv_indev_drv_register(&indev_drv);
#endif
#if ( LV_USE_INDEV & LV_USE_INDEV_MOUSE ) == LV_USE_INDEV_MOUSE/*------------------* Mouse* -----------------*//*Initialize your touchpad if you have*/mouse_init();/*Register a mouse input device*/lv_indev_drv_init(&indev_drv);indev_drv.type = LV_INDEV_TYPE_POINTER;indev_drv.read_cb = mouse_read;indev_mouse = lv_indev_drv_register(&indev_drv);/*Set cursor. For simplicity set a HOME symbol now.*/lv_obj_t * mouse_cursor = lv_img_create(lv_disp_get_scr_act(NULL), NULL);lv_img_set_src(mouse_cursor, LV_SYMBOL_HOME);lv_indev_set_cursor(indev_mouse, mouse_cursor);
#endif
#if ( LV_USE_INDEV & LV_USE_INDEV_KEYPAD ) == LV_USE_INDEV_KEYPAD/*------------------* Keypad* -----------------*//*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 = lv_indev_drv_register(&indev_drv);/* Later you should create group(s) with `lv_group_t * group = lv_group_create()`,* add objects to the group with `lv_group_add_obj(group, obj)`* and assign this input device to group to navigate in it:* `lv_indev_set_group(indev_keypad, group);` */
#endif
#if ( LV_USE_INDEV & LV_USE_INDEV_ENCODER ) == LV_USE_INDEV_ENCODER/*------------------* Encoder* -----------------*//*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_encoder = lv_indev_drv_register(&indev_drv);/* Later you should create group(s) with `lv_group_t * group = lv_group_create()`,* add objects to the group with `lv_group_add_obj(group, obj)`* and assign this input device to group to navigate in it:* `lv_indev_set_group(indev_encoder, group);` */
#endif
#if ( LV_USE_INDEV & LV_USE_INDEV_BUTTON ) == LV_USE_INDEV_BUTTON/*------------------* Button* -----------------*//*Initialize your button if you have*/button_init();/*Register a button input device*/lv_indev_drv_init(&indev_drv);indev_drv.type = LV_INDEV_TYPE_BUTTON;indev_drv.read_cb = button_read;indev_button = lv_indev_drv_register(&indev_drv);/*Assign buttons to points on the screen*/static const lv_point_t btn_points[2] = {{10, 10}, /*Button 0 -> x:10; y:10*/{40, 100}, /*Button 1 -> x:40; y:100*/};lv_indev_set_button_points(indev_button, btn_points);
#endif}/************************************************* 三、根据注释找到 STATIC FUNCTIONS* 下面都是很长的函数实现,我不一一列出来了,* 按照不同的indev根据上面的模板进行预处理语句添加就行* 值得注意的是,我们可能会使用多种indev,所以不宜* 使用“#if”和“#elif”“#endif”,宜使用“#if”和“#endif”************************************************/
三、移植输入设备API
相信大家在上文进行预处理语句的添加的过程中应该有注意各个函数的名字,很直白,函数什么功能基本都能从名字看出来,那我们分别以“touchpad”和“keypad”的移植为例,进行API对接。
(一)以touchpad为例:
打开文件"lv_port_indev.c",找到并参考如下改法:
/*------------------* Touchpad* -----------------*/* /*Initialize your touchpad*/
static void touchpad_init(void)
{/*Your code comes here*//* 你的touch初始化 */touch->init();
}/* Will be called by the library to read the touchpad */
static bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{static lv_coord_t last_x = 0;static lv_coord_t last_y = 0;/*Save the pressed coordinates and the state*//* 这里调用了 touchpad_is_pressed,这个实现在下面 *//* 从名字可以知道,这个函数对“是否有点被触摸”进行判断 */if(touchpad_is_pressed()) {/* touchpad_get_xy 在下面实现 */touchpad_get_xy(&last_x, &last_y);data->state = LV_INDEV_STATE_PR;} else {data->state = LV_INDEV_STATE_REL;}/*Set the last pressed coordinates*/data->point.x = last_x;data->point.y = last_y;/*Return `false` because we are not buffering and no more data to read*/return false;
}/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{/*Your code comes here*//* 在这里我们对触摸屏是否被触摸进行判断 *//* 例如触摸屏一般有INT引脚,就是中断引脚 *//* 我们根据中断引脚是否有信号判断是否被触摸(不过STM32貌似没有电平触发中断,只有边沿触发) *//* 边沿触发只能触发一次,容易判断错误,所以我们一般采用轮询读点 *//* 我们分别以电容和电阻触摸屏为例 */bool res = false;/* 电阻屏 */// res = res_is_touched();// return res;/* 电容屏 *//* 电容屏一般可以读status寄存器是否有值来判断是否有点 */uint8_t status = cap_is_touched();if ( status )return true;return false;
}/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{/*Your code comes here*//* 这里就容易了,按照你的方式读你触摸屏的坐标并赋值就行 */(*x) = my_read_x();(*y) = my_read_y();
}
那么到这里,你的触摸屏API就移植结束了,在外面调用函数lv_port_indev_init();进行初始化就行。
(二)以keypad为例:
1.移植keypad API
打开文件"lv_port_indev.c",找到并参考如下改法:
/*------------------* Keypad* -----------------*//* Initialize your keypad */
static void keypad_init(void)
{/*Your code comes here*//* 你的初始化代码 */my_key_init();
}/* Will be called by the library to read the mouse */
static bool keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{static uint32_t last_key = 0;/*Get the current x and y coordinates*//* 这里官方默认你有鼠标设备,但实际上可能没有,我们注释掉 */// mouse_get_xy(&data->point.x, &data->point.y);/*Get whether the a key is pressed and save the pressed key*//* 这里告诉你,你读到的点要根据你的需求进行转换 *//* 当我通过keypad_get_key()函数获取act_key值后 *//* 转换成LVGL的操作符,如LV_KEY_NEXT等 */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;/*Return `false` because we are not buffering and no more data to read*/return false;
}/*Get the currently being pressed key. 0 if no key is pressed*/
static uint32_t keypad_get_key(void)
{/*Your code comes here*//* LVGL有较多操作符,如果你的按键不够用,可以采用组合键的方案 *//* 当然,使用外部按键的话你应该考虑“按键抖动”的问题,使用软消抖或硬消抖 *//* 假设我有3个按键:“UP”、“SURE”、“DOWN” */switch ( my_read_key() ) {case UP:return 1;case SURE:return 5;case DOWN:return 2;/* 组合键 */case (UP | SURE):return 3;case (DOWN | SURE):return 4;}return 0;
}
LVGL 操作符参考:
keypad比较特殊,光移植完还不行,要使用的话,需要indev group。
2.使用keypad的方法
根据LVGL注释的原话:
/* * Later you should create group(s) with `lv_group_t * group = lv_group_create()`,* add objects to the group with `lv_group_add_obj(group, obj)`* and assign this input device to group to navigate in it:* `lv_indev_set_group(indev_keypad, group);` * */
我们可以知道,我们要使用下面代码创建一个group,以后我们要把UI obj放入group,才可进行操作(触摸屏不用)。
/* 创建group */
lv_group_t * group = lv_group_create();
// 这里的变量“indev_keypad”在文件顶部“STATIC VARIABLES”区有定义
// 这句话要加入void lv_port_indev_init(void);函数对应的keypad的代码里
lv_indev_set_group(indev_keypad, group);/* 例如我们创建了一个button对象 */
lv_obj_t * btn = lv_btn_create( lv_scr_act(), NULL );
/* 我们要通过keypad控制btn,那么我们需要添加进group */
lv_group_add_obj( group, btn );
那么到这里,你的keypad API就移植结束了,在外面调用函数lv_port_indev_init();进行初始化就行。
四、使用示例
#include <lvgl.h>#define LVGL_TICK 5/* 引入之前创建的group */
extern lv_group_t * group; // 如果用触摸屏就不用/************************************************* @brief 事件句柄* * @param obj * @param event ************************************************/
static void event_handler(lv_obj_t * obj, lv_event_t event)
{switch (event) {case LV_EVENT_CLICKED:printf( "btn Clicked\n" );// lv_obj_del( obj ); // 点击就消失break;default:break;}
}static void my_lvgl_test(void)
{lv_obj_t * btn = lv_btn_create( lv_scr_act(), NULL );lv_obj_set_size( btn, 80, 50 );lv_obj_set_event_cb( btn, event_handler ); // 设置事件句柄lv_group_add_obj( group, btn ); // 添加进group 如果用触摸屏就不用lv_obj_align( btn, NULL, LV_ALIGN_CENTER, 0, 0);lv_obj_t * label1 = lv_label_create(lv_scr_act(), NULL);lv_label_set_recolor(label1, true);lv_label_set_text(label1, "#ff0000 btn#");lv_obj_align(label1, btn, LV_ALIGN_CENTER, 0, 0);
}static void lvgl_init( void )
{lv_init();lv_port_disp_init(); // 显示器初始化lv_port_indev_init(); // 输入设备初始化// lv_port_fs_init(); // 文件系统设备初始化
}int main()
{lvgl_init();my_lvgl_test();while(1) {// 先调用 lv_tick_inc 再调用 lv_task_handlerlv_tick_inc(LVGL_TICK);lv_task_handler();delay_ms(LVGL_TICK);}
}
五、启动LVGL
参考我的上一篇文章即可:LittleVGL (LVGL)干货入门教程一之移植到stm32芯片
本篇完
其他:
LittleVGL (LVGL)干货入门教程一之移植到stm32芯片
LittleVGL (LVGL)干货入门教程二之LVGL的输入设备(indev)API对接。
LittleVGL (LVGL)干货入门教程三之LVGL的文件系统(fs)API对接。
LittleVGL (LVGL)干货入门教程四之制作和使用中文汉字字库
下一篇
LittleVGL (LVGL)干货入门教程三之LVGL的文件系统(fs)API对接。
LittleVGL (LVGL)干货入门教程二之LVGL的输入设备(indev)API对接。相关推荐
- LittleVGL (LVGL)干货入门教程四之制作和使用中文汉字字库
LittleVGL (LVGL)干货入门教程四之制作和使用中文汉字字库 前言: 阅读前,请确保你至少拥有以下条件: 已实现显示API(教程一已实现, 链接:LittleVGL (LVGL)入门教程一之 ...
- python elasticsearch 入门教程(二) ---全文搜索
python elasticsearch 入门教程(二) ---全文搜索 截止目前的搜索相对都很简单:单个姓名,通过年龄过滤.现在尝试下稍微高级点儿的全文搜索--一项 传统数据库确实很难搞定的任务. ...
- R语言七天入门教程二:认识变量与运算符
R语言七天入门教程二:认识变量与运算符 一.什么是变量 1.变量 顾名思义,我们可以将变量理解为"可以改变的量",是计算机语言中能储存计算结果或能表示值的抽象概念.这里的值可以是数 ...
- (转)tensorflow入门教程(二十六)人脸识别(上)
https://blog.csdn.net/rookie_wei/article/details/81676177 1.概述 查看全文 http://www.taodudu.cc/news/show- ...
- Android WebRTC 入门教程(二) -- 模拟p2p本地视频传输
Android WebRTC 入门教程(一) – 使用相机 Android WebRTC 入门教程(二) – 模拟p2p本地视频传输 源码工程: https://github.com/LillteZh ...
- c语言类似于 n的标识符,C语言快速入门教程(二)
C语言快速入门教程(二) C语言的基本语法 本节学习路线图: 引言: C语言,顾名思义就是一门语言,可以类比一下英语; 你要说出一个英语的句子需要: 单词 + 语法! 将单词按照一定的语法拼凑起来就成 ...
- 微信小程序云开发 初学者入门教程二
微信小程序云开发 初学者入门教程二-前端操作数据库模块 如何操作数据库,作为一名前端,如果对数据的知识不够熟悉也没关系,从现在开始好好学习就行,数据库的操作内容差不多涉及增删改查四大模块,花一些业余的 ...
- python爬虫入门教程(二):开始一个简单的爬虫
2019/10/28更新 使用Python3,而不再是Python2 转载请注明出处:https://blog.csdn.net/aaronjny/article/details/77945329 爬 ...
- quarkus 入门教程(二) -项目开发模式热更新及项目断点调试方法
quarkus 入门教程(二) -项目断点调试方法 1.项目热更新 quarkus:dev runs 方式启动,项目会以开发者模式启动,当修改了java文件或者resource文件后,项目会在后台编译 ...
最新文章
- Google C++命名规范
- 自动化机器学习(二)自动构建机器学习流水线
- C++STL容器,你真的会用了吗?——插入、删除、遍历和查找操作性能对比——插入(精简易懂版,句句干货)
- 在WebPart中上传图片到SharePoint图片库,读取Exif信息到图片的自定义属性
- 计算机应用作业2,计算机应用2作业
- 世界第一台电脑_阿里推出云电脑“无影”,名片大小的机身,却有无穷的计算能力...
- iOS开发UI篇—IOS开发中Xcode的一些使用技巧
- 微信公众号开发 ----微信获取access_token(2)
- php下载地址转换工具,php把url转换迅雷thunder资源下载地址的简单示例
- OpenGLCG技术之Render To Texture
- 惩罚函数法迭代过程的本质及其他最优化方法中的一些概念
- 电脑知识:台式电脑如何使用无线网上网?
- RFBnet论文及其代码详解
- WebApi编程(一)-DOM
- 易岸公考:最全版本!公务员报考条件
- 【100 种语言速成】第 2 节:Emojicode
- 15 条实用 Linux/Unix 磁带管理命令
- ShardingJDBC使用总结
- 各种品牌的PLC协议转换网关介绍
- LINUX基础试题大全(2)
热门文章
- python十进制转二进制循环,python十进制转二进制的详解
- 第一章中央银行制度的形成与发展
- matlab 计算指北角,尔雅通识课《科学计算与MATLAB语言-示范教学包》网课答案
- 12个小技巧让你在小组讨论时游刃有余(下)
- 全网最全:机器学习算法模型自动超参数优化方法汇总
- java-net-php-python-springboot基于SpringBoot的OA办公管理系统计算机毕业设计程序
- C++中json解析开源库收集,支持json5
- 任务管理器已被管理员禁用
- PHP获取今天、昨天、明天的日期
- XML的数据简化定义文件——XDR