欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 美景 > FreeRTOS 列表和列表项

FreeRTOS 列表和列表项

2025/2/5 6:44:16 来源:https://blog.csdn.net/aasd23/article/details/145116810  浏览:    关键词:FreeRTOS 列表和列表项

FreeRTOS 的源码中大量地使用了列表和列表项,因此想要深入学习 FreeRTOS,列表和列表项是必备的基础知识。这里所说的列表和列表项,是 FreeRTOS 源码中 List List Item 的直译,事实上,FreeRTOS 中的列表和列表项就是数据结构中的链表和节点。

一、FreeRTOS 列表和列表项简介

1、列表(List)

列表是 FreeRTOS 中最基本的一种数据结构,其在物理存储单元上是非连续、非顺序的。列表在 FreeRTOS 中的应用十分广泛,要注意的是,FreeRTOS 中的列表是一个双向链表,在 list.h 文件中,有列表的相关定义,具体代码如下所示:

typedef struct xLIST

{      listFIRST_LIST_INTEGRITY_CHECK_VALUE    

/* 校验值 */

    volatile UBaseType_t    uxNumberOfItems;

/* 列表中列表项的数量 */

    ListItem_t * configLIST_VOLATILE pxIndex;  

/* 用于遍历列表 */

    MiniListItem_t      xListEnd;  

/* 最后一个列表项 */

    listSECOND_LIST_INTEGRITY_CHECK_VALUE    

} List_t;

/* 校验值 */

  1. 在该结构体中,包含了两个宏,分别为 listFIRST_LIST_INTEGRITY_CHECK_VALUE 和 listSECOND_LIST_INTEGRITY_CHECK_VALUE,这两个宏用于存放确定已知常量,FreeRTOS 通过检查这两个常量的值,来判断列表的数据在程序运行过程中,是否遭到破坏,类似这样的宏定义在列表项和迷你列表项中也有出现。该功能一般用于调试,默认是不开启的,因此本教程暂不讨论这个功能。
  2. 成员变量 uxNumberOfItems 用于记录列表中列表项的个数(不包含 xListEnd),当往列表中插入列表项时,该值加 1;当从列表中移除列表项时,该值减 1。
  3. 成员变量 pxIndex 用于指向列表中的某个列表项,一般用于遍历列表中的所有列表项。
  4. 成员变量 xListEnd 是一个迷你列表项(详见 7.1.3 小节),列表中迷你列表项的值一般被设置为最大值,用于将列表中的所有列表项按升序排序时,排在最末尾;同时 xListEnd 也用于挂载其他插入到列表中的列表项。

2、列表项(List Item)

列表项是列表中用于存放数据的地方,在 list.h 文件中,有列表项的相关定义,具体代码如下所示:

struct xLIST_ITEM

{

    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE  /* 用于检测列表项的数据完整性 */     configLIST_VOLATILE TickType_t    xItemValue/* 列表项的值 */     struct xLIST_ITEM * configLIST_VOLATILE  pxNext;   /* 下一个列表项 */     struct xLIST_ITEM * configLIST_VOLATILE  pxPrevious/* 上一个列表项 */

    void *          pvOwner/* 列表项的拥有者 */

    struct xLIST * configLIST_VOLATILE   pxContainer; /* 列表项所在列表 */     listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE  /* 用于检测列表项的数据完整性 */

}; typedef struct xLIST_ITEM ListItem_t;/* 重定义成ListItem_t */

  1. 如同列表一样,列表项中也包含了两个用于检测列表项数据完整性的宏定义。
  2. 成员变量 xItemValue 为列表项的值,这个值多用于按升序对列表中的列表项进行排序。
  3. 成员变量 pxNext 和 pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列表项。
  4. 成员变量 pxOwner 用于指向包含列表项的对象(通常是任务控制块),因此,列表项和包含列表项的对象之间存在双向链接。
  5. 成员变量 pxContainer 用于指向列表项所在列表。

列表项的结构示意图,如下图所示:

3、迷你列表项(Mini List Item)

