当前位置:首页 > 公众号精选 > wenzi嵌入式软件
[导读]由于近期要做一个装置 ,想着把装置做的好看一点,就打算使用 GUI 来做一个信息的相关显示,之前听说过一款比较轻量级的图形库,也就是 lvgl,手头又正好有一块搭配屏幕的野火指南者开发板,单片机型号是 STM32F103VET6,Flash 为 512KB,RAM 为 64KB,屏幕为 3.2 寸电阻触摸屏,我们在来看一下运行 lvgl 这个 GUI 需要的资源。

前言

由于近期要做一个装置 ,想着把装置做的好看一点,就打算使用 GUI 来做一个信息的相关显示,之前听说过一款比较轻量级的图形库,也就是 lvgl,手头又正好有一块搭配屏幕的野火指南者开发板,单片机型号是 STM32F103VET6,Flash 为 512KB,RAM 为 64KB,屏幕为 3.2 寸电阻触摸屏,我们在来看一下运行 lvgl 这个 GUI 需要的资源,所需资源如下图所示:

所需条件

几个比较关键的就是控制器的主频需要大于 16 MHz,对于 STM32F103来说,主频可以达到 72MHz,满足要求,所需要的 Flash 要大于 64KB,对于指南者这款开发板来将,他的主控是 STM32F103VET6,Flash 具有 512KB,远远满足要求。对于 RAM 来讲,lvgl 所需要的 RAM 是 8KB,推荐使用 24 KB,对于具有 64KB的 STM32F103VET6 来讲,是完全满足要求的。

综上,可以知道,使用野火指南者开发板来跑 lvgl 是完全没有问题的。

移植准备

为了更加快捷的完成移植,在这里就直接使用野火官方写好的液晶屏幕的驱动来进行 lvgl 的移植,首先找到野火配套例程中的第 30 号例程,也就是电阻触摸屏--触摸画板这个例程,将这个例程拷贝出来,在这个基础上进行移植。

野火官方例程列表

拷贝出来之后,进入到工程目录里,工程目录结构如下图所示:

工程目录结构

紧接着,我们进到 lvgl 的 github 仓库,选择已经发布的 v7.6.1 版本进行移植,

