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

news2024/12/27 5:14:22

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版本必须要这样设置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1313135.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Fabric使用自己的链码进行测试-go语言

书接前文 Fabric链码部署-go语言 通过上面这篇文章,你可以部署好自己的链码 (后面很多命令是否需要修改,都是根据上面这篇文章来的,如果零基础的话建议先看上面这篇) 就进行下一步 在测试网络上运行自己的链码 目…

STM32单片机项目实例:基于TouchGFX的智能手表设计(5)硬件驱动层程序设计

STM32单片机项目实例:基于TouchGFX的智能手表设计(5)硬件驱动层程序设计 目录 一、 概述 二、 新建工程与外设配置 三、 TouchGFX配置 四、 增加TouchGFX关键驱动 一、 概述 本文内容主要进行工程新建,硬件外设的配置以及添加…

《PySpark大数据分析实战》-10.独立集群模式的代码运行

📋 博主简介 💖 作者简介:大家好,我是wux_labs。😜 热衷于各种主流技术,热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员(PCTA)、TiDB数据库专家(PCTP…

03. 医院设置_后端

1、Swagger2 测试工具 编写和维护接口文档是每个程序员的职责,根据Swagger2可以快速帮助我们编写最新的API接口文档,再也不用担心开会前仍忙于整理各种资料了,间接提升了团队开发的沟通效率。 swagger通过注解表明该接口会生成文档&#xf…

CSC公派研究生项目|电气工程在读博士谈丹麦奥尔堡大学联培体会

2023年已近兔尾,很多人已经开始新一年的规划,对于国内在读博士而言,申请国家留学基金委(CSC)公派研究生项目也开始列入议事日程,然而,如何申请?在国外学习收获如何?本篇知…

IDEA小技巧

目录 1. IDEA自动添加注释 创建类的时候自动添加注释 创建函数、方法的注释 1. IDEA自动添加注释 参考文档:idea java 自动添加文件注释 idea新建类自动注释_mob6454cc73c728的技术博客_51CTO博客 【操作工具】IDEA创建类及已有类添加注释-详细操作_idea设置创建…

【状态机FSM 序列检测 饮料机_2023.12.1】

同步状态机 概念 同步状态机(同一脉冲边沿触发):有限个离散状态及某状之间的转移 异步状态机无法综合 分类 Moore状态机 只和状态有关,与输入无关 Mealy状态机 和状态和输入都有关 Mealy型比Moore型少一个状态 结构 由状态寄…

AI日报:OpenAI向新用户重新开放ChatGPT Plus订阅

欢迎订阅专栏 《AI日报》 获取人工智能邻域最新资讯 文章目录 总览Chatgptplus重新开放订阅#暂停原因功能 OpenAI的1000万美元安全人工智能拨款拨款初衷学术捐赠 总览 ChatGPT Plus再次向新用户开放,但目前每三小时限制发送40条消息。 OpenAI还宣布拨款1000万美元…

喜报!Coremail荣获2023信创“大比武”优秀生态融合奖

近期,2023信创“大比武”金融业务创新应用赛道(简称金融赛道)活动正式落下帷幕。经过赛程的层层考核,中泰证券股份有限公司(简称“中泰证券”)与Coremail联合组成的“中泰证券CACTER邮件安全保卫队”最终在…

Linux篇:信号

一、信号的概念: ①进程必须识别能够处理信号,信号没有产生,也要具备处理信号的能力---信号的处理能力属于进程内置功能的一部分 ②进程即便是没有收到信号,也能知道哪些信号该怎么处理。 ③当进程真的受到了一个具体的信号的时候…

2021实战面试

1、Rem , em , px , % , vw 之间的区别 PX: px像素(Pixel)。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。 em: 1,子元素字体大小的em是相对于父元素字体大小 2,元素的width/height/padding/margin用em的话是相对于该元素的font-size rem:1rem是…

【回眸】Tessy 单元测试软件使用指南(三)怎么打桩和指针测试

目录 前言 Tessy 如何进行打桩操作 普通桩 高级桩 手写桩 Tessy单元测试之指针相关测试注意事项 有类型的指针(非函数指针): 有类型的函数指针: void 类型的指针: 结语 前言 进行单元测试之后,但凡…

免费且强大卸载软件工具-Geek Uninstaller

Geek Uninstaller是一款用于Windows操作系统的免费卸载软件。它提供了一种比Windows内置卸载工具更彻底的卸载程序的方法。界面简单没有广告,操作也十分的简单。 特点 完全的程序卸载:Geek Uninstaller 被设计为彻底卸载程序,包括删除剩余…

YOLOv8改进《目标对象计数》多任务实验:深度集成版来了!支持自定义数据集训练自定义模型

💡该教程为改进YOLO专栏,属于《芒果书》📚系列,包含大量的原创改进方式🚀 💡🚀🚀🚀内含改进源代码 按步骤操作运行改进后的代码即可💡更方便的统计更多实验数据,方便写作 YOLOv8改进《目标对象计数》多任务实验:深度集成版来了!支持自定义数据集训练自定…

springboot发送邮件,内容使用thymeleaf模板引擎排版

springboot发送邮件,内容使用thymeleaf模板引擎排版 1、导入jar包2、yml设置3、收件人以及收件信息设置4、发邮件service5、模版页面6、controller 1、导入jar包 <!--发送邮件--><dependency><groupId>org.springframework.boot</groupId><artifac…

使用Axure RP结合内网穿透工具制作本地静态web页面并实现公网访问

作者简介&#xff1a; 懒大王敲代码&#xff0c;正在学习嵌入式方向有关课程stm32&#xff0c;网络编程&#xff0c;数据结构C/C等 今天给大家讲解使用Axure RP结合内网穿透工具制作本地静态web页面并实现公网访问&#xff0c;希望大家能觉得实用&#xff01; 欢迎大家点赞 &am…

订单系统设计-状态机

1. 状态机 1.1 状态机简介 状态机是有限状态自动机的简称&#xff0c;是现实事物运行规则抽象而成的一个数学模型。 有限状态机一般都有以下特点&#xff1a; 可以用状态来描述事物&#xff0c;并且任一时刻&#xff0c;事物总是处于一种状态&#xff1b;事物拥有的状态总数…

线程安全集合类

文章目录 1. ConcurrentHashMap2. LinkedBlockingQueue 阻塞队列3. ConcurrentLinkedQueue4. CopyOnWriteArrayList JDK1.7 hashmap采用数组加链表头插的方式&#xff0c;在扩容时会出现循环死链问题&#xff0c;A->B->C扩容后C->B->A AB BA出现循环死链。 1. Conc…

Dockerfile的介绍和使用

什么是dockerfile? Dockerfile是一个包含用于组合映像的命令的文本文档。可以使用在命令行中调用任何命令。 Docker通过读取Dockerfile中的指令自动生成映像。 docker build命令用于从Dockerfile构建映像。可以在docker build命令中使用-f标志指向文件系统中任何位置的Dockerf…

【Monitor, Maintenance Operation, Script code/prgramme】

Summary of M,M&O,Program JD) Monitor & M&O Symbio信必优) Job chance/opportunities on Dec 12th, 20231.1) Content 招聘JD job description:1.2) suggestions from Ms Liang/Winnie on Wechat app1.3) Java微服务是什么&#xff1f;1.3.1) [URL Java 微服务](…