LVGL简介以及如何显示中文

LVGL简介

LVGL是一种开源的嵌入式图形库,它用来提供高性能、低功耗的图形显示解决方案。广泛应用于嵌入式系统和IOT设备中,为开发者提供了一整套功能丰富的图形界面开发工具。LVGL能够在各种硬件平台上运行,包括ARM、MIPS、等处理器结构,比如窗口管理、按钮、文本框、滑块、列表框等,方便开发者快速构建用户界面。

除了传统的GUI功能,LVGL还支持多种触摸屏控制器,如电容式、红外线等,并且提供了全面的触摸屏校准功能。另外,LVGL还支持多种显示面板类型。下面是LVGL的官网,可以在官网了解关于LVGL的相关知识,由于各个高校一般都使用Arduino进行开发,而且LVGL下也有Arduino的开发库---即Arduino移植版本。

Arduino下移植LVGL

说是移植,其实就是在Arduino中下载LVGL库,然后下载完成后需要进行相应的移植操作。

 LVGL库下载

在库管理中搜索"lvgl",如果出现"lv_arduino",因为"lv_arduino"是早期版本,现在已经停止维护,所以这里应该安装"lvgl"。

移植LVGL

移植LVGL库,其实就是编辑本地的lv_conf.h文件,在文件资源管理器中,打开文档->Arduino->LVGL,找到"lv_conf_template.h"复制并粘贴到上级目录中,重命名为"lv_conf.h",然后编辑"lv_conf.h"文件。

移植成功后可以到在Arduino库管理中,使用lvgl给出的测试案例进行验证。

LVGL输入

lvgl不仅可以通过注册"显示接口"来对接底层屏幕驱动--根本是封装显示驱动的"绘制矩形区域功能";同理lvgl还可以通过注册"输入接口"来对接底层输入设备--支持"键盘、鼠标、触屏"等常见输入设备,下面给出合宙的0.96寸屏扩展板的案例。

0.96寸屏扩展板

合宙的扩展板附带"五向按键"--上、下、左、右、中,可以作为lvgl的输入设备----lvgl中定义为"LV_INDEV_TYPE_KEYPAD"类型。

要使用按键,首先需要编写驱动--简单的GPIO输入即可,将按键 IO 定义为宏以增加可读性,注意这里的方向是屏幕横置且五向按键居右状态下的方向。相应的初始化即利用pinMode()函数设置IO上拉输入——五向按键按下后都是输出低电平。 然后,读取按键值函数 getKeyValule()直接将对应按键 IO 的编号宏定义作为返回值。

// 按键 IO 编号宏定义(屏幕横放,按键居右)
#define PIN_L 5 // 左键
#define PIN_R 9 // 右键
#define PIN_U 8 // 上键
#define PIN_D 13 // 下键
#define PIN_C 4 // 中键
// 按键读取宏定义
#define KEY_LEFT digitalRead(PIN_L)
#define KEY_RIGHT digitalRead(PIN_R)
#define KEY_UP digitalRead(PIN_U)
#define KEY_DOWN digitalRead(PIN_D)
#define KEY_CENTER digitalRead(PIN_C)
// 按键 IO 初始化函数
void initKeys(void) {
pinMode(PIN_L, INPUT_PULLUP);
pinMode(PIN_R, INPUT_PULLUP);
pinMode(PIN_U, INPUT_PULLUP);
pinMode(PIN_D, INPUT_PULLUP);
pinMode(PIN_C, INPUT_PULLUP);
}
// 按键读取函数——返回按键对应 IO 编号
uint8_t getKeyValue(void) {
if(KEY_LEFT==0 || KEY_RIGHT==0 || KEY_UP==0 || KEY_DOWN==0 || KEY_CENTER==0) {
delay(20); // 延时防抖
if(KEY_LEFT==0) return PIN_L;
else if(KEY_RIGHT==0) return PIN_R;
else if(KEY_UP==0) return PIN_U;
else if(KEY_DOWN==0) return PIN_D;
else if(KEY_CENTER==0) return PIN_C;
}
return 0;
}

输入接口回调需要按照KEYPAD设备进行编写,核心功能是读取按键值,然后将键值转换为对应的"lvgl控件字符",本例生效的是"LV_KEY_PREV、LV_KEY_NEXT、KV_KEY_ENTER",分别代表"焦点向前移动、向后移动、点击"。

void my_keypad_read( lv_indev_drv_t * indev_drv, lv_indev_data_t * data )
{
static uint32_t last_key = 0;
uint32_t act_key = getKeyValue(); // 读取按键值——即按键对应 IO 编号
if(act_key != 0) {
data->state = LV_INDEV_STATE_PR;
/* 转换按键值为“LVGL 控件字符(LVGL control characters)” */
switch(act_key) {
case PIN_L:
act_key = LV_KEY_LEFT; // 减少值或向左移动
break;
case PIN_R:
act_key = LV_KEY_RIGHT; // 减少值或向右移动
break;
case PIN_U:
act_key = LV_KEY_PREV; // 聚焦到上一对象
break;
case PIN_D:
act_key = LV_KEY_NEXT; // 聚焦到下一对象
break;
case PIN_C:
act_key = LV_KEY_ENTER; // 触发 LV_EVENT_PRESSED/CLICKED/LONG_PRESSED
break;
}
last_key = act_key;
} else {
data->state = LV_INDEV_STATE_REL;
}
data->key = last_key;
}

按键作为输入设备时,为了方便操作控件,必须要给控件设置"可选中"属性,也就是控件能够获得焦点。而界面中的全部可选中的控件要"列为一组"。

