当前位置: 首页 > ops >正文

详解FreeRTOS开发过程(五)-- 系统内核控制函数及任务相关API函数

一.系统内核函数

        我们最初看到的计算机称为裸机,在裸机的基础上我们看到最外围的是操作系统,操作系统中的程序主要分为两部分:一是系统系统内核函数,另一个是用户自编程序;其中系统内核函数只供系统内核使用,用户应用程序一般不允许使用,这些 API 函数就是系统内核控制函数;

        内核控制函数如下表所示:        

二. 系统内核函数详解 

1.函数 taskYIELD()

         taskYIELD() 是一个函数调用,用于主动触发任务调度器进行任务切换。当任务调用 taskYIELD() 时,它会主动让出CPU,并将控制权交给调度器,以便调度器可以选择下一个要执行的任务。

        一些常见的使用场景包括:

        任务优先级调整:通过在任务中调用 taskYIELD(),可以使当前任务放弃CPU并允许具有更高优先级的任务运行。这可以有效地改变任务的执行顺序和优先级,以满足不同任务的实时要求。

        资源共享:在某些情况下,多个任务可能需要共享某些资源,如共享数据结构、设备接口等。通过调用 taskYIELD(),可以让其他等待该资源的任务得到执行,从而避免资源的独占和饥饿现象。

        taskYIELD() 并不会强制切换到任何特定的任务,它只是将控制权交给调度器,由调度器决定下一个要运行的任务。因此,具体任务的切换顺序和频率还取决于任务的优先级、时间片轮转等调度策略。

2.函数taskENTER_CRITICAL()

        在FreeRTOS中,临界区是一段代码,需要在其中保证原子性和一致性,防止被并发访问干扰。通常,临界区用于保护对共享资源的访问,以避免竞态条件和数据不一致的问题。

        taskENTER_CRITICAL() 宏定义的作用是禁用任务调度器中断,并保存中断状态。它将执行以下操作:

        禁用任务调度器中断:通过调用 taskDISABLE_CRITICAL() 函数来禁用中断,这样其他中断将无法打断临界区的执行。

        保存中断状态:将当前中断状态保存在一个变量中。这样,在临界区结束后,通过调用 taskEXIT_CRITICAL() 宏来还原中断状态。

        通过使用 taskENTER_CRITICAL() 和 taskEXIT_CRITICAL() 对临界区进行保护,可以确保代码在临界区执行期间不被任务切换或其他中断处理程序打断,从而保证了临界区代码的原子性和一致性。临界区应尽量保持简短,避免在临界区内执行耗时操作,以免影响系统的实时性和响应性。

3. 函数 taskEXIT_CRITICAL()

        在FreeRTOS中,taskEXIT_CEITICAL() 宏定义的作用是恢复之前保存的中断状态,并允许任务调度器中断重新启用。它执行以下操作:   

        恢复中断状态:根据之前保存的中断状态,将中断重新设置为相应的状态,即恢复中断控制器中的中断使能状态。

        可能唤醒任务调度器:如果在临界区期间有更高优先级的任务就绪,并且之前禁止任务调度器中断,taskEXIT_CEITICAL() 将会唤醒任务调度器,并触发任务切换,让更高优先级的任务开始执行(前提是没有其他阻塞或延迟任务)。

        进入临界区和退出临界区的操作应成对出现,确保临界区代码逻辑正确,并且不会长时间禁用任务调度器中断,影响系统的实时性。

4.函数taskENTER_CRITICAL_FROM_ISR()

        在有 taskENTER_CRITICAL 基础上还要引入 taskENTER_CRITICAL_FROM_ISR 的原因是:在中断服务程序执行的上下文不同于任务上下文,因此不能直接使用 taskENTER_CRITICAL 和 taskEXIT_CRITICAL 这些宏来保护临界区。相反,需要使用特定的宏定义来确保在中断服务程序执行期间对共享资源的原子性和一致性保护。

         taskENTER_CRITICAL_FROM_ISR 宏定义的作用是在中断服务程序中禁用中断,并保存中断状态:

        禁用中断:使用适当的机制禁用当前的中断,这样其它中断无法打断临界区的执行。

        保存中断状态:将当前中断保存在一个变量中。这样,在临界区结束以后,通过调用宏 taskEXIT_CRITICAL_FROM_ISR 来恢复中断状态。

        通过使用 taskENTER_CRITICAL_FROM_ISR() 和 taskEXIT_CRITICAL_FROM_ISR() 宏对中断服务程序中的临界区进行保护,可以确保在中断服务程序执行期间不被同优先级的中断或其他任务切换打断,从而保证了临界区代码的原子性和一致性。

