立创梁山派GD32F470ZGT6--LVGL移植

准备工作

1. 开发环境

开发环境介绍主要如下:
■ 硬件开发板:GD32F470ZGT6 立创·梁山派开发板
■ 屏幕:1.69寸 240x280 SPI接口TFT彩屏幕
■ Cortex-M4:GD32F470ZGT6
■ 操作系统:Win10-64 位
■ 开发环境:KEIL 5.37
■ 固件库:GD32F4xx_Firmware_Library V2.1.3
■ GUI:LVGL 8.1.0

1. 准备一个LCD的工程

我的工程是以梁山派GD32F470ZGT6作为主控,以1.69寸TFT彩色的240x280屏幕作为显示。主控与屏幕的连接如下:
在这里插入图片描述
为了提高LVGL的刷新率,建议使用硬件SPI+DMA,最好是双BUFF方式。
关于如何配置使用硬件SPI+DMA以及代码,可以看我上一章的内容:
立创梁山派GD32F470ZGT6–硬件SPI+DMA的快速刷屏

文件移植

材料准备

移植过程中需要用到 LVGL 图形库,LVGL 图形库的下载地址为:https://github.com/lvgl/lvgl
本案例使用的是 LVGL8.2.0 版本
选择V8.2版本
点击下载

删减修改LVGL文件

直接在工程下,新建一个文件【LVGL】。
在这里插入图片描述
将下载的 lvgl 源码解压。
在这里插入图片描述
提取【 example】文件夹 和【 src】 文件夹。提取文件 “lv_conf_template.h” 和 “lvgl.h”
在这里插入图片描述
将提取的文件放到我们工程目录的LVGL 文件夹目录下。并将“lv_conf_template.h”名称修改为“lv_conf.h”;
在这里插入图片描述
在我们之前提取的【examples】文件夹里,将文件夹【porting】提取到【LVGL】文件夹下。
在这里插入图片描述
将【examples】文件夹删除。让我们工程LVGL目录里只剩下文件夹【porting】文件夹【src】文件"lv_conf.h" 文件"lvgl.h"。
在这里插入图片描述
在“LVGL\porting”文件夹目录下,将“lv_port_disp_template.c”和“lv_port_disp_template.h”文件名称修改为“lv_port_disp.c”和“lv_port_disp.h”,将“ lv_port_indev_template.c ” 和 “ lv_port_indev_template.h ” 文 件 名 称 修 改 为“lv_port_indev.c”和“lv_port_indev.h”。
在这里插入图片描述

KEIL中添加LVGL相关文件与路径

添加.h路径
在这里插入图片描述
新建工程目录管理。具体如下:
在这里插入图片描述
往新建的目录文件夹添加文件。文件过多,我这里不在写明,只截图。

  1. lvgl_porting
    在这里插入图片描述

  2. lvgl_core
    将【LVGL】->【src】->【core】下的全部文件添加。
    在这里插入图片描述

  3. lvgl_draw
    添加.\src\draw下所有源码(不要添加文件夹!),以及sw文件夹下所有源码。
    在这里插入图片描述

  4. lvgl_extra
    添加\src\extra下所有源码和layouts、libs、others、themes、widgets下所有源文件。这里的文件很多很杂,只要是说到的文件夹,那么里面的所有文件夹里的.c文件都要全部添加!

  5. lvgl_font
    添加\src\font下所有源码。
    在这里插入图片描述

  6. lvgl_gpu
    添加\src\draw\sdl下所有源码,还有\src\draw\stm32_dma2d下的所有源码。
    在这里插入图片描述

  7. lvgl_hal
    添加\src\hal下所有源码.
    在这里插入图片描述

  8. lvgl_misc
    添加\src\misc下所有源码.
    在这里插入图片描述

  9. lvgl_widgets
    添加\src\widgets下所有源码.
    在这里插入图片描述
    现在文件的移植已经完成,我们进行相关代码修改。

修改报错

尝试编译,出现很多个错误,大多都是找不到lv_conf.h的路径,导致打开文件失败。
在这里插入图片描述
双击上图中画红色方框的地方跳转到对应报错的地方。将

../../lv_conf.h

修改为

../lv_conf.h

