当前位置: 首页 > news >正文

在windows系统搭建LVGL模拟器(codeblock工程)

1.codeblock准备

下载codeblock(mingw),安装。可参考网上教程。

2.pc_simulator_win_codeblocks 工程获取

仓库地址:lvgl/lv_port_win_codeblocks: Windows PC simulator project for LVGL embedded GUI Library (github.com)

 拉取代码到本地硬盘,如下操作步骤:

# 打开git终端输入下面地址并回车
git clone https://github.com/lvgl/lv_sim_codeblocks_win.git

# 进入文件夹lv_sim_codeblocks_win 
cd lv_sim_codeblocks_win 

# 执行下面命令拉取子模块并初始化仓库
git submodule update --init --recursive

# 文件夹介绍:
# lvgl:lvgl源代码

# lv_examples:lvgl 的使用例程(各种控件使用例程,布局使用例程,系统API使用例程,第三方库使用例程...)

# lv_demo:官方给的比较综合的demo示例

# lv_drivers:和平台相关的底层驱动

如下图:

LittlevGL.cbp 就是codeblock工程。

我拉取的LVGL 是V9 版本。

3.编译工程

打开codeblock,选择工程,【File】-【Open】如下图:

设置编译器,【Settings】-【Compiler...】,如下图:

执行【Auto-detect】,或者选取自己的mingw编译器路径,我使用的是QT5自带的编译器

编译并运行,如下图:

等待一段时间,一个默认的demo编译好后自动运行界面如下:

本篇文章不具体讲解LVGL控件使用,可自行在网上找教程,或使用官方教程文档。

4.使用LVGL V9 文件系统报错问题排查

下面我记录下,使用LVGL访问文件系统出现的问题,我一开始参考的教程是百问网的LVGL教程,他使用的LVGL是V8版本,所以我参照教程使用一直报 “未知错误”

LVGL默认支持4种文件系统 分别是 LV_USE_FS_STDIO ,LV_USE_FS_POSIX,LV_USE_FS_WIN32,LV_USE_FS_FATFS

我们使用windows 平台我选择 LV_USE_FS_WIN32 ,对应的底层文件操作都是windows自带的,所以不需要移植了。

在lv_conf.h中打开配置如下:

我挂载到D盘,工作目录 LV_FS_WIN32_PATH ""  不配置。

示例代码如下:

#define FILE_NAME "D:/example/example.txt"
void lv_chenbo_demo_fs(void)
{
#if 1
    lv_fs_file_t f;
    lv_fs_res_t res;

    res = lv_fs_open(&f, FILE_NAME, LV_FS_MODE_RD);
    if(res != LV_FS_RES_OK) {
        LV_LOG_USER("open file error:%d!", res);
        return;
    }

    uint32_t read_num;
    uint8_t buf[32];
    memset(buf,0x0,sizeof buf);
    res = lv_fs_read(&f, buf, 32, &read_num);
    if(res != LV_FS_RES_OK) {
        LV_LOG_USER("read file error!");
    }

    printf("read content:\n%s", buf);

    lv_fs_close(&f);
#endif
}

我在D盘创建文件  example/example.txt

编译运行:

一直报错打开文件失败,错误代码12

跳转到 lv_fs.c 中的 lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode)函数如下:

lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode)
{
    if(path == NULL) {
        LV_LOG_WARN("Can't open file: path is NULL");
        return LV_FS_RES_INV_PARAM;
    }

    char letter = path[0];
    lv_fs_drv_t * drv = lv_fs_get_drv(letter);

    if(drv == NULL) {
        LV_LOG_WARN("Can't open file (%s): unknown driver letter", path);
        return LV_FS_RES_NOT_EX;
    }

    if(drv->ready_cb) {
        if(drv->ready_cb(drv) == false) {
            LV_LOG_WARN("Can't open file (%s): driver not ready", path);
            return LV_FS_RES_HW_ERR;
        }
    }

    if(drv->open_cb == NULL) {
        LV_LOG_WARN("Can't open file (%s): open function not exists", path);
        return LV_FS_RES_NOT_IMP;
    }

    const char * real_path = lv_fs_get_real_path(path);
    void * file_d = drv->open_cb(drv, real_path, mode);

    if(file_d == NULL || file_d == (void *)(-1)) {
        return LV_FS_RES_UNKNOWN;
    }

    file_p->drv = drv;
    file_p->file_d = file_d;

    if(drv->cache_size) {
        file_p->cache = lv_malloc(sizeof(lv_fs_file_cache_t));
        LV_ASSERT_MALLOC(file_p->cache);
        lv_memzero(file_p->cache, sizeof(lv_fs_file_cache_t));
        file_p->cache->start = UINT32_MAX;  /*Set an invalid range by default*/
        file_p->cache->end = UINT32_MAX - 1;
    }

    return LV_FS_RES_OK;
}

