实时操作系统之任务
任务可以以下列状态之一存在:
- 运行
当任务实际执行时,它被称为处于运行状态。它目前正在使用处理器。如果运行RTOS的处理器只有一个内核,那么在任何给定时间只能有一个处于运行状态的任务。
- 准备
就绪任务是那些能够执行的任务(它们不处于“阻塞”或“挂起”状态),但当前未执行,因为具有相同或更高优先级的不同任务已处于“正在运行”状态。
- 阻止
如果任务目前正在等待时间或外部事件,则说该任务处于阻塞状态。例如,如果任务调用vTaskDelay(),它将阻塞(置于阻塞状态)直到延迟时间到期 - 一个时间事件。任务也可以阻塞以等待队列,信号量,事件组,通知或信号量事件。处于阻塞状态的任务通常有一个“超时”时间段,在此之后,任务将超时,并且即使未发生任务等待的事件也会被解除阻塞。
处于阻塞状态的任务不使用任何处理时间,并且不能选择进入运行状态。
- 暂停
与处于阻塞状态的任务类似,处于暂停状态的任务不能被选择为进入运行状态,但处于暂停状态的任务不会超时。相反,只有通过分别通过vTaskSuspend()和xTaskResume()API调用显式指令才能进入或退出暂停状态。
有效的任务状态转换
任务优先级
每个任务都分配了一个从0到(configMAX_PRIORITIES - 1)的优先级,其中configMAX_PRIORITIES在FreeRTOSConfig.h中定义。
如果正在使用的端口实现了使用“计数前导零”类型指令(用于在单条指令中进行任务选择)的端口优化任务选择机制,并且FreeRTOSConfig.h中的configUSE_PORT_OPTIMISED_TASK_SELECTION设置为1,则configMAX_PRIORITIES不能高于32。在所有其他情况下,configMAX_PRIORITIES可以在合理范围内使用任何值 - 但由于RAM使用效率的原因应保持在实际所需的最小值。
低优先级数字表示低优先级任务。该空闲任务的优先级为零(tskIDLE_PRIORITY)。
FreeRTOS调度程序确保处于“就绪”或“正在运行” 状态的任务始终获得处理器(CPU)时间,优先于处于就绪状态的较低优先级任务。换句话说,放置到运行状态的任务始终是能够运行的最高优先级任务。
任何数量的任务都可以共享相同的优先级。如果未定义configUSE_TIME_SLICING,或者将configUSE_TIME_SLICING设置为1,则等待优先级的就绪状态任务将使用时间片循环调度方案共享可用处理时间。
实施一项任务
任务应该具有以下结构:
void vATaskFunction(void * pvParameters) { for(;;) { - 这里的任务应用代码。 - } / *任务不得试图从其实施中返回 功能或其他退出。在较新的FreeRTOS端口 试图这样做将导致configASSERT()是 如果它被定义,则称为。如果有必要完成任务 退出然后让任务调用vTaskDelete(NULL)来确保 它的出口很干净。* / vTaskDelete(NULL); }TaskFunction_t类型被定义为一个返回void的函数,并将void指针作为其唯一参数。所有实现任务的功能都应该是这种类型的。该参数可用于将任何类型的信息传递到任务中 - 这由几个 标准演示应用程序任务演示。
任务函数不应该返回,因此通常以连续循环的形式实现。同样,请参阅RTOS演示应用程序以获取大量示例。
任务通过调用xTaskCreate()或xTaskCreateStatic()来创建,并通过调用vTaskDelete()来删除。
任务创建宏
任务功能可以任选地使用portTASK_FUNCTION和portTASK_FUNCTION_PROTO宏定义。提供这些宏以允许将编译器特定的语法分别添加到函数定义和原型。除非在正在使用的端口的文档(目前仅限于PIC18 fedC端口)中特别声明,否则不需要使用它们。
上面显示的功能原型可以写成:
void vATaskFunction(void * pvParameters);要么,
portTASK_FUNCTION_PROTO(vATaskFunction,pvParameters);同样,上面的函数也可以写成:
portTASK_FUNCTION(vATaskFunction,pvParameters) { for(;;) { - 这里的任务应用代码。 - } }
空闲任务
当RTOS调度程序启动时,空闲任务会自动创建,以确保总是有至少一个能够运行的任务。如果在就绪状态下有更高优先级的应用程序任务,它将以尽可能最低的优先级创建,以确保它不使用任何CPU时间。
空闲任务负责将由RTOS分配的内存释放到已被删除的任务。因此,在使用vTaskDelete()函数来确保空闲任务不会处理时间不足的应用程序中非常重要。空闲任务没有其他主动功能,所以在所有其他条件下可以合理地使微控制器时间减少。
应用程序任务可以共享空闲任务优先级(tskIDLE_PRIORITY)。有关如何配置此行为的信息,请参阅configIDLE_SHOULD_YIELD 配置参数。
空闲任务钩子
空闲任务挂钩是在空闲任务的每个周期中被调用的函数。如果您希望应用程序功能以空闲优先级运行,则有两种选择:- 在空闲任务挂钩中实现功能。
必须至少有一个任务已准备好运行。因此,hook函数不会调用可能导致空闲任务阻塞的任何API函数(例如,vTaskDelay()或具有阻塞时间的队列或信号量函数)。协同例程在钩子函数中被阻塞是可以的。
- 创建一个空闲优先级任务来实现该功能。
这是一个更灵活的解决方案,但具有更高的RAM使用开销。
要创建一个闲置钩子:
- 在FreeRTOSConfig.h中将configUSE_IDLE_HOOK设置为1 。
- 定义一个具有以下名称和原型的函数:
void vApplicationIdleHook(void);