收藏 分享(赏)

FreeRTOS任务.doc

上传人:HR专家 文档编号:11572438 上传时间:2020-07-02 格式:DOC 页数:14 大小:34.33KB
下载 相关 举报
FreeRTOS任务.doc_第1页
第1页 / 共14页
FreeRTOS任务.doc_第2页
第2页 / 共14页
FreeRTOS任务.doc_第3页
第3页 / 共14页
FreeRTOS任务.doc_第4页
第4页 / 共14页
FreeRTOS任务.doc_第5页
第5页 / 共14页
点击查看更多>>
资源描述

1、标签: freertos转:FreeRTOS任务管理分析转自:http:/ avr, pic18, coldfire等众多处理器上;目前已经在rtos的市场上占有不少的份额。它当然不是一个与vxworks之类的rtos竞争的操作系统,它的目标在 于低性能小RAM的处理器上。整个系统只有3个文件,外加上port的和处理器相关的两个文件,实现是很简洁的。与ucosii不同,它是free的,ucosii不是free的,虽然它的代码是公开的。FreeRTOS提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理。FreeRTOS内核支持优先级调度算法,每个任务可根据重要程度的不同被赋予一定的优

2、先级,CPU总是让处于就绪态的、 优先级最高的任务先运行。FreeRT0S内核同时支持轮换调度算法,系统允许不同的任务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先级的任务共享CPU的使用时间。这一点是和ucosii不同的。另外一点不同是freertos既可以配置为可抢占内核也可以配置为不可抢占内核。当FreeRTOS被设置为可剥夺型内核时,处于就绪态的高优先级任务能剥夺低优先级任务的CPU使用权,这样可保证系统满足实时性的要求;当FreeRTOS被设置为不可剥夺型内核时,处于就绪态的高优先级任务只有等当前运行任务主动释放CPU的使用权后才能获得运行,这 样可提高CPU的运行效率

3、。这篇文章是以freertos v5.0版本的代码为例子分析下它的任务管理方面的实现。时间关系可能没有太多时间写的很详细了。1.链表管理freertos里面的任务管理,queue,semaphore管理等都借助于双向链表,它定义了个通用的数据结构struct xLIST_ITEM portTickType xItemValue; /链表节点的数据项,通常用在任务延时,表示 /一个任务延时的节拍数 volatile struct xLIST_ITEM * pxNext; /通过这两个成员变量将所有节点 volatile struct xLIST_ITEM * pxPrevious;/链接成双向链

4、表 void * pvOwner; /指向该item的所有者,通常是任务控制块 void * pvContainer; /指向此链表结点所在的链表 ;这个数据结构定义了一个通用的链表节点;下面的数据结构定义了一个双向链表typedef struct xLIST volatile unsigned portBASE_TYPE uxNumberOfItems;/表示该链表中节点的数目 volatile xListItem * pxIndex;/用于遍历链表,指向上次访问的节点 volatile xMiniListItem xListEnd;/链表尾结点 xList;而下面这个数据结构用在xList

5、中,只是为了标记一个链表的尾,是一个markerstruct xMINI_LIST_ITEM portTickType xItemValue; volatile struct xLIST_ITEM *pxNext; volatile struct xLIST_ITEM *pxPrevious;typedef struct xMINI_LIST_ITEM xMiniListItem;对于链表的操作也定义了一系列的函数和宏,在list.c文件中。如初始化个链表,吧一个节点插入链表等。初始化链表:void vListInitialise( xList *pxList ) /* The list st

6、ructure contains a list item which is used to mark the end of the list. To initialise the list the list end is inserted as the only list entry. */ pxList-pxIndex = ( xListItem * ) &( pxList-xListEnd ); /* The list end value is the highest possible value in the list to ensure it remains at the end of

7、 the list. */ pxList-xListEnd.xItemValue = portMAX_DELAY; /* The list end next and previous pointers point to itself so we know when the list is empty. */ pxList-xListEnd.pxNext = ( xListItem * ) &( pxList-xListEnd ); pxList-xListEnd.pxPrevious = ( xListItem * ) &( pxList-xListEnd ); pxList-uxNumber

