任务创建与删除
1. 任务创建函数
// 创建任务的内存由 RAM 在 heap上动态分配 BaseType_t xTaskCreate( TaskFunction_t pvTaskCode, const char * const pcName, unsigned short usStackDepth, void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pxCreatedTask ); /*注 FreeRTOSConfig.h 中 configSUPPORT_DYNAMIC_ALLOCATION 设为 1 #define configSUPPORT_DYNAMIC_ALLOCATION 1 //支持动态内存申请 */ //创建任务保存数据的内存由 writer 控制 TaskHandle_t xTaskCreateStatic( TaskFunction_t pvTaskCode, const char * const pcName, uint32_t ulStackDepth, void *pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer ); /* example */ /* Define a structure called xStruct and a variable of type xStruct. These are just used to demonstrate a parameter being passed into a task function. */ typedef struct A_STRUCT { char cStructMember1; char cStructMember2; } xStruct; /* Define a variable of the type xStruct to pass as the task parameter. 定义一个参数传给任务*/ xStruct xParameter = { 1, 2 }; /* Define the task that will be created. Note the name of the function that implements the task is used as the first parameter in the call to xTaskCreate() below. */ void vTaskCode( void * pvParameters ) { xStruct *pxParameters; /* Cast the void * parameter back to the required type. 任务接收到创建任务时传递的参数指针*/ pxParameters = ( xStruct * ) pvParameters; /* The parameter can now be accessed as expected. */ if( pxParameters->cStructMember1 != 1 ) { /* Etc. */ } /* Enter an infinite loop to perform the task processing. */ for( ;; ) { /* Task code goes here. */ } } /* Define a function that creates a task. This could be called either before or after the scheduler has been started. */ void vAnotherFunction( void ) { TaskHandle_t xHandle; /* Create the task. */ if( pdPASS != xTaskCreate( vTaskCode, /* Pointer to the function that implements the task. */ "Demo task", /* Text name given to the task. */ STACK_SIZE, /* The size of the stack that should be created for the task. This is defined in words, not bytes. */ (void*) &xParameter,/* A reference to xParameters is used as the task parameter.This is cast to a void * to prevent compiler warnings.此处将定义的参数地址传入 */ TASK_PRIORITY, /* The priority to assign to the newly created task. */ &xHandle /* The handle to the task being created will be placed in xHandle. */ ) ) { /* The task could not be created as there was insufficient heap memory remaining. If heap_1.c, heap_2.c or heap_4.c are included in the project then this situation can be trapped using the vApplicationMallocFailedHook() callback (or ‘hook’) function, and the amount of FreeRTOS heap memory that remains unallocated can be queried using the xPortGetFreeHeapSize() API function.*/ } else { /* The task was created successfully. The handle can now be used in other API functions, for example to change the priority of the task.*/ vTaskPrioritySet( xHandle, 2 ); } }
/*static creat*/
/* Dimensions the buffer that the task being created will use as its stack. NOTE: This is the number of words the stack will hold, not the number of bytes. For example, if each stack item is 32-bits, and this is set to 100, then 400 bytes (100 * 32-bits) will be allocated. */ #define STACK_SIZE 200 /* Structure that will hold the TCB of the task being created. */ StaticTask_t xTaskBuffer; /* Buffer that the task being created will use as its stack. Note this is an array of StackType_t variables. The size of StackType_t is dependent on the RTOS port. */ StackType_t xStack[ STACK_SIZE ]; /* Function that implements the task being created. */ void vTaskCode( void * pvParameters ) { /* The parameter value is expected to be 1 as 1 is passed in the pvParameters parameter in the call to xTaskCreateStatic(). */ configASSERT( ( uint32_t ) pvParameters == 1UL ); for( ;; ) { /* Task code goes here. */ } } /* Function that creates a task. */ void vFunction( void ) { TaskHandle_t xHandle = NULL; /* Create the task without using any dynamic memory allocation. */ xHandle = xTaskCreateStatic( vTaskCode, /* Function that implements the task. */ "NAME", /* Text name for the task. */ STACK_SIZE, /* The number of indexes in the xStack array. */ ( void * ) 1, /* Parameter passed into the task. */ tskIDLE_PRIORITY,/* Priority at which the task is created. */ xStack, /* Array to use as the task's stack. */ &xTaskBuffer ); /* Variable to hold the task's data structure. */ /* puxStackBuffer and pxTaskBuffer were not NULL, so the task will have been created, and xHandle will be the task's handle. Use the handle to suspend the task. */ vTaskSuspend( xHandle ); }
使用 xTaskCreateStatic 进行任务创建时,FreeRTOSConfig.h 中设置 #define configSUPPORT_STATIC_ALLOCATION 1
且在main.c(也可以是其他源文件) 中创建空闲任务和定时模块堆栈变量
#if configSUPPORT_STATIC_ALLOCATION /* 空闲任务任务堆栈 */ static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE]; /* 空闲任务控制块 */ static StaticTask_t IdleTaskTCB; /* 定时器服务任务堆栈 */ static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH]; /* 定时器服务任务控制块 */ static StaticTask_t TimerTaskTCB; #endif #if configSUPPORT_STATIC_ALLOCATION /** * @brief 获取空闲任务地任务堆栈和任务控制块内存,因为本例程使用的静态内存,因此空闲任务的任务堆栈和任务控制块的内存就由用户提供,FreeRTOS提供了接口函数vApplicationGetIdleTaskMemory()实现此函数即可。 * @param ppxIdleTaskTCBBuffer:任务控制块内存 ppxIdleTaskStackBuffer:任务堆栈内存 pulIdleTaskStackSize:任务堆栈大小 * @retval 无 */ void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) { *ppxIdleTaskTCBBuffer = &IdleTaskTCB; *ppxIdleTaskStackBuffer = IdleTaskStack; *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; } /** * @brief 获取定时器服务任务的任务堆栈和任务控制块内存 * @param ppxTimerTaskTCBBuffer:任务控制块内存 ppxTimerTaskStackBuffer:任务堆栈内存 pulTimerTaskStackSize:任务堆栈大小 * @retval 无 */ void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) { *ppxTimerTaskTCBBuffer = &TimerTaskTCB; *ppxTimerTaskStackBuffer = TimerTaskStack; *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; } #endif
参数传递:
任务创建的时候,有一个参数用于向任务传递 data,类型是void *,任务中使用的时候,根据数据类型进行强转。
2. 任务挂起和恢复
vTaskSuspend(Task1_Handler);
vTaskResume(Task1_Handler);
if (KEY0_PRES == keyTemp) { if (NULL != Task1_Handler) { printf("Task1_Handler suspend\r\n"); vTaskSuspend(Task1_Handler); } } else if (KEY1_PRES == keyTemp) { if (NULL != Task1_Handler) { printf("Task1_Handler resum\r\n"); vTaskResume(Task1_Handler); } } else { }
实验现象:
按键触发任务挂起时,任务1 挂起,停止输出;
按键触发任务恢复时,任务1运行,开始输出;
3. 任务删除
//任务删除函数接口
vTaskDelete(Task1_Handler);
if (KEY0_PRES == keyTemp) { if (NULL != Task1_Handler) { // printf("Task1_Handler suspend\r\n"); // vTaskSuspend(Task1_Handler); printf("Task1_Handler delete\r\n"); vTaskDelete(Task1_Handler); } } else if (KEY1_PRES == keyTemp) { if (NULL != Task1_Handler) { // printf("Task1_Handler resum\r\n"); // vTaskResume(Task1_Handler); printf("Task1_Handler recreat\r\n"); CreatTask(); } } else if (KEY2_PRES == keyTemp) { infoPrintf(); }
实验现象:
4. 关闭、开启中断
taskDISABLE_INTERRUPTS( void ); taskENABLE_INTERRUPTS( void );
这两个配套使用,中间代码尽可能的短,保证系统的实时性。
如果没有使能宏 configMAX_SYSCALL_INTERRUPT_PRIORITY 和 configMAX_API_CALL_INTERRUPT_PRIORITY,调用这两个函数将禁用全局中断。
否则,调用 taskDISABLE_INTERRUPTS 将禁用 configMAX_SYSCALL_INTERRUPT_PRIORITY 优先级下的中断,而优先级比其高的中断并不会被禁用。
这两个函数不支持嵌套,即无论调用几次disable,只要调用一次 enable,就会开启中断,如果需要嵌套,使用下面的进入临界区接口
5. 任务临界区
//任务中使用下面函数进入临界区 taskENTER_CRITICAL( void ); taskEXIT_CRITICAL( void ); //中断中使用下面的配套函数 taskENTER_CRITICAL_FROM_ISR( void ); taskEXIT_CRITICAL_FROM_ISR();
进入临界区的代码是保持多任务共享数据的原子性,应该尽可能的短。
通过禁用中断实现,禁用中断范围同4,根据 configMAX_SYSCALL_INTERRUPT_PRIORITY 值来定。
支持嵌套,这两个函数必须配套使用
临界区不能调用FreeRTOS API。
6. xTaskNotifyWait
u int32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ); void vAnEventProcessingTask( void *pvParameters ) { uint32_t ulNotifiedValue; for( ;; ) { /* Block indefinitely (without a timeout, so no need to check the function's return value) to wait for a notification. Bits in this RTOS task's notification value are set by the notifying tasks and interrupts to indicate which events have occurred. */ xTaskNotifyWait( 0x00, /* Don't clear any notification bits on entry. */ ULONG_MAX, /* Reset the notification value to 0 on exit. */ &ulNotifiedValue, /* Notified value pass out in ulNotifiedValue. */ portMAX_DELAY ); /* Block indefinitely. */ /* Process any events that have been latched in the notified value. */ if( ( ulNotifiedValue & 0x01 ) != 0 ) { /* Bit 0 was set - process whichever event is represented by bit 0. */ prvProcessBit0Event(); } if( ( ulNotifiedValue & 0x02 ) != 0 ) { /* Bit 1 was set - process whichever event is represented by bit 1. */ prvProcessBit1Event(); } if( ( ulNotifiedValue & 0x04 ) != 0 ) { /* Bit 2 was set - process whichever event is represented by bit 2. */ prvProcessBit2Event(); } /* Etc. */ } }
如果该任务处于block状态,触发数据接收到后,就会接触block状态到 ready状态。
其他API
xTaskGetCurrentTaskHandle() //获取当前任务的句柄 /* INCLUDE_xTaskGetIdleTaskHandle must be set to 1 in FreeRTOSConfig.h for xTaskGetIdleTaskHandle() to be available. */ xTaskGetIdleTaskHandle( void ); xTaskGetHandle( const char *pcNameToQuery ); //任务在创建时,有一个字符串参数 pcName,通过它进行查找该任务的任务句柄
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构