阅读前,请确保你至少拥有以下条件:
这篇文章会讲
字库的原理就不赘述了,百度一大把,主要就是不同编码字库的每个字,都按照不同的方式排列,根据编码可以进行搜索和定位,最后提取字库并用点阵方式显示就行,PC上多用矢量字体(使用顶点和曲线),一般最简单的方法就是使用点阵字体(也是很常用的形式)。
事实上,字库的制作有专用的工具,例如LVGL的官网提供在线字库转换工具(没网络就不行了,甚至经常抽风,本人就没有成功过,就不讲了,有兴趣可以自己试试)。
有兴趣的话也可以去LVGL官网了解字体相关的接口。
也有第三方大神制作的离线字库转换工具,并且非常简单实用。
可以去这个作者的网站下载:
LVGL字体转换工具:LvglFontTool
LVGL字体乱码:Lvgl之显示汉字出现乱码
直接把生成的C文件添加进项目编译即可,C文件里面包含了字库的查找函数和位图等,和一些LVGL的字库接口,当然不需要你亲自使用,只是为LVGL提供操作接口。
当你使用上述的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)
上面的操作仅仅是声明而已。
使用就基本没什么不同了,下文会统一说怎么使用,但区别在于,外部字库的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
#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);
}
}
/****************************************************************/
编译时,打开Option for target,打开C/C++选项卡,在 “Misc Controls”一栏填入 “–locale=english” 。
参考我的第一篇文章即可:
LittleVGL (LVGL)干货入门教程一之移植到stm32芯片
LittleVGL (LVGL)干货入门教程一之移植到stm32芯片
LittleVGL (LVGL)干货入门教程二之LVGL的输入设备(indev)API对接。
LittleVGL (LVGL)干货入门教程三之LVGL的文件系统(fs)API对接
个人Github页:https://github.com/Trisuborn
待续。。。