本实验主要实现 FreeRTOS 使用动态方法创建和删除任务,本实验设计了四个任务,这四 个任务的功能如下表所示:
软件设计
1. 程序流程图
本实验的程序流程图,如下图所示:
2. FreeRTOS 函数解析
(1) 函数 xTaskCreate()
此函数用于使用动态方法创建任务
(2) 函数 vTaskDelete()
此函数用于删除任务
3. 程序解析
(1) FreeRTOS 配置
由于本实验需要使用动态方法创建任务,因此需要配置 FreeRTOS 以支持动态内存管理, 并向工程添加动态内存管理算法文件。
首先,在 FreeRTOSConfig.h 文件中开启支持动态内存管理,如下所示:
#define configSUPPORT_DYNAMIC_ALLOCATION 1
接着向工程添加动态内存管理算法文件,本实验使用的是 heap_4.c 文件。
(2) start_task 任务
start_task 任务的入口函数代码如下所示:
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); /* 进入临界区 */
/* 创建任务 1 */
xTaskCreate(
(TaskFunction_t )task1, /* 任务函数 */
(const char* )"task1", /* 任务名称 */
(uint16_t )TASK1_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK1_PRIO, /* 任务优先级 */
(TaskHandle_t* )&Task1Task_Handler
); /* 任务句柄 */
/* 创建任务 2 */
xTaskCreate(
(TaskFunction_t )task2, /* 任务函数 */
(const char* )"task2", /* 任务名称 */
(uint16_t )TASK2_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK2_PRIO, /* 任务优先级 */
(TaskHandle_t* )&Task2Task_Handler
); /* 任务句柄 */
/* 创建任务 3 */
xTaskCreate(
(TaskFunction_t )task3, /* 任务函数 */
(const char* )"task3", /* 任务名称 */
(uint16_t )TASK3_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK3_PRIO, /* 任务优先级 */
(TaskHandle_t* )&Task3Task_Handler); /* 任务句柄 */
vTaskDelete(StartTask_Handler); /* 删除开始任务 */
taskEXIT_CRITICAL(); /* 退出临界区 */
}
从上面的代码中可以看到,start_task 任务使用了函数 xTaskCreate(),动态地创建了 task1、
task2 和 task3 任务。
(3) task1 和 task2 任务
void task1(void *pvParameters)
{
uint32_t task1_num = 0;
while (1)
{
lcd_fill(6, 131, 114, 313, lcd_discolor[++task1_num % 11]);
lcd_show_xnum(71, 111, task1_num, 3, 16, 0x80, BLUE);
vTaskDelay(500);
}
}
/**
* @brief task2
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void task2(void *pvParameters)
{
uint32_t task2_num = 0;
while (1)
{
lcd_fill(126, 131, 233, 313, lcd_discolor[11 - (++task2_num % 11)]);
lcd_show_xnum(191, 111, task2_num, 3, 16, 0x80, BLUE);
vTaskDelay(500);
}
}
从以上代码中可以看到,task1 和 task2 任务分别每间隔 500ticks 就区域刷新一次屏幕,task1和 task2 任务主要是用于测试任务的创建与删除,当 task1 和 task2 任务被创建后,就能够看到 屏幕上每间隔 500ticks 进行一次区域刷新;而当 task1 和 task2 任务被删除后,屏幕上显示的内 容就不再变化。
(4) task3 任务
void task3(void *pvParameters)
{
uint8_t key = 0;
while (1)
{
key = key_scan(0);
switch (key)
{
case KEY0_PRES: /* 删除任务 1 */
{
vTaskDelete(Task1Task_Handler);
break;
}
case KEY1_PRES: /* 删除任务 2 */
{
vTaskDelete(Task2Task_Handler);
break;
}
default:
{
break;
}
}
vTaskDelay(10);
}
}
从上面的代码中可以看到,task3 任务负责扫描按键,当检测到 KEY0 按键被按下时候,调 用函数 vTaskDelaete()删除 task1 任务;当检测到 KEY1 按键被按下时,调用函数 vTaskDelete()
删除 task2 任务。
下载验证
编译并下载代码,复位后可以看到 LCD 屏幕上显示了本次实验的相关信息,如下图所示:
其中,每间隔 500ticks,Task1 和 Task2 的屏幕区域就刷新一次,并且 Task1 和 Task2 后方 数字也随之加一,此时表示 task1 和 task2 任务均被创建,并且正在运行中。
当按下 KEY0 按键后,task1 任务被删除,此时,Task1 的屏幕区域不再刷新,并且 Task1
后方的数字也不再改变,表明 task1 任务已被删除,不再运行。当按下 KEY1 按键后,task2 任 务被删除,此时,Task2 的屏幕区域不再刷新,并且 Task2 后方的数字也不再改变,表明 task2
任务已经被删除,不再运行。