FreeRTOS个人笔记-列表与列表项

根据个人的学习方向,学习FreeRTOS。由于野火小哥把FreeRTOS讲得比较含蓄,打算在本专栏尽量细化一点。作为个人笔记,仅供参考或查阅。

配套资料:FreeRTOS内核实现与应用开发实战指南、野火FreeRTOS配套视频源码、b站野火FreeRTOS视频。搭配来看更佳哟!!!         

提示一下,FreeRTOS针对不同的处理器,对标准C的数据类型进行了重定义。并且一般命名有规范,对变量名、函数名以及宏一般会在加上一下前缀。

/* 数据类型重定义 */
#define portCHAR		char
#define portFLOAT		float
#define portDOUBLE		double
#define portLONG		long
#define portSHORT		short
#define portSTACK_TYPE	uint32_t
#define portBASE_TYPE	long

typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;

对于变量名,加前缀:数据类型缩写(一个或以上)。

前缀原型 符号
char c
short s
long l
结构体,数据结构,任务句柄,队列句柄等 x
无符号unsigned u
指针 p

对于函数名,加前缀:返回值类型、所在文件名、函数功能。如prv代表private(私有)的前缀。

void vTaskPrioritySet()代表返回值为void,在task.c文件定义。

xQueueReceive()代表返回值为portBASE_TYPE,在queue.c文件定义。        

vSemaphoreCreateBinary()代表返回值为void,在semaphr.h文件定义。

对于宏,加前缀:哪个头文件定义。

前缀 宏定义的文件
port(如portMAX_DELAY) portable.h
task(如taskENTER_CRITICAL()) task.h
pd(如pdTRUE) projdefs.h
config(如configUSE_PREEMPTION) FreeRTOSConfig.h
err(如errQUEUE_FULL) projdefs.h

注意一下

实际值
pdTRUE 1
pdFALSE 0
pdPASS 1
pdFALL 0

列表与列表项

主要围绕节点与链表展开。节点=列表,链表=列表项。

结构体

节点结构体

struct xLIST_ITEM
{
	TickType_t 			 	xItemValue;   /* 数值,每个节点都有,用于链表排序(一般升序) */			
	struct xLIST_ITEM *  	pxNext;       /* 指向链表下一个节点 */		
	struct xLIST_ITEM *  	pxPrevious;   /* 指向链表前一个节点 */	
	void * 				 	pvOwner;	  /* 指向拥有该节点的内核对象,通常是TCB(任务控制块) 。每个节点都有一个TCB,用于任务调度*/
	void * 				 	pvContainer;  /* 指向该节点所在的链表,即记录当前所处链表 */
};
typedef struct xLIST_ITEM 	ListItem_t;   /* 节点数据类型重定义 */

mini节点结构体,即尾节点结构体

/* mini节点结构体定义,作为双向链表的结尾。因为双向链表是首尾相连的,头即是尾,尾即是头 */
struct xMINI_LIST_ITEM
{
	TickType_t 				xItemValue;   /* 数值,每个节点都有,用于链表排序(一般升序) */
	struct xLIST_ITEM * 	pxNext;       /* 指向链表下一个节点 */
	struct xLIST_ITEM * 	pxPrevious;   /* 指向链表前一个节点 */
};	
typedef struct xMINI_LIST_ITEM MiniListItem_t;  /* 最小节点数据类型重定义 */

链表根节点,即链表结构体

/* 链表结构体定义 */
typedef struct xLIST
{
	UBaseType_t 	uxNumberOfItems;    /* 链表节点计数器 */
	ListItem_t *  	pxIndex;			/* 链表节点索引指针 */
	MiniListItem_t 	xListEnd;			/* 链表最后一个节点 */
}List_t;

上述结构体中,TickType_t在portmacro.h文件中定义。

#define configUSE_16_BIT_TICKS		0

#if( configUSE_16_BIT_TICKS == 1 )
	typedef uint16_t TickType_t;
	#define portMAX_DELAY ( TickType_t ) 0xffff
#else
	typedef uint32_t TickType_t;
	#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
#endif

图形化后。

FreeRTOS个人笔记-列表与列表项_第1张图片

初始化

节点初始化

/* 节点初始化 */
void vListInitialiseItem( ListItem_t * const pxItem )
{
	/* 初始化该节点所在的链表为空,表示节点还没有插入任何链表 */
	pxItem->pvContainer = NULL;
}

链表根节点初始化,即链表初始化。(往后不一一赘述了)

/* 链表根节点初始化 */
void vListInitialise( List_t * const pxList )
{
	/* 将链表索引指针指向最后一个节点 */
	pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );

	/* 将链表最后一个节点的辅助排序的值设置为最大,确保该节点就是链表的最后节点 */
	pxList->xListEnd.xItemValue = portMAX_DELAY;

    /* 将最后一个节点的pxNext和pxPrevious指针均指向节点自身,表示链表为空 */
	pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
	pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );

	/* 初始化链表节点计数器的值为0,表示链表为空 */
	pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
}

图形化后。

FreeRTOS个人笔记-列表与列表项_第2张图片

 

列表与列表项操作

将节点插入到链表尾部 

/* 将节点插入到链表的尾部 */
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
	ListItem_t * const pxIndex = pxList->pxIndex;	//pxIndex作为END节点

	pxNewListItem->pxNext = pxIndex;                    //第一点
	pxNewListItem->pxPrevious = pxIndex->pxPrevious;    //第二点
	pxIndex->pxPrevious->pxNext = pxNewListItem;        //第三点
	pxIndex->pxPrevious = pxNewListItem;                //第四点

	/* 记录该节点所在的链表 */
	pxNewListItem->pvContainer = ( void * ) pxList;

	/* 链表节点计数器++,即链表长度++ */
	( pxList->uxNumberOfItems )++;
}