迷你列表项也是列表项,但迷你列表项仅用于标记列表的末尾和挂载其他插入列表中的列表项,用户是用不到迷你列表项的,在 list.h 文件中,有迷你列表项的相关定义,具体的代码录下所示:

struct xMINI_LIST_ITEM

{

    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE/* 用于检测列表项的数据完整性 */     configLIST_VOLATILE TickType_t    xItemValue/* 列表项的值 */     struct xLIST_ITEM * configLIST_VOLATILE  pxNext;   /* 下一个列表项 */     struct xLIST_ITEM * configLIST_VOLATILE  pxPrevious/* 上一个列表项 */

}; typedef struct xMINI_LIST_ITEM MiniListItem_t;/* 重定义成MiniListItem_t */

  1. 迷你列表项中也同样包含用于检测列表项数据完整性的宏定义。
  2. 成员变量 xItemValue 为列表项的值,这个值多用于按升序对列表中的列表项进行排序。
  3. 成员变量 pxNext 和 pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列表项。
  4. 迷你列表项相比于列表项,因为只用于标记列表的末尾和挂载其他插入列表中的列表项,因此不需要成员变量 pxOwner 和 pxContainer,以节省内存开销。

迷你列表项的结构示意图,如下图所示:

二、FreeRTOS 列表和列表项相关 API 函数

函数

描述

vListInitialise()

初始化列表

vListInitialiseItem()

初始化列表项

vListInsertEnd()

列表末尾插入列表项

vListInsert()

列表插入列表项

uxListRemove()

列表移除列表项

表 7.2.1 列表和列表项相关 API 函数

1、函数 vListInitialise()

此函数用于初始化列表,在定义列表之后,需要先对其进行初始化,只有初始化后的列表,才能够正常地被使用。列表初始化的过程,其实就是初始化列表中的成员变量。函数原型如下

所示:

void vListInitialise(List_t * const pxList);

函数 vListInitialise()的形参描述,如下表所示:

形参

描述

pxList

待初始化列表

表 7.2.1.1 函数 vListInitialise()形参相关描述

函数 vListInitialise()无返回值。

函数 vListInitialise()在 list.c 文件中有定义,具体的代码如下所示:

void vListInitialise(

    List_t * const pxList)

{

    /* 初始化时,列表中只有xListEnd,因此pxIndex指向xListEnd */

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

    /* xListEnd的值初始化为最大值,用于列表项升序排序时,排在最后 */

    pxList->xListEnd.xItemValue = portMAX_DELAY;

    

    /* 初始化时,列表中只有xListEnd,因此上一个和下一个列表项都为xListEnd本身 */

    pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );     pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );     

    /*初始化时,列表中的列表项数量为0(不包含xListEnd */

    pxList->uxNumberOfItems = ( UBaseType_t ) 0U;

    

    /* 初始化用于检测列表数据完整性的校验值 */

    listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );     listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ); }

函数 vListInitialise()初始化后的列表结构示意图,如下图所示:

2、函数 vListInitialiseItem()

此函数用于初始化列表项,如同列表一样,在定义列表项之后,也需要先对其进行初始化,只有初始化有的列表项,才能够被正常地使用。列表项初始化的过程,也是初始化列表项中的成员变量。函数原型如下所示:

void vListInitialiseItem(ListItem_t * const pxItem);

函数 vListInitialiseItem()的形参描述,如下表所示:

形参

描述

pxItem

待初始化列表项

函数 vListInitialiseItem()无返回值。函数 vListInitialiseItem()在 list.c 文件中有定义,具体的代码如下所示:

void vListInitialiseItem(

    ListItem_t * const pxItem)

{

    /* 初始化时,列表项所在列表设为空 */

    pxItem->pxContainer = NULL;

    

    /* 初始化用于检测列表项数据完整性的校验值 */

    listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );     listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );

}

这个函数比较简单,只需将列表项所在列表设置为空,以保证列表项不再任何一个列表项

中即可。函数 vListInitialiseItem()初始化后的列表项结构示意图,如下图所示:

xList_Item

xItemValue

*pvOwner

