FreeRTOS从代码层面进行原理分析(1 任务的建立)

FreeRTOS_分析

FreeRTOS 是一个开源的实时操作系统。可以在很的低内存使用的情况下运行在单片机上,使得单片机可以并发(虽然某一时刻还是只有一个任务运行) 的运行程序。关于一些 FreeRTOS 优缺点的介绍文章很多,这里就不再赘述直接深入代码探究原理。

关于 FreeRTOS 的疑问

在刚接触 FreeRTOS 的时候我是有以下几个问题的。
1. FreeRTOS 是如何建立任务的呢?
2. FreeRTOS 是调度和切换任务的呢?
3. FreeRTOS 是如何保证实时性呢?

这篇就是对第一个问题,FreeRTOS 是如何建立任务从代码上进行分析。

在 FreeRTOS 官方的指南上对创建任务就是调用了 xTaskCreate 函数。下面的图截取与官方的教程,里面对 xTaskCreate 函数的用法进行了展示,并对参数也进行了大体上的介绍。

在这里插入图片描述

xTaskCreate 函数分析

这个函数被包含在 FreeRTOS 代码的 task.c 中。这个函数比较长,下面贴出的函数对里面的内容进行了省略。

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                            const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                            const configSTACK_DEPTH_TYPE usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask )
    {
   
   
        TCB_t * pxNewTCB;
        BaseType_t xReturn;

            /* Allocate space for the TCB.  Where the memory comes from depends on
             * the implementation of the port malloc function and whether or not static
             * allocation is being used. */
            pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
            ...
            pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocStack( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); 
        ...
        prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
        prvAddNewTaskToReadyList( pxNewTCB );
        xReturn = pdPASS;

从代码中很容易看出,xTaskCreate 函数主要的工作就是 3 步。

第1步 给新的任务申请空间

pvPortMalloc 函数,其作用是给新的任务申请一块任务控制块(TCB, Task Control Block)空间。后面继续使用 pvPortMallocStack 函数为新的任务申请一块栈空间。 其具体的实现在 heapX.c 中 X 可以是1~5。相关的细节可以看一下相关的介绍,这里的2个用于申请空间的函数可以简单的看作是 malloc 函数就可以了。

第2步 为新任务初始化空间

prvInitialiseNewTask 函数也很长,故省略里面很多的内容。专注于实现逻辑,先放弃具体细节。

static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
                                  const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                                  const uint32_t ulStackDepth,
                                  void * const pvParameters,
                                  UBaseType_t uxPriority,
                                  TaskHandle_t * const pxCreatedTask,
                                  TCB_t * pxNewTCB,
                                  const MemoryRegion_t * const xRegions )
### FreeRTOS 任务调度原理 #### 就绪链表的作用 在FreeRTOS中,任务的调度紧密依赖于一个全局的就绪链表。该链表用于跟踪所有处于就绪状态的任务,并按照优先级顺序排列这些任务[^1]。 #### 可剥夺型内核的工作方式 当FreeRTOS被配置为可剥夺型内核时,在任何时刻如果有更高优先级的任务进入就绪态,则当前正在运行较低优先级的任务会被立即挂起并切换至新的高优先级任务继续执行。这种机制确保了系统的实时响应能力。 #### 同等优先级下的轮转调度 对于具有相同优先级的任务而言,FreeRTOS采用时间片轮转的方式让它们依次获得CPU资源来执行。这意味着即使多个同级别重要性的进程存在竞争关系也能公平分配处理机时间[^2]。 #### 不同优先级任务的竞争逻辑 一旦有更高级别的线程变为可用状态(即从等待转变为准备),它将会打断现有活动中的较次级别的程序流而取得控制权;反之如果仅有低等级成员处于活跃状况下则不会影响到其他较高层次者正常运作直至前者完成其周期或再次陷入阻塞为止。 #### 调度器初始化与空闲任务 为了保证至少始终有一个有效的实体可供选择作为下一个要激活的对象,系统会在启动初期自动生成所谓的“空闲”实例——这是一种特殊类型的后台服务进程,默认情况下它的权限设定位于整个体系结构最底层位置上。每当没有任何用户定义的应用层组件准备好接管计算单元之前,“空闲”的循环体就会持续占用着核心直到接收到中断信号或者其他形式的通知提示出现了更适合担任前台角色的新候选名单成员出现[^3]。 ```c // 下面是一个简化版的FreeRTOS调度函数伪代码表示: void vTaskSwitchContext(void) { // 获取最高优先级非空列表的第一个节点 UBaseType_t uxTopReadyPriority; do { pxCurrentTCB = NULL; /* 初始化 */ // 遍历各个优先级队列寻找第一个非空项 for (uxTopReadyPriority = ( configMAX_PRIORITIES - 1 ); uxTopReadyPriority > tskIDLE_PRIORITY; --uxTopReadyPriority ) { if ( listLIST_IS_EMPTY(&(pxReadyTasksLists[uxTopReadyPriority])) == pdFALSE ) { break; } } // 如果找到合适的候选项, 更新当前上下文指针指向新选中的 TCB 结构. if(pxCurrentTCB != NULL){ taskSWITCH_CONTEXT(pxCurrentTCB); }else{ // 若无合适的选择, 则默认回到 IDLE Task 上去. portYIELD(); } } while(0); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值