【嵌入式——FreeRTOS】任务

发布于:2024-06-27 ⋅ 阅读:(131) ⋅ 点赞:(0)

任务创建和删除

动态方式创建任务

任务的任务控制块以及任务的栈空间所需的内存,均由freeRTOS从freeRTOS管理的堆中分配。此函数创建任务会立刻进入就绪态,由任务调度器调度运行。
任务的优先级,值越大,优先级越高

函数

xTaskCreate();
//返回值为pdPASS,任务创建成功。
//返回值为errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY,任务创建失败

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,  				//指向任务函数的指针
                        const char * const pcName,  				//任务名字 最大长度configMAX_TASK_NAME_LEN(20)
                        const configSTACK_DEPTH_TYPE usStackDepth,	//任务堆栈大小 字为单位
                        void * const pvParameters,  				//传递给任务函数的参数
                        UBaseType_t uxPriority, 					//任务优先级 范围 0 ~ configMAX_PRIORITIES(32)-1 
                        TaskHandle_t * const pxCreatedTask ) 		//任务句柄,任务的任务控制块

示例

static void udpserver_sendto_client (void* argument){}

static TaskHandle_t	udpserver_tid;

#define UDPSERVER_THREAD_NAME       "task name"
#define UDPSERVER_THREAD_STKSZ      (configMINIMAL_STACK_SIZE * 4)
#define UDPSERVER_THREAD_PRIO       (tskIDLE_PRIORITY + 3)

BaseType_t ret = xTaskCreate(udpserver_sendto_client, UDPSERVER_THREAD_NAME, UDPSERVER_THREAD_STKSZ, 
NULL, UDPSERVER_THREAD_PRIO, &udpserver_tid);

实现动态创建任务流程

  1. 将FreeRTOSConfig.h文件中的configSUPPORT_DYNAMIC_ALLOCATION宏配置为1;
  2. 定义函数入口参数;
  3. 编写任务函数。

动态创建任务内部实现

  1. 申请堆栈内存和任务控制块内存;
  2. TCB结构体成员赋值;(把前面申请的堆栈地址,赋值给控制块的堆栈成员)
  3. 初始化控制块中的成员
  4. 添加新任务到就绪列表。

静态方式创建任务

任务的任务控制块以及任务的栈空间所需的内存,需用户分配提供。

函数

xTaskCreateStatic();
//返回值为句柄或者其他值,任务创建成功。
//返回值为NULL,任务创建失败。


TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,			//指向任务函数的指针
                                const char * const pcName, 			//任务名字 最大长度configMAX_TASK_NAME_LEN(20)
                                const uint32_t ulStackDepth,		//任务堆栈大小 字为单位
                                void * const pvParameters,			//传递给任务函数的参数
                                UBaseType_t uxPriority,				//任务优先级 范围 0 ~ configMAX_PRIORITIES(32)-1 
                                StackType_t * const puxStackBuffer,	//任务堆栈,一般为数组由用户分配
                                StaticTask_t * const pxTaskBuffer ) //任务控制块指针,由用户分配
								PRIVILEGED_FUNCTION;

示例

#define STACK_SIZE 200

//空闲任务配置
StaticTask_t idle_task_tcb;
StackType_t idle_task_stack[configMINIMAL_STACK_SIZE];

//软件定时器任务配置
StaticTask_t time_task_tcb;
StackType_t time_task_stack[configTIMER_TASK_STACK_DEPTH];


StaticTask_t xTaskBuffer;
StackType_t xStack[ STACK_SIZE ];


//空闲任务内存分配
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
	*ppxIdleTaskTCBBuffer = &idle_task_tcb;
	*ppxIdleTaskStackBuffer = idle_task_stack;
	*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;

}

//软件定时器内存分配
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
                                     StackType_t ** ppxTimerTaskStackBuffer,
                                     uint32_t * pulTimerTaskStackSize )
{
	*ppxTimerTaskTCBBuffer = &time_task_tcb;
	*ppxTimerTaskStackBuffer = time_task_stack;
	pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;

}


void vTaskCode( void * pvParameters ){}