5.函数 taskEXIT_CRITICAL_FROM_ISR()

        taskEXIT_CRITICAL_FROM_ISR() 宏定义的作用是恢复之前保存的中断状态,并允许同优先级的中断重新启用。它执行以下操作:

        恢复中断状态:根据之前保存的中断状态,将中断重新设置为相应的状态,即恢复中断控制器中的中断使能状态。

        唤醒更高优先级的中断:如果在临界区期间有更高优先级的中断发生,并且之前禁止同优先级的中断,taskEXIT_CRITICAL_FROM_ISR() 将会唤醒该中断,让它继续执行(前提是没有其他阻塞或延迟任务)。

6.函数 taskDISABLE_INTERRUPTS()

        在 FreeRTOS 中,taskDISABLE_INTERRUPST() 函数的作用是禁用任务调度器中断。调用该函数将禁用中断,防止中断处理程序打断正在执行的任务,从而确保任务的原子性和一致性。

        禁用中断会影响系统的实时性和响应性,因此应谨慎使用。通常情况下,禁用中断是为了保护关键的数据操作或临界区。禁用中断的时间应尽量控制在最短的时间内,以避免对系统的影响过大。

         在使用 taskDISABLE_INTERRUPTS() 函数禁用中断后,可以使用 taskENABLE_INTERRUPTS() 函数来重新启用中断。taskDISABLE_INTERRUPTS() 函数和 taskENABLE_INTERRUPTS() 函数通常用于任务上下文中,而在中断服务程序(ISR)中,应使用适当的宏定义来禁用和启用中断,如 portENTER_INTERRUPTS() 和portEXIT_INTERRUPTS()。

7.函数 taskENABLE_INTERRUPTS()

        在 FreeRTOS 中,taskENTER_INTERRUPTS() 函数的作用是启用任务调度器中断。调用该函数将允许中断处理程序打断正在执行的任务,使得系统能够响应其他中断和事件。

        在使用 taskDISABLE_INTERRUPTS() 函数禁用中断后,可以使用 taskENABLE_INTERRUPTS() 函数来重新启用中断,从而恢复任务的正常调度和中断处理。

8.函数 vTaskStartScheduler()

        在 FreeRTOS 中,任务调度器是负责任务调度和管理的核心部件。在应用程序初始化完成以后,调用 vTaskStartScheduler() 函数可以启动任务调度器,使得任务能够按照特定的调度算法进行调度和执行。

        vTaskStartScheduler() 函数执行以下操作:

        初始化任务管理器。首先,它会初始化任务管理器,设置相关的数据结构和全局变量,为任务调度器做准备。

        进入主调度循环。它会进入一个主调度循环,不断地选择要执行的下一个任务,并将控制权转移到该任务的执行函数。

        任务切换和调度。在主调度循环中,任务调度器根据任务的优先级、调度策略和调度算法,决定在给定时间片内应该运行哪个任务。任务切换涉及保存当前任务的上下文,切换到下一个任务的上下文,并执行与任务切换相关的操作,如栈切换、任务状态更新等。

        vTaskStartScheduler() 函数只能在初始化完所有任务和相关的 FreeRTOS 组件后调用,且不能返回。一旦任务调度器启动,它将接管程序的控制权,并开始调度和执行任务。在调用 vTaskStartScheduler() 函数之前,通常需要先创建并初始化任务、队列、信号量、定时器等相关的 FreeRTOS 组件,以确保任务调度器具备正确的任务和资源配置。

