这一期我们接着学习 FreeRTOS 系统的知识,这一期我们讲的内容是任务相关的API函数,讲完这一期,我们就可以去创建一个多任务程序的模板了。
任务创建和删除API函数
FreeRTOS 最基本的功能就是任务管理,而任务管理最基本的操作就是创建和删除任务,FreeRTOS 的任务创建和删除 API 函数如表 6.1.1.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 : 任务创建失败,因为堆内存不足!
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 )
参数和xTaskCreate()函数相比多出了一个puxStackBuffer和pxTaskBuffer,puxStackBuffer这个东西在上一期讲过。
puxStackBuffer:任务堆栈,一般为数组,数组类型要为 StackType_t 类型。
pxTaskBuffer:任务控制块。
返回值:NULL : 任务创建失败,puxStackBuffer 或 pxTaskBuffer 为 NULL 的时候会导致这个错误 的发生。其他值 : 任务创建成功,返回任务的任务句柄。
xTaskCreateRestricted()函数
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition,
TaskHandle_t * pxCreatedTask )
参数:pxTaskDefinition: 指向一个结构体 TaskParameters_t ,这个结构体描述了任务的任务函 数、 堆栈大小、优先级等。此结构体在文件 task.h 中有定义。pxCreatedTask: 任务句柄。
返回值:pdPASS: 任务创建成功。其他值 : 任务未创建成功,很有可能是因为 FreeRTOS 的堆太小了。
vTaskDelete()函数
vTaskDelete( TaskHandle_t xTaskToDelete )
参数:xTaskToDelete: 要删除的任务的任务句柄。
任务创建和删除实验
完成前面两期的学习,我们现在可以进行创建和删除实验,写一个自己的多任务程序模板了。
首先第一步是进行任务设置
#define START_TASK_PRIO 1 //任务优先级 (1)
#define START_STK_SIZE 128 //任务堆栈大小 (2)
TaskHandle_t StartTask_Handler; //任务句柄 (3)
void start_task(void *pvParameters); //任务函数 (4)
/*
...
同样地宏定义START任务外其他任务如:TASK1任务等的各个参数
*/
(1) 、 start_task 任务的任务优先级,此处用宏来表示,以后所有的任务优先级都用宏来表示。创建任务设置优先级的时候就用这个宏,当然了也可以直接在创建任务的时候指定任务优 先级。(2) 、 start_task 任务的任务堆栈大小。(3) 、 start_task 任务的任务句柄。(4) 、 start_task 任务的任务函数声明。
第二步就是写主函数
int main(void)
{
/*
...
初始化处理
*/
//创建开始任务
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 开始行。
接下来第三步我们来写任务函数
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
BinarySemaphore2=xSemaphoreCreateBinary();
BinarySemaphore3=xSemaphoreCreateBinary();
//创建 TASK1 任务
xTaskCreate((TaskFunction_t )Task1_task,
(const char* )"Task1_task",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_TASK_PRIO,
(TaskHandle_t* )&TASK1_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* )&TASK2_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
(1) 、 start_task 任务的任务函数,在此任务函数中我们创建了另外两个任务 task1_task 和task2_task 。 start_task 任务的职责就是用来创建其他的任务或者信号量、消息队列等的,当创建完成以后就可以删除掉 start_task 任务。(2) 、删除 start_task 任务,注意函数 vTaskDelete() 的参数就是 start_task 任务的任务句柄StartTask_Handler 。
这里我的是START函数的任务函数,START函数任务就是创建其他任务函数,我们其他的任务函数就是实现各种相应任务的函数,其他任务函数基本格式如下:
void Task1_task(void *pvParameters)
{
while(1)
{
/*
...
相应任务功能
*/
vTaskDelay(10); //延时
}
}
上面是创建任务的动态方法,也是最常用的方法,而静态创建任务和动态创建有一点点的不同,在这里就不讲静态创建任务的方法了,想要学习的小伙伴可以自己去看资料学习。
这一期的内容就到这里,我们下期见。