FreeRTOS个人笔记-列表与列表项_第3张图片

将节点按照升序排列插入链表

/* 将节点按照升序排列插入到链表 */
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
	ListItem_t *pxIterator;
	
	/* 获取节点的排序辅助值 */
	const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;

	/* 寻找节点要插入的位置 */
	if( xValueOfInsertion == portMAX_DELAY )
	{
		pxIterator = pxList->xListEnd.pxPrevious;    //END节点
	}
	else
	{
		for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd );
		     pxIterator->pxNext->xItemValue <= xValueOfInsertion; 
			 pxIterator = pxIterator->pxNext )
		{
			/* 没有事情可做,不断迭代只为了找到节点要插入的位置 */			
		}
	}

    //此时,理论上,pxIterator作为pxNewListItem上一个节点
	pxNewListItem->pxNext = pxIterator->pxNext;
	pxNewListItem->pxNext->pxPrevious = pxNewListItem;
	pxNewListItem->pxPrevious = pxIterator;
	pxIterator->pxNext = pxNewListItem;
    //此时,pxNewListItem插入成功

	/* 记录该节点所在的链表 */
	pxNewListItem->pvContainer = ( void * ) pxList;

	/* 链表节点计数器++,即链表长度++*/
	( pxList->uxNumberOfItems )++;
}

下图,先将xItemValue = 2 的节点省略,再作为插入节点插入到链表中进行程序验证。 

FreeRTOS个人笔记-列表与列表项_第4张图片

将节点从链表删除 

/* 将节点从链表中删除 */
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
	/* 获取节点所在的链表 */
	List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;

	pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
	pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

	/* Make sure the index is left pointing to a valid item. */
	if( pxList->pxIndex == pxItemToRemove )
	{
		pxList->pxIndex = pxItemToRemove->pxPrevious;
	}

	/* 初始化该节点所在的链表为空,表示节点还没有插入任何链表,即释放节点 */
	pxItemToRemove->pvContainer = NULL;
	
	/* 链表节点计数器--,即链表长度-- */
	( pxList->uxNumberOfItems )--;

	/* 返回链表中剩余节点的个数 */
	return pxList->uxNumberOfItems;
}

 FreeRTOS个人笔记-列表与列表项_第5张图片

列表与列表项已经到了尾声

最后带宏小函数 

/*
************************************************************************
*                                宏定义
************************************************************************
*/
/* 初始化节点的拥有者 */
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )		( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
/* 获取节点拥有者 */
#define listGET_LIST_ITEM_OWNER( pxListItem )	( ( pxListItem )->pvOwner )

/* 初始化节点排序辅助值 */
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue )	( ( pxListItem )->xItemValue = ( xValue ) )

/* 获取节点排序辅助值 */
#define listGET_LIST_ITEM_VALUE( pxListItem )	( ( pxListItem )->xItemValue )

/* 获取链表根节点的节点计数器的值 */
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )	( ( ( pxList )->xListEnd ).pxNext->xItemValue )

/* 获取链表的入口节点 */
#define listGET_HEAD_ENTRY( pxList )	( ( ( pxList )->xListEnd ).pxNext )

/* 获取链表的第一个节点 */
#define listGET_NEXT( pxListItem )	( ( pxListItem )->pxNext )

/* 获取链表的最后一个节点 */
#define listGET_END_MARKER( pxList )	( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )

/* 判断链表是否为空 */
#define listLIST_IS_EMPTY( pxList )	( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) )

/* 获取链表的节点数 */
#define listCURRENT_LIST_LENGTH( pxList )	( ( pxList )->uxNumberOfItems )

/* 获取链表节点的OWNER,即TCB */
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )										\
{																							\
	List_t * const pxConstList = ( pxList );											    \
	/* 节点索引指向链表第一个节点调整节点索引指针,指向下一个节点,
    如果当前链表有N个节点,当第N次调用该函数时,pxInedex则指向第N个节点 */\
	( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;							\
	/* 当前链表为空 */                                                                       \
	if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )	\
	{																						\
		( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;						\
	}																						\
	/* 获取节点的OWNER,即TCB */                                                             \
	( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;											 \
}

#define listGET_OWNER_OF_HEAD_ENTRY( pxList )  ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )

附上main()函数用例

/* 定义链表根节点 */
struct xLIST       List_Test;

/* 定义节点 */
struct xLIST_ITEM  List_Item1;
struct xLIST_ITEM  List_Item2;
struct xLIST_ITEM  List_Item3;
    /* 链表根节点初始化 */
    vListInitialise( &List_Test );
    
    /* 节点1初始化 */
    vListInitialiseItem( &List_Item1 );
    List_Item1.xItemValue = 1;
    
    /* 节点2初始化 */    
    vListInitialiseItem( &List_Item2 );
    List_Item2.xItemValue = 2;
    
    /* 节点3初始化 */
    vListInitialiseItem( &List_Item3 );
    List_Item3.xItemValue = 3;
    
    /* 将节点插入链表,按照升序排列 */
    vListInsert( &List_Test, &List_Item2 );    
    vListInsert( &List_Test, &List_Item1 );
    vListInsert( &List_Test, &List_Item3 );    

 

你可能感兴趣的:(FreeRTOS个人笔记,操作系统,c语言,stm32,单片机)