ITPub博客

首页 > 嵌入式/内核开发 > 嵌入式/内核开发 > 《LVGL开发指南 V1.0(G4电机开发板专用)》第三章 LVGL带操作系统移植

《LVGL开发指南 V1.0(G4电机开发板专用)》第三章 LVGL带操作系统移植

原创 嵌入式/内核开发 作者:正点原子 时间:2026-05-14 09:44:14 0 删除 编辑

第三章 LVGL带操作系统移植


       本章主要讲解带操作系统(FreeRTOS)的LVGL移植。虽然LVGL是支持操作系统的,但是其内部实现机制和RTOS类似,因此工程可能存在线程不安全的问题。如果用户的工程仅涉及纯软件的项目,则不建议使用RTOS。

       本章节将分为以下几个小节:

       3.1 移植准备工作

       3.2 编写FreeRTOS相关代码

       3.3 调用接口函数

        3.4 下载验证


        3.1 移植准备工作

       1. 移植FreeRTOS

       LVGL移植操作系统的步骤并不复杂,我们只需要把上一章中移植好的工程换成任务或者线程的形式即可。注意:关于FreeRTOS的移植,这里不展开介绍,具体的步骤请参考正点原子《 FreeRTOS开发指南.pdf》。

       2. 为LVGL提供时基

       在裸机移植的时候,我们使用基本定时器为LVGL提供时基,而当有了系统之后,提供时基的方式就有了第二种选择。需要使用RTOS提供时基,我们首先打开lv_conf.h文件,把LV_TICK_CUSTOM宏定义置1,然后设置LV_TICK_CUSTOM_INCLUDE和LV_TICK_CUSTOM_SYS_TIME_EXPR配置项,具体源码如下:

/* 使用自定义tick源,以毫秒为单位告诉运行时间。它不需要手动更新 `lv_tick_inc()函数` */
#define LV_TICK_CUSTOM                      1
#if LV_TICK_CUSTOM
#define LV_TICK_CUSTOM_INCLUDE            "FreeRTOS.h"     /* 系统时间函数头 */
/* 计算系统当前时间的表达式(以毫秒为单位) */
    #define LV_TICK_CUSTOM_SYS_TIME_EXPR    (xTaskGetTickCount())       
#endif   /*LV_TICK_CUSTOM*/

       由上述源码可知,我们使用FreeRTOS的xTaskGetTickCount函数来为LVGL提供时基。注意:在FreeRTOSConfig.h文件中,必须把configTICK_RATE_HZ宏定义设置为1000(没有改动的情况下,默认就是1000)。


        3.2 编写FreeRTOS相关代码

       新建两个文件:lvgl_demo.c、lvgl_demo.h,并将它们存放在User目录下,如下图所示:


图3.2.1新建RTOS相关文件


       这两个文件用于存放RTOS相关的代码,具体源码如下:

       1. lvgl_demo.c

#include "lvgl_demo.h"
#include "./BSP/LED/led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "lvgl.h"
#include "lv_port_disp_template.h"
#include "lv_port_indev_template.h"
#include "lv_demo_stress.h"
 
/* FreeRTOS配置 */
 
/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO     1           /* 任务优先级 */
#define START_STK_SIZE      128         /* 任务堆栈大小 */
TaskHandle_t StartTask_Handler;         /* 任务句柄 */
void start_task(void *pvParameters);    /* 任务函数 */
 
/* LV_DEMO_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define LV_DEMO_TASK_PRIO   3           /* 任务优先级 */
#define LV_DEMO_STK_SIZE    1024        /* 任务堆栈大小 */
TaskHandle_t LV_DEMOTask_Handler;       /* 任务句柄 */
void lv_demo_task(void *pvParameters);  /* 任务函数 */
 
/* LED_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define LED_TASK_PRIO       4           /* 任务优先级 */
#define LED_STK_SIZE        128         /* 任务堆栈大小 */
TaskHandle_t LEDTask_Handler;           /* 任务句柄 */
void led_task(void *pvParameters);      /* 任务函数 */
/***************************************************************************/
/**
 * @brief       lvgl_demo入口函数
 * @param       无
 * @retval      无
 */