这个函数是LVGL提供的是一个抽象的文件操作API,他根据不同的文件系统去调用更底层的文件系统接口。

问题出在这里:

    const char * real_path = lv_fs_get_real_path(path);
    void * file_d = drv->open_cb(drv, real_path, mode);

    if(file_d == NULL || file_d == (void *)(-1)) {
        return LV_FS_RES_UNKNOWN;
    }

看下static const char * lv_fs_get_real_path(const char * path) 函数

/**
 * Skip the driver letter and the possible : after the letter
 * @param path path string (E.g. S:/folder/file.txt)
 * @return pointer to the beginning of the real path (E.g. /folder/file.txt)
 */
static const char * lv_fs_get_real_path(const char * path)
{
    path++; /*Ignore the driver letter*/
    if(*path == ':') path++;

    return path;
}

它的功能就是获取路径 : 后面的字符地址,也就是他把盘符D: 去掉了。

drv->open_cb()是一个回调函数,我们使用是WIN32平台的文件系统所以看

lv_fs_win32.c 中的static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)

函数如下:

/**
 * Open a file
 * @param drv pointer to a driver where this function belongs
 * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
 * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
 * @return pointer to FIL struct or NULL in case of fail
 */
static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)
{
    LV_UNUSED(drv);

    DWORD desired_access = 0;

    if(mode & LV_FS_MODE_RD) {
        desired_access |= GENERIC_READ;
    }

    if(mode & LV_FS_MODE_WR) {
        desired_access |= GENERIC_WRITE;
    }

    /*Make the path relative to the current directory (the projects root folder)*/

    char buf[MAX_PATH];
    lv_snprintf(buf, sizeof(buf), LV_FS_WIN32_PATH "%s", path);

    return (void *)CreateFileA(
               buf,
               desired_access,
               FILE_SHARE_READ,
               NULL,
               OPEN_EXISTING,
               FILE_ATTRIBUTE_NORMAL,
               NULL);
}

看下面代码(重点):

    char buf[MAX_PATH];
    lv_snprintf(buf, sizeof(buf), LV_FS_WIN32_PATH "%s", path);

这个功能是:把我们传过来的路径(前面已经去掉D:) 然后和 LV_FS_WIN32_PATH 拼接在一起,还记得之前这个宏定义我们设置的是空字符串"",这样拼成的新的路径传递给windows底层API使用,造成的结果就是路径错误("/example/examle.txt")。

所以我们就算不配置工作路径,也要把盘符设置一下:

/*API for CreateFile, ReadFile, etc*/
#define LV_USE_FS_WIN32 1
#if LV_USE_FS_WIN32
    #define LV_FS_WIN32_LETTER 'D'     /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
    #define LV_FS_WIN32_PATH "D:"         /*Set the working directory. File/directory paths will be appended to it.*/
    #define LV_FS_WIN32_CACHE_SIZE 1024   /*>0 to cache this number of bytes in lv_fs_read()*/
#endif

这样编译,在运行:

D:/example/example.txt 文件中的 hello,world 被读取出来并显示。

注意:我实际测试的LVGL V9版本必须要这样设置。

相关文章:

  • [论文笔记] 大模型主流Benchmark测试集介绍
  • 【第二章】docker +Jenkins+git+allure+python3安装
  • 『K8S 入门』二:深入 Pod
  • 云原生之深入解析如何在Kubernetes中快速启用Cgroup V2支持
  • Docker与K8s的区别
  • 数据可视化设计:让数据故事更有说服力
  • Excel实现字母+数字拖拉自动递增,步长可更改
  • [算法基础 ~排序] Golang 实现
  • 实战指南:使用 Nginx 反向代理实现多端口跳转
  • python实现最小二叉堆---最小堆结构
  • Hazel引擎学习(十二)
  • 软件设计师——软件工程(一)
  • k8s中EmptyDir、HostPath、NFS三种基本存储方式介绍
  • Mac 如何删除文件及文件夹?可以尝试使用终端进行删除
  • 051:vue项目webpack打包后查看各个文件大小
  • 虹科Pico汽车示波器 | 汽车免拆检修 | 2019款别克GL8豪华商务车前照灯水平调节故障
  • 深度学习基本概念
  • FFmpeg-基础组件-AVFrame
  • vs2017+qt5.14.2遇到的问题
  • 低代码开发入局,同飞股份应用云表自主开发MES管理系统
  • 大风暴雨致湖南岳阳县6户房屋倒塌、100多户受损
  • 特朗普政府拟终止太空污染研究,马斯克旗下太空公司将受益
  • 视频丨习近平主席出席俄方在机场举行的迎宾仪式
  • 售卖自制外挂交易额超百万元,一男子因提供入侵计算机系统程序被抓
  • 夜读丨最美的风景,在亲人的目光里
  • 黄道炫:南京102天——黄镇球的防空日记