*pxContainer=NULL

*pxPrevious

*pxNext

7.2.2.1 初始化后的列表项结构示意图

3、 函数 vListInsertEnd()

此函数用于将待插入列表的列表项插入到列表 pxIndex 指针指向列表项的前面,是一种无

序的插入方法。函数原型如下所示:

void vListInsertEnd(

    List_t * const pxList,

    ListItem_t * const pxNewListItem);

函数 vListInsertEnd()的形参描述,如下表所示:

形参

描述

pxList

列表

pxNewListItem

待插入列表项

表 7.2.3.1 函数 vListInsertEnd()形参相关描述

函数 vListInsertEnd()无返回值。函数 vListInsertEnd()在 list.c 文件中有定义,具体的代码如下所示:

void vListInsertEnd(

    List_t * const pxList,

    ListItem_t * const pxNewListItem)

{

    /* 获取列表pxIndex指向的列表项 */

    ListItem_t * const pxIndex = pxList->pxIndex;

    

    /* 检查参数是否正确 */

    listTEST_LIST_INTEGRITY( pxList );     listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );

    

    /* 更新待插入列表项的指针成员变量 */

    pxNewListItem->pxNext = pxIndex;

    pxNewListItem->pxPrevious = pxIndex->pxPrevious;

    

    /* 测试使用,不用理会 */

    mtCOVERAGE_TEST_DELAY();

    

    /* 更新列表中原本列表项的指针成员变量 */

    pxIndex->pxPrevious->pxNext = pxNewListItem;     pxIndex->pxPrevious = pxNewListItem;

    

    /* 更新待插入列表项的所在列表成员变量 */

    pxNewListItem->pxContainer = pxList;

    

    /* 更新列表中列表项的数量 */

    ( pxList->uxNumberOfItems )++; }

从上面的代码可以看出,此函数就是将待插入的列表项插入到列表 pxIndex 指向列表项的前面,要注意的时,pxIndex 不一定指向 xListEnd,而是有可能指向列表中任意一个列表项。函数 vListInsertEnd()插入列表项后的列表结构示意图,如下图所示:

4、函数 vListInsert()

此函数用于将待插入列表的列表项按照列表项值升序排序的顺序,有序地插入到列表中。

函数原型如下所示:

void vListInsert(

    List_t * const pxList,

    ListItem_t * const pxNewListItem);

函数 vListInsert()的形参描述,如下表所示:

形参

描述

pxList

列表

pxNewListItem

待插入列表项

表 7.2.4.1 函数 vListInsert()形参相关描述

函数 vListInsert()无返回值。

函数 vListInsert()在 list.c 文件中有定义,具体的代码如下所示:

void vListInsert(

    List_t * const pxList,

    ListItem_t * const pxNewListItem)

{

    ListItem_t * pxIterator;

    const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;     

    /* 检查参数是否正确 */

    listTEST_LIST_INTEGRITY( pxList );

    listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );

    

    /* 如果待插入列表项的值为最大值 */

    if( xValueOfInsertion == portMAX_DELAY )

    {

      /* 插入的位置为列表xListEnd前面 */

      pxIterator = pxList->xListEnd.pxPrevious;

    }     else

    {

      /* 遍历列表中的列表项,找到插入的位置 */

      for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd );         pxIterator->pxNext->xItemValue <= xValueOfInsertion;         pxIterator = pxIterator->pxNext )

      {

      

      }

    }

    

    /* 将待插入的列表项插入指定位置 */

    pxNewListItem->pxNext = pxIterator->pxNext;     pxNewListItem->pxNext->pxPrevious = pxNewListItem;     pxNewListItem->pxPrevious = pxIterator;     pxIterator->pxNext = pxNewListItem;

    

    /* 更新待插入列表项所在列表 */

    pxNewListItem->pxContainer = pxList;

    

    /* 更新列表中列表项的数量 */

    ( pxList->uxNumberOfItems )++; }

