彩屏充电仓JL701N LVGL入门到进阶指导文档
📎 原始文档:https://www.kdocs.cn/l/cet7FRB1cpyS 彩屏充电仓JL701N LVGL入门到进阶指导文档
目前最新发布版本:彩屏仓资料SDK-V201-20240624
📌杰理工具说明文档:
(程序开发工具、固件处理工具、量产相关工具)
欢迎使用杰理工具文档 — JL Project Documentation
温馨提示:
※AC982空片不能使用1拖8烧录!AC982空片不能使用1拖8烧录!AC982空片不能使用1拖8烧录!
※AC982硬件设计必须按照标准原理图规范,VPWR与VL/VR是外露金属必须加TVS管!!!否则容易引入静电和浪涌,导致芯片异常
📌硬件及工具相关
| 硬件设计事项 | 彩屏仓 硬件开发指南 与 量产作业流程规范.otl |
|---|---|
| 烧录升级 | 彩屏仓 AC98N和JL701烧录升级注意事项.otl |
| 下载/升级工具 | 手表烧录_升级工具说明.otl |
| 认证资料获取汇总 | 认证资料获取汇总(最新资料后台会更新).otl |
| 量产 | 彩屏仓 硬件开发指南 与 量产作业流程规范.otl |
📌软件调试相关
| AC982调试 | 彩屏仓982相关.otl彩屏仓配对流程优化(3.11).otl |
|---|---|
| JL7012调试 | 彩屏LVGL UI设计及工具使用.otl彩屏仓免32K晶体修改说明.pdf彩屏仓功耗优化.otl |
| 各个系列耳机对应的SDK | 彩屏仓耳机介绍(本链接给出各个系列耳机搭配彩屏仓的SDK软件) 彩屏仓耳机介绍.otl |
| 耳机调试 | 彩屏仓耳机介绍.otl抖音翻页器开发注意点.pdf耳机本地播放说明.otl |
| SDK | 彩屏仓资料SDK-V301-2026-1-27 color_screen_charging_case_701n-sdk_v3.0.1 2026-1-27.zip ![]() |
~~https://kdocs.cn/l/clwQvjWvHLdK ~~ | |
| 补丁列表 | 彩屏仓补丁list.otl |
- 软件环境搭建
1.1 VSCode
仓端701的SDK、耳机的SDK都是基于VSCode开发和编译
该文档也基于VSCode开发环境进行示范操作,请事先搭建VSCode开发环境
VSCode环境搭建可参考《JL701N-入门指导》:穿戴手表JL701N-入门到进阶开发指导.otl
1.2 GUI Guider
GUI Guider是恩智浦为LVGL开发了一个上位机GUI设计工具,可以通过拖放控件的方式设计LVGL GUI页面,加速GUI的设计。在彩屏仓项目中,GUI Guider主要充当辅助工具,进行UI布局和页面仿真,生成基础的UI初始化代码,减少开发者编码工作量。因版权问题,推荐自行安装GUI Guider 1.6.1:
官网地址:GUI Guider | NXP Semiconductors
1.3 Cmake环境
1.3.1 Cmake
在官网进行下载:cmake(用于makefile的构建,目前使用的是3.26版本,建议安装在c盘)
(这里以3.28版本进行演示,建议使用3.26以上的版本)
双击cmake-3.28.0-windows-x86_64.msi进行安装,按照图示配置,下一步即可:
需要点击为所有用户安装
以及安装到C盘,这样会避免很多麻烦。
1.3.2 Mingw64
在官网进行下载: mingw64(cmake需要依赖于mingw64)
(这里以8.10版本进行演示,尽量安装在C盘)
解压x86_64-8.1.0-release-win32-sjlj-rt_v6-rev0.7z,将mingw64文件夹拷贝到C盘根路径下:
添加环境变量:此电脑右键,点击“属性”
点击“高级系统设置”
点击“环境变量”,在系统变量中找到“path”,选中后点击“编辑”
点击“编辑”,添加刚刚拷贝过去的ming64路径,在这里为C:\ming64\bin
最后点击“确定”即可
1.3.3 验证脚本环境
在SDK的code\sdk\lv_charging_case路径下,双击运行makefile_maker.bat
运行该脚本成功后,lv_charging_case子路径下的.mk文件均会更新时间
若命令行中出现下图所示打印,则说明脚本运行环境已经安装成功
1.3.4 常见运行异常
① 路径索引报错
不建议将SDK路径放得太深,否则可能会超出路径范围,从而导致有些文件索引不到。
若运行makefile_maker.bat时出现下图所示打印,则说明是部分文件超出路径范围。
②Cmake未安装
若运行makefile_maker.bat时出现下图所示打印,则说明是Cmake未安装,请重新安装Cmake
1.4 资源打包环境
1.4.1 Python部署
资源打包脚本由Python编写,要求部署python
【2024】Python安装教程_python安装教程csdn-CSDN博客
1.4.2 验证脚本环境
在SDK的code\sdk\lv_charging_case\res-pack-tools\imb-rle-pack路径下,双击运行run.exe,打包过程可能需要手动回车,若最后出现下图所示打印,则说明资源打包脚本运行环境已安装成功。
二、 UI辅助工具(GUI Guider)
在彩屏仓项目中,GUI Guider主要充当辅助工具,进行UI布局和页面仿真,生成基础的UI初始化代码,减少开发者编码工作量。但是该工具生成的代码不能直接用于SDK中,需要经过改造适配。可以把该工具生成的代码理解为空壳,开发者的工作就是把空壳移植到SDK中,然后在空壳中去填充逻辑。
2.1 软件界面介绍
GUI Guider用户界面说明_第3讲_哔哩哔哩_bilibili
2.2 控件布局介绍
2.3 页面图层关系
在LVGL中的页面里,容器控件是用来搭建层次关系
2.4 控件操作流程
2.4.1 控件命名
控件命名=控件类型_自定义后缀
以音乐播放界面的播放按钮为例,控件类型为imgbtn,加上自定义后缀后:
该控件的控件命名为:screen_music_imgbtn_music_play_or_stop
2.4.2 控件句柄命名
代码中控件句柄命名=控件所在屏幕名_控件名
以音乐播放界面的播放按钮:imgbtn_music_play_or_stop为例:
该控件的控件句柄名称为:screen_music_imgbtn_music_play_or_stop
2.4.3 控件的初始化
在lv_charging_case\lv_frame\generated\gui_guider.h里的结构体lv_ui定义了所有控件句柄
在lv_charging_case\lv_frame\generated\setup_scr_screen_music.c里面setup_scr_screen_music接口对screen_music下的所有控件进行初始化
没有实例化的控件句柄为野指针!不能对未实例化(未初始化)的控件句柄进行访问!
2.4.5 控件响应注册
控件响应函数=控件所在屏幕名_控件名_event_handler
因此该控件的控件响应接口为:screen_music_imgbtn_music_play_or_stop_event_handler
2.4.6 控件事件类型
在控件响应接口,通过区分控件事件,进行自定义逻辑编程
LVGL中有很多控件事件类型,可以到事件枚举列表查看:lvgl\src\core\lv_event.h
比如说我单击播放,长按暂停,就可以这样写:
2.5 UI代码生成
代码用C语言生成
注意事项:
为了节省控件,使用了图片资源的控件,需要把外部存储打开,进行代码生成
内部存储:图片会以数组的形式存储在.h里面,占用代码空间(不推荐)
外部存储:图片会以文件系统路径访问,图片资源需另外单独通过杰理资源打包工具打包烧录
打开外部储存后,不能以C语言运行仿真器,会资源索引报错,但可以用python仿真器。
2.6 UI模拟仿真
仿真用python仿真,用C语言仿真会报错
2.7 UI工程分辨率
.guiguider工程文件实际上就是一个json格式的文件,存储了UI工程的所有差参数信息,从GUI Guider上位机的修改实际上就是修改json文件的参数。用文本形式打开.guiguider工程文件,搜索定位参数resolution,该参数为工程分辨率,修改成屏幕实际的分辨率,然后保存。
然后重新用GUI Guider打开.guiguider工程文件,手动调整其他控件的参数。
2.8 GUI Guider生成的代码拷贝到工程上
对比拷贝GUI Guider生成的generated文件夹与SDK的generated文件夹。建议参考其它页面模板要增加的特殊处理,比如使用页面框架的页面需要增加一下两行代码:
lv_page_manager_page_adapte(ui->screen_light); // 使用页面管理模块时,需对页面进行适配
lv_page_manager_preempt_page_bg_adapte(ui->screen_light); // 适配为抢断页面

