小白理解 抛砖引玉 欢迎加v共同学习!!!加V请备注"Freertos "。备注:本系列均基于stm32cubeIDE,并非keilV5哦!!!
在Middleware下勾选Freertos,接口选择CMSIS_V1或CMSIS_V1,点击上方小齿轮重生成代码后,将在“project explorer->Middlewares->Third_Party->FreeRTOS->Source"目标下生成若干文件和文件夹。
(1):include文件夹、portable文件夹、CMSIS_RTOS或CMSIS_RTOS_V2文件夹(这两个文件加2选1,如果Freertos的接口选择为CMSIS_V1则为CMSIS_RTOS;否则为接口选择为CMSIS_V2则为CMSIS_RTOS_V2);
(2):croutine.c、event_groups.c、list.c、queue.c、stream_buffer.c、task.c、timers.c.这里只需要关心list.c就可以了,其他头文件说明将在之后进行更新。
list:实际上是C语言中的链表,而list_item即C语言中链表的节点。
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现。链表的节点包括数据项和指针项;其中数据项用来存储数据,指针项指向下一个/上一个节点的物理地址!链表的节点/结点实际上是一种特殊的结构体。ps:(链表的【头节点/头结点】只存在指针项不存在数据项,指针项用来指出链表物理存储区域的开始地址,链表可以不需要【头节点/头结点】)。在list.h中定义FreeRTOS使用的xLIST_ITEM、xMINI_LIST_ITEM、xLIST三种结构体。首元节点:链表种第一个含有数据项的节点。
list.h定义了3种链表节点,分别是普通节点xLIST_ITEM、精简节点xMINI_LIST_ITEM、头节点xLIST。因为头节点和普通节点的数据结构和含义并不完全相同,因此尽管头节点xLIST包含数据项,我在这里任然称其为头节点,而不是首元节点。三种结构的定义依次如下:
struct
struct
typedef
其中list.c中定义了以下5个函数。
void
链表节点(将list_item翻译为“列表项”,我认为不合适。链表和列表的数据结构是不同的)初始化。
pxItem
上句将节点所属的链表指向为空,此时链表节点不属于任何链表。此链表节点包括5个参数项!!使用的是ListItem_t 不是xMINI_ListItem_t 。
void
uxNumberOfItems记录本链表种普通节点(ListItem_t节点)的总数量;
pxList
pxList
void
PS:图中1号节点为链表的首元节点。
pxIndex = pxList->pxIndex; 链表的头节点的xLIST_ITEM节点地址,图中0号节点。
pxNewListItem->pxNext = pxIndex; 新增链表节点的下一个节点是头节点内的xLIST_ITEM节点。即图中的0号节点。
pxNewListItem->pxPrevious = pxIndex->pxPrevious;新增链表节点的上一个节点是原来头节点内的xLIST_ITEM节点的上一个节点,即节点4.
pxIndex->pxPrevious->pxNext = pxNewListItem;原来的头节点内的xLIST_ITEM节点的上一个节点(图中节点4)的下一个节点应该为新增加的链表节点5。
pxIndex->pxPrevious = pxNewListItem; 头节点内的xLIST_ITEM节点的上一个节点是新增链表节点5。
PS:头节点内xLIST_ITEM节点的上一个节点为除xLIST_ITEM节点外的最后一个节点,即图中节点4(pxIndex->pxPrevious);头节点的xLIST_ITEM节点的下一个节点为除xLIST_ITEM节点外的第一节点(pxIndex->pxNext),即图中节点1。
pxNewListItem->pvContainer = ( void * ) pxList;
新增的普通链表节点属于pxList指向的链表;
( pxList->uxNumberOfItems )++;
上句设置头节点的链表计数器uxNumberOfItems加1
UBaseType_t
这个返回有返回值,返回的是删除节点后,链表的数量。UBaseType_t 类型是usigned long
List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;找到要删除普通链表节点pxItemToRemove所属的 节点的;并将地址存储在指针变量pxList上。
pxItemToRemove
将要删除的链表节点的下一个节点(图中3号节点)的上一个节点指向要删除的节点的上一个节点(图中1号节点);
将要删除的链表节点的上一个节点(图中1号节点)的下一个节点指向要删除节点的下一个节点(图中3号节点)。
PS:图中1号节点为链表的首元节点。
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
xList->pxIndex == pxItemToRemove,如果要删除的节点是头节点内的xListEnd,即链表的最后一个节点。则将除头节点内的xListEnd节点外的最后一个节点作为头节点的xListEnd。
pxItemToRemove->pvContainer = NULL;
( pxList->uxNumberOfItems )--;
return pxList->uxNumberOfItems;
将删除的链表做初始化处理,即不属于任何链表;链表的计数器uxNumberOfItems减1;返回链表删除后的普通链表节点的数量uxNumberOfItems。
负责将pxNewListItem指向的普通节点插入pxList指向的首元节点(链表)的末尾;
void
TickType_t xValueOfInsertion = pxNewListItem->xItemValue;首先是获取待插入的链表节点的赋值值xItemValue;TickType_t 是类型uint32_t或uint16_t,由portmacro.h中的configUSE_16_BIT_TICKS定义;首先判定该值是否为最大值portMAX_DELAY。如果是,直接将待插入的普通链表节点插入到链表的末尾即可。否则进入for循环,找到待插入的位置。比如现在有5个节点,他们的xItemValue分别是11,13,15,17,19。如果待插入的链表节点的xItemValue=XX,XX大于等于19或等于portMAX_DELAY。则插入后的顺序为头节点,11,13,15,17,19,XX。
for
假设XX=13则for循环以后pxIterator等于xItemValue=13对应节点的物理地址。
假设XX=14则for循环以后pxIterator等于xItemValue=15对应节点的物理地址。
假设XX=15则for循环以后pxIterator等于xItemValue=15对应节点的物理地址。
以XX=15为例:
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
list.h文件还定义了若干的带宏参数:
#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_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext )
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
获取头节点内xListEnd节点的下一个链表节点地址的,即实际的链表的首元节点地址
获取首元节点的xItemValue值。
#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext )
获取链表节点的下一个节点的地址
#define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
获取链表的头节点内xListEnd的地址,即最后一个节点的物理地址。
#define listLIST_IS_EMPTY( pxList ) ( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) )
#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
判断链表是否为空及链表拥有普通链表节点的数量uxNumberOfItems,uxNumberOfItems=0时为链表为空链表。
#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )
获取链表首元节点的内核对象拥有者
#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer )
获取链表节点所属的链表
#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( BaseType_t ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) ) )
判断链表节点是否被指定的链表所包含
#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )
判断链表是否完成初始化
void
这一段没看懂,求大神赐教
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )
{
List_t * const pxConstList = ( pxList );
/* Increment the index to the next item and return the item, ensuring */
/* we don't return the marker used at the end of the list. */
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;
if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )
{
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;
}
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;
}
获取首元节点所属的内核对象拥有者
#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
/* Define the macros to do nothing. */
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
#define listTEST_LIST_ITEM_INTEGRITY( pxItem )
#define listTEST_LIST_INTEGRITY( pxList )
#else
/* Define macros that add new members into the list structures. */
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue1;
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue2;
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1;
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2;
/* Define macros that set the new structure members to known values. */
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
/* Define macros that will assert if one of the structure members does not
contain its expected value. */
#define listTEST_LIST_ITEM_INTEGRITY( pxItem ) configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
#define listTEST_LIST_INTEGRITY( pxList ) configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */
以上代码用于检查链表节点数据的完整性,目前还没有接触到。等研究明白了更新。或者指导的大神,请不吝赐教。谢谢
c语言知识链表参考:https://blog.csdn.net/baidu_41813368/article/details/82776527