从上面的代码可以看出,此函数在将待插入列表项插入列表之前,会前遍历列表,找到待插入列表项需要插入的位置。待插入列表项需要插入的位置是依照列表中列表项的值按照升序排序确定的。函数 vListInsert()插入列表项后的列表结构示意图,如下图所示:

5、 函数 uxListRemove()

此函数用于将列表项从列表项所在列表中移除,函数原型如下所示: 

UBaseType_t uxListRemove(ListItem_t * const pxItemToRemove);

函数 uxListRemove()的形参描述,如下表所示:

形参

描述

pxItemToRemove

待移除的列表项

表 7.2.5.1 函数 uxListRemove()形参相关描述

函数 uxListRemove()的返回值,如下表所示:

返回值

描述

整数

待移除列表项移除后,所在列表剩余列表项的数量

表 7.2.5.2 函数 uxListRemove()返回值相关描述函数 uxListRemove()在 list.c 文件中有定义,具体的代码如下所示:

UBaseType_t uxListRemove(

    ListItem_t * const pxItemToRemove)

{

    List_t * const pxList = pxItemToRemove->pxContainer;     

    /* 从列表中移除列表项 */

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

    /* 测试使用,不用理会 */

    mtCOVERAGE_TEST_DELAY();

    

    /* 如果pxIndex正指向待移除的列表项 */

    if( pxList->pxIndex == pxItemToRemove )

    {

        /* pxIndex指向上一个列表项 */

        pxList->pxIndex = pxItemToRemove->pxPrevious;

    }     else     {

        mtCOVERAGE_TEST_MARKER();

    }

    

    /* 将待移除列表项的所在列表指针清空 */

    pxItemToRemove->pxContainer = NULL;

    /* 更新列表中列表项的数量 */

    ( pxList->uxNumberOfItems )--;

    

    /* 返回列表项移除后列表中列表项的数量 */

    return pxList->uxNumberOfItems;

}

要注意的是函数 uxListRemove()移除后的列表项,依然于列表有着单向联系,即移除后列表项中用于指向上一个和下一个列表项的指针,依然指向列表中的列表项。函数 uxListRemove() 移除列表项后的列表结构示意图,如下图所示:

三、FreeRTOS 操作列表和列表项的宏

在 list.h 文件中定义了大量的宏,用来操作列表以及列表项,如下表所示:

宏定义

描述

listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )

设置列表项的拥有者

listGET_LIST_ITEM_OWNER( pxListItem )

获取列表项的拥有者

listSET_LIST_ITEM_VALUE( pxListItem, xValue )

设置列表项的值

listGET_LIST_ITEM_VALUE( pxListItem )

获取列表项的值

listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )

获取列表头部列表项的值

listGET_HEAD_ENTRY( pxList )

获取列表的头部列表项

listGET_NEXT( pxListItem )

获取列表项的下一个列表项

listGET_END_MARKER( pxList )

获取列表的尾部列表项

listLIST_IS_EMPTY( pxList )

判断列表是否为空

listCURRENT_LIST_LENGTH( pxList )

获取列表包含的列表项数量

listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )

获取下一个列表项的拥有者

listREMOVE_ITEM( pxItemToRemove )

将列表项从列表中移除

listINSERT_END( pxList, pxNewListItem )

列表末尾插入列表项

listGET_OWNER_OF_HEAD_ENTRY( pxList )

获取列表头部列表项的拥有者

listIS_CONTAINED_WITHIN( pxList, pxListItem )

判断列表项是否在列表中

listLIST_ITEM_CONTAINER( pxListItem )

获取列表项所在列表

listLIST_IS_INITIALISED( pxList )

判断列表是否完成初始化

这些宏操作列表及列表项的实现都比较简单,读者可阅读 list.h 文件,查看具体的实现方法;也可在后续阅读 FreeRTOS 源码时,遇到这些宏定义时,再进行查阅。

四、 FreeRTOS 列表项的插入与删除实验

任务名

任务功能描述

start_task

用于创建其他任务

task1

用于进行列表项的插入与删除

注意:注意查看打印的列表地址