9.函数 vTaskEndScheduler()

        在 FreeRTOS 中,任务调度器负责任务的调度和管理。调用 vTaskEndScheduler() 函数可以结束任务调度器的运行,终止任务的调度和执行。

        调用 vTaskEndScheduler() 函数执行以下操作:

        停止任务调度。停止任务调度器的运行,禁止任务切换和调度。

        清理资源。执行一些清理操作,释放任务调度器和其他相关组件占用的资源,包括堆栈空间、定时器资源、队列和信号量等。

10.函数 vTaskSuspendAll()

        挂起任务调度器,调用此函数不需要关闭可屏蔽中断即可挂起任务调度器,此函数在文件 tasks.c中有如下定义:

void vTaskSuspendAll(void)
{++uxSchedulerSuspended;
}

        此函数只是简单的将变量uxSchedulerSuspended加一,uxSchedulerSuspended是挂起嵌套计数器,调度器挂起是支持嵌套的。使用函数xTaskResumeAll()可以恢复任务调度器,调用了几次vTaskSuspendAll()挂起调度器,同样的也得调用几次 xTaskResumeAll()才会最终恢 复任务调度器。

        有一个任务 1 ,等待队列而处于阻塞态,有段程序调用了 vTaskSuspendAll() 挂起了任务调度器,任务调度器不能再进行任务切换了,在还没有恢复之前, 有一个中断服务函数,中断服务函数向任务 1 发送了队列,如果任务调度器没有被挂起的话,现在任务 1 是要进入就绪态的,但是因为被挂起了,所以现在任务 1 不是进入就绪态,而是被添加到了一个叫做 xPendingReadyList 的列表中;此时如果调用函数 xTaskResumeAll() 恢复调度器的话,被挂到列表 xPendingReadyList 中的任务会重新移动到它们所对应的就绪列表 pxReadyTasksLists 中。

11.函数 xTaskResumeAll() 

         在 FreeRTOS 中,任务抢占是通过嵌套中断计数实现的。当调用 xTaskResumeAll() 函数时,它会将中断嵌套计数减一。当中断嵌套计数为 0 时,低优先级的任务将有机会重新抢占执行,以确保多任务间的公平调度。

        xTaskResumeAll() 函数执行以下操作:

        递减中断嵌套计数。该函数将嵌套中断计数减一,表示允许任务调度器重新对低优先级任务进行调度。

        是否进行任务切换。如果中断嵌套计数减一后为 0 ,并且当前的中断处于待处理状态,则可以发生任务切换。这将使得等待执行的低优先级任务得到机会,并可能暂停当前正在执行的高优先级任务。

        xTaskResumeAll() 函数必须与先前调用的 vTaskSuspendAll() 函数成对使用,以确保正确的中断嵌套计数管理。在调用 vTaskSuspendAll() 函数后,任务调度器将停止进行任务切换,所有任务都会暂时被挂起。而在调用 xTaskResumeAll() 函数后,中断嵌套计数将递减并可能导致任务切换。

BaseType_t xTaskResumeAll( void ) 
{ TCB_t *pxTCB = NULL; BaseType_t xAlreadyYielded = pdFALSE; configASSERT( uxSchedulerSuspended ); taskENTER_CRITICAL();   //进入临界区。{ --uxSchedulerSuspended;     //调度器挂起嵌套计数器uxSchedulerSuspended减一if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )  //如果uxSchedulerSuspended为0说明所有的挂起都已经解除,调度器可以开始运行了。{ if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U ) { //处理列表xPendingReadyList,只要列表 xPendingReadyList 不为空,说明还有任务挂到了列表xPendingReadyList上,//这里需要将这些任务从列表xPendingReadyList 上移除并添加到这些任务所对应的就绪列表中。 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ){ pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY\     //遍历列表 xPendingReadyList,获取挂到列表xPendingReadyList上的任务对应的任务控制块。( ( &xPendingReadyList ) ); ( void ) uxListRemove( &( pxTCB->xEventListItem ) );    //将任务从事件列表上删除。( void ) uxListRemove( &( pxTCB->xStateListItem ) );    //将任务从状态列表上移除。prvAddTaskToReadyList( pxTCB );     //调用函数prvAddTaskToReadyList()将任务添加到就绪列表中。//判断任务的优先级是否高于当前正在运行的任务,如果是的话需要将xYieldPending标记为pdTRUE,表示需要进行任务切换。if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) { xYieldPending = pdTRUE; } else { mtCOVERAGE_TEST_MARKER(); } } /************************************************************************/ 
/****************************省略部分代码********************************/ 
/************************************************************************/ if( xYieldPending != pdFALSE )  //需要进行任务切换{ #if( configUSE_PREEMPTION != 0 ) { xAlreadyYielded = pdTRUE;   //变量 xAlreadyYielded 用于标记在函数xTaskResumeAll()中是否有进行任务切换} #endif taskYIELD_IF_USING_PREEMPTION();    //调用函数 taskYIELD_IF_USING_PREEMPTION()进行任务切换} else { mtCOVERAGE_TEST_MARKER(); } } } else { mtCOVERAGE_TEST_MARKER(); } } taskEXIT_CRITICAL();    //退出临界区//返回变量 xAlreadyYielded,如果为 pdTRUE 的话表示在函数 xTaskResumeAll()中进行了任务切换,如果为pdFALSE的话表示没有进行任务切换。 return xAlreadyYielded; 
} 