8、OfItems = 0;把一个节点插入到链表尾部:void vListInsertEnd( xList *pxList, xListItem *pxNewListItem )volatile xListItem * pxIndex; /* Insert a new list item into pxList, but rather than sort the list, makes the new list item the last item to be removed by a call to pvListGetOwnerOfNextEntry. This means it has to

9、be the item pointed to by the pxIndex member. */ pxIndex = pxList-pxIndex; pxNewListItem-pxNext = pxIndex-pxNext; pxNewListItem-pxPrevious = pxList-pxIndex; pxIndex-pxNext-pxPrevious = ( volatile xListItem * ) pxNewListItem; pxIndex-pxNext = ( volatile xListItem * ) pxNewListItem; pxList-pxIndex = (

10、 volatile xListItem * ) pxNewListItem; /* Remember which list the item is in. */ pxNewListItem-pvContainer = ( void * ) pxList; ( pxList-uxNumberOfItems )+;这些就不多说了。2.任务控制块typedef struct tskTaskControlBlock volatile portSTACK_TYPE *pxTopOfStack;/指向堆栈顶xListItem xGenericListItem; /通过它将任务连入就绪链表或者延时链表或者挂

11、起链表中 xListItem xEventListItem;/通过它把任务连入事件等待链表 unsigned portBASE_TYPE uxPriority;/优先级 portSTACK_TYPE *pxStack; /指向堆栈起始位置 signed portCHAR pcTaskName configMAX_TASK_NAME_LEN ; #if ( portCRITICAL_NESTING_IN_TCB = 1 ) unsigned portBASE_TYPE uxCriticalNesting; #endif #if ( configUSE_TRACE_FACILITY = 1 ) u

12、nsigned portBASE_TYPE uxTCBNumber;/用于trace,debug时候提供方便 #endif #if ( configUSE_MUTEXES = 1 ) unsigned portBASE_TYPE uxBasePriority;/当用mutex发生优先级反转时用 #endif #if ( configUSE_APPLICATION_TASK_TAG = 1 ) pdTASK_HOOK_CODE pxTaskTag; #endif tskTCB;其中uxBasePriority用于解决优先级反转,freertos采用优先级继承的办法解决这个问题,在继承时,将任务原

13、先的优先级保存在这个成员中,将来再从这里恢复任务的优先级。3.系统全局变量freertos将任务根据他们的状态分成几个链表。所有就绪状态的任务根据任务优先级加到对应的就绪链表中。系统为每个优先级定义了一个xList。如下:static xList pxReadyTasksLists configMAX_PRIORITIES ; /* Prioritised ready tasks. */此外,所有延时的任务加入到两个延时链表之一。static xList xDelayedTaskList1; static xList xDelayedTaskList2; 还定义了两个指向延时链表的指针:sta

14、tic xList * volatile pxDelayedTaskList; static xList * volatile pxOverflowDelayedTaskList; freertos弄出两个延时链表是因为它的延时任务管理的需要。freertos根据任务延时时间的长短按序将任务插入这两个链表之一。在插入前先把任务将要延时的xTicksToDelay数加上系统当前tick数,这样得到了一个任务延时due time(到期时间)的绝对数值。但是有可能这个相加操作会导致溢出,如果溢出则加入到pxOverflowDelayedTaskList指向的那个链表,否则加入pxDelayedTas

15、kList指向的链表。freertos还定义了个pending链表:static xList xPendingReadyList;这个链表用在调度器被lock(就是禁止调度了)的时期,如果一个任务从非就绪状态变为就绪状态,它不直接加到就绪链表中,而是加到这个pending链表中。等调度器重新启动(unlock)的时候再检查这个链表,把里面的任务加到就绪链表中static volatile xList xTasksWaitingTermination; /* Tasks that have been deleted - but the their memory not yet freed. */