void lvgl_demo(void)
{
    lv_init();                  /* lvgl系统初始化 */
    lv_port_disp_init();        /* lvgl显示接口初始化,放在lv_init()的后面 */
    lv_port_indev_init();       /* lvgl输入接口初始化,放在lv_init()的后面 */
 
    xTaskCreate((TaskFunction_t )start_task,            /* 任务函数 */
                (const char*    )"start_task",          /* 任务名称 */
                (uint16_t       )START_STK_SIZE,        /* 任务堆栈大小 */
                (void*          )NULL,                  /* 传递给任务函数的参数 */
                (UBaseType_t    )START_TASK_PRIO,       /* 任务优先级 */
                (TaskHandle_t*  )&StartTask_Handler);   /* 任务句柄 */
 
    vTaskStartScheduler();                              /* 开启任务调度 */
}
 
/**
 * @brief       start_task
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void start_task(void *pvParameters)
{
    pvParameters = pvParameters;
    taskENTER_CRITICAL();           /* 进入临界区 */
 
    /* 创建LVGL任务 */
    xTaskCreate((TaskFunction_t )lv_demo_task,
                (const char*    )"lv_demo_task",
                (uint16_t       )LV_DEMO_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LV_DEMO_TASK_PRIO,
                (TaskHandle_t*  )&LV_DEMOTask_Handler);
 
    /* LED测试任务 */
    xTaskCreate((TaskFunction_t )led_task,
                (const char*    )"led_task",
                (uint16_t       )LED_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )LED_TASK_PRIO,
                (TaskHandle_t*  )&LEDTask_Handler);
 
    taskEXIT_CRITICAL();            /* 退出临界区 */
    vTaskDelete(StartTask_Handler); /* 删除开始任务 */
}
 
/**
 * @brief       LVGL运行例程
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void lv_demo_task(void *pvParameters)
{
    pvParameters = pvParameters;
   
    lv_demo_stress();       /* 测试的demo */
    
    while(1)
    {
        lv_timer_handler(); /* LVGL计时器 */
        vTaskDelay(5);
    }
}
 
/**
 * @brief       led_task
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void led_task(void *pvParameters)
{
    pvParameters = pvParameters;
    
    while(1)
    {
        LED0_TOGGLE();
        vTaskDelay(1000);
    }
}

       lvgl_demo.c文件的代码实现可分为4个步骤:

       (1) 包含头文件;

       (2) 定义FreeRTOS相关变量以及宏定义;

       (3) 编写LVGL接口函数lvgl_demo,在其中初始化LVGL、显示设备以及输入设备,并创建开始任务;

       (4) 在开始任务中创建lvgl示例任务以及led任务,调用压力测试相关的函数。

       注意:如果使用的是其他的官方例程,请根据实际的例程来包含头文件以及调用demo函数,上述代码中以压力测试为例。

       2. lvgl_demo.h

#ifndef __LVGL_DEMO_H
#define __LVGL_DEMO_H
 
void lvgl_demo(void);
 
#endif

       这个文件很简单,只是声明了LVGL的接口函数。


        3.3 调用接口函数

       接下来只需要在main.c文件中调用LVGL的接口函数lvgl_demo即可,具体源码如下所示:

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "lvgl_demo.h"
 
int main(void)
{
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(85, 2, 2, 4, 8);       /* 设置时钟,170Mhz */
    delay_init(170);                            /* 延时初始化 */
    usart_init(115200);                         /* 串口初始化为115200 */
    led_init();                                 /* 初始化LED */
 
    lvgl_demo();                                /* 运行FreeRTOS例程 */
}


        3.4 下载验证

       编译工程并下载到开发板中,代码的运行界面如下图所示:


图3.4.1压力测试界面


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70040860/viewspace-3117814/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2024-08-30

  • 博文量
    588
  • 访问量
    764183