把GUI Guider生成的原图资源拷贝到SDK的imbtools目录下,按照3.1.2的方法打包。

三、资源打包/替换(res-pack-tools)
资源打包工具路径:..\lv_charging_case\res-pack-tools
3.1 图片资源打包
| 内部图片 | 外部图片 | |
|---|---|---|
| 存储位置 | 占用代码空间 | 占用资源空间 |
| 应用场景 | FLASH资源够,图片少前提下 | FLASH资源宝贵,图片多前提下 |
| 支持格式 | BMP、PNG、JPG(JPG要求图像的长和宽都是16的倍数) |
JPEG(Joint Photographic Experts Group)是一种常见的图像压缩格式,它使用一种称为离散余弦变换(DCT)的算法来压缩图像。DCT 算法通常要求图像的长和宽都是16的倍数,这是因为在DCT处理过程中,图像被分成16x16的小块,这样可以更高效地进行压缩和解压缩操作,减少处理时的边界效应,提高压缩效率和图像质量。
3.1.1 内部图片打包
内部图片实际上是以C数组形式存储图片数据,可以利用官方在线图片转换工具:
Online image converter - BMP, JPG or PNG to C array | LVGL
3.1.2 外部图片打包
- 静态图片打包
| 静态图片 | |
|---|---|
| 资源引用方式 | 静态图片通过路径引用:"F:/图片名称.bin" 示例:给一个图片控件设置图片,图片文件为test.png lv_img_set_src(图片控件句柄, "F:/test.bin"); |
| 资源打包流程 | 以下说明如何新增一个静态图片资源,并加载到UI控件上: 静态图片打包工具位置: ..\lv_charging_case\res-pack-tools\imb-rle-pack 静态图片资源放置: ..\lv_charging_case\res-pack-tools\imb-rle-pack\imbtools\images ①在..\imbtools\images添加图片,支持PNG、BMP、JPG,可以添加多级文件夹 ②双击run.exe生成资源 ![]() ③编译SDK ④LVGL代码调用 路径查找:lv_img_set_src(img_obj, "F:/usr_pic.bin"); |
- 动态图片打包
| 动态图片 | |
|---|---|
| 资源引用方式 | 动图通过文件夹名称引用:"文件夹名称",且只能加载到动画控件上(通过lv_animimg_create创建的控件) 示例:在动画控件animimg上设置动画,动画对应动图文件夹名称为TEST 若动画控件已加载一组动画,但你想替换另一种动画,需要先释放对旧动画资源占用 usr_free_animing(animimg, (const void **) screen_loop_img_bg_imgs, 1, 100, LV_ANIM_REPEAT_INFINITE); 然后再加载新的一组动画 usr_update_animing(animimg, "TEST"); 动画控件删除之前,需要先释放对动画资源的占用 usr_free_animing(animimg, (const void **)screen_loop_img_bg_imgs, 1, 100, LV_ANIM_REPEAT_INFINITE); |
| 资源打包流程 | 以下说明如何新增一个动画资源,并加载到UI控件上: 动态图片打包工具位置: ..\lv_charging_case\res-pack-tools\用户动画更换入口 一个文件夹对应一个动图,文件夹名字就是动图资源的名字 ![]() ①先新建一个文件夹TEST(文件夹名只允许大写字母与数字,命名长度7个字符以内) ![]() ②然后在TEST文件夹添加图片,规则如下: •放GIF图:文件夹放入一张gif图,配置cfg.txt转换切图格式,不配置做默认转成PNG切图 ![]() •放切图文件夹:新建一个时间戳文件夹,比如想要切图间隔40ms,就新建一个40ms的文件夹,把切图放到xxms文件夹里,支持PNG/BMP/JPG格式 ![]() ![]() ③点击run.exe生成资源 ![]() ④修改批处理文件 添加资源文件打包列表指令pack_code.exe和-filelist指令添加TEST,例如添加7个外部动画: ....\packres.exe -keep-suffix-case BIG1.bin BIG1.res -n res -o TEST ....\fat_comm.exe -pad-backup2 -force-align-fat -out new_res.bin -image-size 16 -filelist myFont.bin ui TEST -remove-empty -remove-bpb -mark-bad-after 0xfe0000 -key %CHIPKEY% -address 0 ![]() ⑤代码调用 若动画控件已加载一组动画,但你想替换另一种动画,需要先释放对旧动画资源占用 usr_free_animing(animimg, (const void **) screen_loop_img_bg_imgs, 1, 100, LV_ANIM_REPEAT_INFINITE); 然后再加载新的一组动画 usr_update_animing(animimg, "TEST"); 动画控件删除之前,需要先释放对动画资源的占用 usr_free_animing(animimg, (const void **)screen_loop_img_bg_imgs, 1, 100, LV_ANIM_REPEAT_INFINITE); ✅建议参考公版代码里面是如何调用的,跟一下逻辑了解! |
- 图片资源压缩 减少图片:减少照片,或不需要透明度的照片
压缩图片:不需要透明度的照片,转为bmp或jpg再去打包压缩,对于杰理的资源打包工具而言,bmp/jpg打包后的压缩率比png高
😃推荐用蜂蜜图片浏览器,进行图片转换:https://www.bandisoft.com/honeyview/


