【STM32与FreeRTOS】任务管理详解
使用 RTOS 的实时应用程序可以被构建为一组独立的任务。每个任务在自己的上下文中执行,不依赖于系统内的其他任务或 RTOS 调度器本身。在任何时间点,应用程序中只能执行一个任务,实时 RTOS 调度器负责决定所要执行的任务。因此, RTOS 调度器可以在应用程序执行时重复启停每个任务(将任务调入或调出)。由于任务不了解 RTOS 调度器活动,因此实时 RTOS 调度器负责确保任务调入时的处理器上下文(寄存器值、堆栈内容等)与任务调出时的处理器上下文完全相同。为实现这一点,每个任务都分配有自己的堆栈。当任务调出时,执行上下文被保存到该任务的堆栈中,以便以后再调入相同的任务时可以准确地恢复其执行上下文。
任务状态
FreeRTOS中任务共有4中状态:

任务调度
FreeRTOS一共支持三种任务调度方式:
“时间片” 是指调度器会在每个 tick 中断上在同等优先级任务之间进行切换, tick 中断之间的时间构成一个时间片。(tick 中断是 RTOS 用来衡量时间的周期性中断。)
总是运行优先级最高且可运行的任务的后果是, 永远不会进入“阻塞”或 “挂起”状态的高优先级任务会让所有任意执行时长的低优先级任务永久饥饿 。这就是为什么通常最好创建事件驱动型任务的原因之一 。例如,如果一个高优先级任务正在等待一个事件, 那么它就不应处于该事件的循环(轮询)中,因为如果处于轮询中,它会一直运行,永远不进入“阻塞”或“挂起”状态。 反之,该任务应进入“阻塞” 状态来等待事件。可以使用众多 FreeRTOS 任务间通信和同步原语之一将事件发送给任务。接收到 事件后, 优先级更高的任务会自动解除“阻塞”状态。高优先级任务处于“阻塞”状态时, 低优先级任务会运行。
动态创建任务和删除任务
#define configSUPPORT_DYNAMIC_ALLOCATION 1
上述宏定义配置为1的时候,才支持动态创建。
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE uxStackDepth,
void *pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask
);
创建一项新任务的时候,会将其添加到就绪任务列表中。
void vTaskDelete( TaskHandle_t xTask );
从RTOS内核管理中删除任务时,要删除的任务将从所有就绪、阻塞、挂起和事件列表中移除。空闲任务负责释放由RTOS内核分配给已删除任务的内存。因此,如果应用程序调用了vTaskDelete,请务必确保空闲任务获取足够的微控制器处理时间。任务代码分配的内存不会自动释放,应在任务删除之前手动释放。
任务的挂起和恢复
void vTaskSuspend( TaskHandle_t xTaskToSuspend );
挂起的任务将无法获取任何微控制器处理时间。对vTaskSuspend的调用不会累计计数,若在同一任务上调用多次,仍然仅需调用一次vTaskResume,即可恢复挂起的任务。
void vTaskResume( TaskHandle_t xTaskToResume );
BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume );
返回:
portYIELD_FROM_ISR(x)
调用此函数进行任务上下文切换,传入参数不为pdFALSE时,就执行上下文切换函数。
注意:任务挂起就是相当于暂停,任务恢复就是继续执行。所以任务恢复的时候不是说在任务函数中从头开始。
其他
临界段代码保护
临界段:也叫做临界区,是指那些必须完整运行,不能被打断的代码段。
适用场合如:
那么,什么东西可以打断当前的程序呢?有中断,有系统任务调度器。其实任务调度器也是在PendSV中断函数中调用的,所以如果关闭中断,就没有东西可以打断程序了。
本质:FreeRTOS在进入临界段代码的时候其实是关闭中断,当处理完临界段代码以后再打开中断。
void taskENTER_CRITICAL( void );
void taskEXIT_CRITICAL( void );
UBaseType_t taskENTER_CRITICAL_FROM_ISR( void );
void taskEXIT_CRITICAL_FROM_ISR( UBaseType_t uxSavedInterruptStatus );
任务调度器的挂起和恢复
挂起任务调度器,调用此函数不需要关闭中断。
void vTaskSuspendAll( void );
BaseType_t xTaskResumeAll( void );
作者:heater404