TaskHandle_t xHandle = xTaskCreateStatic(
                     vTaskCode,       // Function that implements the task.
                     "NAME",          // Text name for the task.
                     STACK_SIZE,      // Stack size in words, not bytes.
                     ( 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.

静态创建任务使用流程

  1. 将FreeRTOSConfig.h文件中的configSUPPORT_STATIC_ALLOCATION宏配置为1;

  2. 定义空闲任务和定时器任务的任务堆栈即TCB;

  3. 实现两个接口函数

    1. vApplicationGetIdleTaskMemory()
    2. vApplicationGetTimerTaskMemory();可选的
  4. 定义函数入口参数;

  5. 编写任务函数;

静态创建任务内部实现

  1. TCB结构体成员赋值;
  2. 添加新任务到就绪列表;

删除任务

用于删除已经被创建的任务。被删除的任务将从就绪态任务列表,阻塞态任务列表,挂起态任务列表和事件列表中移除。

函数

vTaskDelete();

void vTaskDelete( TaskHandle_t xTaskToDelete )
//xTaskToDelete 待删除的任务句柄

注意

  1. 当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)。
  2. 空闲任务会负责释放被删除任务中由系统分配的内存,但是由用户在任务删除前申请的内存,则需要由用户在任务被删除前提前释放,否则将导致内存泄漏。

删除任务流程

  1. 将INCLUDE_vTaskDelete宏配置为1;
  2. 入口参数输入需要删除的任务句柄(NULL代表自身);

删除任务内部实现过程

  1. 获取所要删除任务的控制块;

  2. 将被删除的任务移除所在列表;

  3. 判断所需删除的任务

    1. 删除任务自身,需先添加到等待删除列表,内存释放将在空闲任务进行。
    2. 删除其他任务,释放内存,任务数量–
  4. 更新下个任务的阻塞时间;

任务切换

调度器

实现任务间的切换。本质就是CPU寄存器的切换

//启动任务,开启调度
vTaskStartScheduler();

当由任务A切换到任务B时,主要分为两步

第一步:需暂停任务A的执行,并将此时任务A的寄存器保存到任务堆栈,这个过程叫做保存现场。
第二步:将任务B的各个寄存器值(被存于任务堆栈中)恢复到CPU寄存器中,这个过程叫做恢复现场。对任务A保存现场,对任务B恢复现场,这个过程被称为上下文切换。

任务切换流程

  1. 触发PendSV中断
  2. 当前的psp是正在运行的任务的栈指针,读取当前psp进程指针,存入r0
  3. 压栈(保存现场)
  4. 获取当前最高优先级任务的任务控制块
  5. 出栈(恢复现场)
  6. 更新切换后的任务的栈指针给psp
  7. bx r14指向新任务函数

PendSV中断如何触发

  1. 滴答定时器中断调用。
  2. 执行FreeRTOS提供的相关API函数,portYIELD();

任务挂起

挂起任务

函数

此函数用于挂起任务,使用时将FreeRTOSConfig.h文件中宏INCLUDE_vTaskSuspend配置为1。
无论优先级如何,被挂起的任务都将不再被执行,直到任务被恢复。
当传入参数为NULL,则代表挂起任务自身(当前正在运行的任务)。

void vTaskSuspend( TaskHandle_t xTaskToSuspend ) PRIVILEGED_FUNCTION;
//xTaskToSuspend  待挂起任务的句柄

任务恢复

恢复被挂起的任务

函数

此函数用于恢复任务,使用时将FreeRTOSConfig.h文件中宏INCLUDE_vTaskSuspend配置为1。
任务无论被挂起多少次,只需在任务中调用vTaskResume()恢复一次,就可以继续运行,且被恢复的任务会进入就绪状态。
在中断中恢复被挂起的任务。带有“FromISR”后缀是在终端函数中专用的API函数

void vTaskResume( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;
//xTaskToResume 待恢复任务的任务句柄

此函数用于恢复任务,使用时将FreeRTOSConfig.h文件中宏INCLUDE_vTaskSuspend配置为1,宏INCLUDE_xTaskResumeFromISR配置为1。
被恢复的任务的优先级大于当前执行的任务的优先级,就会返回pdTRUE需要手动执行任务切换(portYIELD_FROM_ISR()函数)。
中断服务程序中要调用freeRTOS的API函数则中断优先级不能高于freeRTOS所管理的最高优先级(5~15)。

BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;
//xTaskToResume 待恢复任务的任务句柄
//返回值 pdTRUE 任务恢复后需要进行任务切换  pdFALSE任务恢复后不需要进行任务切换

相关API函数

函数 描述
uxTaskPriorityGet() 获取任务优先级
vTaskPrioritySet() 设置任务优先级
uxTaskGetNumberOfTasks() 获取系统中任务的数量
uxTaskGetSystemState() 获取所有任务状态信息
vTaskGetInfo() 获取指定单个任务信息
xTaskGetCurrentTaskHandle() 获取当前任务的任何句柄
xTaskGetHandle() 根据任务名获取该任务的任何句柄
uxTaskGetStackHighWaterMark() 获取任务的任务栈历史剩余最小值
eTaskGetState() 获取任务状态
vTaskList() 以表格形式获取所有任务的信息
vTaskGetRunTimeStats() 获取任务的运行时间

更多API请查看官网


网站公告

今日签到

点亮在社区的每一天
去签到