FreeRTOS任务.docx

上传人:b****5 文档编号:7198343 上传时间:2023-01-21 格式:DOCX 页数:16 大小:23.58KB
下载 相关 举报
FreeRTOS任务.docx_第1页
第1页 / 共16页
FreeRTOS任务.docx_第2页
第2页 / 共16页
FreeRTOS任务.docx_第3页
第3页 / 共16页
FreeRTOS任务.docx_第4页
第4页 / 共16页
FreeRTOS任务.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

FreeRTOS任务.docx

《FreeRTOS任务.docx》由会员分享,可在线阅读,更多相关《FreeRTOS任务.docx(16页珍藏版)》请在冰豆网上搜索。

FreeRTOS任务.docx

FreeRTOS任务

标签:

freertos  

转:

FreeRTOS任务管理分析

转自:

是一个轻量级的rtos,它目前实现了一个微内核,并且port到arm7,avr,pic18,coldfire等众多处理器上;目前已经在rtos的市场上占有不少的份额。

它当然不是一个与vxworks之类的rtos竞争的操作系统,它的目标在于低性能小RAM的处理器上。

整个系统只有3个文件,外加上port的和处理器相关的两个文件,实现是很简洁的。

与ucosii不同,它是free的,ucosii不是free的,虽然它的代码是公开的。

FreeRTOS提供的功能包括:

任务管理、时间管理、信号量、消息队列、内存管理。

FreeRTOS内核支持优先级调度算法,每个任务可根据重要程度的不同被赋予一定的优先级,CPU总是让处于就绪态的、优先级最高的任务先运行。

FreeRT0S内核同时支持轮换调度算法,系统允许不同的任务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先级的任务共享CPU的使用时间。

这一点是和ucosii不同的。

另外一点不同是freertos既可以配置为可抢占内核也可以配置为不可抢占内核。

当FreeRTOS被设置为可剥夺型内核时,处于就绪态的高优先级任务能剥夺低优先级任务的CPU使用权,这样可保证系统满足实时性的要求;当FreeRTOS被设置为不可剥夺型内核时,处于就绪态的高优先级任务只有等当前运行任务主动释放CPU的使用权后才能获得运行,这样可提高CPU的运行效率。

这篇文章是以freertos版本的代码为例子分析下它的任务管理方面的实现。

时间关系可能没有太多时间写的很详细了。

1.链表管理

freertos里面的任务管理,queue,semaphore管理等都借助于双向链表,它定义了个通用的数据结构

structxLIST_ITEM

{

   portTickTypexItemValue;Toinitialisethelistthelistendisinserted

   astheonlylistentry.*/

   pxList->pxIndex=(xListItem*)&(pxList->xListEnd);

   /*Thelistendvalueisthehighestpossiblevalueinthelistto

   ensureitremainsattheendofthelist.*/

   pxList->=portMAX_DELAY;

   /*Thelistendnextandpreviouspointerspointtoitselfsoweknow

   whenthelistisempty.*/

   pxList->=(xListItem*)&(pxList->xListEnd);

   pxList->=(xListItem*)&(pxList->xListEnd);

   pxList->uxNumberOfItems=0;

}

把一个节点插入到链表尾部:

voidvListInsertEnd(xList*pxList,xListItem*pxNewListItem)

{

volatilexListItem*pxIndex;

   /*InsertanewlistitemintopxList,butratherthansortthelist,

   makesthenewlistitemthelastitemtoberemovedbyacallto

   pvListGetOwnerOfNextEntry. Thismeansithastobetheitempointedtoby

   thepxIndexmember.*/

   pxIndex=pxList->pxIndex;

   pxNewListItem->pxNext=pxIndex->pxNext;

   pxNewListItem->pxPrevious=pxList->pxIndex;

   pxIndex->pxNext->pxPrevious=(volatilexListItem*)pxNewListItem;

   pxIndex->pxNext=(volatilexListItem*)pxNewListItem;

   pxList->pxIndex=(volatilexListItem*)pxNewListItem;

   /*Rememberwhichlisttheitemisin.*/

   pxNewListItem->pvContainer=(void*)pxList;

   (pxList->uxNumberOfItems)++;

}

这些就不多说了。

 

2.任务控制块

typedefstructtskTaskControlBlock

