一、背景分析
1、说明:
当前Esp32s3驱动ILI9488显示中文汉字方案研究了两种,一种TTF转C数组方案,另一种是TTF动态加载方案,这俩种方案各有利弊。
2、开发环境
1. ubuntu下ESP-IDF开发环境(ubuntu仅编译调试,在source insight中编写代码)
2. LVGL版本9.2.2
3.ESP32芯片型号ESP32S3 N16R8(flash 16M PSRAM 8M)
二、TTF转C数组方案(高效但固定)
2.1、实现原理
提前转化:使用工具将TTF文件转化成LVGL专用的.c字体文件。
特性限制:固定字号,且仅包含指定Unicode范围内的字符。
2.2、实现步骤
2.2.1 下载TTF字符库文件
TTF字符库可以百度搜索下载,也可以找电脑上的字符库,我用的是电脑上的TTF字符库。
1. 打开本电脑C:\Windows\Fonts,可以看到很多字体,选择一款自己喜欢的字体
2.复制字体到一个新的文件夹,作为转化文件夹,我选用的是黑体常规字体
2.2.2 使用转化工具转化C数组
打开LVGL官方文字转换网址Font Converter — LVGL,配置如下
name: 输出文件名(自定义文件名,比如simhei.ttf转化后我定义为my_font_simhei_24_4bpp.c)。
size:字体大小(如常用的小字号16,中字号24,大字号32)。
Bpp:字体质量 (我一般用4bpp)。
Browse: 选择我们前面下载的TTF字体库(如:simhei.ttf)。
Range: 中文字符的Unicode编码范围,填写0x0000-0xFFFF,基本包含了常用汉字以及中文标点符号。
Symbols: 可以不填
Submit:点击后等待生my_font_simhei_24_4bpp.c文件,下载到文件夹中(网页翻译大概8s,耐心等待)
2.2.3 修改生成的C文件
修改代码第10行为 "../../lvgl.h" (未修改前为:"lvgl/lvgl"),修改后的文件拷贝到LVGL9组件库下(lvgl-9.2.2/src/font/)。
2.2.4 修改后的C文件拷贝到LVGL9组件库的src/font/路径下
2.2.5 修改lvgl-9.2.2\scripts\built_in_font\generate_all.py文件
print("\nGenerating 16 px my_font_simhei_CJK")
os.system(u"./built_in_font_gen.py --size 16 -o my_font_simhei_16_4bpp.c --bpp 4")
print("\nGenerating 24 px my_CJK")
os.system(u"./built_in_font_gen.py --size 24 -o my_font_simhei_24_4bpp.c --bpp 4")
2.2.6 修改lvgl-9.2.2\src\font\lv_font.h文件
新增如下两行
LV_FONT_DECLARE(my_font_simhei_24_4bpp)
LV_FONT_DECLARE(my_font_simhei_16_4bpp)
2.2.7 修改lvgl-9.2.2\src\lv_conf_kconfig.h文件
新增如下两行代码
#define CONFIG_LV_FONT_DEFAULT &my_font_simhei_16_4bpp
#define CONFIG_LV_FONT_DEFAULT &my_font_simhei_24_4bpp
2.3、使用案例
void send_question_cb(lv_event_t * e) {
lv_obj_t * textarea = (lv_obj_t *)lv_event_get_user_data(e);
const char * question = lv_textarea_get_text(textarea);
// 模拟回答(实际可对接ChatGPT或本地逻辑)
char answer[256];
snprintf(answer, sizeof(answer), "回答:已收到问题——%s", question);
// 更新回答区域
lv_textarea_set_text(lv_obj_get_child(lv_obj_get_parent(textarea), 1), answer);
lv_textarea_set_text(textarea, ""); // 清空输入框
}
void create_chat_ui() {
// 创建父容器(全屏)
lv_obj_t * parent = lv_obj_create(lv_scr_act());
lv_obj_set_size(parent, LV_PCT(100), LV_PCT(100));
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_text_font(parent, &my_font_simhei_24_4bpp, 0);
// 1. 问题区域
lv_obj_t * label_question = lv_label_create(parent);
lv_label_set_text(label_question, "问题:如何点亮LED?");
lv_obj_set_width(label_question, LV_PCT(100));
// 2. 回答区域(可滚动)
lv_obj_t * textarea_answer = lv_textarea_create(parent);
lv_textarea_set_text(textarea_answer, "回答:使用gpio_set_level(LED_PIN, 1);");
lv_obj_set_width(textarea_answer, LV_PCT(100));
lv_obj_set_flex_grow(textarea_answer, 1); // 占据剩余空间
lv_textarea_set_placeholder_text(textarea_answer, "等待回答...");
// 3. 底部输入框和按钮
lv_obj_t * panel_footer = lv_obj_create(parent);
lv_obj_set_width(panel_footer, LV_PCT(100));
lv_obj_set_flex_flow(panel_footer, LV_FLEX_FLOW_ROW);
lv_obj_t * textarea_input = lv_textarea_create(panel_footer);
lv_obj_set_flex_grow(textarea_input, 1);
lv_textarea_set_placeholder_text(textarea_input, "输入问题...");
lv_obj_t * btn_send = lv_btn_create(panel_footer);
lv_obj_t * label_btn = lv_label_create(btn_send);
lv_label_set_text(label_btn, "发送");
lv_obj_add_event_cb(btn_send, send_question_cb, LV_EVENT_CLICKED, textarea_input);
}
void setup()
{
Serial.begin( 115200 );
lv_init();
lv_display_t * disp;
#if LV_USE_TFT_ESPI
/*TFT_eSPI can be enabled lv_conf.h to initialize the display in a simple way*/
disp = lv_tft_espi_create(TFT_HOR_RES, TFT_VER_RES, draw_buf, sizeof(draw_buf));
lv_display_set_rotation(disp, TFT_ROTATION);//设置图片旋转角度
//lv_display_set_flush_cb(disp, my_disp_flush);
#else
/*Else create a display yourself*/
disp = lv_display_create(TFT_HOR_RES, TFT_VER_RES);
lv_display_set_flush_cb(disp, my_disp_flush);
lv_display_set_buffers(disp, draw_buf, NULL, sizeof(draw_buf), LV_DISPLAY_RENDER_MODE_PARTIAL);
#endif
create_chat_ui();
}
void loop()
{
lv_timer_handler(); /* let the GUI do its work */
delay(5); /* let this time pass */
}
2.4、效果展示
三:TTF动态加载方案(灵活但缓慢)
基本流程已经跑通,待整理文档
四、后语
整体流程已经基本调通,效果展示已拍照记录。
测试代码已完整提供。
从无到有实现目前的效果,有参考其他大佬的帖子,也有自己摸索实现的部分,知识劳动成果,实属不易。
如果需要技术支持,欢迎骚扰(+v:Sw-striving)!