目录
2.3.2.2删除uC/OS使用但不适合FreeRTOS的相关代码:
2.3.2.4修改delay_init函数,用configTICK_RATE_HZ替换delay_ostickspersec:
2.3.2.5修改delay_us函数,删除uC/OS相关的代码:
3.1.2新建lvgl_demo.c/.h文件,创建OS任务,编写测试代码
3.1.3.2包含lvgl_demo.h头文件,调用lvgl_demo函数:
1.准备资料
1.1 基础工程获取
《lvgl裸机》源码(详情参考上篇LVGL移植到STM32F103ZE裸机流程演示(附源码)-CSDN博客)
并改名为“STM32F103ZE移植FreeRTOS”。
1.2 FreeRTOS源码获取
方式1,通过官网下载
方式2,通过正点原子开发板A盘资料获取
方式3,通过百度网盘下载
1.3 精简FreeRTOS源码
首先复制一份\FreeRTOSv202112.00\FreeRTOS\路径下的Source文件夹,更名为“FreeRTOS”,并删除多余的“.gitmodules”文件:
接着,删除\portable\路径下除了Keil、MemMang、RVDS外的所有文件夹:
最后,将精简后的FreeRTOS文件夹复制到基础工程的\Middlewares\路径下:
2.移植步骤
2.1添加FreeRTOS源码
2.1.1添加源码
新增分组Middlewares/FreeRTOS_CORE,并添加相应文件:
接着,再新增分组Middlewares\FreeRTOS_PORT,并添加相应文件:
2.1.3添加路径
添加以下路径:
..\Middlewares\FreeRTOS\include
..\Middlewares\FreeRTOS\portable\RVDS\ARM_CM3
2.2.添加FreeRTOSConfig.h配置文件
2.2.1生成FreeRTOSConfig.h文件
(建议放到\Middlewares\FreeRTOS\include\路径下)
方式1,从FreeRTOS源码中复制过来(路径:\FreeRTOSv202112.00\FreeRTOS\Demo\CORTEX_STM32F103_Keil\FreeRTOSConfig.h)
方式2:自己编新建一个(不建议,高手自便)
方式3:直接从正点原子资料移植好的工程中复制(推荐)
2.2.2配置FreeRTOSConfig.h文件
由于我选了上述方式3,故此步骤跳过。
2.3修改系统文件
2.3.1修改sys.h
2.3.2修改delay.c
2.3.2.1替换头文件:
2.3.2.2删除uC/OS使用但不适合FreeRTOS的相关代码:
2.3.2.3修改SysTick_Handler函数:
2.3.2.4修改delay_init函数,用configTICK_RATE_HZ替换delay_ostickspersec:
2.3.2.5修改delay_us函数,删除uC/OS相关的代码:
2.3.2.6修改delay_ms函数:
2.3.3修改usart.c
删除关于uCOS相关的代码:
2.4修改中断相关文件
由于Systick、SVC、PendSV这三个中断函数已经在FreeRTOS中定义,因此需要屏蔽stm32f1xx_it.c文件中的这三个函数,为方便,采用宏定义方式屏蔽:
2.5修改stm32f103xe.h文件
对于不芯片修改的文件,请参考下表:
将“#define __NVIC_PRIO_BITS 4U”改成“#define __NVIC_PRIO_BITS 4”:
3.功能测试
3.1编写应用程序
3.1.1更改lvgl时钟源(针对LVGL)
在lvgl.h文件中配置自定义时钟源:
删除定时器提供时基的部分代码:
3.1.2新建lvgl_demo.c/.h文件,创建OS任务,编写测试代码
在\USER\路径下新建lvgl_demo.c/.h文件:
在lvgl_demo.c文件创建OS任务,编写测试代码:
#include "lvgl_demo.h"
#include "FreeRTOS.h"
#include "task.h"
#include "lvgl.h"
#include "lv_port_disp_template.h"
#include "lv_port_indev_template.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_TASK1_PRIO 3 /* 任务优先级 */
#define LV_DEMO1_STK_SIZE 1024 /* 任务堆栈大小 */
TaskHandle_t LV_DEMOTask1_Handler; /* 任务句柄 */
void lv_demo_task1(void *pvParameters); /* 任务函数 */
/* LED_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define LV_DEMO_TASK2_PRIO 4 /* 任务优先级 */
#define LV_DEMO2_STK_SIZE 1024 /* 任务堆栈大小 */
TaskHandle_t LV_DEMOTask2_Handler; /* 任务句柄 */
void lv_demo_task2(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任务1 */
xTaskCreate((TaskFunction_t )lv_demo_task1,
(const char* )"lv_demo_task1",
(uint16_t )LV_DEMO1_STK_SIZE,
(void* )NULL,
(UBaseType_t )LV_DEMO_TASK1_PRIO,
(TaskHandle_t* )&LV_DEMOTask1_Handler);
/* 创建LVGL任务2 */
xTaskCreate((TaskFunction_t )lv_demo_task2,
(const char* )"lv_demo_task2",
(uint16_t )LV_DEMO2_STK_SIZE,
(void* )NULL,
(UBaseType_t )LV_DEMO_TASK2_PRIO,
(TaskHandle_t* )&LV_DEMOTask2_Handler);
taskEXIT_CRITICAL(); /* 退出临界区 */
vTaskDelete(StartTask_Handler); /* 删除开始任务 */
}
/**
* @brief LVGL运行例程
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void lv_demo_task1(void *pvParameters)
{
int task_cnt = 0;
char *pBuf[3] = {"LVGL task1 running0...","LVGL task1 running1...","LVGL task1 running2..."};
pvParameters = pvParameters;
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "LVGL task1 running...");
lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 0);
while(1)
{
task_cnt++;
if (task_cnt>=3) task_cnt = 0;
lv_label_set_text(label, (const char*)pBuf[task_cnt]);
lv_timer_handler(); /* LVGL计时器 */
vTaskDelay(1000);
}
}
/**
* @brief led_task
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void lv_demo_task2(void *pvParameters)
{
int task_cnt = 0;
char *pBuf[3] = {"LVGL task2 running0...","LVGL task2 running1...","LVGL task2 running2..."};
pvParameters = pvParameters;
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "LVGL task2 running...");
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
while(1)
{
task_cnt++;
if (task_cnt>=3) task_cnt = 0;
lv_label_set_text(label, (const char*)pBuf[task_cnt]);
lv_timer_handler(); /* LVGL计时器 */
vTaskDelay(2000);
}
}
3.1.3修改在main.c
3.1.3.1删除多余代码:
3.1.3.2包含lvgl_demo.h头文件,调用lvgl_demo函数:
3.2烧录程序测试功能
烧录程序后看到:LCD上方依次循环显示“LVGL task1 running0...”、“LVGL task1 running1...”、“LVGL task1 running2...”;LCD中间依次循环显示“LVGL task2 running0...”、“LVGL task2 running1...”、“LVGL task2 running2...”:
4.可能出现的问题
问题1:如果发现RAM内存不足,则需要调整内存分配
解决方法1:缩减FreeRTOS的内存
在FreeRTOSConfig.h中降低configTOTAL_HEAP_SIZE的大小:
解决方法2:缩减LVGL的内存LV_MEM_SIZE的大小:
问题2:运行时程序卡死在HardFault_Handler函数
解决方法1:可能是任务堆栈大小不够,可尝试增大堆栈大小
问题3:如果调用延时函数后任务不切换
解决方法1:可能原因有任务创建失败,要解决此问题,需要在FreeRTOSConfig.h中增大configTOTAL_HEAP_SIZE的大小。
5.源码下载
百度网盘下载: https://pan.baidu.com/s/1OYzZCEubGpH0_4geJxHX5g?pwd=kjcn