![修改后](https://img-blog.csdnimg.cn/980013659cb24a80a85f7b1bc5094b39.png
继续编译,还是很多个错误。因为LVGL的源码需要C99的支持,否则编译无法通过。
将编译模式,修改为C99模式。
在这里插入图片描述
再编译,就没有错误,只有警告了。
在这里插入图片描述
如果大家编译还是有错误。参考如下:
如果编译还是有错,.\Objects\Application.axf: Error: L6218E: Undefined symbol __aeabi_assert (referred from qrcodegen.o).

qrcodegen 中使用了 assert这个断言

断言里面用到了 __aeabi_assert,这个NDEBUG没有定义所以报错了
在这里插入图片描述
我们可以在外面定义__aeabi_assert这个函数如下,或者通过添加定义 NDEBUG宏来失效断言

void __aeabi_assert(const char *err, const char *file, int line)
{
    /* 输出内容自己定 */
}

在这里插入图片描述
如果工程之中没有内存管理,则需要修改启动文件中的堆栈。根据官方推荐我们可以把堆栈修改为4K,假如使用的功能比较多,还需要再适当增大。
在这里插入图片描述
打开lv_conf.h文件中的条件编译。
在这里插入图片描述

现在移植成功了,但是还显示不了,我们还需要去实现显示的相关接口。

修改显示接口文件

默认【 lv_port_disp.c】 和 【lv_port_disp.h】 的条件编译是关闭的,我们需要把他打开并修改包含目录层级。
在这里插入图片描述
在这里插入图片描述
将【 lv_port_disp.c】里的头文件 #include “lv_port_disp_template.h” 修改为 #include “lv_port_disp.h”。并将 #include “. ./. ./lvgl.h” 修改为 #include “. ./lvgl.h”
在这里插入图片描述

更改【lv_port_disp.c 】文件中 lv_port_disp_init 驱动函数。此函数提供了三种写缓存方式,保留其中一种即可,本案例采用方式一。
方式一:单缓存显示(10行),主控内存较小时选用此方式。
方式二:双缓存显示(两个10行),此方式支持DMA交替传输,缓存区越大,显示效果越好(有条件两个满屏缓存)。
方式三:双满屏缓存显示,相当于有条件的方式二
注释方式二和方式三,更改第一种方式如下:
在这里插入图片描述
将报错的宏【MY_DISP_HOR_RES】定义为我们屏幕的宽,这里我的屏幕宽是280,所以我重新宏定义为 280。这里建议大家直接将屏幕的宽定义拿过来定义。拿过来的话,需要像我一样导入LCD的头文件。LCD_W = 280 LCD_H = 240
在这里插入图片描述

更改屏幕大小
在这里插入图片描述
在static void disp_init(void)中,添加你的LCD初始化函数。
在这里插入图片描述

修改disp_flush函数

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
    int32_t x;
    int32_t y;
    for(y = area->y1; y <= area->y2; y++) {
        for(x = area->x1; x <= area->x2; x++) {
            /*Put a pixel to the display. For example:*/
            /*put_px(x, y, *color_p)*/
             LCD_DrawPointFlush(x,y,color_p->full);
            color_p++;
        }
    }
//	LCD_DrawLump(area->x1,area->y1,area->x2,area->y2,(uint32_t)color_p);
    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

其中,LCD_DrawPointFlush 函数 在lcdgui.中,根据上一片文章得来:
立创梁山派GD32F470ZGT6–硬件SPI+DMA的快速刷屏

/************************************************************
 * 函数名称:LCD_DrawPointFlush
 * 函数说明:在指定地方画点
 * 型    参:x,y显示坐标
             color 显示的颜色
 * 返 回 值:无
 * 备    注:无
*************************************************************/
void LCD_DrawPointFlush( uint16_t x, uint16_t y, uint16_t color)
{
    Show_Gram[((LCD_W * y) + x)] = color;
}

去到【lv_port_disp.h】文件,将头文件路径 :#include “lvgl/lvgl.h” 修改为 #include “. ./lvgl.h”
在这里插入图片描述
根据需求修改lv_conf.h中的宏定义

  • LV_COLOR_DEPTH:屏幕的色彩深度,支持1bit、8bit、16bit、32bit。
  • LV_COLOR_16_SWAP:字节交换,使用SPI或者DMA刷屏的时候需要置1。
  • LV_MEM_SIZE:GUI可支配的内存空间,根据使用的功能调节。
  • LV_USE_PERF_MONITOR:显示CPU使用率和FPS计数。
  • LV_USE_MEM_MONITOR:显示已使用的内存和内存碎片。
    • LV_FONT_MONTSERRAT_*:字体大小,太小会很模糊。

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
修改上面字体时,下面这个地方也要修改:例如改为16大小,则将14改为16即可。
在这里插入图片描述
这里需要注意,在设置里不能使用 Use MicroLIB 不然会卡死。将【Use MicroLIB】选项的打勾取消。
在这里插入图片描述
如果需要通过 printf 打印一些信息。则将以下代码,写入串口文件中。

#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
/************************************************
函数名称 : fputc
功    能 : 串口重定向函数
参    数 : 
返 回 值 : 
作    者 : LC
*************************************************/
int fputc(int ch, FILE *f)
{
     usart_send_data(ch);
     // 等待发送数据缓冲区标志置位
     return ch;
}

这样就可以使用 printf 了。

要让LVGL运行还需要给LVGL周期的运行两个函数。【lv_tick_inc】【lv_task_handler】。其中【lv_tick_inc】的运行周期单位为ms。这里我将其放在滴答定时器中断中,每隔1ms调用一次。
在这里插入图片描述

LVGL显示验证

在main.c中

#include "gd32f4xx.h"
#include "systick.h"
#include "bsp_led.h"
#include "lcdinit.h"
#include "lcdgui.h"
#include "bsp_usart.h"
#include "stdio.h"
#include "string.h"

#include "lv_conf.h"
#include "lv_port_disp.h"
#include "lvgl.h"




void Lvgl_Lable_Demo(void)
{
    lv_obj_t *scr = lv_scr_act();
    lv_obj_t * label1 = lv_label_create(scr);
    lv_label_set_long_mode(label1, LV_LABEL_LONG_WRAP);    
    lv_label_set_recolor(label1, true);                      
    lv_label_set_text(label1, "#0000ff Re-color# #ff00ff words# #ff0000 of a# label, align the lines to the center "
                              "and wrap long text automatically.");	
    lv_obj_set_width(label1, 150);  
    lv_obj_set_style_text_align(label1, LV_TEXT_ALIGN_CENTER, 0);	
    lv_obj_align(label1, LV_ALIGN_CENTER, 0, -40);	


    lv_obj_t * label2 = lv_label_create(scr);
    lv_label_set_long_mode(label2, LV_LABEL_LONG_SCROLL_CIRCULAR);     
    lv_obj_set_width(label2, 150);	
    lv_label_set_text(label2, "It is a circularly scrolling text. ");	
    lv_obj_align(label2, LV_ALIGN_CENTER, 0, 40);	
}

/******************************************************************
 * 函 数 名 称:main
 * 函 数 说 明:主函数
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者: LC
 * 备       注:无
******************************************************************/
int main(void)
{
	int i=0;
    Subscribe_message_struct data;

    nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);  // 优先级分组

    //滴答定时器初始化 1us
    systick_config();

    //sram初始化
    exmc_synchronous_dynamic_ram_init(EXMC_SDRAM_DEVICE0);   
 
    //串口0初始化(调试)
    usart_gpio_config( 115200U );
    printf("start\r\n");
    
    //lcd初始化
	LCD_Init();
//    Lcd_Gram_Fill(BLACK);
//    LCD_Show_Gram();
//    //等待一帧数据搬运完成
//	while(get_show_over_flag());
	lv_init();						// 初始化lvgl
	lv_port_disp_init();  			// 显示初始化
    Lvgl_Lable_Demo();				//LVGL显示测试
	//开启定时器固定刷屏
	Lcd_Show_Time_config();
	while(1)
	{   
       //定时器循环固定数据刷屏
       while(get_show_over_flag());
       set_show_update_flag(1);
       while(get_show_update_flag());
	}
}

实物展示
请添加图片描述

关于其他:

LVGL帧率限制
LVGL是有一个帧率刷新周期的宏定义,在lv_conf.h里。LVGL会通过LVGL内部的tick,定时去刷屏幕,也就是说该宏定义限定了LVGL刷屏帧率的上限,默认满帧33帧。这里的30即1000ms/30ms=33FPS,这里我们直接改成10ms刷新一次,满帧100帧。满帧是指达到显示器刷新率的上限。
在这里插入图片描述
在lv_conf.h里配置DPI:

/*
  * LV_DPI_DEF 注意这里,虽然LVGL的作者说这个没这么重要,但他会严重影响到LVGL的动画效果
  * 你应该进行DPI的手动计算,例如280*240分辨率1.69英寸的屏幕,那么 DPI = (280*280+240*240)^0.5 / 1.69 = 153
  */
#define LV_DPI_DEF                  218  /*[px/inch]*/

在这里插入图片描述

目前只移植了显示部分,后面完善触摸或者编码器部分。

代码:

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老怪.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值