freeRTOS基础——状态切换

freeRTOS基础

1 任务状态

FreeRTOS任务状态及状态机跳转

FreeRTOS是一个流行的实时操作系统,其核心功能之一是任务管理。任务状态定义了任务在系统中的当前行为,状态机跳转描述了任务在不同状态间的转换规则。下面我将逐步介绍任务状态及其转换机制,确保内容清晰易懂。

1. FreeRTOS任务状态

在FreeRTOS中,任务有五种主要状态,每个状态表示任务的不同执行阶段:

  • 就绪状态(Ready):任务已准备好运行,但尚未被调度器选中执行。任务处于就绪队列中等待CPU资源。
  • 运行状态(Running):任务正在CPU上执行。同一时间,只有一个任务处于此状态(单核系统中)。
  • 阻塞状态(Blocked):任务因等待外部事件(如信号量、队列消息或延时)而暂停执行。任务不会占用CPU资源。
  • 挂起状态(Suspended):任务被显式挂起(例如通过API调用),无法运行,直到被恢复。任务不参与调度。
  • 删除状态(Deleted):任务已被删除,资源被释放。任务不再存在。

这些状态共同构成任务的生命周期,确保系统高效管理资源。
状态跳转如图所示:
在这里插入图片描述

2. 状态机跳转

状态机跳转描述了任务状态间的转换逻辑,由事件或API调用触发。下面用文字描述主要转换路径(类似状态图),并解释转换条件:

  • 从就绪到运行:当调度器选中任务时发生。例如,高优先级任务进入就绪状态后,如果CPU空闲,会立即跳转到运行状态。
  • 从运行到就绪:任务被更高优先级任务抢占时发生。调度器强制当前任务退出运行状态,返回就绪队列。
  • 从运行到阻塞:任务调用阻塞API(如vTaskDelay()xQueueReceive())时触发。任务等待事件完成,例如延时结束或队列数据到达。
  • 从阻塞到就绪:当等待的事件发生时(如延时结束或信号量释放),任务自动退出阻塞状态,进入就绪队列。
  • 从运行到挂起:任务调用挂起API(如vTaskSuspend())时触发。任务被手动暂停,不再参与调度。
  • 从挂起到就绪:任务调用恢复API(如vTaskResume())时触发。任务重新加入就绪队列。
  • 从运行或就绪到删除:任务调用删除API(如vTaskDelete())时触发。任务资源被释放,状态变为删除。
  • 其他转换:例如,从阻塞到挂起(通过API强制挂起阻塞任务),但较少见。

状态跳转示例流程:

  • 任务启动时通常进入就绪状态。
  • 调度器选中后跳转到运行状态。
  • 如果任务需要延时,调用vTaskDelay()进入阻塞状态。
  • 延时结束后,自动返回就绪状态。
  • 任务完成后,调用vTaskDelete()进入删除状态。
3. 代码示例

以下C代码展示了FreeRTOS API如何触发状态跳转。代码中,任务从运行状态转换到阻塞状态(通过延时),然后恢复运行。

#include "FreeRTOS.h"
#include "task.h"

void vExampleTask(void *pvParameters) {
    while (1) {
        // 任务处于运行状态
        // 执行一些操作...

        // 触发运行到阻塞的跳转:调用vTaskDelay()等待1000个tick
        vTaskDelay(1000 / portTICK_PERIOD_MS);  // 延时期间任务进入阻塞状态

        // 事件(延时结束)后,任务自动从阻塞跳转到就绪,再被调度为运行状态
    }
}

int main() {
    // 创建任务,初始状态为就绪
    xTaskCreate(vExampleTask, "ExampleTask", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    vTaskStartScheduler();  // 启动调度器
    return 0;
}
  • 关键API说明
    • vTaskDelay():使任务阻塞指定时间。
    • vTaskSuspend():手动挂起任务。
    • vTaskResume():恢复挂起的任务。
    • vTaskDelete():删除任务。
4. 空闲任务和钩子函数
4.1 介绍

空闲任务的作用之一:释放被删除的任务的内存。
为什么必须要有空闲任务?一个良好的程序,它的任务都是事件驱动的:大部分时间处于阻塞状态。可能我们自己创建的所有任务都无法执行,但是调度器必须找到一个可以运行的任务,所以,我们需要提供空闲任务。在使用vTaskStartScheduler()函数来创建,启动调度器时,这个函数内部会创建空闲任务:

  • 空闲任务优先级为0:它不能阻碍用户任务运行

  • 空闲任务要么处于就绪态,要么处于运行态,永远不会阻塞

空闲任务的优先级为0,这意味着一旦某个用户的任务变为就绪态,那么空闲任务马上被切换出去,让这个用户任务运行。在这种情况下,我们说用户任务"抢占"(pre-empt)了空闲任务,这是由调度器实现的。

要注意的是:如果使用vTaskDelete()来删除任务,那么你就要确保空闲任务有机会执行,否则就无法释放被删除任务的内存。
我们可以添加一个空闲任务的钩子函数(Idle Task Hook Functions),空闲任务的循环每执行一次,就会调用一次钩子函数。钩子函数的作用有这些:

  • 执行一些低优先级的、后台的、需要连续执行的函数
  • 测量系统的空闲时间:空闲任务能被执行就意味着所有的高优先级任务都停止了,所以测量空闲任务占据的时间,就可以算出处理器占用率。
  • 让系统进入省电模式:空闲任务能被执行就意味着没有重要的事情要做,当然可以进入省电模式了。
  • 空闲任务的钩子函数的限制:
  • 不能导致空闲任务进入阻塞状态、暂停状态
  • 如果你会使用vTaskDelete()来删除任务,那么钩子函数要非常高效地执行。如果空闲任务移植卡在钩子函数里的话,它就无法释放内存。
4.2 使用钩子函数前提

在FreeRTOS\Source\tasks.c中,可以看到如下代码,所以前提就是

  • 把这个宏定义为1:configUSE_IDLE_HOOK
  • 实现vApplicationIdleHook函数
    在这里插入图片描述
4. 总结

FreeRTOS的任务状态机确保了实时性和资源高效利用。状态跳转基于事件驱动:

  • 就绪、运行和阻塞状态是动态转换核心。
  • 挂起和删除状态用于管理任务生命周期。
    理解这些状态及其转换,有助于优化任务调度和系统性能。例如,避免任务长时间阻塞可提升响应速度。

参考链接
https://rtos.100ask.net/zh/FreeRTOS/DShanMCU-F103/chapter9.html#_9-7-1-%E4%BB%8B%E7%BB%8D

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值