一、FreeRTOS任务基本概念
任务(Task):FreeRTOS 中的任务是程序执行的基本单位。任务以优先级的方式管理,高优先级的任务比低优先级的任务更容易被执行。每个任务都具有不同的堆栈和一组标志,用于控制任务的行为和与其他任务和内核进行通信。
二、动态创建任务
在FreeRTOS中的task.c中我们可以找到动态创建任务的函数原型:
BaseType_t xTaskCreate(
TaskFunction_t pvTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask
);
1.TaskFunction_t pvTaskCode:任务函数的指针。这个参数是一个函数指针,指向一个任务的实际执行代码。任务函数的原型必须符合 TaskFunction_t 类型,即 void func(void *pvParameters),其中 pvParameters 是一个指向和任务相关的参数的指针。
2.const char * const pcName:任务的名称。这个参数是一个字符串常量,用于标识任务。
3.const configSTACK_DEPTH_TYPE usStackDepth:任务栈的大小。这个参数表示任务栈的深度、空间或者大小,以字节为单位。在创建任务时需要提供一个足够大的堆栈以确保任务可以运行。
4.void * const pvParameters:任务参数的指针。这个参数是任务的实际参数,它的类型可以是 void 指针或者其他任意类型的指针。在任务执行时,可以通过此参数来传递任务需要的参数。
5.UBaseType_t uxPriority:任务的优先级。这个参数用于指定任务的优先级,数值越大表示优先级越高。优先级的取值范围根据量化数值的位数而定,一般来说,取值范围是 0-31,在 FreeRTOS 中,0 号优先级最低,而 31 号优先级最高。
6.TaskHandle_t * const pxCreatedTask:用于返回创建的任务的句柄。创建任务成功后,系统将返回一个指向该任务的任务句柄。
TaskHandle_t xHandleTask1;//任务句柄
TaskHandle_t xHandleTask2;//任务句柄
//任务执行函数
void Task1(void * param)
{
while (1)
{
printf("1");
}
}
//任务执行函数
void Task2(void * param)
{
while (1)
{
printf("2");
}
}
xTaskCreate(Task1, "Task1", 100, NULL, 1, &xHandleTask1);//创建一个任务
xTaskCreate(Task2, "Task2", 100, NULL, 1, &xHandleTask2);//创建一个任务
三、静态创建任务
使用 xTaskCreateStatic() 函数静态创建任务。该函数与 xTaskCreate() 类似,但它使用静态分配的任务控制块和堆栈空间,而不是在运行时动态分配。函数原型如下:
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
);
通过静态创建方式,可以使用编译器的内存分配器来分配任务所需的内存空间,从而避免了动态分配内存的开销和潜在的内存泄漏问题。静态创建方式还可以在一些对内存使用有限制的场合下有效地管理系统资源,提高系统的稳定性和性能。
四、静态创建任务和动态创建任务的区别
静态创建任务是在编译时为任务分配内存,这意味着任务在运行时之前已经预分配了足够的内存。这种方法不需要在运行时使用动态内存分配函数,因此更加可靠和节省内存。在静态方式下,任务可以使用xTaskCreateStatic()函数创建。
动态创建任务是在运行时通过动态内存分配函数分配任务内存。这种分配方式可以更灵活地适应不同大小和数量的任务,并且支持删除或重新创建任务。然而,在动态方式下,程序需要在运行时使用动态内存分配函数,这可能会导致内存泄漏和堆碎片等问题。在动态方式下,任务需要使用xTaskCreate()函数创建。
选择使用哪种方式创建任务取决于应用程序的设计和实际需要。如果应用程序中的任务数量和大小已知,则可以使用静态方式分配内存,并且无需动态内存分配。如果应用程序需要更多的灵活性,并且需要在运行时根据需要创建或删除任务,则应使用动态方式分配内存。
需要注意的是,静态方式创建任务需要事先知道任务所需的内存大小,以及将任务的堆栈和控制块明确地分配给该任务。如果任务使用的内存超出了分配的内存,则可能会发生严重错误,例如内存泄漏或严重的崩溃。在动态方式下,内存分配在运行时动态进行,因此可以更好地处理任务所需的内存。
五、任务的删除
有任务的创建那么肯定就有任务的删除,下面我们来看看怎么进行任务的删除。
在FreeRTOS中,任务可以使用vTaskDelete()函数进行删除,该函数会立即终止当前正在运行的任务,并释放该任务所使用的内存资源。
vTaskDelete函数原型:
只需要传入要删除的任务句柄即可将任务删除,在一个任务中想要将自己删除的话需要传入的是NULL。
//任务执行函数
void Task1(void * param)
{
static int i = 0;
while (1)
{
i++;
if(i == 100)
{
vTaskDelete(xHandleTask2);//删除任务2
}
if(i == 200)
{
vTaskDelete(NULL);//删除自己
}
printf("1");
}
}
六、实例工程配置及代码分析
内容静态创建串口打印任务
代码分析:
void USART_TEST(void const * argument)
{
/* USER CODE BEGIN USART_TEST */
/* Infinite loop */
for(;;)
{
HAL_Delay(2000);
printf("this is usart task");
osDelay(5000);
}
/* USER CODE END USART_TEST */
}
在任务中,间隔2秒打印一次,至于HAL_delay和osDelay下次在分析。
实现结果: