第三章 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/ ,如需转载,请注明出处,否则将追究法律责任。