任务创建与删除
创建任务
BaseType_t xTaskCreate(
TaskFunction_t pxTaskCode, // 函数指针, 任务函数
const char * const pcName, // 任务的名字
const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为word,10表示40字节
void * const pvParameters, // 调用任务函数时传入的参数
UBaseType_t uxPriority, // 优先级
TaskHandle_t * const pxCreatedTask ); // 任务句柄, 以后使用它来操作这个任务
pxTaskCreat是函数指针,可以简单的理解为一个C函数或者函数名。pcName是任务名,"taskname",usStackDepth是栈大小,每个任务都有自己的栈,其值通常为估计,精确的办法是看反汇编码。接下来的是函数指针的参数,没有的写NULL。在优先级中,数值越小优先级越低。最后的句柄是用来操作任务的,比如需要修改它的优先级,就需要它输出的handle。
在函数指针中,实际是先定义了void (*TaskFunction_t)( void * ),表示一个TaskFunction_t的之这个,一个指向返回值为void,参数为void*的指针。再加上typedef后,TaskFunction_t就不再是一个函数指针了,它代表着一种类型,这种类型可以定义一个指向返回值为void,参数为void *类型的指针。
typedef在语句中所起的作用就是把语句原先定义变量的功能变成了定义类型的功能,仅此而已。也就是说TaskFunction_t是一个数据类型,用来定义一个函数指针,该指针指向有一个void参数,并且返回值为空的函数。我们知道C语言中函数名实际上是函数的首地址,也就是说函数名可以是一个指针。所以我们在创建任务是填入的函数名参数实际上是一个地址,且被TaskFunction_t类型定义为了一个指向返回值为void,参数为void *类型的指针。在xTaskCreate函数pxTaskCode被传入了prvInitialiseNewTask使用。
此外,typedef unsigned long UBaseType_t,表示优先级的数据类型是unsigned long。
FreeRTOS创建任务需要:函数指针、任务名、参数、栈的大小、优先级、句柄
实例:LED闪烁与OLED计数的同时运行
/* USER CODE BEGIN FunctionPrototypes */
void LEDTask(void *argument)
{
while(1)
{
Led_Test();
}
}
void OLEDTask(void *argument)
{
while(1)
{
OLED_Test();
}
}
/* USER CODE END FunctionPrototypes */
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
xTaskCreate(LEDTask,"FirstTask",128,NULL,osPriorityNormal,NULL);
xTaskCreate(OLEDTask,"SecondTask",128,NULL,osPriorityNormal,NULL);
/* USER CODE END RTOS_THREADS */
删除任务
在freeRTOS中,任务的删除是通过vtaskdelete()来实现的,传入的参数是要删除的任务的句柄,句柄在创建任务是生成,也可以不生成。传入句柄或删除任务有三种方式。
- 自杀:vTaskDelete(NULL)
- 被杀:别的任务执行vTaskDelete(pvTaskCode),pvTaskCode是自己的句柄
- 杀人:执行vTaskDelete(pvTaskCode),pvTaskCode是别的任务的句柄
任务优先级与调度
任务优先级
在freeRTOS中,有四种任务状态。就绪状态(Ready)、行状态(Running)、阻塞状态(Blocked)、暂定/挂起状态 (Suspended)。
其调度规则为:1、高优先级的先运行2、相同优先级的轮流运行
根据规则能推导出:1、高优先级的任务没有停止运行,低优先级的任务永远无法执行;2、高优先级的任务有多个,则多个高优先级的任务轮流运行;3、一旦高优先级的任务就绪,马上运行,一位着高优先级的任务可以打断正在运行的低优先级的任务
任务调度及其实现原理
freeRTOS中,任务的优先级是由链表实现的。在代码可以找到pxReadTasksLists [configMAX_priorities],表示就绪态优先级的链表数为56个。
上述freeRTOS优先级规则由链表和tick中断、调度算法实现。在cubeMX中定义了一个TICK_RATE_HZ = 1000,T=1/f可知,每一毫秒产生一个tick中断。每个任务在不被更高优先级任务打断的情况下运行1ms。在产生tick中断时,rtos会做两件事。1、计数count++,以此作为一个时钟基准;2、发起一次调度。
任务调度器会从高优先级遍历至优先级,即从list[55]遍历至list[0]。同意优先级的就绪态任务被放置在list[N]中。当任务处于blocked状态时,将会被移到xDelayTaskList中。在task.c中,我们发现有xDelayTaskList1和xDelayTaskList2两个链表,这是为了防止定时器溢出的情况,以及在freeRTOS存在相对延时与绝对延时。当使用vTaskSuspend()函数暂定任务时,会将其从delay链表移动到suspend链表。
在产生tick中断时,rtos会判断delay链表的任务是否可以恢复,可恢复的话会将其移动到ready链表。