一、任务创建和删除 API 函数
FreeRTOS 最基本的功能就是任务管理,而任务管理最基本的操作就是创建和删除任务,FreeRTOS 的任务创建和删除 API 函数如下表所示:
1. xTaxkCreate()
此函数用来创建一个任务,任务需要 RAM 来保存与任务有关的状态信息(任务控制块),任务也需要一定的 RAM 来作为任务堆栈。如果使用函数 xTaskCreate()来创建任务的话那么这些所需的 RAM 就会自动的从 FreeRTOS 的堆中分配,因此必须提供内存管理文件,默认我们使用heap_4.c 这个内存管理文件,而且宏 configSUPPORT_DYNAMIC_ALLOCATION 必须为 1。如果使用函数 xTaskCreateStatic()创建的话这些 RAM 就需要用户来提供了。新创建的任务默认就是就绪态的,如果当前没有比它更高优先级的任务运行那么此任务就会立即进入运行态开始运行,不管在任务调度器启动前还是启动后,都可以创建任务。此函数也是我们以后经常用到的,本篇用此函数来创建任务,函数原型如下:
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
参数:
pxTaskCode: 任务函数。
pcName: 任务名字,一般用于追踪和调试,任务名字长度不能超过configMAX_TASK_NAME_LEN。
usStackDepth: 任务堆栈大小,注意实际申请到的堆栈是usStackDepth 的 4 倍。其中空闲任务的任务堆栈大小为 configMINIMAL_STACK_SIZE。
pvParameters: 传递给任务函数的参数。
uxPriotiry: 任务优先级,范围 0~ configMAX_PRIORITIES-1。
pxCreatedTask: 任务句柄,任务创建成功以后会返回此任务的任务句柄,这个句柄其实就是任务的任务堆栈。此参数就用来保存这个任务句柄。其他 API 函数可能会使用到这个句柄。
返回值:
pdPASS: 任务创建成功。
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY: 任务创建失败,因为堆内存不足!
2. xTaskCreateStatic()
此函数和 xTaskCreate()的功能相同,也是用来创建任务的,但是使用此函数创建的任务所需 的 RAM 需 要 用 用 户来提供 。 如果要 使 用 此 函 数 的 话 需 要 将 宏configSUPPORT_STATIC_ALLOCATION 定义为 1。函数原型如下:
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer )
参数:
pxTaskCode: 任务函数。
pcName: 任务名字,一般用于追踪和调试,任务名字长度不能超过configMAX_TASK_NAME_LEN。
usStackDepth: 任务堆栈大小,由于本函数是静态方法创建任务,所以任务堆栈由用户给出,一般是个数组,此参数就是这个数组的大小。
pvParameters: 传递给任务函数的参数。
uxPriotiry: 任务优先级,范围 0~ configMAX_PRIORITIES-1。
puxStackBuffer: 任务堆栈,一般为数组,数组类型要为StackType_t 类型。
pxTaskBuffer: 任务控制块。
返回值:
NULL: 任务创建失败,puxStackBuffer 或 pxTaskBuffer 为 NULL 的时候会导致这个错误的发生。
其他值: 任务创建成功,返回任务的任务句柄。
3. xTaskCreateRestricted()
此函数也是用来创建任务的,只不过此函数要求所使用的 MCU 有 MPU(内存保护单元),用此函数创建的任务会受到 MPU 的保护。其他的功能和函数 xTaxkCreate()一样。
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition,
TaskHandle_t * pxCreatedTask )
参数:
pxTaskDefinition: 指向一个结构体 TaskParameters_t,这个结构体描述了任务的任务函数、堆栈大小、优先级等。此结构体在文件 task.h 中有定义。
pxCreatedTask: 任务句柄。
返回值:
pdPASS: 任务创建成功。
其他值: 任务未创建成功,很有可能是因为 FreeRTOS 的堆太小了。
4. vTaskDelete()
删除一个用函数 xTaskCreate()或者 xTaskCreateStatic()创建的任务,被删除了的任务不再存在,也就是说再也不会进入运行态。任务被删除以后就不能再使用此任务的句柄!如果此任务
是使用动态方法创建的,也就是使用函数 xTaskCreate()创建的,那么在此任务被删除以后此任务之前申请的堆栈和控制块内存会在空闲任务中被释放掉,因此当调用函数 vTaskDelete()删除任务以后必须给空闲任务一定的运行时间。
只有那些由内核分配给任务的内存才会在任务被删除以后自动的释放掉,用户分配给任务的内存需要用户自行释放掉,比如某个任务中用户调用函数 pvPortMalloc()分配了 500 字节的内存,那么在此任务被删除以后用户也必须调用函数 vPortFree()将这 500 字节的内存释放掉,否则会导致内存泄露。此函数原型如下:
vTaskDelete( TaskHandle_t xTaskToDelete )
参数:
xTaskToDelete: 要删除的任务的任务句柄。
返回值:
无
二、任务创建和删除实验(动态方法)
1. 实验程序设计
(1)实验目的
上篇讲解了 FreeRTOS 的任务创建和删除的 API 函数,本篇就来学习如何使用这些API 函数,本篇学习 xTaskCreate()和 vTaskDelete()这两个函数的使用
(2)实验设计
本实验设计三个任务:start_task、task1_task 和 task2_task ,这三个任务的任务功能如下:
start_task:用来创建其他两个任务。
task1_task :当此任务运行 5 此以后就会调用函数 vTaskDelete()删除任务 task2_task,此任务也会控制 LED0 的闪烁,并且周期性的刷新 LCD 指定区域的背景颜色。
task2_task :此任务普通的应用任务,此任务也会控制 LED1 的闪烁,并且周期性的刷新LCD 指定区域的背景颜色。
(3)实验程序与分析
● 任务设置
#define START_TASK_PRIO 1 //任务优先级 (1)
#define START_STK_SIZE 128 //任务堆栈大小 (2)
TaskHandle_t StartTask_Handler; //任务句柄 (3)
void start_task(void *pvParameters); //任务函数 (4)
#define TASK1_TASK_PRIO 2 //任务优先级
#define TASK1_STK_SIZE 128 //任务堆栈大小
TaskHandle_t Task1Task_Handler; //任务句柄
void task1_task(void *pvParameters); //任务函数
#define TASK2_TASK_PRIO 3 //任务优先级
#define TASK2_STK_SIZE 128 //任务堆栈大小
TaskHandle_t Task2Task_Handler; //任务句柄
void task2_task(void *pvParameters); //任务函数
//LCD 刷屏时使用的颜色
int lcd_discolor[14]={ WHITE, BLACK, BLUE, BRED,
GRED, GBLUE, RED, MAGENTA,
GREEN, CYAN, YELLOW, BROWN,
BRRED, GRAY };
(1) 、start_task 任务的任务优先级,此处用宏来表示,以后所有的任务优先级都用宏来表示。创建任务设置优先级的时候就用这个宏,当然了也可以直接在创建任务的时候指定任务优先级。
(2)、start_task 任务的任务堆栈大小。
(3)、start_task 任务的任务句柄。
(4)、start_task 任务的任务函数声明。
● main()函数
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组 4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化 LED
LCD_Init(); //初始化 LCD
POINT_COLOR = RED;
LCD_ShowString(30,10,200,16,16,"ATK STM32F103/F407");
LCD_ShowString(30,30,200,16,16,"FreeRTOS Examp 6-1");
LCD_ShowString(30,50,200,16,16,"Task Creat and Del");
LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,90,200,16,16,"2016/11/25");
//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数 (1)
(const char* )"start_task", //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度 (2)
}
(1)、调用函数 xTaskCreate()创建 tart_task 任务,函数中的各个参数就是上面的任务设置中定义的,其他任务的创建也用这种方法。
(2)、调用函数 vTaskStartScheduler()开启 FreeRTOS 的任务调度器,FreeRTOS 开始运行。
● 任务函数文章来源:https://www.toymoban.com/news/detail-419171.html
//开始任务任务函数
void start_task(void *pvParameters) (1)
{
taskENTER_CRITICAL(); //进入临界区
//创建 TASK1 任务
xTaskCreate((TaskFunction_t )task1_task,
(const char* )"task1_task",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_TASK_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
//创建 TASK2 任务
xTaskCreate((TaskFunction_t )task2_task,
(const char* )"task2_task",
(uint16_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_TASK_PRIO,
(TaskHandle_t* )&Task2Task_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务 (2)
taskEXIT_CRITICAL(); //退出临界区
}
//task1 任务函数
void task1_task(void *pvParameters) (3)
{
u8 task1_num=0;
POINT_COLOR = BLACK;
LCD_DrawRectangle(5,110,115,314); //画一个矩形
LCD_DrawLine(5,130,115,130); //画线
POINT_COLOR = BLUE;
LCD_ShowString(6,111,110,16,16,"Task1 Run:000");
while(1)
{
task1_num++; //任务执 1 行次数加 1 注意 task1_num1 加到 255 的时候会清零!!
LED0=!LED0;
printf("任务 1 已经执行:%d 次\r\n",task1_num);
if(task1_num==5)
{
vTaskDelete(Task2Task_Handler);//任务 1 执行 5 次删除任务 2 (4)
printf("任务 1 删除了任务 2!\r\n");
}
LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]); //填充区域
LCD_ShowxNum(86,111,task1_num,3,16,0x80); //显示任务执行次数
vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍
}
}
//task2 任务函数
void task2_task(void *pvParameters) (5)
{
u8 task2_num=0;
POINT_COLOR = BLACK;
LCD_DrawRectangle(125,110,234,314); //画一个矩形
LCD_DrawLine(125,130,234,130); //画线
POINT_COLOR = BLUE;
LCD_ShowString(126,111,110,16,16,"Task2 Run:000");
while(1)
{
task2_num++; //任务 2 执行次数加 1 注意 task1_num2 加到 255 的时候会清零!!
LED1=!LED1;
printf("任务 2 已经执行:%d 次\r\n",task2_num);
LCD_ShowxNum(206,111,task2_num,3,16,0x80); //显示任务执行次数
LCD_Fill(126,131,233,313,lcd_discolor[13-task2_num%14]); //填充区域
vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍
}
}
(1)、start_task 任务的任务函数,在此任务函数中我们创建了另外两个任务 task1_task 和task2_task。start_task 任务的职责就是用来创建其他的任务或者信号量、消息队列等的,当创建完成以后就可以删除掉 start_task 任务。
(2)、删除 start_task 任务,注意函数 vTaskDelete()的参数就是 start_task 任务的任务句柄StartTask_Handler。
(3)、task1_task 任务函数(任务 1),任务比较简单,每隔 1 秒钟 task1_num 加一并且 LED0反转,串口输出任务运行的次数,其实就是 task1_num 的值。当 task1_task 运行 5 次以后就调用函数 vTaskDelete()删除任务 task2_task。
(4)、任务 task1_task 运行了 5 次,调用函数 vTaskDelete()删除任务 task2_task。
(5)、task2_task 任务函数(任务 2),和 task1_task 差不多。
在 main 函数中一开始肯定是初始化各种硬件外设,初始化完外设以后调用函数xTaskCreate()创建一个开始任务,注意创建开始任务是在调用函数 vTaskStartScheduler()开启任务调度器之前,这样当后面开启任务调度器以后就会直接运行开始任务了。其他任务的创建就放到开始任务的任务函数中,由于开始任务的职责就是创建其他应用任务和信号量、队列等这些内核对象的,所以它只需要执行一次,当这些东西创建完成以后就可以删除掉开始任务了。
三、任务创建和删除实验(静态方法)
● 任务设置
#define START_TASK_PRIO 1 //任务优先级
#define START_STK_SIZE 128 //任务堆栈大小
StackType_t StartTaskStack[START_STK_SIZE]; //任务堆栈 (1)
StaticTask_t StartTaskTCB; //任务控制块 (2)
TaskHandle_t StartTask_Handler; //任务句柄
void start_task(void *pvParameters); //任务函数
#define TASK1_TASK_PRIO 2 //任务优先级
#define TASK1_STK_SIZE 128 //任务堆栈大小
StackType_t Task1TaskStack[TASK1_STK_SIZE]; //任务堆栈
StaticTask_t Task1TaskTCB; //任务控制块
TaskHandle_t Task1Task_Handler; //任务句柄
void task1_task(void *pvParameters); //任务函数
#define TASK2_TASK_PRIO 3 //任务优先级
#define TASK2_STK_SIZE 128 //任务堆栈大小
StackType_t Task2TaskStack[TASK2_STK_SIZE]; //任务堆栈
StaticTask_t Task2TaskTCB; //任务控制块
TaskHandle_t Task2Task_Handler; //任务句柄
void task2_task(void *pvParameters); //任务函数
//LCD 刷屏时使用的颜色
int lcd_discolor[14]={ WHITE, BLACK, BLUE, BRED,
GRED, GBLUE, RED, MAGENTA,
GREEN, CYAN, YELLOW, BROWN,
BRRED, GRAY };
(1)、静态创建任务需要用户提供任务堆栈,这里定义一个数组作为任务堆栈,堆栈数组为StackType_t 类型。
(2)、定义任务控制块,注意任务控制块类型要用 StaticTask_t,而不是 TCB_t 或 tskTCB!
● main()函数
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组 4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化 LED
LCD_Init(); //初始化 LCD
POINT_COLOR = RED;
LCD_ShowString(30,10,200,16,16,"ATK STM32F103/407");
LCD_ShowString(30,30,200,16,16,"FreeRTOS Examp 6-2");
LCD_ShowString(30,50,200,16,16,"Task Creat and Del");
LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,90,200,16,16,"2016/11/25");
//创建开始任务
StartTask_Handler=xTaskCreateStatic((TaskFunction_t)start_task, //任务函数 (1)
(const char* )"start_task", //任务名称
(uint32_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(StackType_t* )StartTaskStack, //任务堆栈 (2)
(StaticTask_t* )&StartTaskTCB); //任务控制块(3)
vTaskStartScheduler(); //开启任务调度
}
(1)、调用函数 xTaskCreateStatic()创建任务。
(2)、将定义的任务堆栈数组传递给函数。
(3)、将定义的任务控制块传递给函数。
可以看出在用法上 xTaskCreateStatic()和 xTaskCreate()没有太大的区别,大多数的参数都相同。
● 任务函数
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
//创建 TASK1 任务
Task1Task_Handler=xTaskCreateStatic((TaskFunction_t )task1_task, (1)
(const char* )"task1_task",
(uint32_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_TASK_PRIO,
(StackType_t* )Task1TaskStack,
(StaticTask_t* )&Task1TaskTCB);
//创建 TASK2 任务
Task2Task_Handler=xTaskCreateStatic((TaskFunction_t )task2_task, (2)
(const char* )"task2_task",
(uint32_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_TASK_PRIO,
(StackType_t* )Task2TaskStack,
(StaticTask_t* )&Task2TaskTCB);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//task1 任务函数
void task1_task(void *pvParameters)
{
u8 task1_num=0;
POINT_COLOR = BLACK;
LCD_DrawRectangle(5,110,115,314); //画一个矩形
LCD_DrawLine(5,130,115,130); //画线
POINT_COLOR = BLUE;
LCD_ShowString(6,111,110,16,16,"Task1 Run:000");
while(1)
{
task1_num++; //任务执 1 行次数加 1 注意 task1_num1 加到 255 的时候会清零!!
LED0=!LED0;
printf("任务 1 已经执行:%d 次\r\n",task1_num);
if(task1_num==5)
{
vTaskDelete(Task2Task_Handler);//任务 1 执行 5 次删除任务 2
printf("任务 1 删除了任务 2!\r\n");
}
LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]); //填充区域
LCD_ShowxNum(86,111,task1_num,3,16,0x80); //显示任务执行次数
vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍
}
}
//task2 任务函数
void task2_task(void *pvParameters)
{
u8 task2_num=0;
POINT_COLOR = BLACK;
LCD_DrawRectangle(125,110,234,314); //画一个矩形
LCD_DrawLine(125,130,234,130); //画线
POINT_COLOR = BLUE;
LCD_ShowString(126,111,110,16,16,"Task2 Run:000");
while(1)
{
task2_num++; //任务 2 执行次数加 1 注意 task1_num2 加到 255 的时候会清零!!
LED1=!LED1;
printf("任务 2 已经执行:%d 次\r\n",task2_num);
LCD_ShowxNum(206,111,task2_num,3,16,0x80); //显示任务执行次数
LCD_Fill(126,131,233,313,lcd_discolor[13-task2_num%14]); //填充区域
vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍
}
}
(1)、使用静态任务创建函数 xTaskCreateStatic()来创建任务 task1_task。
(2)、使用静态任务创建函数 xTaskCreateStatic()来创建任务 task2_task。文章来源地址https://www.toymoban.com/news/detail-419171.html
到了这里,关于FreeRTOS 任务相关 API 函数(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!