12.函数 vTaskStepTick()

        此函数在使用 FreeRTOS 的低功耗 tickless 模式的时候会用到,即宏 configUSE_TICKLESS_IDLE 为 1。当使能低功耗 tickless 模式以后在执行空闲任务的时候系统时钟节拍中断就会停止运行,系统时钟中断停止运行的这段时间必须得补上,这个工作就是由函数 vTaskStepTick() 来完成的。

void vTaskStepTick( const TickType_t xTicksToJump ) 
{ configASSERT( ( xTickCount + xTicksToJump ) <= xNextTaskUnblockTime ); //xTicksToJump 是要加上的时间值,系统节拍计数器 xTickCount 加上这个时间值得到新的系统时间。xTickCount += xTicksToJump;     traceINCREASE_TICK_COUNT( xTicksToJump ); 
}

三.FreeRTOS其他任务API函数

1.任务相关API函数预览

2. 任务相关API函数详解

1.函数uxTaskPriorityGet()

        此函数用来设置指定任务的优先级,要使用此函数的话宏 INCLUDE_uxTaskPriorityGet 应设置为 1 ,函数原型如下:

UBaseType_t uxTaskPriorityGet(TaskHandle_t xTask)xTask: 要查找任务的任务句柄返回值: 获取到的对应任务的任务优先级

        任务的任务优先级值越高,任务获得 CPU 执行时间的优先级也越高。FreeRTOS 任务调度器根据任务的优先级来决定任务的执行顺序。

2.函数 vTaskPrioritySet()

        此函数用于改变某一个任务的任务优先级,要使用此函数的话宏 INCLUDE_vTaskPrioritySet 应该定义为 1,函数原型如下:

void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )
xTask: 要查找的任务的任务句柄
uxNewPriority: 任务要使用的新的优先级,可以是 0~configMAX_PRIORITIES - 1
返回值: 无

3.函数 uxTaskGetSystemState()

        此函数用于获取系统中所有任务的任务状态,每个任务的状态信息保存在一个 TaskStatus_t 类型的结构体里面,这个结构体里面包含了任务的任务句柄、任务名字、堆栈、优先级等信息,要使用此函数的话宏 configUSE_TRACE_FACILITY 应该定义为 1,函数原型如下:

UBaseType_t uxTaskGetSystemState(TaskStatus_t* const  pxTaskStatusArray,const UBaseType_t    uxArraySize,uint32_t* const      pulTotalRunTime)\pxTaskStatusArray: 指向 TaskStatus_t 结构体类型的数组首地址,每个任务至少需要一个 TaskStatus_t 结构体,任务的数量可以使用函数 uxTaskGetNumberOfTasks() 来获取。uxArraySize:保存任务状态数组的数组的大小pulTotalRunTime:如果configGENERATE_RUN_TIME_STATS为1的话此参数用来保存系统总的运行时间返回值:统计到的任务状态的个数,也就是填写到数组 pxTaskStatusArray 中的个数,此值应该等于函数 uxTaskGetNumberOfTasks() 的返回值。如果参数 uxArraySize 太小的话返回值可能为 0.

        结构体 TaskStatus_t 在文件 task.h 中有如下定义:

