LittleVGL (LVGL)干货入门教程四之制作和使用中文汉字字库

LittleVGL (LVGL)干货入门教程四之制作和使用中文汉字字库


前言:

阅读前,请确保你至少拥有以下条件:

  1. 已实现显示API(教程一已实现, 链接:LittleVGL (LVGL)入门教程一之移植到stm32芯片
  2. 已实现输入设备API(教程二已实现,链接:LittleVGL (LVGL)干货入门教程二之LVGL的输入设备(indev)API对接。
  3. 已实现文件系统API(教程三已实现,链接:LittleVGL (LVGL)干货入门教程三之LVGL的文件系统(fs)API对接

这篇文章会讲

  • LVGL字库的制作
  • LVGL的字库的各种使用方式(本文重点)


字库的原理就不赘述了,百度一大把,主要就是不同编码字库的每个字,都按照不同的方式排列,根据编码可以进行搜索和定位,最后提取字库并用点阵方式显示就行,PC上多用矢量字体(使用顶点和曲线),一般最简单的方法就是使用点阵字体(也是很常用的形式)。


一、LVGL字库的种类介绍。

  • 内部大数组(字体体量小时常用,如纯英文字体)
  • 外部bin文件(字体体量大时常用,如中文字体)

二、字库如何制作?

事实上,字库的制作有专用的工具,例如LVGL的官网提供在线字库转换工具(没网络就不行了,甚至经常抽风,本人就没有成功过,就不讲了,有兴趣可以自己试试)。
有兴趣的话也可以去LVGL官网了解字体相关的接口
也有第三方大神制作的离线字库转换工具,并且非常简单实用。

可以去这个作者的网站下载:
LVGL字体转换工具:LvglFontTool
LVGL字体乱码:Lvgl之显示汉字出现乱码


三、如何使用字库?

(一)添加外部或内部字库。

(1)内部字库

直接把生成的C文件添加进项目编译即可,C文件里面包含了字库的查找函数和位图等,和一些LVGL的字库接口,当然不需要你亲自使用,只是为LVGL提供操作接口。

(2)外部字库

当你使用上述的LvglFontTool进行外部字体转换后,会得到两个文件,假如我的字体名为“font”,那么生成的这两个文件名为“font.c”和“font.bin”,C文件提供了字库的查找函数(不需要你使用,只是为LVGL提供操作接口)和使用字库的API(需要自行对接API),bin文件即字库文件。

(二)声明制作好的字库。

当你使用上述工具制作好字库后,会得到字库名,你可以通过三种方法调用这个字库:

第一种:

extern lv_font_t font_name;		/* 第一种 */

第二种:

LV_FONT_DECLARE(font_name);		/* 第二种,其实就是把第一种封装起来了 */

第三种(改lv_conf.h):
在 lv_conf.h 里找到宏定义 “LV_FONT_CUSTOM_DECLARE”:

/* 各种不同的声明,这里的字体名由你自己生成的字体名决定,可以自己添加修改 */
#define LV_FONT_CUSTOM_DECLARE  LV_FONT_DECLARE( ariblk_12 )            \
                                LV_FONT_DECLARE( ariblk_14 )            \
                                LV_FONT_DECLARE( ariblk_16 )            \
                                LV_FONT_DECLARE( ariblk_36_num )        \
                                LV_FONT_DECLARE(MSYH_BD_12_CN)

上面的操作仅仅是声明而已。

(三)对接字库API。

使用就基本没什么不同了,下文会统一说怎么使用,但区别在于,外部字库的C文件需要对接一个API,实现提取存储设备字库文件指定偏移内容的功能(例如把字库文件放在SD卡或者SPI Flash里,把里面的内容提取给LVGL使用)。


生成外部字库的C文件后,找到函数 “__user_font_getdata” 和数组 “__g_font_buf” 。

/* 如果你没有外部RAM(外部SRAM、SDRAM等),就取消__g_font_buf的注释 */ 
/* 这里的__g_font_buf大小为323,这个参数是转换工具自动生成的,不需要改, */
/* 不同大小的字体buf大小不同 */
static uint8_t __g_font_buf[323];	//如bin文件存在SPI FLASH可使用此buff


static uint8_t *__user_font_getdata(int offset, int size) {
    
    
	/* 这里提供几种思路:
	 * 一、 如果已加载字体文件到外部RAM,那么直接返回外部RAM字体文件的
	 * 	   基址+offset。
	 * 二、 如果你没有外部RAM,则有两种方法提取数据:
	 *     1. 使用FS(文件系统)的API,如open、read等。
	 * 	   2. 不使用FS(效率高),直接通过你实现的最底层读取函数提取offset位置的
	 *        数据到__g_font_buf里
	 * 
	 * 下面实现三种不同方法
	 */

	/* 1 使用SDRAM,前提是你提前加载字体文件到SDRAM的某个地址 */
	return (uint8_t*)((uint32_t)(SDRAM_FONT_BASE_ADDR + offset)); 

	/* 2 直接使用最底层FLASH读取函数 */
	/* spi flash读取指定偏移地址函数 */
	sf_of_read(__g_font_buf, offset, size);
	return __g_font_buf;

	/* 3 使用FATFS,这种方法效率极低,因为LVGL会在画面发生变化时频繁读取文件 */
	/* 阻塞情况非常严重,仅适用于RAM有限的情况,不然不是首选 */
	FRESULT fres = FR_NOT_READY;
	FIL file = {
    
    0};
	fres = f_open(&file, font_path, FA_OPEN_EXISTING | FA_READ);
	if (fres != FR_OK)
		goto __out;		// goto常用于错误处理
	fres = f_lseek(&file, offset);		// 寻址
	if (fres != FR_OK)
		goto __out;		
	fres = f_read(&file, __g_font_buf, NULL, NULL);
	if (fres == FR_OK)	// 成功则直接返回
		goto __out;		
	else
		memset(__g_font_buf, 0, sizeof(__g_font_buf));  // 清空数组
		
__out:
	if (file)
		f_close(&file);
    return __g_font_buf;
}

如果你完成了上述的API对接,那么接下来把C文件加入工程编译,并且把bin字库文件烧写到spi flash或者使用文件系统放入文件即可。

(四)使用字库

接下来算是重头戏了,就是如何使用字库,使用方面的话,无论是内部还是外部的字库,操作都是一样的,下面给出例程,例程创建了一个label,并用2种不同方式使用font,并居中显示中文文字:

#include <lvgl.h>
#include "main.h"

#define LVGL_TICK 	10

/************************************************
 * @brief font example
 *
 * @param method
 *        1: example 1
 *        0: example 2
 *************************************************/
static void lvgl_font_test(uint8_t method)
{
    
    
	static lv_style_t label_style ={
    
     0 };	// style 必须要为static
    lv_obj_t* label1 = NULL;

    label1 = lv_label_create(lv_scr_act(), NULL);
    lv_label_set_recolor(label1, true);
    lv_label_set_text(label1, (LV_SYMBOL_HOME "你好 #ff0000 Trisuborn"));
    lv_obj_align(label1, NULL, LV_ALIGN_CENTER, 0, 0);

    LV_FONT_DECLARE(font_name);	// 声明过了就不用
    if ( method ) {
    
    
        lv_style_set_text_font(&label_style, LV_STATE_DEFAULT, &font_name);
        lv_obj_add_style(label1, LV_LABEL_PART_MAIN, &label_style);
    } else {
    
    
        lv_obj_set_style_local_text_font(
            label1,
            LV_LABEL_PART_MAIN,
            LV_STATE_DEFAULT,
            &font_name
        );
    }
}

/* 文档里一种动态加载字体的方法 */
static void lvgl_font_test2(void)
{
    
    
	lv_font_t * my_font;
	my_font = lv_font_load(X/path/to/my_font.bin);

	/*Use the font*/
	lv_obj_t* label2 = lv_label_create(lv_scr_act(), NULL);
    lv_label_set_text(label2, (LV_SYMBOL_HOME "你好 世界"));
    lv_obj_align(label2, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0);

	/*Free the font if not required anymore*/
	lv_font_free(my_font);
}

/* LVGL初始化 */
static void lvgl_init( void ) 
{
    
    
    lv_init();
    lv_port_disp_init();        // 显示器初始化
    lv_port_indev_init();       // 输入设备初始化
    lv_port_fs_init();          // 文件系统设备初始化
}

/****************************************************************/
int main(void)
{
    
    
	lvgl_init();
	
	lvgl_font_test(1);
	// lvgl_font_test(0);
	
	// lvgl_font_test2();
	
	while(1) {
    
    
		lv_tick_inc(LVGL_TICK);
		lv_task_handler();
		delay_ms(LVGL_TICK);
	}
}
/****************************************************************/

(五)KEIL MDK中文编译报错

编译时,打开Option for target,打开C/C++选项卡,在 “Misc Controls”一栏填入 “–locale=english” 。


五、启动LVGL

参考我的第一篇文章即可:
LittleVGL (LVGL)干货入门教程一之移植到stm32芯片


本篇完


其他:

LittleVGL (LVGL)干货入门教程一之移植到stm32芯片

LittleVGL (LVGL)干货入门教程二之LVGL的输入设备(indev)API对接。

LittleVGL (LVGL)干货入门教程三之LVGL的文件系统(fs)API对接

个人Github页:https://github.com/Trisuborn


下一篇

待续。。。


猜你喜欢

转载自blog.csdn.net/qq_26106317/article/details/113393286