16、static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;一个任务被删除的时候加入到xTasksWaitingTermination链表中,uxTasksDeleted跟中系统中有多少任务被删除(即加到xTasksWaitingTermination链表的任务数目).static xList xSuspendedTaskList; /* Tasks that are currently suspended. */这个链表记录着所有被xTaskSuspend挂起的任务,注意这不是那些等

17、待信号量的任务。static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks;记录了当前系统任务的数目static volatile portTickType xTickCount;是自启动以来系统运行的ticks数static unsigned portBASE_TYPE uxTopUsedPriority;记录当前系统中被使用的最高优先级,static volatile unsigned portBASE_TYPE uxTopReadyPriority;记录当前系统中处于就绪状态的最高优先级。static volatile si

18、gned portBASE_TYPE xSchedulerRunning ;表示当前调度器是否在运行,也即内核是否启动了4.任务管理freertos与ucosii不同,它的任务控制块并不是静态分配的,而是在创建任务的时候动态分配。另外,freertos的优先级是优先级数越大优先级越高,和ucosii正好相反。任务控制块中也没有任务状态的成员变量,这是因为freertos中的任务总是根据他们的状态连入对应的链表,没有必要在任务控制块中维护一个状态。此外freertos对任务的数量没有限制,而且同一个优先级可以有多个任务。先看任务创建:/*参数: pvTaskCode-任务函数名称* pcName

19、-任务名字,可选*ucStackDepth-任务堆栈的深度,即大小* pvParamenters-参数,即传给任务函数的参数,所有的任务函数原型是void task (void *pvParameters)* uxPriority任务优先级* pxCreatedTask可选,通过它返回被创建任务的tcb*/signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameter

20、s, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask )signed portBASE_TYPE xReturn;tskTCB * pxNewTCB;#if ( configUSE_TRACE_FACILITY = 1 ) static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberate - this is guarded before use. */#endif /*动态分配tcb和任务堆栈*/ pxNewTCB = p

21、rvAllocateTCBAndStack( usStackDepth ); /*如果分配成功的话*/ if( pxNewTCB != NULL ) portSTACK_TYPE *pxTopOfStack; /*初始化tcb*/ prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority ); /*计算堆栈的顶*/ #if portSTACK_GROWTH pxStack + ( usStackDepth - 1 ); #else pxTopOfStack = pxNewTCB-pxStack; #endif /* 初始化任务堆栈,并将返回

22、地址保存在tcb中的pxTopOfStack变量*/ pxNewTCB-pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pvTaskCode, pvParameters ); /*关中断*/ portENTER_CRITICAL(); /*更新系统的任务数*/ uxCurrentNumberOfTasks+; if( uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 1 ) /*如果这是系统中第一个任务,则把它设为当前任务*/ pxCurrentTCB = pxNewTCB; /*如果

23、这是系统中的第一个任务,那也就意味着内核刚准备启动,实际上这第一个任务一定是idle任务,这个时候我们要做一些系统初始化,即初始化那些全局链表*/ prvInitialiseTaskLists(); else /* 如果内核还没有运行,则把当前任务设成已经创建的任务中优先级最高的那个,将来内核一旦运行,调度器会马上选择它运行*/ if( xSchedulerRunning = pdFALSE ) if( pxCurrentTCB-uxPriority uxPriority uxTopUsedPriority ) uxTopUsedPriority = pxNewTCB-uxPriority;

24、#if ( configUSE_TRACE_FACILITY = 1 ) /* Add a counter into the TCB for tracing only. */ pxNewTCB-uxTCBNumber = uxTaskNumber; uxTaskNumber+; #endif /*把新创建的任务加到就绪链表*/ prvAddTaskToReadyQueue( pxNewTCB ); xReturn = pdPASS; traceTASK_CREATE( pxNewTCB ); portEXIT_CRITICAL(); /*如果分配内存失败,我们返回错误*/ else xRetu