typedef struct xTASK_STATUS 
{ TaskHandle_t xHandle; //任务句柄 const char * pcTaskName; //任务名字UBaseType_t xTaskNumber; //任务编号 eTaskState eCurrentState; //当前任务壮态,eTaskState 是一个枚举类型 UBaseType_t uxCurrentPriority; //任务当前的优先级 UBaseType_t uxBasePriority; //任务基础优先级 uint32_t ulRunTimeCounter;//任务运行的总时间 StackType_t * pxStackBase; //堆栈基地址 uint16_t usStackHighWaterMark; //从任务创建以来任务堆栈剩余的最小大小,此 //值如果太小的话说明堆栈有溢出的风险。 
} TaskStatus_t; 

4.函数 vTaskGetInfo()

        此函数是用来获取某个任务的任务信息。但是获取的是指定的单个任务的任务状态,任务的状态信息填充到参数 pxTaskStatus 中,这个参数也是 TaskStatus_t 类型的。要使用此函数的话宏 configUSE_TRACE_FACILITY 要定义为 1,函数原型如下:

void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t * pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ) 
xTask:要查找的任务的任务句柄pxTaskStatus:指向类型为 TaskStatus_t 的结构体变量xGetFreeStackSpace: 在结构体 TaskStatus_t 中有个字段 usStackHighWaterMark 来保存自任务运行以来任务堆栈剩余的历史最小大小,这个值越小说明越接近堆栈溢出,但是计算这个值需要花费一点时间,所以我们可以通过将 xGetFreeStackSpace 设置为 pdFALSE 来跳过这个步骤,当设置为 pdTRUE 的时候就会检查堆栈的历史剩余最小值。eState:  结构体 TaskStatus_t 中有个字段 eCurrentState 用来保存任务运行状态,这个字段是 eTaskState 类型的,这个是枚举类型,在 task.h 中如下定义:

5.函数 xTaskGetApplicationTaskTag()

        此函数用于获取任务的 Tag(标签)值,任务控制块中有个成员变量 pxTaskTag 来保存任务的标签值。标签的功能由用户自行决定,此函数就是用来获取这个标签值的,FreeRTOS 系统内核是不会使用到这个标签的。要使用此函数的话宏 configUSE_APPLICATION_TASK_TAG 必须为 1,函数原型如下:

TaskHookFunction_t xTaskGetApplicationTaskTag(TaskHandle_t     xTask)xTask: 要获取标签值的任务对应的任务句柄,如果为 NULL 的话就获取当前正在运行的任务标签值返回值: 任务的标签值

6.函数 xTaskGetCurrentTaskHandle()

        此函数用来获取当前任务的任务句柄,其实获取到的就是任务控制块,任务句柄其实就是任务控制。如果要使用此函数的话宏 INCLUDE_xTaskGetCurrentTaskHandle 应该为 1,函数原型如下:

TaskHandle_t xTaskGetCurrentTaskHandle(void)

7.函数 xTaskGetHandle()

        此函数根据任务名字获取任务的任务句柄,在使用函数 xTaskCreate() 或 xTaskCreateStatic() 创建任务的时候都会给任务分配一个任务名,函数 xTaskGetHandle() 就是使用这个任务名字来查询对应的任务句柄的。要使用此函数的话宏 INCLUDE_xTaskGetHandle 应该设置为 1,此函数原型如下: 

TaskHandle_t xTaskGetHandle(const char*    pcNameToQuery)pcNameToQuery: 任务名,C语言字符串返回值:NULL: 没有任务名 pcNameToQuery 所对应的任务其他值: 任务名 pcNameToQuery 所对应的任务句柄

8.函数 xTaskGetIdleTaskHandle()

        此函数返回空闲任务的任务句柄,要使用此函数的话宏 INCLUDE_xTaskGetIdleTaskHandle 必须为 1 ,函数原型如下:

TaskHandle_t xTaskGetIdleTaskHandle(void)
参数: 无返回值: 空闲任务的任务句柄

