osThreadNew
和 xTaskCreate
都是用于创建任务(线程)的函数,但它们属于不同的接口和框架。
接口层级:
-
- xTaskCreate: 是 FreeRTOS 的原生 API 直接用于创建任务,属于 FreeRTOS 的核心函数。这是一个更低级的接口,直接与 FreeRTOS 的调度器交互。
- osThreadNew: 是根据 CMSIS-RTOS API 规范定义的接口,目的是提供一个更高层次的、硬件无关的 RTOS 接口。CMSIS-RTOS API 可以被视为在 FreeRTOS 之上提供了一层抽象,使得代码更具可移植性。
- 使用
xTaskCreate
是一个针对 FreeRTOS 的直接接口,提供了更底层的控制。 - 使用
osThreadNew
则是一个更加标准化和可移植的方式,适合需要与不同 RTOS 系统兼容的项目。
创建任务时使用的函数:(静态和动态)
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 ); // 任务句柄, 以后使用它来操作这个任务
参数说明:
参数 | 描述 |
---|---|
pvTaskCode | 函数指针,任务对应的 C 函数。任务应该永远不退出,或者在退出时调用 "vTaskDelete(NULL)"。 |
pcName | 任务的名称,仅用于调试目的,FreeRTOS 内部不使用。pcName 的长度为 configMAX_TASK_NAME_LEN。 |
usStackDepth | 每个任务都有自己的栈,usStackDepth 指定了栈的大小,单位为 word。例如,如果传入 100,表示栈的大小为 100 word,即 400 字节。最大值为 uint16_t 的最大值。确定栈的大小并不容易,通常是根据估计来设定。精确的办法是查看反汇编代码。 |
pvParameters | 调用 pvTaskCode 函数指针时使用的参数:pvTaskCode(pvParameters)。 |
uxPriority | 任务的优先级范围为 0~(configMAX_PRIORITIES – 1)。数值越小,优先级越低。如果传入的值过大,xTaskCreate 会将其调整为 (configMAX_PRIORITIES – 1)。 |
pxCreatedTask | 用于保存 xTaskCreate 的输出结果,即任务的句柄(task handle)。如果以后需要对该任务进行操作,如修改优先级,则需要使用此句柄。如果不需要使用该句柄,可以传入 NULL。 |
返回值 | 成功时返回 pdPASS,失败时返回 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY(失败原因是内存不足)。请注意,文档中提到的失败返回值是 pdFAIL 是不正确的。pdFAIL 的值为 0,而 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY 的值为 -1。 |
TaskHandle_t xTaskCreateStatic ( TaskFunction_t pxTaskCode, // 函数指针, 任务函数 const char * const pcName, // 任务的名字 const uint32_t ulStackDepth, // 栈大小,单位为word,10表示40字节 void * const pvParameters, // 调用任务函数时传入的参数 UBaseType_t uxPriority, // 优先级 StackType_t * const puxStackBuffer, // 静态分配的栈,就是一个buffer StaticTask_t * const pxTaskBuffer // 静态分配的任务结构体的指针,用它来操作这个任务 );
相比于使用动态分配内存创建任务的函数,最后2个参数不一样:
参数 | 描述 |
---|---|
pvTaskCode | 函数指针,可以简单地认为任务就是一个C函数。 它稍微特殊一点:永远不退出,或者退出时要调用"vTaskDelete(NULL)" |
pcName | 任务的名字,FreeRTOS内部不使用它,仅仅起调试作用。 长度为:configMAX_TASK_NAME_LEN |
usStackDepth | 每个任务都有自己的栈,这里指定栈大小。 单位是word,比如传入100,表示栈大小为100 word,也就是400字节。 最大值为uint16_t的最大值。 怎么确定栈的大小,并不容易,很多时候是估计。 精确的办法是看反汇编码。 |
pvParameters | 调用pvTaskCode函数指针时用到:pvTaskCode(pvParameters) |
uxPriority | 优先级范围:0~(configMAX_PRIORITIES – 1) 数值越小优先级越低, 如果传入过大的值,xTaskCreate会把它调整为(configMAX_PRIORITIES – 1) |
puxStackBuffer | 静态分配的栈内存,比如可以传入一个数组, 它的大小是usStackDepth*4。 |
pxTaskBuffer | 静态分配的StaticTask_t结构体的指针 |
返回值 | 成功:返回任务句柄; 失败:NULL |
编程实例
在02_freertos_first_app中,默认任务运行LCD程序,显示字符,自己使用xTaskCreate函数创建的任务中运行LED闪烁程序。LCD程序和LED闪烁程序内部都是死循环实现,在裸机中是不可能同时运行的,但是在freertos中,通过任务调度,可以让用户看到两个程序同时运行的现象。(本质上是交替执行的)
void Led_Test(void) { Led_Init(); while (1) { Led_Control(LED_GREEN, 1); HAL_Delay(500); Led_Control(LED_GREEN, 0); HAL_Delay(500); } } void OLED_Test(void) { uint16_t cnt=0; OLED_Init(); // 清屏 OLED_Clear(); while (1) { // 在(0, 0)打印'A' OLED_PutChar(0, 0, 'A'); // 在(1, 0)打印'Y' OLED_PutChar(1, 0, 'Y'); // 在第0列第2页打印一个字符串"Hello World!" OLED_PrintString(0, 2, "Hello World!"); OLED_PrintSignedVal(0, 4, cnt++); } } //默认任务 defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes); //led任务 xTaskCreate(MyTask,"myfirsttask",128,NULL,osPriorityNormal,NULL); void StartDefaultTask(void *argument) { /* USER CODE BEGIN StartDefaultTask */ /* Infinite loop */ for(;;) { //osDelay(1); //Led_Test(); LCD_Test(); } } void MyTask(void *argument) { while(1) { Led_Test(); } }
在创建任务时,FreeRTOS会在堆中开辟出一块空间,用于存放任务的控制信息TCB块和栈区Stack用于储存任务相关的变量,每一个任务都有自己的栈。
在任务切换时,FreeRTOS 需要保存当前任务的上下文,以便将来能够恢复。而后,切换到新任务时,FreeRTOS 需要加载新的任务上下文。这一过程称为上下文切换。保存现场保存在哪里呢,就保存在栈里。保存的什么呢,包括寄存器的值,pc,sp等。
标签:const,FreeRTOS,FreeRtos,void,OLED,任务,理解,xTaskCreate From: https://www.cnblogs.com/lichungang/p/18518912