代码:

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"/******************************************************************************************************/
/*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO 1                   /* 任务优先级 */
#define START_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            StartTask_Handler;  /* 任务句柄 */
void start_task(void *pvParameters);        /* 任务函数 *//* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_PRIO      2                   /* 任务优先级 */
#define TASK1_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task1Task_Handler;  /* 任务句柄 */
void task1(void *pvParameters);             /* 任务函数 */List_t                  TestList;           /* 定义测试列表 */
ListItem_t              ListItem1;          /* 定义测试列表项1 */
ListItem_t              ListItem2;          /* 定义测试列表项2 */
ListItem_t              ListItem3;          /* 定义测试列表项3 *//******************************************************************************************************//*** @brief       FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{lcd_show_string(10, 10, 220, 32, 32, "STM32", RED);lcd_show_string(10, 47, 220, 24, 24, "List & ListItem", RED);lcd_show_string(10, 76, 220, 16, 16, "ATOM@ALIENTEK", RED);xTaskCreate((TaskFunction_t )start_task,            /* 任务函数 */(const char*    )"start_task",          /* 任务名称 */(uint16_t       )START_STK_SIZE,        /* 任务堆栈大小 */(void*          )NULL,                  /* 传入给任务函数的参数 */(UBaseType_t    )START_TASK_PRIO,       /* 任务优先级 */(TaskHandle_t*  )&StartTask_Handler);   /* 任务句柄 */vTaskStartScheduler();
}/*** @brief       start_task* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void start_task(void *pvParameters)
{taskENTER_CRITICAL();           /* 进入临界区 *//* 创建任务1 */xTaskCreate((TaskFunction_t )task1,(const char*    )"task1",(uint16_t       )TASK1_STK_SIZE,(void*          )NULL,(UBaseType_t    )TASK1_PRIO,(TaskHandle_t*  )&Task1Task_Handler);vTaskDelete(StartTask_Handler); /* 删除开始任务 */taskEXIT_CRITICAL();            /* 退出临界区 */
}/*** @brief       task1* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void task1(void *pvParameters)
{/* 第一步:初始化列表和列表项 */vListInitialise(&TestList);                 /* 初始化列表 */vListInitialiseItem(&ListItem1);            /* 初始化列表项1 */vListInitialiseItem(&ListItem2);            /* 初始化列表项2 */vListInitialiseItem(&ListItem3);            /* 初始化列表项3 *//* 第二步:打印列表和其他列表项的地址 */printf("/**************第二步:打印列表和列表项的地址**************/\r\n");printf("项目\t\t\t地址\r\n");printf("TestList\t\t0x%p\t\r\n", &TestList);printf("TestList->pxIndex\t0x%p\t\r\n", TestList.pxIndex);printf("TestList->xListEnd\t0x%p\t\r\n", (&TestList.xListEnd));printf("ListItem1\t\t0x%p\t\r\n", &ListItem1);printf("ListItem2\t\t0x%p\t\r\n", &ListItem2);printf("ListItem3\t\t0x%p\t\r\n", &ListItem3);printf("/**************************结束***************************/\r\n");printf("按下KEY0键继续!\r\n\r\n\r\n");while (key_scan(0) != KEY0_PRES){vTaskDelay(10);}/* 第三步:列表项1插入列表 */printf("/*****************第三步:列表项1插入列表******************/\r\n");vListInsert((List_t*    )&TestList,         /* 列表 */(ListItem_t*)&ListItem1);       /* 列表项 */printf("项目\t\t\t\t地址\r\n");printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));printf("/**************************结束***************************/\r\n");printf("按下KEY0键继续!\r\n\r\n\r\n");while (key_scan(0) != KEY0_PRES){vTaskDelay(10);}/* 第四步:列表项2插入列表 */printf("/*****************第四步:列表项2插入列表******************/\r\n");vListInsert((List_t*    )&TestList,         /* 列表 */(ListItem_t*)&ListItem2);       /* 列表项 */printf("项目\t\t\t\t地址\r\n");printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));printf("/**************************结束***************************/\r\n");printf("按下KEY0键继续!\r\n\r\n\r\n");while (key_scan(0) != KEY0_PRES){vTaskDelay(10);}/* 第五步:列表项3插入列表 */printf("/*****************第五步:列表项3插入列表******************/\r\n");vListInsert((List_t*    )&TestList,         /* 列表 */(ListItem_t*)&ListItem3);       /* 列表项 */printf("项目\t\t\t\t地址\r\n");printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));printf("/**************************结束***************************/\r\n");printf("按下KEY0键继续!\r\n\r\n\r\n");while (key_scan(0) != KEY0_PRES){vTaskDelay(10);}/* 第六步:移除列表项2 */printf("/*******************第六步:移除列表项2********************/\r\n");uxListRemove((ListItem_t*   )&ListItem2);   /* 移除列表项 */printf("项目\t\t\t\t地址\r\n");printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));printf("/**************************结束***************************/\r\n");printf("按下KEY0键继续!\r\n\r\n\r\n");while (key_scan(0) != KEY0_PRES){vTaskDelay(10);}/* 第七步:列表末尾添加列表项2 */printf("/****************第七步:列表末尾添加列表项2****************/\r\n");vListInsertEnd((List_t*     )&TestList,     /* 列表 */(ListItem_t* )&ListItem2);   /* 列表项 */printf("项目\t\t\t\t地址\r\n");printf("TestList->pxIndex\t\t0x%p\r\n", TestList.pxIndex);printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));printf("/************************实验结束***************************/\r\n");while(1){vTaskDelay(10);}
}

