本专栏是笔者另一个专栏《龙芯+RT-Thread+LVGL实战笔记》的姊妹篇,主要的区别在于实时操作系统的不同,章节的安排和任务的推进保持一致,并对源码做了改进和优化,各位可以先到本人主页下去浏览另一专栏的博客列表(目前已撰写36篇,图1所示),再决定是否订阅。此外,也可以前往本人在B站的视频合集(图2所示)观看所有演示视频,合集首个视频链接为:
此外,关于专栏的收费,无非就是笔者想增加一些创作的动力。由于上个专栏受到了厂家关注并请求本人下架,但是已收费的资源不可下架,所以只能无奈的上调了价格(涨价了就无法降价)。而本专栏笔者不再顾忌,将维持该定价,希望朋友们理解和支持。
上一篇我们完成了最基本的移植工作,接下来就可以此基础上规划任务了,首当其冲的就是一个优先级最高的主任务,这个主任务能够保证整个系统最基本的运作。
一、工程文件和任务框架
开撸代码之前,这里先根据样题的编排(图3所示),把工程文件和任务的整体脉络梳理在图4中。当然,这只是本人的规划思路,并不一定是最合理的,供各位借鉴和参考。后续的版本和代码都将依据图4的规划来推进。
二、准备工程和文件
如图5所示,我们把上一次的整个工程复制另存一份,作为1.0的版本,并在 src 目录下新建两个文件:task_top.c 和 task_top.h。当然,别忘了把 .c 文件加入到工程中(.h文件可加可不加),如图6所示。
三、编写源码
3.1 程序运行流程
阅读源码之前,先说明一下程序运行的基本流程,请大家对照着图7来看:
- 首先,是一些列的初始化,包括 BSP 驱动、新增的硬件初始化以及 LVGL 初始化。
- 接着,就可以按照 FreeRTOS 常用的启动流程,来创建一个启动任务 start_task,即图中黄色背景部分,紧跟着就开始任务调度,随后的所有工作就可以交给 FreeRTOS 了。
- 然后,start_task 的使命是创建最核心的主任务 top_task,即图中蓝色背景部分,创建成功便全身而退。
- 最后,在 top_task 任务里,运行 LVGL 的任务处理器,保证最基本的系统响应。
基于上述流程,下面的源码将按照 main.c、task_top.h 和 task_top.c 这三个文件的顺序来解读。
3.2 main.c 文件源码
该文件的源码如代码清单1所示,直接看 main() 函数,一上来就执行几个必要的初始化:
- BSP 的初始化 ls1x_drv_init(),该函数会将工程下 ls1x-drv 目录下涉及到的板载硬件进行初始化。
- 第三方库的初始化 install_3th_libraries(),LVGL 的初始化就在该函数中。
- 我们自己编写的硬件初始化 Hardware_Init(),只不过这个函数暂时为空,后面会根据需要陆续往里添加。
- 接下来,执行 freertos_start() 函数,该函数的定义在 task_top.c 文件中,源码见下面的3.4小节。
/****************************************************************************
* 代码清单1:main.c
*
* 项目名称:龙芯1B200 + FreeRTOS + LVGL7
*
* 项目描述:嵌入式系统应用开发赛项第一模块样题任务
*
* 项目日期:2024/08/17
*
* 作 者:老耿
*
* 版本说明:1.移植了FreeRTOS系统和LVGL7.0.1组件
* 2.添加了优先级最高的主任务top_task,并部署了一个开关来测试LVGL
***************************************************************************/
//---------------------------------------------------------------------------
// 必要的库头文件、BSP头文件、src头文件
//---------------------------------------------------------------------------
#include "mips.h"
#include <time.h>
#include "bsp.h"
#include "task_top.h"
#if defined(BSP_USE_FB)
#include "ls1x_fb.h"
#ifdef XPT2046_DRV
char LCD_display_mode[] = LCD_800x480;
#elif defined(GT1151_DRV)
char LCD_display_mode[] = LCD_800x480;
#else
#error "在bsp.h中选择配置 XPT2046_DRV 或者 GT1151_DRV"
"XPT2046_DRV: 用于800*480 横屏的触摸屏."
"GT1151_DRV: 用于480*800 竖屏的触摸屏."
"如果都不选择, 注释掉本 error 信息, 然后自定义: LCD_display_mode[]"
#endif
#endif
/*---------------------------------------------------------------------------
* 函数名称:Hardware_Init
* 功 能:硬件初始化
* 入口参数:无
* 返 回 值:无
* 说明描述:把所有硬件的初始化都集中在这个函数里
*-------------------------------------------------------------------------*/
void Hardware_Init(void)
{
//暂无,后续将硬件的初始化都写在本函数中
}
/*--------------------------------------------------------------------------
* 函数名称:main
* 功 能:主函数
* 入口参数:主函数入口参数格式
* 返 回 值:
* 说明描述:把硬件和LVGL初始化以后,剩下的就交给FreeRTOS了
*-------------------------------------------------------------------------*/
int main(int argc, char** argv)
{
printk("\r\nLS1B200 + FreeRTOS + LVGL7\r\n");
ls1x_drv_init(); /* BSP驱动初始化 */
install_3th_libraries(); /* 第三方库初始化,包括LVGL */
Hardware_Init(); /* 硬件初始化 */
freertos_start(); /* 启动任务,开启调度 */
return 0;
}
3.3 task_top.h 文件源码
该头文件的源码如代码清单2所示,按照笔者的规划,任务堆栈的大小以128(单位:字)为基数,任务优先级最高不超过8。因此,这两个参数以宏的形式进行了定义。另外,就是声明了一下上面提到 freertos_start() 函数。
//---------------------------------------------------------
// 代码清单2:task_top.h
//---------------------------------------------------------
#ifndef _TASK_TOP_H
#define _TASK_TOP_H
//---------------------------------------------------------
// 必要的宏定义
//---------------------------------------------------------
#define STACK_SIZE 128 //任务堆栈大小(基数)
#define MAX_PRIO 8 //任务最高优先级(暂定为8)
//---------------------------------------------------------
// 函数声明
//---------------------------------------------------------
void freertos_start(void);
#endif
3.4 task_top.c 文件源码
该文件的源码如代码清单3所示,大家可以对照上面的流程图和注释来阅读。freertos_start() 函数一旦执行,便启动了 start_task 任务,同时开启了 FreeRTOS 的任务调度,而 start_task 里又创建了优先级最高的 top_task 任务,在该任务中,部署了一个用于测试的开关组件,随后就保持着 LVGL 运行。
/*************************************************************
* 代码清单3:task_top.c
*
* 文件描述:主任务和主界面
*
* 作 者:老耿
*
* 版 本:V1.0 @ 2024/08/17
***********************************************************/
//-----------------------------------------------------------
// 必要的库头文件、LVGL头文件、BSP头文件、src头文件
//-----------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include "FreeRTOS.h"
#include "task.h"
#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
#include "bsp.h"
#include "task_top.h"
//-----------------------------------------------------------------
// 相关的任务句柄和任务函数
//-----------------------------------------------------------------
static TaskHandle_t StartTask_Handler; //启动任务句柄
static void start_task(void *pvParameters); //启动任务函数
static TaskHandle_t TopTask_Handler; //主任务句柄
static void top_task(void *pvParameters); //主任务函数
/*----------------------------------------------------------------
* 函数名称:start_task
* 功 能:启动任务
* 入口参数:*pvParameters --- 传入参数(未用到)
* 返 回 值:无
* 说明描述:创建主任务即可
*---------------------------------------------------------------*/
static void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
//创建主界面任务
xTaskCreate((TaskFunction_t )top_task, //任务函数
(const char* )"top_task", //任务名称
(uint16_t )STACK_SIZE, //任务堆栈大小
(void* )NULL, //传给任务函数的参数
(UBaseType_t )MAX_PRIO, //任务优先级(最高)
(TaskHandle_t* )&TopTask_Handler); //任务句柄
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
/*------------------------------------------------------------------
* 函数名称:top_task
* 功 能:生成主界面的任务
* 入口参数:*pvParameters --- 传入参数(未用到)
* 返 回 值:无
* 说明描述:要处理LVGL任务,需要定期在OS任务中调用lv_task_handler()
*-----------------------------------------------------------------*/
static void top_task(void *pvParameters)
{
//在屏幕中央部署一个开关,测试LVGL的运行
lv_obj_t *sw = lv_switch_create(lv_scr_act(), NULL);
lv_obj_set_width(sw, 80);
lv_obj_set_height(sw, 50);
lv_obj_align(sw, NULL, LV_ALIGN_CENTER, 0, 0);
while(1)
{
lv_task_handler(); //在主线程中定期调用LVGL任务处理器
vTaskDelay(5); //计时并不严格,大约5ms以保持系统响应
}
}
/*----------------------------------------------------------------
* 函数名称:freertos_start
* 功 能:FreeRTOS入口函数
* 入口参数:无
* 返 回 值:无
* 说明描述:在该函数里创建启动任务,并开启任务调度
*---------------------------------------------------------------*/
void freertos_start(void)
{
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char* )"start_task", //任务名称
(uint16_t )STACK_SIZE, //任务堆栈大小
(void* )NULL, //传入给任务函数的参数
(UBaseType_t )MAX_PRIO-7, //任务优先级(最低)
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度
}
四、程序运行与测试
编译没错的话就可以运行或下载本程序了,具体效果见下面的演示视频。至此,FreeRTOS 和 LVGL 都能够正常运行了,后续我们将结合更丰满的图形化组件,去创建下面的子任务,实现样题的一个个要求。
新版的《龙芯+FreeRTOS+LVGL实战》系列启动了,从搞定移植开始
(本文完)