25、rn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; traceTASK_CREATE_FAILED( pxNewTCB ); if( xReturn = pdPASS ) if( ( void * ) pxCreatedTask != NULL ) /*将新创建任务的tcb返回给调用者 *pxCreatedTask = ( xTaskHandle ) pxNewTCB; /*如果调度器已经运行*/ if( xSchedulerRunning != pdFALSE ) /*如果新创建的任务的优先级高于当前正在运行的任务,则调度 */ if( pxCurrent

26、TCB-uxPriority pxStack = ( portSTACK_TYPE * ) pvPortMalloc( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ); if( pxNewTCB-pxStack = NULL ) /* Could not allocate the stack. Delete the allocated TCB. */ vPortFree( pxNewTCB ); pxNewTCB = NULL; else /* Just to help debugging. */ memset( pxNewTCB

27、-pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) ); return pxNewTCB;再看任务删除。freertos的任务删除分两步完成,第一步在vTaskDelete中完成,FreeRTOS先把要删除的任务从就绪任务链表和事件等待链表中删除,然后把此任务添加到任务删除链表(即那个xTasksWaitingTermination),若删除的任务是当前运行任务,系统就执行任务调度函数.第2步则是在idle任务中完成,idle任务运行时,检查xTasksWaitingTermination链表,如果有任务在

28、这个表上,释放该任务占用的内存空间,并把该任务从任务删除链表中删除。/*参数:pxTaskToDelete是一个指向被删除任务的句柄,这里其实就是等价于任务控制块*如果这个句柄=NULL,则表示要删除当前任务*/void vTaskDelete( xTaskHandle pxTaskToDelete ) tskTCB *pxTCB; taskENTER_CRITICAL(); /* 如果删除的是当前任务,则删除完成后需要进行调度*/ if( pxTaskToDelete = pxCurrentTCB ) pxTaskToDelete = NULL; /*通过传进来的任务句柄得到对应的tcb*/

29、 pxTCB = prvGetTCBFromHandle( pxTaskToDelete ); traceTASK_DELETE( pxTCB ); /* 把任务从就绪链表或者延时链表或者挂起链表中删除*/ vListRemove( &( pxTCB-xGenericListItem ) ); /* 判断任务是否在等待事件(semaphore消息队列等) */ if( pxTCB-xEventListItem.pvContainer ) /如果是,则把它从事件等待链表中删除 vListRemove( &( pxTCB-xEventListItem ) ); /插入等待删除链表 vListIns

30、ertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB-xGenericListItem ) ); /增加uxTasksDeleted计数 +uxTasksDeleted; taskEXIT_CRITICAL(); /*如果调度器已经运行,并且删除的是当前任务,则调度*/ if( xSchedulerRunning != pdFALSE ) if( ( void * ) pxTaskToDelete = NULL ) taskYIELD(); 再看空闲任务做的第2步工作:static portTASK_FUNCTION( prvIdleT

31、ask, pvParameters ) /* Stop warnings. */ ( void ) pvParameters; for( ; ) /* See if any tasks have been deleted. */ prvCheckTasksWaitingTermination(); .这里prvCheckTasksWaitingTermination()就是干这第2步的工作:每次调用它删除一个任务static void prvCheckTasksWaitingTermination( void ) #if ( INCLUDE_vTaskDelete = 1 ) portBASE

32、_TYPE xListIsEmpty; /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called too often in the idle task. */ if( uxTasksDeleted ( unsigned portBASE_TYPE ) 0 ) /禁止调度 vTaskSuspendAll(); xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); /打开调度 xTaskResumeAll(); if( !xListIsEmpty ) tskTCB *pxTCB; /关中断 portENTER_CRITICAL(); pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) ); vListRemove( &( pxTCB-xGenericListItem ) ); -uxCurrentNumberOfTasks;

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

当前位置:首页 > 外语学习 > 英语学习

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报