目录
一.FreeRTOS任务挂起与恢复的API函数
二.任务挂起和恢复的基本操作
1.任务挂起:
2.任务恢复:
三.任务挂起与恢复的实现步骤
任务挂起的实现
任务恢复的实现
在实时操作系统FreeRTOS中,任务的挂起与恢复是一项重要的控制功能。任务挂起相当于暂停任务的执行,直到条件满足才恢复继续运行。这种机制在任务的调度和系统资源管理上起到了关键作用。本篇文章将通过FreeRTOS提供的任务挂起和恢复API函数及相关实验来深入理解这一机制。
一.FreeRTOS任务挂起与恢复的API函数
在FreeRTOS中,以下几个API函数用于实现任务的挂起和恢复:
vTaskSuspend(TaskHandle_txTaskToSuspend):挂起指定任务。
vTaskResume(TaskHandle_txTaskToResume):恢复指定任务。
xTaskResumeFromISR(TaskHandle_txTaskToResume):在中断服务例程(ISR)中恢复任务。
特别注意:如果API函数名称中包含"FromISR"后缀,它只能用于中断服务中调用。例如,xTaskResumeFromISR用于在中断中恢复被挂起的任务。挂起任务时需要将宏INCLUDE_vTaskSuspend配置为1,表示启用该功能。
二.任务挂起和恢复的基本操作
1.任务挂起:
使用vTaskSuspend()函数来挂起任务。无论任务的优先级高低,被挂起后便停止执行,直到通过恢复函数vTaskResume()使其继续执行。
当传入的任务句柄参数为NULL时,表示挂起当前运行的任务自身。
void task3( void * pvParameters )
{uint8_t key = 0;while(1){key = key_scan(0);if(key == KEY0_PRES){printf("挂起task1\r\n");vTaskSuspend(task1_handler);} else if(key == KEY_UP){printf("挂起task3\r\n");vTaskSuspend(task1_handler);}vTaskDelay(10);}
}
2.任务恢复:
调用vTaskResume()函数恢复被挂起的任务。值得注意的是,无论任务被vTaskSuspend()挂起多少次,vTaskResume()只需调用一次便可恢复该任务继续运行。
xTaskResumeFromISR()用于在中断服务中恢复被挂起的任务。在任务恢复时,需要检查任务的优先级以判断是否需要进行任务切换。
void task3( void * pvParameters )
{uint8_t key = 0;while(1){key = key_scan(0);if(key == KEY1_PRES){printf("在任务中恢复task1\r\n");vTaskResume(task1_handler);}vTaskDelay(10);}
}
三.任务挂起与恢复的实现步骤
任务挂起的实现
1.确保INCLUDE_vTaskSuspend宏定义为1
-功能选择性启用:如果INCLUDE_vTaskSuspend未定义或定义为0,则编译时FreeRTOS不会包含与任务挂起和恢复相关的代码逻辑。这种选择性的编译配置可以减少代码体积,节省内存资源。这对于嵌入式系统尤其重要,因为这些系统的存储和内存通常有限。
-API功能可用性:如果未定义为1,那么vTaskSuspend()和vTaskResume()函数将不会被包含,任何试图调用这些函数的代码都会在编译时报错。定义宏为1才能确保这些API函数能够被正常调用。
-系统效率优化:通过使用宏开关,FreeRTOS可以根据不同项目需求来裁剪无关的功能模块,从而优化系统运行效率。这样可以减轻调度器的负担,使任务切换和资源管理更加高效。
2.通过任务句柄获取任务控制块(TCB)
任务控制块(TCB)是FreeRTOS中存储任务状态的核心数据结构。通过任务句柄可以直接访问到任务的TCB,从而执行挂起操作。具体步骤如下:
-获取TCB:任务句柄在创建任务时生成,指向该任务的TCB结构。调用vTaskSuspend()时,如果传入的句柄为某个任务的句柄,则会对该任务执行挂起操作。
-挂起当前任务:如果传入的句柄为NULL,则表示挂起当前运行的任务。此时FreeRTOS会自动找到当前任务的TCB,并执行后续的挂起操作。
3.将待挂起的任务从状态列表和事件列表中移除,并插入挂起任务列表
挂起任务涉及将任务从调度器的管理列表中移出并转入挂起列表,以防其继续参与系统的任务调度。具体操作如下:
-移出状态列表:在FreeRTOS中,所有任务根据状态(就绪、阻塞、延时等)被组织在不同的状态列表中。当任务被挂起时,需要将它从这些状态列表中移除,以避免调度器将其视为可调度任务。
-移出事件列表:任务可能因等待事件(如信号量、消息队列等)而被阻塞。挂起操作需要将任务从任何事件等待列表中移出,以确保它不再响应这些事件。
-插入挂起列表:将任务添加到挂起列表中,以便在任务恢复时能够方便地从该列表中移回到就绪列表。
4.若挂起的是当前任务且调度器正在运行,则需要一次任务切换
挂起当前任务时,如果调度器处于运行状态,则需要立即进行任务切换,以确保系统有其他任务可以运行:
-判断调度器状态:首先,FreeRTOS会检查调度器是否正在运行。如果调度器暂停,则挂起当前任务不会触发任务切换;若调度器正在运行,则系统必须在挂起当前任务后立即切换到优先级最高的可运行任务。
-任务切换:一旦确认需要切换任务,FreeRTOS会查找下一个优先级最高的就绪任务,并将其切换到执行状态。这确保了系统不会因为挂起当前任务而停滞,保证实时性。
这一任务切换机制在FreeRTOS中称为“上下文切换”,它确保调度器始终运行优先级最高的任务。
任务恢复的实现
1.确保宏INCLUDE_vTaskSuspend定义为1,恢复的任务不能是当前运行任务
在执行任务恢复时,首先需要确认以下两点:
-启用挂起和恢复功能:INCLUDE_vTaskSuspend宏必须定义为1。它决定了FreeRTOS是否包含和启用任务挂起和恢复功能。如果该宏未定义,编译时将不包含与恢复功能相关的代码,导致恢复API不可用。
-不能恢复当前运行任务:如果试图恢复当前运行的任务,会导致任务行为异常,因为当前任务本身已经处于就绪状态且正在执行。恢复操作应仅作用于挂起状态的任务,因此调用恢复函数时需确保目标任务并非当前任务。
2.检查恢复的任务是否在挂起列表中,若是,则将其移除并添加到就绪列表
任务恢复时,首先需要验证该任务是否确实处于挂起状态:
-挂起列表检查:FreeRTOS将所有挂起任务保存在挂起列表中。当调用恢复函数时,系统会先查找目标任务是否在该列表中,以确保仅对实际被挂起的任务执行恢复操作。
-从挂起列表移除:如果目标任务确实在挂起列表中,则将其移出挂起列表,表示该任务将重新进入调度器的管理,能够再次参与任务调度。
-添加到就绪列表:被移出挂起列表后,目标任务会被添加到就绪列表。就绪列表中包含所有可以立即调度的任务。此时,恢复的任务可以根据其优先级重新参与任务调度。
3.比较恢复任务的优先级与当前任务的优先级,若高于当前任务则触发任务切换
任务恢复后,需要判断是否立即切换到该任务:
-优先级比较:FreeRTOS在恢复任务后会将其优先级与当前任务进行比较。如果恢复的任务优先级高于当前运行的任务,则系统会触发任务切换,以立即执行优先级更高的任务。
-任务切换:如果优先级比较结果需要切换,则系统会触发上下文切换,将CPU控制权交给恢复的高优先级任务。这种任务切换确保了系统始终执行优先级最高的任务,以满足实时性的要求。
通过这些步骤,FreeRTOS实现了对任务恢复的完整操作,确保任务能有效地从挂起状态回到正常调度,且不会影响当前任务的执行逻辑。
通过上述的API解析和实验步骤,相信大家对FreeRTOS任务的挂起与恢复有了更深入的理解。这些操作在嵌入式系统中灵活地管理任务的执行,为实时调度提供了强有力的支持。