3.2 字库(多国语言)
| 内部字库 | 外部字库 | |
|---|---|---|
| 存储位置 | 占用代码空间 | 占用资源空间 |
| 应用场景 | 能预知的字符:如标题、提示语等 | 不能预知的字符:如歌词、消息通知等 |
显示阿拉伯语、波斯语需要打开宏:LV_USE_BIDI、LV_USE_ARABIC_PERSIAN_CHARS
务必按下图配置:
3.2.1 内部字库
- 内部字库的生成 内部字库实际上是以C数组形式存储字库字模数据
利用官方在线字库转换工具:Online font converter - TTF or WOFF fonts to C array | LVGL
- Name:输入要生成的字体名称(最后会生成同名的 C 文件)
- Size:输入要转换的字体大小
- Bpp:您可以以每像素位数为单位定义字母边缘的模糊度
- file:选择本地 TTF 或者 WOFF 格式的字体文件,(请确保该字体为免费商用)
- Range:自定义字母范围,即要包含的范围和/或字符,例如 0x20-0x7F、0x200、450
- Symbols:输入字库需要包含的文字,如需空格,符号,数字,字母也需一并输入 完成上述五步必须操作,点击 convert 进行在线转换,字体会自动下载到本地
利用GUI Guider生成内部字库:
生成的内部字库文件在..\generated\guider_customer_fonts目录下:
- 字库声明和调用 内部字库.c复制到lv_charging_case\lv_frame\generated\guider_customer_fonts目录下
然后运行lv_charging_case\makefile_maker.bat把内部字库.c添加到编译列表
在lv_charging_case\lv_frame\generated\gui_guider.h中用LV_FONT_DECLARE对字库声明
代码调用lv_obj_set_style_text_font将字库应用到文字控件上
3.2.2 外部字库
参考:https://kdocs.cn/l/ckqU56AWc49k
利用LvglFontTool工具生成外部字库,位置:..\lv_charging_case\res-pack-tools\字库工具