9.函数 uxTaskGetStackHighWaterMark()

        每个任务都有自己的堆栈,堆栈的总大小在创建任务的时候就确定了,此函数用于检查任务从创建好到现在的历史剩余最小值,这个值越小说明任务堆栈溢出的可能性就越大!FreeRTOS 把这个历史剩余最小值叫做 “高水位线”。此函数相对来说会多耗费一点时间,所以在代码调试阶段可以使用,产品发布的时候最好不要使用。要使用此函数的话宏 INCLUDE_uxTaskGetStackHighWaterMark 必须为 1,此函数原型如下:

UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t  xTask)
xTask:要查询的任务的任务句柄,当这个参数为 NULL 的话说明查询自身任务(即调用函数uxTaskGetStackHighWaterMark() 的任务)的 “高水位线”返回值: 任务堆栈的 “高水位线” 值,也就是堆栈的历史剩余最小值。

10.函数 eTaskGetState()

        此函数用于查询某个任务的运行状态,比如:运行态、阻塞态、挂起态、就绪态等,返回值是个枚举类型。要使用此函数的话宏 INCLUDE_eTaskGetState 必须为 1,函数原型如下: 

eTaskState  eTaskGetState(TaskHandle_t   xTask)
xTask:要查询的任务的任务句柄返回值:返回值为 eTaskState 类型,这是个枚举类型,在文件 task.h 中有定义

11.函数 pcTaskGetName()

        此函数用以根据某个任务的任务句柄来查询这个任务对应的任务名,函数原型如下:

char *pcTaskGetName(TaskHandle_t    xTaskToQuery)

12.函数 xTaskGetTickCount()

        此函数用以查询任务调度器从启动到现在时间计数器 xTickCount 的值。xTickCount 是系统的时钟节拍值,并不是真实的时间值。每个滴答定时器中断 xTickCount 就会加 1 ,一秒钟滴答定时器中断多少次取决于宏 configTICK_RATE_HZ 。理论上 xTickCount 存在溢出的问题,但是这个溢出对于 FreeRTOS 的内核没有影响,但是如果用户的应用程序有使用到的话就要考虑溢出了。什么时候溢出取决于宏 configUSE_16_BIT_TICKS,当此宏为 1 的时候 xTickCount 就是个 16 位的变量,当为 0 的时候就是个 32 位的变量。函数原型如下:

TickType_t      xTaskGetTickCount(void)

13.函数 xTaskGetTickCountFromISR()

        此函数是 xTaskGetTickCount() 的中断级版本,用于在中断服务函数中获取时间计数器 xTickCount 的值,函数原型如下:

TickType_t   xTaskGetTickCountFromISR(void)

14.函数 xTaskGetSchedulerState()

        此函数用于获取 FreeRTOS 的任务调度器运行情况:运行?关闭?还是挂起!要使用此函数的话宏 INCLUDE_xTaskGetSchedulerState 必须为 1,此函数原型如下:

BaseType_t    xTaskGetSchedulerState(void)
返回值:                            
taskSCHEDULER_NOT_STARTED:  调度器未启动,调度器的启动是通过函数 vTaskStartScheduler() 来完成,
所以在函数 vTaskStartScheduler() 未调用之前调用函数 xTaskGetSchedulerState() 的话就会返回此值。taskSCHEDULER_RUNNING:  调度器正在运行taskSCHEDULER_SUSPENDED: 调度器挂起

15.函数 uxTaskGetNumberOfTasks()

        此函数用于查询系统当前存在的任务数量,函数原型如下:

UBaseType_t    uxTaskGetNumberOfTasks(void)
返回值:当前系统中存在的任务数量,此值 = 挂起态的任务 + 阻塞态的任务 + 就绪态的任务 + 空闲任务 + 运行态的任务。

 16.函数vTaskList()

         此函数会创建一个表格来描述每个任务的详细信息。函数原型如下:

void vTaskList(char *pcWriteBuffer)

17.函数 vTaskGetRunTimeStats()

        FreeRTOS 可以通过相关的配置来统计任务的运行时间信息,任务的运行时间信息提供了每个任务获取到 CPU 使用权总的时间。函数 vTaskGetRunTimeState() 会将统计到的信息填充到一个表里面,表里面提供了每个任务的运行时间和其所占总时间的百分比。函数原型如下:

void vTaskGetRunTimeStats(char *pcWriteBuffer)

