FreeRTOS列表和列表项(STM32F103C8T6)

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

 

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 也用于挂 载其他插入到列表中的列表项。
列表的结构示意图,如下图所示:

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

1. 如同列表一样,列表项中也包含了两个用于检测列表项数据完整性的宏定义。 

2. 成员变量 xItemValue 为列表项的值,这个值多用于按升序对列表中的列表项进行排序。 

3. 成员变量 pxNext 和 pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列 表项。 

4. 成员变量 pxOwner 用于指向包含列表项的对象(通常是任务控制块),因此,列表项和 包含列表项的对象之间存在双向链接。 

5. 成员变量 pxContainer 用于指向列表项所在列表。

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

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

1. 迷你列表项中也同样包含用于检测列表项数据完整性的宏定义。 

2. 成员变量 xItemValue 为列表项的值,这个值多用于按升序对列表中的列表项进行排序。 

3. 成员变量 pxNext 和 pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列 表项。 

4. 迷你列表项相比于列表项,因为只用于标记列表的末尾和挂载其他插入列表中的列表项, 因此不需要成员变量 pxOwner 和 pxContainer,以节省内存开销。 迷你列表项的结构示意图,如下图所示:

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

FreeRTOS 中列表和列表项相关的 API 函数如下表所示:

函数 vListInitialise()

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

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

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

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

 函数 vListInitialiseItem()

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

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

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

       这个函数比较简单,只需将列表项所在列表设置为空,以保证列表项不再任何一个列表项 中即可。函数 vListInitialiseItem()初始化后的列表项结构示意图,如下图所示:

函数 vListInsertEnd() 

       此函数用于将待插入列表的列表项插入到列表 pxIndex 指针指向列表项的前面,是一种无 序的插入方法。函数原型如下所示:

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

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

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

函数 vListInsert()

       此函数用于将待插入列表的列表项按照列表项值升序排序的顺序,有序地插入到列表中。 函数原型如下所示:

       函数 vListInsert()无返回值。

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

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

函数 uxListRemove()

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

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

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

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

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

FreeRTOS 操作列表和列表项的宏

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

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

首先是测试列表和列表项的定义:

List_t TestList;
ListItem_t ListItem1;
ListItem_t ListItem2;
ListItem_t ListItem3;

然后是具体的代码操作逻辑:

void task1_task(void *pvParameters)
{
    vListInitialise(&TestList);
    vListInitialiseItem(&ListItem1);
    vListInitialiseItem(&ListItem2);
    vListInitialiseItem(&ListItem3);
    
    printf("\r\n");
    printf("打印列表和列表项的地址\r\n");
    printf("项目\t\t\t地址\r\n");
    
    printf("\r\n");
    printf("TestList地址\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("TestList->uxNumberOfItems\t%ld\t\r\n", TestList.uxNumberOfItems);
    
    printf("\r\n");
    printf("列表项地址\r\n");
    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("在TestList列表中插入列表项1,2,3,xItemValue的值为1,2,3\r\n");
    ListItem1.xItemValue = 1;
    ListItem2.xItemValue = 2;
    ListItem3.xItemValue = 3;
    vListInsert((List_t *)&TestList, (ListItem_t *)&ListItem1);
    vListInsert((List_t *)&TestList, (ListItem_t *)&ListItem2);
    vListInsert((List_t *)&TestList, (ListItem_t *)&ListItem3);
    
    printf("\r\n");
    printf("TestList信息更新\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("TestList->uxNumberOfItems\t%ld\t\r\n", TestList.uxNumberOfItems);
    TestList.pxIndex = TestList.xListEnd.pxPrevious;
    printf("倒数第二个列表项\t0x%p\t\r\n", (TestList.pxIndex));
    TestList.pxIndex = TestList.pxIndex->pxPrevious;
    printf("倒数第三个列表项\t0x%p\t\r\n", (TestList.pxIndex));
    TestList.pxIndex = TestList.pxIndex->pxPrevious;
    printf("倒数第四个列表项\t0x%p\t\r\n", (TestList.pxIndex));
    
    printf("\r\n");
    printf("在TestList列表中插入列表项1,2,3,xItemValue的值为3,2,1\r\n");
    ListItem1.xItemValue = 3;
    ListItem2.xItemValue = 2;
    ListItem3.xItemValue = 1;
    vListInsert((List_t *)&TestList, (ListItem_t *)&ListItem1);
    vListInsert((List_t *)&TestList, (ListItem_t *)&ListItem2);
    vListInsert((List_t *)&TestList, (ListItem_t *)&ListItem3);
    
    printf("\r\n");
    printf("TestList信息更新\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("TestList->uxNumberOfItems\t%ld\t\r\n", TestList.uxNumberOfItems);
    TestList.pxIndex = TestList.xListEnd.pxPrevious;
    printf("倒数第二个列表项\t0x%p\t\r\n", (TestList.pxIndex));
    TestList.pxIndex = TestList.pxIndex->pxPrevious;
    printf("倒数第三个列表项\t0x%p\t\r\n", (TestList.pxIndex));
    TestList.pxIndex = TestList.pxIndex->pxPrevious;
    printf("倒数第四个列表项\t0x%p\t\r\n", (TestList.pxIndex));
    
    printf("\r\n");
    printf("在TestList列表移除列表项2\r\n");
    uxListRemove((ListItem_t *)&ListItem2);
    
   printf("\r\n");
    printf("TestList信息更新\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("TestList->uxNumberOfItems\t%ld\t\r\n", TestList.uxNumberOfItems);
    TestList.pxIndex = TestList.xListEnd.pxPrevious;
    printf("倒数第二个列表项\t0x%p\t\r\n", (TestList.pxIndex));
    TestList.pxIndex = TestList.pxIndex->pxPrevious;
    printf("倒数第三个列表项\t0x%p\t\r\n", (TestList.pxIndex));
    TestList.pxIndex = TestList.pxIndex->pxPrevious;
    printf("倒数第四个列表项\t0x%p\t\r\n", (TestList.pxIndex));
    
    printf("\r\n");
    printf("在TestList列表中末尾插入列表项2\r\n");
    vListInsertEnd((List_t *)&TestList, (ListItem_t *)&ListItem2);
    
    printf("\r\n");
    printf("TestList信息更新\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("TestList->uxNumberOfItems\t%ld\t\r\n", TestList.uxNumberOfItems);
    TestList.pxIndex = TestList.xListEnd.pxPrevious;
    printf("倒数第二个列表项\t0x%p\t\r\n", (TestList.pxIndex));
    TestList.pxIndex = TestList.pxIndex->pxPrevious;
    printf("倒数第三个列表项\t0x%p\t\r\n", (TestList.pxIndex));
    TestList.pxIndex = TestList.pxIndex->pxPrevious;
    printf("倒数第四个列表项\t0x%p\t\r\n", (TestList.pxIndex));
    
    while(1)
    {
         vTaskDelay(1000);
    }
}

实际运行示例:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

moon2shine

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值