![github仓库](https://gitee.com/wenzi_D/images4mk/raw/master/lvgl github仓库.png)

我们将代码下载下来,放到 Libraries 里面,如下图所示:

代码下载

至此,我们就完成了移植前的准备工作,接下来进行移植代码。

导入 lvgl 库到 keil 工程中

首先在 keil 工程中新建 lvgl Groups 组,然后将 lvgl/src/lv_core lvgl/src/lv_draw lvgl/src/lv_font lvgl/src/lv_hal lvgl/src/lv_misc lvgl/src/lv_themes lvgl/src/lv_widgets 路径下的文件加入到新建的组中, 如下图所示:

image-20201102140053808

紧接着,我们来看一下 lvgl 官网中的文档对于 lvgl 运行的要求:

![lvgl 运行要求](https://gitee.com/wenzi_D/images4mk/raw/master/lvgl 运行要求.png)

从序号 1 ,可以看出,栈空间需要大于 2KB 的空间,推荐大于 8 KB,我们这里设置栈空间为 8KB,也就是将如下所示位置的值改为 0x00002000

image-20201102141620914

从序号 2 可以知道,它需要 C99 或者更新的编译器,我们这里选择 C99 进行编译,

![image-20201102141751510](https://gitee.com/wenzi_D/images4mk/raw/master/C99 编译器.png)

修改 lv_conf.h 配置文件

接下来,需要修改 lv_conf.h 这个文件,这个文件需要修改的地方有好几个,分别是如下几个地方:

  • 首先先将田间编译宏更改为 #if 1

  • 修改屏幕的分辨率,由于当前所用的野火指南者所搭配的是分辨率为 320 * 240 的,因此需要将 LV_HOR_RES_MAX更改为 240以及将 LV_VER_RES_MAX 更改为 320 ,如下图所示:

image-20201102142651831
  • 修改 LV_COLOR_DEPTH,此值 1 是用于单色屏,当前我们的是彩色屏,应该设置为 16

  • 修改LV_DPI 的值,默认值为 130,我们把他设置到 60,这个宏是用来调节界面缩放比例的,此值越大,控件分布的就越散,控件自身的间隔也会变大 ,如下图所示:

image-20201102143128962
  • 配置 lvgl 运行的动态堆的大小,再官方给出的堆的要求中,对于堆的要求是这样的:

  • image-20201102143456908

推荐使用大于 16KB 的堆内存,因此这里配置的是 20KB,也就是将LV_MEM_SIZE 设置为 20KB,也就是将 LV_MEM_SIZE 的值设置为 20U * 1024U

  • 因为当前开发板没有使用到 GPU 和文件系统,所以将 GPU 和文件系统的宏定义设置为 0,如下所示:

  • ![image-20201102144629570](https://gitee.com/wenzi_D/images4mk/raw/master/GPU 和文件系统.png)

至此,lvgl 的文件就修改完毕了。接下来,就需要提供 lvgl 运行的心跳节拍

lvgl 心跳节拍设置

这里采取的一个方案是通过定时器来为 lvgl 来提供心跳节拍,更为直观的叙述也就是通过定时器产生 1ms 的定时中断,然后在中断服务函数里调用 lvgl 的心跳函数。野火的官方例程李提供了定时中断的代码,我们直接将这部分代码移植过来就好,下面是定时中断服务函数里面的相关内容:

#include "lvgl.h"
void TIM6_IRQHandler(void)
{
    if ( TIM_GetITStatus( TIM6, TIM_IT_Update) != RESET ) 
    {   
        lv_tick_inc(1);                     //lvgl 的 1ms 心跳
        TIM_ClearITPendingBit(TIM6 , TIM_FLAG_Update);           
    }
}

有了中断服务函数,那相应的就需要有初始化,下面是主函数的相关代码:

int main(void)
{        
    //LCD 初始化
    ILI9341_Init();  

    //触摸屏初始化
    XPT2046_Init();

    BASIC_TIM_Init();

    lv_init();          /* lv 系统初始化 */

    //其中0、3、5、6 模式适合从左至右显示文字,
    //不推荐使用其它模式显示文字 其它模式显示文字会有镜像效果          
    //其中 6 模式为大部分液晶例程的默认显示方向  
    ILI9341_GramScan ( 3 );    

    while ( 1 )
    {
        lv_task_handler();
    }

}

最后,我们需要将 lvgl 的相关头文件路径加入到 keil 的工程路径中去,添加完成之后,就可以编译了,但是使用野火的编写的 LCD 驱动编译之后会出现三个错误,如下图所示:

image-20201102151736551

出现该错误的原因是因为 C99 跟内联函数的一些关联,具体的细节不在这里深究了,更改方式是在三个函数前加上 static,如下图所示:

image-20201102152010830


image-20201102152104102

这样更改之后,整个代码就编译通过了。

移植底层屏幕驱动

接下来就需要完成移植屏幕底层驱动了,对于这部分内容,总的来说分为两部分:

  • 移植底层显示驱动

  • 移植底层触摸驱动

我们将 Libraries\lvgl\examples\porting里面的文件复制到Libraries\lvgl_driver里面,并重命名为如下几个文件:

image-20201102153053489

移植底层显示驱动

移植底层显示驱动只需要更改 lv_port_disp.c和 lv_port_disp.h两个文件,首先是 lv_port_disp.h的更改,更改后的文件为:

#if 1

#ifndef LV_PORT_DISP_H
#define LV_PORT_DISP_H

#ifdef __cplusplus
extern "C" {
#endif

#include "lvgl/lvgl.h"

void lv_port_disp_init(void);

#ifdef __cplusplus
/* extern "C" */
#endif

#endif /*LV_PORT_DISP_TEMPL_H*/

#endif /*Disable/Enable content*/

更改后的lv_port_disp.c文件为:

image-20201102153910631

第一个是留下一个例子,第二个是更改屏幕的分辨率。第三部分是

image-20201102154028802

红色标注部分的函数也就是以单个像素点填充屏幕的函数,这个函数野火写的不满足调用要求,笔者稍微将原来的驱动代码进行了更改,实现了如下所示的单个像素点填充函数:

void ILI9341_DrawPixel(uint16_t usX, uint16_t usY,uint16_t color)
{
    if ((usX < LCD_X_LENGTH) && (usY < LCD_Y_LENGTH))
    {
        ILI9341_SetCursor (usX,usY);

        ILI9341_FillColor (1,color);
    }
}

这样,就完成了底层屏幕显示驱动的移植。

底层屏幕触摸驱动移植

移植底层屏幕触摸驱动只需要更改 lv_port_indev.c和 lv_port_indev.h两个文件,首先是 lv_port_indev.h的更改,更改后的文件为

#if 1

#ifndef LV_PORT_INDEV_H
#define LV_PORT_INDEV_H

#ifdef __cplusplus
extern "C" {
#endif

#include "lvgl/lvgl.h"
void lv_port_indev_init(void);


#ifdef __cplusplus
/* extern "C" */
#endif

#endif /*LV_PORT_INDEV_TEMPL_H*/

#endif /*Disable/Enable content*/

紧接着就是lv_port_indev.c的更改,关于这部分代码,lvgl 官方给出了好几个输入设备的函数,触摸屏,鼠标,小键盘,旋钮,按键等输入设备,我们这里所选用的是触摸屏,那么就可以把其他的都删去。下面是几处关键代码:

image-20201102160432067

最后,加入一个简单的示例,GUI 就可以运行起来了,加如的程序如下所示:

static void btn_event_cb(lv_obj_t * btn, lv_event_t event)
{
    if(event == LV_EVENT_CLICKED) {
        static uint8_t cnt = 0;
        cnt++;

        /*Get the first child of the button which is the label and change its text*/
        lv_obj_t * label = lv_obj_get_child(btn, NULL);
        lv_label_set_text_fmt(label, "Button: %d", cnt);
    }
}

/**
 * Create a button with a label and react on Click event.
 */

void lv_ex_get_started_1(void)
{
    lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL);     /*Add a button the current screen*/
    lv_obj_set_pos(btn, 1010);                            /*Set its position*/
    lv_obj_set_size(btn, 12050);                          /*Set its size*/
    lv_obj_set_event_cb(btn, btn_event_cb);                 /*Assign a callback to the button*/

    lv_obj_t * label = lv_label_create(btn, NULL);          /*Add a label to the button*/
    lv_label_set_text(label, "Button");                     /*Set the labels text*/
}

主函数如下所示:

int main(void)
{        
    //LCD 初始化
    ILI9341_Init();  

    //触摸屏初始化
    XPT2046_Init();

    BASIC_TIM_Init();

    lv_init();          /* lv 系统初始化 */
    lv_port_disp_init();    /* lvgl 显示接口初始化,放在 lv_init()后面 */
    lv_port_indev_init();   /* lvgl 输入接口初始化,放在 lv_init() 后面 */

    lv_ex_get_started_1();


    //其中0、3、5、6 模式适合从左至右显示文字,
    //不推荐使用其它模式显示文字 其它模式显示文字会有镜像效果          
    //其中 6 模式为大部分液晶例程的默认显示方向  
    ILI9341_GramScan ( 6 );    

    while ( 1 )
    {
        lv_task_handler();
    }

}

最终的显示效果如下图所示:

image-20201102160808774

官方的 github 仓库也有做好的比较完善的 demo 可供参考,下图是 github 上的例程的截图:

image-20201104122144298

参照 README.md 文档就可以顺利跑起来,下图是运行 demo 的动图,效果还是很华丽的。

screenshot1

总结

上述就是移植 lvgl 的整个过程,写下来记录一下,移植结束,可以学习如何制作一个精美的界面了,这次的内容就到这里,如果在使用过程中,有新的体会,再进行更文~

如果你觉得我的文章对你有所帮助,欢迎再看,点赞,转发三连呐~欢迎各位添加好友,下图是笔者的个人微信名片

个人微信号名片

欢迎关注笔者的公众号,笔者将不定期更新文章~

公众号名片


免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

这款全新的中端MCU系列为设计人员提供了更高水平的安全性和灵活性

关键字: 嵌入式 单片机

2024年4月11日,中国——意法半导体的ST25R100近距离通信(NFC)读取器芯片独步业界,集先进的技术功能、稳定可靠的通信连接和低廉的成本价格于一身,在大规模制造的消费电子和工控设备内,可以提高非接触式互动功能的...

关键字: 嵌入式 数据读取器 芯片

单片机是一种嵌入式系统,它是一块集成电路芯片,内部包含了处理器、存储器和输入输出接口等功能。

关键字: 单片机 编写程序 嵌入式

深圳2024年4月23日 /美通社/ -- 全球AI解决方案与工业级存储领导品牌宜鼎国际 (Innodisk)持续深化边缘AI布局,今(23)日发表全球首创"MIPI over Type-C"独家技术,让旗下嵌入式相机模...

关键字: AI 嵌入式 相机

在现代电子技术的快速发展中,单片机以其高度的集成性、稳定性和可靠性,在工业自动化、智能家居、医疗设备、航空航天等诸多领域得到了广泛应用。S32单片机,作为其中的佼佼者,其引脚功能丰富多样,是实现与外部设备通信、控制、数据...

关键字: s32单片机引脚 单片机

在微控制器领域,MSP430与STM32无疑是两颗璀璨的明星。它们各自凭借其独特的技术特点和广泛的应用领域,在市场上占据了重要的位置。本文将深入解析MSP430与STM32之间的区别,探讨它们在不同应用场景下的优势和局限...

关键字: MSP430 STM32 单片机

为增进大家对嵌入式主板的认识,本文将对嵌入式主板以及嵌入式主板常见问题及其解决方法予以介绍。

关键字: 嵌入式 指数 主板

为增进大家对嵌入式系统的认识,本文将对嵌入式系统、嵌入式系统的特点予以介绍。

关键字: 嵌入式 指数 嵌入式系统

为增进大家对嵌入式的认识,本文将对嵌入式、嵌入式工作相关的内容予以介绍。

关键字: 嵌入式 指数 嵌入式技术

机器人操作系统(ROS)驱动程序基于ADI产品而开发,因此可直接在ROS生态系统中使用这些产品。本文将概述如何在应用、产品和系统(例如,自主导航、安全气泡地图和数据收集机器人)中使用和集成这些驱动程序;以及这样将如何有助...

关键字: 电机控制器 机器人 嵌入式
关闭
关闭