18.函数 vTaskSetApplicationTaskTag()

        此函数是为高级用户准备的,此函数用于设置某个任务的标签值,这个标签值的具体函数和用法由用户自行决定,FreeRTOS 内核不会使用这个标签值,如果要使用的话宏 configUSE_APPLICATION_TASK_TAG 必须为 1 ,函数原型如下:

void vTaskSetApplicationTaskTag(TaskHandle_t        xTask,TaskHookFunction_t  pxHookFunction)

 19.函数 SetThreadLocalStoragePointer()

        此函数用于设置线程本地存储指针的值,每个任务都有它自己的指针数组来作为线程本地存储,使用这些线程本地存储可以用来在任务控制块中存储一些应用信息,这些信息只属于任务自己。线程本地存储指针数组的大小由宏 configNUM_THREAD_LOCAL_STORAGE_POINTERS 来决定的。如果要使用此函数的话宏 configNUM_THREAD_LOCAL_STORAGE_ POINTER 不能为 0。宏的具体值是本地存储指针数组的大小,函数原型如下:

void vTaskSetThreadLocalStoragePointer(TaskHandle_t    xTaskToSet,BaseType_t      xIndex,void*           pvValue)xTaskToSet:要设置线程本地存储指针的任务的任务句柄,如果是 NULL 的话表示设置任 务自身的线程本地存储指针。xIndex:要设置的线程本地存储指针数组的索引。pvValue: 要存储的值。

20.函数 GetThreadLocalStoragePointer()

        此函数用于获取线程本地存储指针的值,如果要使用此函数的话宏 configNUM_THREAD_LOCAL_STORAGE_POINTERS 不能为 0 ,函数原型如下:

void *pvTaskGetThreadLocalStoragePointer(TaskHandle_t  xTaskToQuery,BaseType_t    xIndex)xTaskToSet:要获取的线程本地存储指针的任务句柄,如果是 NULL 的话表示获取任务自身的线程本地存储指针。xIndex:要获取的线程本地存储指针数组的索引。返回值: 获取到的线程本地存储指针的值。
http://www.xdnf.cn/news/16142.html

相关文章:

  • 低功耗设计双目协同画面实现光学变焦内带AI模型
  • vs调试C++,无法显示长字符串所有内容
  • 上证50ETF期权的交易时间是什么时候?
  • 模块化商城的快速部署之道:ZKmall开源商城如何让电商功能即插即用
  • rustfs/rustfs基于 Rust 的高性能分布式存储系统
  • 多模态数据处理系统:用AI读PDF的智能助手系统分析
  • 物流仓储自动化升级:Modbus TCP与DeviceNet的协议融合实践
  • EVAL长度限制突破方法
  • java实体类常规校验(字符串不包含空格)
  • mac电脑(m1) - flask断点失效
  • 2025年区块链安全威胁全景:新兴漏洞、攻击向量与防护策略深度解析
  • 【数据结构初阶】--二叉树(二)
  • SAP-MM-采购订单批量创建 excel 版
  • MYOJ_10583:CSP初赛题单7:计算机常识综合练习
  • 人工智能与云计算双轮驱动:元宇宙如何重构全球产业生态
  • linux入门 相关linux系统操作命令(二)--文件管理系统 ubuntu22.04
  • Windows本地部署DeepSeek
  • Leetcode力扣解题记录--第2题(加法模拟)
  • 量子威胁下的区块链进化:后量子密码学时代的分布式账本革命
  • 从手动操作到自动化:火语言 RPA 在多系统协作中的实践
  • Elasticsearch 高级查询语法 Query DSL 实战指南
  • C#_定时器_解析
  • 光猫配置DMZ到路由器
  • 20-ospf技术
  • Kafka入门指南:从零开始掌握分布式消息队列
  • AI 在金融:重塑金融服务的智能革命
  • Linux中虚拟地址和物理地址互相转化之页表的详解
  • 微算法科技(NASDAQ: MLGO)研究量子信息递归优化(QIRO)算法,为组合优化问题拓展解决新思路
  • C++图论全面解析:从基础概念到算法实践
  • [iOS开发工具] 【iOS14以及以下】cydia商店按键精灵iOS新版V2.X安装教程