{

      volatileportSTACK_TYPE    *pxTopOfStack;统全局变量

freertos将任务根据他们的状态分成几个链表。

所有就绪状态的任务根据任务优先级加到对应的就绪链表中。

系统为每个优先级定义了一个xList。

如下:

staticxListpxReadyTasksLists[configMAX_PRIORITIES];   /*

此外,所有延时的任务加入到两个延时链表之一。

staticxListxDelayedTaskList1;                                       

staticxListxDelayedTaskList2;    

还定义了两个指向延时链表的指针:

staticxList*volatilepxDelayedTaskList;                         

staticxList*volatilepxOverflowDelayedTaskList;                 

freertos弄出两个延时链表是因为它的延时任务管理的需要。

freertos根据任务延时时间的长短按序将任务插入这两个链表之一。

在插入前先把任务将要延时的xTicksToDelay数加上系统当前tick数,这样得到了一个任务延时duetime(到期时间)的绝对数值。

但是有可能这个相加操作会导致溢出,如果溢出则加入到pxOverflowDelayedTaskList指向的那个链表,否则加入pxDelayedTaskList指向的链表。

freertos还定义了个pending链表:

staticxListxPendingReadyList;

这个链表用在调度器被lock(就是禁止调度了)的时期,如果一个任务从非就绪状态变为就绪状态,它不直接加到就绪链表中,而是加到这个pending链表中。

等调度器重新启动(unlock)的时候再检查这个链表,把里面的任务加到就绪链表中

 

staticvolatilexListxTasksWaitingTermination;           /*

staticvolatileunsignedportBASE_TYPEuxTasksDeleted=(unsignedportBASE_TYPE)0;

一个任务被删除的时候加入到xTasksWaitingTermination链表中,uxTasksDeleted跟中系统中有多少任务被删除(即加到xTasksWaitingTermination链表的任务数目).

staticxListxSuspendedTaskList;                              /*

这个链表记录着所有被xTaskSuspend挂起的任务,注意这不是那些等待信号量的任务。

 

staticvolatileunsignedportBASE_TYPEuxCurrentNumberOfTasks;记录了当前系统任务的数目

staticvolatileportTickTypexTickCount;是自启动以来系统运行的ticks数

staticunsignedportBASE_TYPEuxTopUsedPriority;记录当前系统中被使用的最高优先级,

staticvolatileunsignedportBASE_TYPEuxTopReadyPriority;记录当前系统中处于就绪状态的最高优先级。

staticvolatilesignedportBASE_TYPExSchedulerRunning ;表示当前调度器是否在运行,也即内核是否启动了

 

4.任务管理

freertos与ucosii不同,它的任务控制块并不是静态分配的,而是在创建任务的时候动态分配。

另外,freertos的优先级是优先级数越大优先级越高,和ucosii正好相反。

任务控制块中也没有任务状态的成员变量,这是因为freertos中的任务总是根据他们的状态连入对应的链表,没有必要在任务控制块中维护一个状态。

此外freertos对任务的数量没有限制,而且同一个优先级可以有多个任务。

 

先看任务创建:

/***************************************************************

**参数:

pvTaskCode---任务函数名称

**pcName---任务名字,可选

**ucStackDepth---任务堆栈的深度,即大小

**pvParamenters---参数,即传给任务函数的参数,所有的任务函数原型是voidtask(void*pvParameters)

**uxPriority—任务优先级

**pxCreatedTask—可选,通过它返回被创建任务的tcb

*******************************************************************/

signedportBASE_TYPExTaskCreate(pdTASK_CODEpvTaskCode,constsignedportCHAR*constpcName,unsignedportSHORTusStackDepth,void*pvParameters,unsignedportBASE_TYPEuxPriority,xTaskHandle*pxCreatedTask)

{

signedportBASE_TYPExReturn;

tskTCB*pxNewTCB;

#if(configUSE_TRACE_FACILITY==1)

      staticunsignedportBASE_TYPEuxTaskNumber=0;/*lint!

e956Staticisdeliberate-thisisguardedbeforeuse.*/

#endif

 

      /*动态分配tcb和任务堆栈*/

      pxNewTCB=prvAllocateTCBAndStack(usStackDepth);

  /*如果分配成功的话*/

      if(pxNewTCB!

=NULL)

      {           

             portSTACK_TYPE*pxTopOfStack;

       /*初始化tcb*/

             prvInitialiseTCBVariables(pxNewTCB,pcName,uxPriority);

 

             /*计算堆栈的顶*/

             #ifportSTACK_GROWTH<0

             {

                    pxTopOfStack=pxNewTCB->pxStack+(usStackDepth-1);

             }

             #else

             {

                    pxTopOfStack=pxNewTCB->pxStack;     

             }

             #endif

 

             /*初始化任务堆栈,并将返回地址保存在tcb中的pxTopOfStack变量*/

             pxNewTCB->pxTopOfStack=pxPortInitialiseStack(pxTopOfStack,pvTaskCode,pvParameters);

 

             /*关中断*/

             portENTER_CRITICAL();

             {/*更新系统的任务数*/

                    uxCurrentNumberOfTasks++;

                    if(uxCurrentNumberOfTasks==(unsignedportBASE_TYPE)1)

                    {

                           /*如果这是系统中第一个任务,则把它设为当前任务*/

                           pxCurrentTCB= pxNewTCB;

                           /*如果这是系统中的第一个任务,那也就意味着内核刚准备启动,实际上这第一个任务一定是idle任务,这个时候我们要做一些系统初始化,即初始化那些全局链表*/

                           prvInitialiseTaskLists();

                    }

                    else

                    {    

                           /*如果内核还没有运行,则把当前任务设成已经创建的任务中优先级最高的那个,将来内核一旦运行,调度器会马上选择它运行*/

                           if(xSchedulerRunning==pdFALSE)

                           {

                                  if(pxCurrentTCB->uxPriority<=uxPriority)

                                  {

                                         pxCurrentTCB=pxNewTCB;      

                                  }

                           }

                    }                         

 

                    /*我们记录下当前使用的最高优先级,这为了方便任务调度*/

                    if(pxNewTCB->uxPriority>uxTopUsedPriority)

                    {

                           uxTopUsedPriority=pxNewTCB->uxPriority;

                    }

                    #if(configUSE_TRACE_FACILITY==1)

                   {

                           /*AddacounterintotheTCBfortracingonly.*/

                           pxNewTCB->uxTCBNumber=uxTaskNumber;

                           uxTaskNumber++;

                    }

                    #endif

                    /*把新创建的任务加到就绪链表*/

                    prvAddTaskToReadyQueue(pxNewTCB);

                    xReturn=pdPASS;

                    traceTASK_CREATE(pxNewTCB);

             }

            portEXIT_CRITICAL();

      }

/*如果分配内存失败,我们返回错误*/

      else

      {

             xReturn=errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;

             traceTASK_CREATE_FAILED(pxNewTCB);

      }

 

      if(xReturn==pdPASS)

      {

             if((void*)pxCreatedTask!

=NULL)

             {

                    /*将新创建任务的tcb返回给调用者

                    *pxCreatedTask=(xTaskHandle)pxNewTCB;

             }

       /*如果调度器已经运行*/

             if(xSchedulerRunning!

=pdFALSE)

             {

                    /*如果新创建的任务的优先级高于当前正在运行的任务,则调度*/

                    if(pxCurrentTCB->uxPriority

                    {

                           taskYIELD();

                    }

             }

      }

 

      returnxReturn;

}

其中prvAllocateTCBAndStack分配tcb和stack内存,这个里面调用了pvportMalloc和pvPortFree函数来分配和释放内存,这两个函数对应于C标准库里面的malloc和free。

但是标准库中的mallo和free存在以下缺点:

并不是在所有的嵌入式系统中都可用,要占用不定的程序空间,可重人性欠缺以及执行时间具有不可确定性,而且多次反复调用可能导致严重的内存碎片。

因此freertos在内存管理那块自己实现了这两个函数。

statictskTCB*prvAllocateTCBAndStack(unsignedportSHORTusStackDepth)

{

tskTCB*pxNewTCB;

 

      /*AllocatespacefortheTCB. Wherethememorycomesfromdependson

      theimplementationoftheportmallocfunction.*/

      pxNewTCB=(tskTCB*)pvPortMalloc(sizeof(tskTCB));

 

      if(pxNewTCB!

=NULL)

      {

             /*Allocatespaceforthestackusedbythetaskbeingcreated.

             ThebaseofthestackmemorystoredintheTCBsothetaskcan

             bedeletedlaterifrequired.*/

             pxNewTCB->pxStack=(portSTACK_TYPE*)pvPortMalloc(((size_t)usStackDepth)*sizeof(portSTACK_TYPE));

 

             if(pxNewTCB->pxStack==NULL)

             {

                    /*Couldnotallocatethestack. DeletetheallocatedTCB.*/

                    vPortFree(pxNewTCB);                   

                    pxNewTCB=NULL;                  

             }           

             else

             {

                    /*Justtohelpdebugging.*/

                    memset(pxNewTCB->pxStack,tskSTACK_FILL_BYTE,usStackDepth*sizeof(portSTACK_TYPE));

             }

      }

 

      returnpxNewTCB;

}

 

再看任务删除

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 工作计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1