LVGL文件系统移植
2.1、LVGL文件系统接口
该笔记内容适用于LVGLV6、V7版本两个版本,均实际使用过. V8版本没有看过,所以不确定能否使用.
最近开发过程中用到了LVGL的文件系统读取文件显示到LCD,在前些笔记里面也有人询问文件系统的使用,做个笔记记录一下移植过程.
要使用LVGL的文件系统接口,首先要明确你使用LVGL的项目中的文件系统接口怎么用.
比如你使用的是RTT的DFS,那么你可以选择使用RTT官方提供的POSIX接口,也可以使用dfs的抽象接口.或者使用的是FATFS系统,那么你只能选择f_open,f_close等FATFS的接口.
模拟器同理.
2.1.1 文件系统移植
下面以模拟器举例.
打开你的LVGL模拟器工程中的lv_port_fs_template.c
和lv_port_fs_template.h
文件.
2.1.1.1、打开开关
两个文件默认状态下在文件起始位置有如下内容.
//省略若干内容
#if 0
//省略若干内容
#endif
将两个文件内的#if 0
修改为#if 1
.
在lv_port_fs_template.c
文件中添加如下语句.
#include <stdio.h>
2.1.1.2、修改文件
在lv_port_fs_template.h
文件中添加如下语句.
void lv_port_fs_init(void);
在lv_port_fs_template.c
文件修改如下函数.
-
lv_port_fs_init
void lv_port_fs_init(void) { fs_init(); lv_fs_drv_t fs_drv; lv_fs_drv_init(&fs_drv); /*Set up fields...*/ fs_drv.file_size = sizeof(file_t); fs_drv.letter = 'S'; fs_drv.open_cb = fs_open; fs_drv.close_cb = fs_close; fs_drv.read_cb = fs_read; // fs_drv.write_cb = fs_write; fs_drv.seek_cb = fs_seek; // fs_drv.tell_cb = fs_tell; // fs_drv.free_space_cb = fs_free; // fs_drv.size_cb = fs_size; // fs_drv.remove_cb = fs_remove; // fs_drv.rename_cb = fs_rename; // fs_drv.trunc_cb = fs_trunc; fs_drv.rddir_size = sizeof(dir_t); fs_drv.dir_close_cb = fs_dir_close; fs_drv.dir_open_cb = fs_dir_open; fs_drv.dir_read_cb = fs_dir_read; lv_fs_drv_register(&fs_drv); }
-
fs_open
static lv_fs_res_t fs_open (lv_fs_drv_t * drv, >void * file_p, const char * path, lv_fs_mode_t >mode) { lv_fs_res_t res = LV_FS_RES_NOT_IMP; if(mode == LV_FS_MODE_WR) { /*Open a file for write*/ /* Add your code here*/ fp = fopen(path, "wb"); if (NULL == fp) { res = LV_FS_RES_FS_ERR; } else { res = LV_FS_RES_OK; } } else if(mode == LV_FS_MODE_RD) { /*Open a file for read*/ /* Add your code here*/ fp = fopen(path, "rb"); if (NULL == fp) { res = LV_FS_RES_FS_ERR; } else { res = LV_FS_RES_OK; } } else if(mode == (LV_FS_MODE_WR | >LV_FS_MODE_RD)) { /*Open a file for read and write*/ /* Add your code here*/ fp = fopen(path, "wb+"); if (NULL == fp) { res = LV_FS_RES_FS_ERR; } else { res = LV_FS_RES_OK; } } return res; }
-
fs_close
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p) { lv_fs_res_t res = LV_FS_RES_NOT_IMP; /* Add your code here*/ if (0 == fclose(fp)) { res = LV_FS_RES_OK; } else { res = LV_FS_RES_FS_ERR; } return res; }
-
fs_read
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br) { lv_fs_res_t res = LV_FS_RES_NOT_IMP; /* Add your code here*/ *br = fread(buf, (size_t)1, (size_t)btr, fp); if (*br == btr) { res = LV_FS_RES_OK; } else { res = LV_FS_RES_FS_ERR; } return res; }
-
fs_seek
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos) { lv_fs_res_t res = LV_FS_RES_NOT_IMP; /* Add your code here*/ if (0 == fseek(fp, pos, SEEK_SET)) { res = LV_FS_RES_OK; } else { res = LV_FS_RES_FS_ERR; } return res; }
最后在lv_port_fs_template.c
文件中增加一个全局变量,如下所示.
static FILE* fp;
2.1.2、使用文件系统
在实际使用中,目前我用的最多的场景是图片存在外部存储介质,通过文件系统从外部存储介质读取文件到控制器内显示.所以下面只介绍图片的显示.
lv_obj_t* bg_img = lv_img_create(lv_scr_act(), NULL);
lv_img_set_src(bg_img, "S:/alarm_clock.bin");
lv_obj_align(bg_img,NULL,LV_ALIGN_CENTER,0,0);
需要注意的是LVGL文件系统使用过程中的根目录同模拟器工程文件是同级目录.即上述代码对应的实际路径如下图所示.
最后说一点,代码中的bin文件路径之所以写成S:/xxxxx.bin
是为了和lv_port_fs_init
函数中的fs_drv.letter = 'S';
对应上,如果两个路径对应不上,则无法显示.