效果:

LCD ID:7789
/**************第二步:打印列表和列表项的地址**************/
项目			地址
TestList		0x200000cc	
TestList->pxIndex	0x200000d4	
TestList->xListEnd	0x200000d4	
ListItem1		0x200000e0	
ListItem2		0x200000f4	
ListItem3		0x20000108	
/**************************结束***************************/
按下KEY0键继续!/*****************第三步:列表项1插入列表******************/
项目				地址
TestList->xListEnd->pxNext	0x200000e0
ListItem1->pxNext		0x200000d4
TestList->xListEnd->pxPrevious	0x200000e0
ListItem1->pxPrevious		0x200000d4
/**************************结束***************************/
按下KEY0键继续!/*****************第四步:列表项2插入列表******************/
项目				地址
TestList->xListEnd->pxNext	0x200000e0
ListItem1->pxNext		0x200000f4
ListItem2->pxNext		0x200000d4
TestList->xListEnd->pxPrevious	0x200000f4
ListItem1->pxPrevious		0x200000d4
ListItem2->pxPrevious		0x200000e0
/**************************结束***************************/
按下KEY0键继续!/*****************第五步:列表项3插入列表******************/
项目				地址
TestList->xListEnd->pxNext	0x200000e0
ListItem1->pxNext		0x200000f4
ListItem2->pxNext		0x20000108
ListItem3->pxNext		0x200000d4
TestList->xListEnd->pxPrevious	0x20000108
ListItem1->pxPrevious		0x200000d4
ListItem2->pxPrevious		0x200000e0
ListItem3->pxPrevious		0x200000f4
/**************************结束***************************/按下KEY0键继续!/*******************第六步:移除列表项2********************/
项目				地址
TestList->xListEnd->pxNext	0x200000e0
ListItem1->pxNext		0x20000108
ListItem3->pxNext		0x200000d4
TestList->xListEnd->pxPrevious	0x20000108
ListItem1->pxPrevious		0x200000d4
ListItem3->pxPrevious		0x200000e0
/**************************结束***************************/
按下KEY0键继续!/****************第七步:列表末尾添加列表项2****************/
项目				地址
TestList->pxIndex		0x200000d4
TestList->xListEnd->pxNext	0x200000e0
ListItem1->pxNext		0x20000108
ListItem2->pxNext		0x200000d4
ListItem3->pxNext		0x200000f4
TestList->xListEnd->pxPrevious	0x200000f4
ListItem1->pxPrevious		0x200000d4
ListItem2->pxPrevious		0x20000108
ListItem3->pxPrevious		0x200000e0
/************************实验结束***************************/

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com