- 添加字符集 提供一套字符集如下,根据需求自行裁剪和补充,其中包括:中文、英文、日文、韩语、俄语、法语、西班牙语、泰语、孟加拉语、波斯语、阿拉伯语、印地语等等语言字符集
font_characters.txt
显示阿拉伯语、波斯语需要打开宏:LV_USE_BIDI、LV_USE_ARABIC_PERSIAN_CHARS
务必按下图配置:
由于阿拉伯语、波斯语有连写规则,文字控件不能有字符间隔
lv_obj_set_style_text_letter_space(lable, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
这个函数是设置文字控件的字符间距的,第二个参数是字符间距值,代码里有些默认是2,需要改为0才能连起来,务必全局搜一下修改一下
有连写规则的语言(如阿拉伯语、波斯语等),如果要显示一段字符,字库要求要打包该语言的所有字符,才能正常显示
我们在生产全量字体库时,如果把所有汉字都生成出来,这样会导致生成的运行程序非常大。建议在生产汉字的时候,在Symbols中填入国标一级汉字集合,这已经满足99%的使用场景。
在数以亿计的浩翰文献资料中,统计出实际使用的不同的汉字数为6335个,而其中有3000多个汉字的累计使用频度达到了99.9%,而另外的3000多个累计频度不到0.1%,说明了常用汉字与次常用汉字的数量不足7000个,这就为国家制定汉字库标准提供了依据。
下面连接为国标一级汉字、国标二级汉字的连接:
https://www.qqxiuzi.cn/zh/yijiziku-erjiziku.php
2. 配置字体参数 这个是索引你windows系统里面已安装的字体,你没找到证明你没安装到系统里面
字号越大,采集的TTF字模越大,字库体积越大
工具打包的字库不能包含多个字号的,如果你想用多种字号,就另外打包一个其他字号的外部字库
一个字库能否显示所有字号?
答:不可以,在LVGL(轻量级图形库)中,直接使用一个字库显示多种字号的字符并不直接支持。LVGL主要面向资源受限的嵌入式系统,其默认的字体处理方式基于固定点阵字模,即每个字符对应一个固定大小的点阵数据。在这种模式下,为显示不同字号的字符,通常需要为每种字号单独生成对应的字模文件,并在LVGL中分别加载这些不同字号的字库。
在MCU上的字库解析,和电脑上的字库解析是不一样的,电脑上用几M的TTF就能显示任何大小的字,但是在MCU上我们是先利用TTF生成某个字符某个字号的字模,再下载到MCU里面的,因此不同字号字模,占用的空间不一样的,要是可以这字库得多大。
3. 配置生成参数 按下图设置,抗锯齿值(bpp)越大,字库体积越大(bpp>=2,推荐2)
在 LVGL 中,字体是渲染字母(字形)图像所需的位图和其他信息的集合。
字体具有bpp(像素深度)属性。它显示了使用多少位来描述字体中的像素。为像素存储的值决定了像素的不透明度。 这样,使用更高的 bpp,字母的边缘可以更平滑。可能的 bpp值为 1、2、4 和 8(值越高表示质量越好)。
bpp还会影响存储字体所需的内存大小。例如,bpp = 4的字体所占用的内存比 bpp = 1的字体所占用的内存大近4倍。
4. 外部字库命名 自定义字库名称,推荐遵循LVGL字库命名规范,方便快速辨识字库信息:
lv_font_字体名称_样式_字号
生成外部字库 点击右下角开始转换,生成两个文件,一个为外部字库资源文件.bin,一个为字库访问驱动.c
.c复制到lv_charging_case\lv_frame\generated\guider_customer_fonts目录下
.bin复制到cpu\br28\tools\ui_resource目录下
然后运行lv_charging_case\makefile_maker.bat把.c添加到编译列表.c替换杰理接口 工具生成的.c文件中的__user_font_getdata接口用下面的杰理接口进行替换
注意代码中的path中的XXX.bin需要替换成和生成的字库名称一致
#include "res/resfile.h"
static uint8_t *__user_font_getdata(int offset, int size){
static u32 file_addr=0;
if(!file_addr){
char * path = "storage/virfat_flash/C/myFont.bin";
struct flash_file_info ui_resfile_info;
int ret = ui_res_flash_info_get(&ui_resfile_info, path, "res");
if(!ret){
file_addr = ui_resfile_info.tab[0] + ui_resfile_info.offset;//计算文件的物理地址
ui_res_flash_info_free(&ui_resfile_info, "res");
printf("打开外部字库 %s 成功 %x", path, file_addr);
put_buf(file_addr, 64);
} else {
printf("打开外部字库 %s 失败", path);
file_addr = 0;
return 0;
}
}
if(offset<0)offset=0;
int addr = file_addr + offset;
return addr;;
}
- 字库声明和调用 在lv_charging_case\lv_frame\generated\gui_guider.h中用LV_FONT_DECLARE对字库声明
代码调用lv_obj_set_style_text_font将字库应用到文字控件上
3.2.3 字库资源压缩
- 外部字库方面:裁剪字库字符,抗锯齿值bpp调低到2
- 内部字库方面:裁剪预置的内部字库,LVGL预置了一些内部字库,可以关闭来裁剪代码大小 下面是一些常见的字库目录:
lv_charging_case\lv_frame\lvgl\src\font
lv_charging_case\lv_frame\generated\guider_fonts
lv_charging_case\lv_frame\generated\guider_customer_fonts
内部字库.C文件,有编译开关宏,关闭后不会编译该字库,同时外部不能访问该字库
四、SDK代码说明(🚧待施工)
4.1 外设适配
4.1.1 屏幕驱动
SDK内部内置了部分型号的屏幕驱动,并通过宏进行管理,只能启用一个屏驱,否则有编译问题。
可以通过全局搜索屏驱的宏,定位驱动文件的位置、引脚配置的位置,如屏幕引脚配置:
屏幕驱动介绍:
上图中列举了部分屏幕参数,其中:
LCD_DRIVE_CONFIG::推屏时序
如QSPI_RGB565_SUBMODE2_1T2B对应的是QSPI时序,数据结构为RGB565、1个周期发2字节数据;
具体可以参阅《701N屏幕驱动配置说明》:..\701n_watch_release_v2.X.X\doc\固件资料\UI
- SCR_X、SCR_Y:屏幕x轴和y轴偏移,不需要偏移的话默认填0即可。
- SCR_W、SCR_H、LCD_W和LCD_H:屏驱宽高,一般填屏幕分辨率即可。
- LCD_BLOCK_W:分块buf的宽度,一般是按行分块,宽度设置为跟LCD_W一致即可。
- LCD_BLOCK_H:分块buf高度,可以根据需求修改。
- BUF_NUM:buf数量默认设置2,一般不需要修改。
- LCD_FORMAT:推屏数据格式,默认设置RGB565,一般不需要修改。 以上提及的数据,一般只需要修改SCR_W、SCR_H、LCD_W和LCD_H和LCD_BLOCK_W即可。
屏幕初始化命令如上图所示,用户添加新的屏驱时需要按照一定规则去修改屏驱初始化命令,其中_BEGIN_和_END_分别为开始标志位和结束标志位,这两个标志位跟实际上推屏数据无关,只是作为杰理lcd模块用于控制数据发送的信号。
BEGIN_后的第一个参数是命令,后续的则是数据,如_BEGIN, 0xc0, 0x5a, 0x5a, _END_中,命令是0xc0,数据是0x5a, 0x5a。
可以理解为,以上命令是屏厂驱动的SPI_WriteComm(0xc0);SPI_WriteData(0x5a);SPI_WriteData(0x5a);转换而来。
fps:fps为设置的帧率,默认为60,底层会根据fps算出合适的时钟速率,如果想要了解fps和时钟速率的一个对应关系,可以将app_config.c里面的log_tag_const_d_UI AT(.LOG_TAG_CONST)设置为true,在打印中搜索fps相关打印即可找到两者直接的对应关系。
debug_mode_en:debug模式开关,置为true后不会推合成后的数据,而是根据debug_mode_color设定的颜色值去显示,一般用于推屏数据的排查。
debug_mode_color:debug模式时显示的颜色值。
注册lcd设备,在这个步骤中,会将屏驱相关信息注册进去,用户可以根据需求修改logo以及名称。
注意:ST77903系列屏幕,需要PSRAM参与驱动,请确认目前的主控芯片是否内置PSRAM,或硬件上是否外挂PSRAM。
4.1.2 触控驱动
触控驱动影响传递给LVGL只有“按下”和“抬起”的状态和坐标值数据,以CST820触控驱动为例
/* LVGL touch_panel*/
volatile u8 touch_down = 0;
volatile int touch_x = 0;
volatile int touch_y = 0;
apps\common\device\touch_panel\cst820\cst820.c
cpu\br28\ui_driver\lvgl\lv_port_indev.c
4.2 UI线程处理
| 功能 | 接口 | 说明 |
|---|---|---|
| LVGL 线程初始化 | lvgl_test_init | |
| LVGL 线程主体 | lvgl_task | |
| LVGL 线程消息处理 | lv_os_event_handle | |
| LVGL 线程消息传递 | post_ui_msg | 该线程基于线程名“ui”创建 可以通过post_ui_msg传递消息 |
| LVGL 线程低功耗判条件断 | lvgl_idle_query |

4.2.1 自动息屏
| 功能 | 接口 | 说明 |
|---|---|---|
| 亮屏指令 | lv_exit_sleep | 可以跨线程使用 |
| 灭屏指令 | lv_enter_sleep | 可以跨线程使用 |
| 背光控制 | usr_bl_update | 可以跨线程使用 |
| 自动息屏使能 | lv_auto_sleep_enable | 可以跨线程使用 |
4.2.2 帧率/内存监控
LV_USE_PERF_MONITOR、LV_USE_MEM_MONITOR
4.3 UI应用层框架
4.3.1 页面类型
页面有两种:
一种是卡片页面管理器内的页面
一种是抢断页面,卡片页面管理器相当于一个抢断页面,参与页面链表调度
4.3.2 页面文件架构
页面的逻辑代码在:..\lv_charging_case\lv_frame\custom
我们为各个页面都单独创建了文件夹,页面的逻辑都在各自的文件夹下,开发者可以很直观地找到页面相关的代码位置;
4.3.3 页面优先级链表
页面优先级链表的逻辑代码在:device_refresh_control.h / device_refresh_control.c
① 工作原理
页面优先级链表会自动按照优先级排序
链表的头结点永远是优先级最高的节点
当前屏幕显示的也是优先级最高的节点
② 页面优先级
屏幕ID号,反映优先级关系,ID号越大优先级越高,如下图所示,卡片页面管理器优先级最低。
③ 相关API
| 功能 | 接口 | 参数 | 说明 |
|---|---|---|---|
| 添加节点 | screen_list_add | void (*Init)():当调度到该屏幕或上层屏幕退出时,调用该接口对该屏幕进行初始化 void (*Deinit)():当该屏幕退出或被其他屏幕覆盖时,调用该接口删除该屏幕资源 void (*Load)():当调度到该屏幕或上层屏幕退出时,调用该接口把屏幕推到上层显示 void (*Refresh)():当该屏幕正显示在最上层时,调用该接口刷新该屏幕的控件状态 int Screen_Id:屏幕ID号,反映优先级关系,ID号越大优先级越高 | 该接口把一个屏幕添加到链表调度,链表会根据优先级由高到低排序,该接口根据Screen_Id判断优先级插入链表对应位置,但是不意味着能够马上显示,当前显示的屏幕取决于链表的头结点,而头结点是优先级最高的节点 |
| 删除节点 | screen_list_del | int Screen_Id:屏幕ID号 | 删除链表中所有Screen_Id的节点 |
| 清空节点 | screen_list_clean | 无 | 删除链表中所有的节点 |
| 节点打印 | screen_list_printf | 无 | 打印链表中所有的节点 |
| 节点状态更新 | screen_list_refresh | 无 | 由循环定时器驱动,调用链表头结点入队时screen_list_add注册进去的Refresh |
4.3.4 卡片页面管理器
卡片页面管理器的逻辑代码在:lv_charging_case\lv_frame\custom\screen_loop_manager
- 工作原理 当我们滑动卡片菜单页面时,会同时加载当前显示的页面的相邻页面,相反,如果页面不再是当前显示页面的相邻页面,会删除释放。

| 页面布局 | 初始化接口 | 相关说明 |
|---|---|---|
| 管理器主体 | PM_Init | |
| 卡片页面背景 | CreateBackgroud | |
| 卡片页面顶部栏 | lv_status_bar_top_init | 顶部栏状态更新:status_bar_top_refresh |
| 卡片页面底部栏 | lv_status_bar_bottom_init | 页面序点更新:lv_upadate_status_bar_bottom_by_id |
| 卡片菜单页面 | 在卡片页面各自的代码目录下 | 创建页面关系:PM_AddPage 配置页面链接关系:PM_SetPageMoveMode |
页面增删排列 卡片页面的排列关系在卡片页面管理器初始化的时候固定下来:PageManagerInit

滑动效果参数 把EnergyTrigger使能后,下图参数都可以调节,按照图示修改体验。或者自行实践调节,调到你想要的滑动效果。

4.3.5多国语言管理模块
多国语言管理模块的逻辑代码在:lv_charging_case\lv_frame\custom\lv_demo_multilingual
- 工作原理 通过预先设置一个utf8编码映射表multilingualMap,以及设定一个基准语言,根据基准语言在映射表中查表实现映射。对应用户来说只要设置基准语言的字符串并调用切换语言的接口即可进行语言切换显示,在lvgl底层传入编码前,会根据输入基准语言的具体字符串确定映射表的行,再根据设置的语言确定当前列,最后根据行列锁定需要设置的字符串,将原本的字符串进行替换,从而实现不同语言体系的整体切换。
如上图所示:
DEFAULT_LANGUAGE:基准语言,默认设置为简体中文,即调用lv_label_set_text和lv_label_set_text_fmt时,传参只需要传中文字符串即可;
multilingualMap:utf8映射表,对用户来说类似手表sdk的 多国语言表.xls ,其中每列代表不同的语言,如第一列代表简中、第二列代表繁中、第三列代表英语和第四列代表日语等等。而每行代表不同的字符串,也就是不同的词条。
在设置字符串以及重新设置语言后,多国语言管理模块会在lv_label_set_text和lv_label_set_text_fmt处进行拦截,先查映射表获取新的字符串再进行显示。
如上图multilingual_text_remap接口会在进入lvgl的流程前把utf8编码给替换掉。
- 使用案例
/* setup_scr_screen_anc.c */
void setup_scr_screen_anc(lv_ui *ui, lv_obj_t *page)
{
......
lv_label_set_text(ui->screen_anc_label_anc_title, "降噪");
......
}
/* 以上处理的目的在于初始化设置语言 */
/* lv_demo_anc.c */
static const char *noise_reduction_title[] = {"降噪", "Noise Reduction"};
/* 假如此时在其他地方调用box_info_base_cb.lv_language_set(),比如设置为英语:box_info_base_cb.lv_language_set(M_ENGLISH); */
void screen_anc_refresh()
{
u8 language = box_info_base_cb.lv_language_get(); /* 获取当前设置的语言 */
/* 设置映射表选择语言,返回0表示设置成功 */
if(!lv_set_language(language)) {
......
lv_label_set_text(guider_ui.screen_anc_label_anc_title, noise_reduction_title[0]);
......
}
}
/* 以上处理直接配置字符串为noise_reduction_title[0]的目的是兼容前面版本,也可以直接传入“降噪” */
/* 但要注意必须要在刷新函数中使用,如上图中的screen_anc_refresh,因为编码更新后需要重新配置 */
/* 即需要重新调用lv_label_set_text接口,而在刷新函数中会自动帮我们调用该接口 */
/* 进行上述操作后,控件guider_ui.screen_anc_label_anc_title将会显示"ANC" */
以上例子中,真正关键的地方其实只有两处,一处是box_info_base_cb.lv_language_set()进行语言设置,另一处是screen_anc_refresh()中获取语言并且更新映射表锁定列,重新调用lv_label_set_text设置,如lv_label_set_text此时设置为“降噪”,并通过box_info_base_cb.lv_language_set()设置为英语,那么此时将会锁定“ANC”字符串,在设置语言后,定时器会调用screen_anc_refresh,把guider_ui.screen_anc_label_anc_title控件内容更新为“ANC”,其他字符串也是同理,均按照基准语言进行输入即可,当前基准语言是简体中文,故对用户来说,lv_label_set_text传入的字符串需要均为中文,再切换语言,多国语言管理模块会帮我们进行重映射,实现一改全改的效果。
由此可知,若要增删多国语言,只需要维护multilingualMap即可,通过增加新的列来添加新的语种,通过增加新的行来添加新的词条。
总结一下,对用户来说,使用步骤如下:
1. 根据需求配置multilingualMap映射表,完成翻译关系映射,保证所用到的需要切换语言的固定词条均被包含在映射表中; 2. 针对需要切换语言的控件,调用lv_label_set_text或者lv_label_set_text_fmt进行设置,以及要在对应页面的refresh函数中进行更新,其中传入的字符串要与基准语言一致,如默认以简中为基准语言,故只传入简中即可; 3. 根据需求调用切换语言接口,即可进行多国语言的整体切换。
- 注意事项
- 映射表不一定是要做成翻译表,这里只是代表一种映射关系,根据输入字符串确定行,根据设置语言确定列,根据行列锁定字符串;
- 若用到多国语言管理模块,需要在对应的refresh函数中重新设置文字控件,具体参考 ②使用案例 中在refresh函数中的使用,若发现调用切换语言的接口后,实际上语言并没有切换过来,优先怀疑没有在refresh函数中重新配置文字控件;
- 多语言管理模块基于lvgl字库进行使用,字库生成具体参考 第三章-3.2字库(多国语言);
- multilingual_text_remap接口中,会对地址进行过滤,若地址范围不符合指定范围则不会经过映射表,根据这个特性可以区分多国语言固定词条与不固定字符串显示(歌词、消息等);
- 使用lv_label_set_text_fmt时,使用%s同样无法经过映射表进行重新映射,同样利用该特性,可以区分多国语言固定词条和不固定字符串显示,如:
/* 1.显示不固定字符串,不会经过映射表进行重映射 */
/* lv_demo_music.c */
char lyrics_content_array[STR_MAX_SIZE] = {0};
/* 歌词接收处把歌词保存到lyrics_content_array */
void lv_lyrics_data_update()
{
......
/* 这里使用了%s,不会经过映射表重映射 */
lv_label_set_text_fmt(lyrics_data, "%s", lyrics_content_array);
......
}
/* 2.显示固定词条,会经过映射表进行重映射 */
/* setup_scr_screen_anc.c */
void setup_scr_screen_anc(lv_ui *ui, lv_obj_t *page)
{
......
lv_label_set_text(ui->screen_anc_label_anc_title, "降噪");
......
}
在以上例子中,切换语言不会对例子1产生影响,但会对例子2产生影响。
6. 若要数字与文字结合显示,并且需要经过映射表,具体参考控件的guider_ui.screen_alarm_label_alarm_time使用
lv_label_set_text_fmt(guider_ui.screen_alarm_label_alarm_time, "%d分钟", clock_time[0]);
同时映射表需要配置如下:
7. 若输入字符串在映射表的基准语言列中找不到相同的字符串,切换语言后则不会进行映射; 8. 若基准语言列中有两个相同的字符串,进行重映射时会根据数组靠前的字符串进行映射,故不建议出现两个相同的字符串对应不同映射,否则可能会出现不符合预期的情况; 1. 若用户不想使用公版多国语言管理模块,可以把MULT_ENLAUGE_REMAP_ENABLE设置为0,关闭公版多国语言管理模块,并接入自己的多国语言管理模块。
4.4 UI公版页面介绍
4.4.1 卡片页面
- 音乐控制
| 代码文件夹 | lv_demo_music |
|---|---|
| 页面初始化 | init_screen_music |
| 页面去初始化 | deinit_screen_music |
蓝牙歌词功能需要打开APP端的车载歌词功能
- 语言切换
| 代码文件夹 | lv_demo_language |
|---|---|
| 页面初始化 | init_screen_language |
| 页面去初始化 | deinit_screen_language |
- 抖音控制
| 代码文件夹 | lv_demo_tiktok |
|---|---|
| 页面初始化 | init_screen_tiktok |
| 页面去初始化 | deinit_screen_tiktok |
触控焦点调整
长按点赞标题,进入触控点调节页面,手动调整手机屏幕的触控焦点,有些手机点赞位置和仓发的位置对不上,可以手动调整适配(移动焦点后,由于焦点已经偏移,回到抖音界面,最好按一次pp键复位原点)
4. 拍照控制
| 代码文件夹 | lv_demo_snap |
|---|---|
| 页面初始化 | init_screen_snap |
| 页面去初始化 | deinit_screen_snap |
- EQ控制
| 代码文件夹 | lv_demo_equalizer |
|---|---|
| 页面初始化 | init_screen_equalizer |
| 页面去初始化 | deinit_screen_equalizer |
- ANC控制
| 代码文件夹 | lv_demo_anc |
|---|---|
| 页面初始化 | init_screen_anc |
| 页面去初始化 | deinit_screen_anc |
- 音量调节
| 代码文件夹 | lv_demo_volume |
|---|---|
| 页面初始化 | init_screen_volume |
| 页面去初始化 | deinit_screen_volume |
- 背光调节
| 代码文件夹 | lv_demo_brightness |
|---|---|
| 页面初始化 | init_screen_brightness |
| 页面去初始化 | deinit_screen_brightness |
4.4.2 来电
| 代码文件夹 | lv_demo_call |
|---|---|
| 页面初始化 | screen_call_init |
| 页面去初始化 | screen_call_deinit |
4.4.3 闹钟
| 代码文件夹 | lv_demo_ring |
|---|---|
| 页面初始化 | screen_ring_init |
| 页面去初始化 | screen_ring_deinit |
4.4.4 闹钟响起
| 代码文件夹 | lv_demo_ring |
|---|---|
| 页面初始化 | screen_alarm_ring_init |
| 页面去初始化 | screen_alarm_ring_deinit |
4.4.5充电
| 代码文件夹 | lv_demo_charging |
|---|---|
| 页面初始化 | screen_charging_init |
| 页面去初始化 | screen_charging_deinit |
4.4.6 开机
| 代码文件夹 | lv_demo_poweron |
|---|---|
| 页面初始化 | screen_poweron_init |
| 页面去初始化 | screen_poweron_deinit |
4.4.7 关机
| 代码文件夹 | lv_demo_poweroff |
|---|---|
| 页面初始化 | screen_poweroff_init |
| 页面去初始化 | screen_poweroffl_deinit |
4.4.8 锁屏
| 代码文件夹 | lv_demo_lock |
|---|---|
| 页面初始化 | screen_lock_init |
| 页面去初始化 | screen_lock_deinit |
4.4.9 产测
| 代码文件夹 | lv_demo_product_test |
|---|---|
| 页面初始化 | screen_product_test_init |
| 页面去初始化 | screen_product_test_deinit |
壁纸切换页面,右切键快速按6下以上,然后长按中间的小壁纸,进产测页面
- PC模式 typec线直连PC和仓typec充电口,然后点击产测页面上的PC按钮,PC会出盘。
PC模式下出盘后,可以直接编译代码实现烧录 - 船运模式 701关机,关机前给982发船运串口指令,982关闭与701串口交互,只能插充电激活
- 蓝牙测试
- 触控测试 产测界面,点击触控测试按钮,测试触控功能
- 按键测试
- 屏幕测试 产测界面,点击屏幕测试按钮,进入颜色测试

🚧待施工
五、功耗参考

六、常见问题
6.1 如何新增页面
新增一个界面,包括新增普通界面、新增卡片界面、新增菜单图标等。
LVGL耳机舱新增界面方法.otl
6.2 自定义ble广播
自定义ble广播字段,以满足某些app连接需求。
6.3 自定义ble服务(用于开发自己的app等)
自定义ble服务回调,以满足app功能开发。
6.4 补丁
有些已经处理过的问题,在公版代码更新前,以补丁的形式增加,如果遇到蓝牙死机、蓝牙断连等bug,请打补丁,见以下链接:彩屏仓补丁list.otl








