0%

stm32F407移植LVGL+GUI

stm32F407移植LVGL+GUI

前期准备

移植LVGL

1、准备LVGL源码

1、当你从上述网址中下载了LVGL的源码后,你会得到一个压缩包,解压后会得到一个如图所示的文件夹。

2、将上图中的lv_conf_template.h 文件改名为 lv_conf.h。然后打开这个文件,在最开始的地方,找到下面的代码,并按下面的要求修改。

1
2
3
4
5
6
7
修改前:

#if 0 /*Set it to "1" to enable content*/

修改后:

#if 1 /* 把#if 0 修改成

3、删除一些我们不要的文件。

在lvgl-8.2.0目录下的文件,除了demos、examples、src、lv_conf.h、lvgl.h,其他文件全部删除。最后的结果如图

然后打开文件examples,将其中的文件除了porting,其他全部删除。结果如图。

2、裸机移植LVGL

打开内存管理实验文件夹,没有移植之前的工程目录大概如下。

我们在其中新建一些文件夹,用来存放我们要移植的代码,从Middlewares开始创建,内容如图.

创建完成后,我们可以把处理好的LVGL中的文件examples、src、lv_conf.h、lvgl.h这四个复制到Middlewares/LVGL/GUI/lvgl目录下。结果如图

打开内存管理的工程,进入到keil界面的操作。

点击图中红色方框。

进入到下图这个界面按照图中创建分组,并添加相关的代码。(请注意,添加的代码比较烦,所以一定要注意)

添加相关的头文件路径(按照图中自上而下顺序操作)

开启C99模式

然后编译一下,如果报错了,请检查一下,文件是否添加进来了,头文件路径是否正确。如果正常没有报错,但是会有一些报错。不必理会。

修改代码

1、为LVGL提供时基。

打开我们工程中的timer.c。在头部添加LVGL的头文件。

1
#include "lvgl.h"  

在中断中添加lvgl的心跳函数。

1
2
3
4
5
6
7
8
9
//定时器3中断服务函数
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
{
lv_tick_inc ( 1 );
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中断标志位
}

上述源码中,定时器中断回调函数调用了 LVGL 的 lv_tick_inc 函数,该函数可以让 LVGL内部的时基参数加 1 (入口参数为 1 的情况下), 这里要注意,你定时器设置多少毫秒进入一次中断,那么, lv_tick_inc();函数的入口参数就设置为多少,不然时基就不准确。

接下来打开main.c文件,在mian函数中添加初始化。

1
TIM3_Int_Init(999,167);

2、配置显示屏、触摸输入驱动。

打开 Middlewares/lvgl/examples/porting 分组中的 lv_port_disp_template.c/h(显示屏相关)和 lv_port_indev_template.c/h (触摸输入相关)文件,将这 4 个文件中的条件编译指令 #if 0 都修改成#if 1 ,如下源码所示:

1
2
3
4
5
6
7
修改前:

#if 0 /*Set it to "1" to enable content*/

修改后:

#if 1 /* 把#if 0 修改成
  • 1、修改lv_port_disp_template.c文件。(基本按照图中改好,可能跟下面的截图不同,以下为准,因为这是我添加别的功能,修改了代码)

    • 添加lcd的头文件,我们要使用lcd显示界面。

      1
      #include "lcd.h"
    • 配置屏幕的分辨率。我是用的3.5存的TFTLCD屏幕,代码如下

      1
      2
      #define MY_DISP_HOR_RES 320   /* 屏幕宽度 */
      #define MY_DISP_VER_RES 480 /* 屏幕高度 */

    • 在lv_port_disp_init函数中,按照图片注释下面的,保留上面的。初始化缓冲区,我们默认使用单行缓冲区。

    • 修改分辨率。

    • 在disp_init函数中,添加LCD的初始化。

    • 配置花点函数,这个函数在lcd.h中可以找到。

  • 2、修改lv_port_indev_template.c文件

    • 添加头文件

    • 注销处理显示屏之外的东西

    • 触摸屏初始化

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      static void touchpad_init(void)
      {
      /*Your code comes here*/
      tp_dev . init ();
      /* 电阻屏坐标矫正 */
      if (KEY_Scan( 0 ) == KEY0_PRES) /* KEY0 按下 , 则执行校准程序 */
      {
      LCD_Clear(WHITE); /* 清屏 */
      TP_Adjust(); /* 屏幕校准 */
      TP_Save_Adjdata();
      }

      //TP_Init();
      }
    • 检测屏幕是否被按下,

      1
      2
      3
      4
      5
      6
      7
      8
      9
      /*Return true is the touchpad is pressed*/
      static bool touchpad_is_pressed(void)
      {
      /*Your code comes here*/
      tp_dev.scan(0);
      if(tp_dev.sta & TP_PRES_DOWN)
      return true;
      return false;
      }
    • 返回按下的坐标

      1
      2
      3
      4
      5
      6
      7
      static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
      {
      /*Your code comes here*/
      (*x) = tp_dev.x[0];
      (*y) = tp_dev.y[0];
      }

  • 3、修改main.c文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #include "sys.h"
    #include "delay.h"
    #include "usart.h"
    #include "led.h"
    #include "lcd.h"
    #include "key.h"
    #include "malloc.h"


    #include "timer.h"
    #include "sram.h"



    /* LVGL */
    #include "lvgl.h"
    #include "lv_port_indev_template.h"
    #include "lv_port_disp_template.h"

    #include "lv_demo_stress.h"



    int main(void)
    {
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    delay_init(168);
    uart_init(115200);
    LED_Init();
    LCD_Init();
    KEY_Init();
    TIM3_Int_Init(999,167);

    lv_init();
    lv_port_disp_init();
    lv_port_indev_init();

    lv_obj_t *label = lv_label_create(lv_scr_act());
    lv_label_set_text(label,"Hello KUrumi!!!");
    lv_obj_center(label);/

    while(1)
    {
    lv_task_handler();
    delay_ms(5);
    }
    }

  • 然后你会在屏幕上看到相对应的字符串。说明移植成功。

