当前位置:   article > 正文

【嵌入式——FreeRTOS】任务

【嵌入式——FreeRTOS】任务

任务创建和删除

动态方式创建任务

任务的任务控制块以及任务的栈空间所需的内存,均由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 ) 		//任务句柄,任务的任务控制块
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

示例

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

实现动态创建任务流程

  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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

示例

#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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

静态创建任务使用流程

  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
  • 2
  • 3
  • 4

注意

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

删除任务流程

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

删除任务内部实现过程

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

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

  3. 判断所需删除的任务

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

任务切换

调度器

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

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

当由任务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  待挂起任务的句柄
  • 1
  • 2

任务恢复

恢复被挂起的任务

函数

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

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

此函数用于恢复任务,使用时将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任务恢复后不需要进行任务切换
  • 1
  • 2
  • 3

相关API函数

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

更多API请查看官网

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/789242
推荐阅读
相关标签
  

闽ICP备14008679号