LVGL显示中文

lv_font_conf自定义字体(添加汉字)

lv_font_conv 是 LVGL 官方编写的一套离线字体转换工具,由于此工具是由 node.js 写的,所以要在第一步安装 node 运行环境。离线工具没有图形化界面,需要使用命令行输入命令来转换,要比在线复杂点,离线的优点就是无需网络,而且速度非常快。

首先需要全局安装lv_font_conf工具------npm i lv_font_conf -g

lv_font_conv 需要 Node.js,建议通过 npm 进行全局安装(命令如上图所示)。然后, 就是选取字体文件(*.ttf 格式),这里选取系统自带的任何一种字体作为示例——当然也可以网上下载其它有特色的字体文件,这里选取"方正姚体"进行测试。

接着,命令行进入到自建文件夹目录,通过 lv_font_conv 进行字体转换:

lv_font_conv --no-compress --format lvgl --font ./FZYTK.TTF -o ./aita_FZYT16.c --bpp 4 --size 25 --symbols 我不是药神_大大怪将军 -r

这样我们就得到了 LVGL 需要的字体源文件,可以使用上Arduino中的lvgl库函数项目进行测试,,把“aita_FZYT16.c”拷贝到项目目录再打开 Arduino IDE。Arduino IDE 中打开“aita_FZYT16.c”,并在第一行添加宏定义“#define LV_LVGL_H_INCLUDE_SIMPLE”——控制导入“lvgl.h”(Arduino 编译器的限制,导入 “lvgl/lvgl.h”会头文件找不到错误)。下面给出测试案例:

#include <lvgl.h>
#include <TFT_eSPI.h>
// 申明字体
LV_FONT_DECLARE(aita_FZYT16);
// 定义屏幕尺寸
static const uint16_t screenWidth = TFT_WIDTH;
static const uint16_t screenHeight = TFT_HEIGHT;
// lvgl 专用的显示缓存区定义
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ screenWidth * screenHeight / 10 ];
// 定义 LCD 驱动实例
TFT_eSPI tft = TFT_eSPI();
// 默认没有开启 LVGL 日志功能,所以 my_print()没有用
#if LV_USE_LOG != 0
/* Serial debugging */
void my_print(const char * buf)
{
Serial.printf(buf);
Serial.flush();
}
#endif
// 自定义的显示刷新接口
void my_disp_flush( lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t
*color_p )
{
uint32_t w = ( area->x2 - area->x1 + 1 );
uint32_t h = ( area->y2 - area->y1 + 1 );
tft.startWrite();
tft.setAddrWindow( area->x1, area->y1, w, h );
tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
tft.endWrite();
lv_disp_flush_ready( disp_drv );
}
// 自定义输入事件接口(暂不使用)
void my_touchpad_read( lv_indev_drv_t * indev_drv, lv_indev_data_t * data )
{
}
void setup()
{
// 串口初始化,输出 LVGL 版本号
Serial.begin( 115200 );
String LVGL_Arduino = "Hello Arduino! ";
LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() +
"." + lv_version_patch();
Serial.println( LVGL_Arduino );
Serial.println( "I am LVGL_Arduino" );
// LVGL 初始化
lv_init();
// 日志功能初始化(未使用)
#if LV_USE_LOG != 0
lv_log_register_print_cb( my_print ); /* register print function for debugging
*/
#endif
// LCD 初始化
tft.begin();
// tft.setRotation(0); // 2.4 寸屏 竖屏方向
tft.setRotation(3); // 0.96 寸屏 横屏方向
pinMode(TFT_BL, OUTPUT);
ledcSetup(0, 1000, 10);
ledcAttachPin(TFT_BL, 0);
ledcWrite(0, 100);
// 暂不使用输入,XPT2046 校准先不做
// uint16_t calData[5] = { 434, 3407, 304, 3392, 3 };
// tft.setTouch(calData); // 第二次设置校准值
// 显示缓存区初始化
lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * screenHeight / 10 );
// 显示初始化
static lv_disp_drv_t disp_drv;
lv_disp_drv_init( &disp_drv );
/* 2.4 寸竖屏设置 */
// disp_drv.hor_res = screenWidth;
// disp_drv.ver_res = screenHeight;
/* 0.96 寸横屏设置 */
disp_drv.hor_res = screenHeight;
disp_drv.ver_res = screenWidth;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register( &disp_drv );
// 输入初始化(未使用)
// static lv_indev_drv_t indev_drv;
// lv_indev_drv_init( &indev_drv );
// indev_drv.type = LV_INDEV_TYPE_POINTER;
// indev_drv.read_cb = my_touchpad_read;
// lv_indev_drv_register( &indev_drv );
// 创建风格,用以设置字体
static lv_style_t label_style;
lv_style_init(&label_style);
lv_style_set_text_font(&label_style, &aita_FZYT16);
// 屏幕居中显示文本
lv_obj_t *label = lv_label_create( lv_scr_act() );
lv_label_set_text( label, "大大怪将军");
lv_obj_align( label, LV_ALIGN_CENTER, 0, 0 );
lv_obj_add_style(label, &label_style, LV_PART_MAIN);
Serial.println( "Setup done" );
}
void loop()
{
// 构建 LVGL 库的内部时钟,5ms 周期
lv_timer_handler(); /* let the GUI do its work */
delay( 5 );
}

如果想要导入图标,可以使用阿里巴巴矢量图标库,具体方法和导入字体的方式一样,这里就不再介绍了。

阿里巴巴矢量图标库icon-default.png?t=N7T8https://www.iconfont.cn/按照上述步骤去查看效果吧~

  • 17
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值