移植GUI

1、首先你要下载一个软件,GUI-Guider工具,提供了界面设计和代码生成的功能,使用这个工具能够让我们很快的设计好一个界面。(注意:你所下载的版本最好和LVGL的版本所匹配,GUI是基于LVGL的一个工具。)

2、下载后,打开软件,你会看到下面这个界面。点击创建新建项目。

3、然后你会进入一个选择LVGL版本的界面,如图,选择你项目中使用的版本号。前面使用的v8.2,所以我们选择v8.2。点击下一步。

跳转到下面的界面,双击simulator(模拟器),这一步是选择空白的模拟器。再点击下一步。

进入到了Templates模板界面中,我们选择EmptyUI。

进入带项目配置信息界面。再右侧输入栏中。我们先填写项目的名称,例如我们输入xianshi。下面是工程的路径,最后生成的代码也在这。在下面是面板类型,我们在下拉菜单中选择Custom…,下面出现新的一行,我们依次输入LCD,宽度:320;高度:480。输入完成后,点击创建。

然后进入到了下面的界面,你就可以创建你的界面了。

下面编辑界面我就不讲解了,讲起来比较麻烦,截图太多。下面我讲解你设计好界面后如何生成代码,如何加入到工程中。

插一句:如果你设计好了界面,想看看效果,GUI提供了模拟器,可以查看,点击图中绿色的按钮,选择C,就可以模拟。但是有一个前提,就是要在你的电脑上安装Java环境,才能用模拟器。

如何导出代码。有两种办法。

  • 你可以去你创建时的那个目录中寻找。

  • 你可以直接在工具栏中选择工具-》代码导出-》路径选择桌面。

我用的第二种方法,在桌面上你可以看到两个文件夹,custom和generated。

复制这两个文件夹到我们工程目录的中 “移植gui\Middlewares\LVGL\GUI_APP\“目录中

打开工程,在keil添加分组,为分组中添加文件中所有的.c文件。再添加文件路径。

这样就成功把GUi生成的代码加入到了我们工程中了。

然后再修改mian.c中的内容。

  • 添加头文件

    1
    2
    3
    4

    #include "gui_guider.h"
    #include "events_init.h"
    #include "custom.h"
  • 添加全局变量

    1
    lv_ui guider_ui;
  • 在mian函数中添加初始化。

    1
    2
    3
    setup_ui(&guider_ui);
    events_init(&guider_ui);
    custom_init(&guider_ui);
  • 编译没有报错,你就可以在你的LCD屏幕上看到你设计的界面了。

  • 如果编译报错,如下面这样,提示#include “lv_font.h”出错,找到guider_fonts.h文件,修改#include “lv_font.h”。修改完成后如下,或者你可直接找到lv_font.h文件,直接复制到generated文件夹中。

    1
    2
    ..\Middlewares\LVGL\GUI_APP\generated\guider_fonts\guider_fonts.h(8): error:  #5: cannot open source input file "lv_font.h": No such file or directory
    #include "lv_font.h"
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #ifndef GUIDER_FONTS_H
    #define GUIDER_FONTS_H
    #ifdef __cplusplus
    extern "C" {
    #endif

    #include "../../GUI/lvgl/src/font/lv_font.h"



    #ifdef __cplusplus
    }
    #endif
    #endif