FreeRTOS 列表
列表的数据结构:
listFIRST_LIST_INTEGRITY_CHECK_VALUE
configLIST_VOLATILE UBaseType_t uxNumberOfItems;
ListItem_t * configLIST_VOLATILE pxIndex;
listSECOND_LIST_INTEGRITY_CHECK_VALUE
#ifndef configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES
#define configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 0
#if (configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0)
#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 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;
列表的元素分析:
列表的首尾两个元素,都是用来检查列表完整性的,需要将宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 设置为 1,开启以后会向这两个地方分别添加一个变量 xListIntegrityValue1 和 xListIntegrityValue2,在初始化列表的时候会这两个变量中写入一个特殊的值,默认不开启这个功能;
uxNumberOfItems 用来记录列表中列表项的数量;
pxIndex 用来记录当前列表项索引号,用于遍历列表;
列表中最后一个列表项,用来表示列表结束,此变量类型为 MiniListItem_t,这是一个迷你列表项;
列表的结构图:
列表项:
列表项就是存放在列表中的项目,FreeRTOS 提供了两种列表项:列表项和迷你列表项;
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
configLIST_VOLATILE TickType_t xItemValue;
struct xLIST_ITEM *configLIST_VOLATILE pxNext;
struct xLIST_ITEM *configLIST_VOLATILE pxPrevious;
void *configLIST_VOLATILE pvContainer;
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
typedef struct xLIST_ITEM ListItem_t;
首尾两项与列表类似,为完整性检查;
xItemValue 为列表项值;
pxNext 指向下一个列表项,pxPrevious 指向前一个列表项,和 pxNext 配合起来实现类似双向链表的功能;
pvOwner 记录此链表项归谁拥有,通常是任务控制块;
pvContainer 用来记录此列表项归哪个列表;
列表项的结构示意图:
任务控制块的数据结构:
迷你列表项:
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;
参数说明:
列表和列表项相关的操作:
1 列表初始化示意图:
2 列表的升序插入示意图:
插入单个列表项
插入多个列表项
列表的初始化 排序插入等操作,都不需要操作遍历指针 pxList->pxIndex 这个指针。
链表的尾部插入:
由于是环形链表,所以根本就没有头部和尾部之说。那么,如何确定链表开始的地方?这就要靠遍历指针 pxList->pxIndex
pxIndex这个指针指向的列表项,就是链表的开始,那么很明显,pxIndex->Previous指向的列表项就是链表的结尾;
我们所说的链表尾部插入,就是要插入到pxIndex->Previous处。
重点分析:
void vListInsertEnd(List_t *const pxList, ListItem_t *const pxNewListItem)
ListItem_t *const pxIndex = pxList->pxIndex;
pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
pxNewListItem->pvContainer = (void *)pxList;
(pxList->uxNumberOfItems)++;
插入位置分析:
尾部插入的图示:
插入前:
插入后:
列表的遍历:
列表项的插入和删除实验
代码如下:
void list_task(void *pvParameters)
vListInitialise(&testList);
vListInitialiseItem(&ListItem1);
vListInitialiseItem(&ListItem2);
vListInitialiseItem(&ListItem3);
ListItem1.xItemValue = 40;
ListItem2.xItemValue = 60;
ListItem3.xItemValue = 50;
printf("\n/*********************列表和列表项地址************************/\n");
printf("testList %#X \n", (int)&testList);
printf("testList->pxIndex %#X \n", (int)testList.pxIndex);
printf("testList->xListEnd %#X \n", (int)&testList.xListEnd);
printf("ListItem1 %#X \n", (int)&ListItem1);
printf("ListItem2 %#X \n", (int)&ListItem2);
printf("ListItem3 %#X \n", (int)&ListItem3);
printf("/***************************结束*****************************/\n");
printf("按下K1按键继续!\r\n\r\n");
while (key_scan(KEY1_GPIO_Port, KEY1_Pin) != KEY_ON);
vListInsert(&testList, &ListItem1);
printf("\n/*******************添加列表项ListItem1**********************/\n");
printf("testList->xListEnd->pxNext %#X \n", (int)testList.xListEnd.pxNext);
printf("ListItem1->pxNext %#X \n", (int)ListItem1.pxNext);
printf("/**********************前后向连接分割线***********************/\n");
printf("testList->xListEnd->pxPrevious %#X \n", (int)testList.xListEnd.pxPrevious);
printf("ListItem1->pxPrevious %#X \n", (int)ListItem1.pxPrevious);
printf("/***************************结束*****************************/\n");
printf("按下K1按键继续!\r\n\r\n");
while (key_scan(KEY1_GPIO_Port, KEY1_Pin) != KEY_ON);
vListInsert(&testList, &ListItem2);
printf("\n/*******************添加列表项ListItem2**********************/\n");
printf("testList->xListEnd->pxNext %#X \n", (int)testList.xListEnd.pxNext);
printf("ListItem1->pxNext %#X \n", (int)ListItem1.pxNext);
printf("ListItem2->pxNext %#X \n", (int)ListItem2.pxNext);
printf("/**********************前后向连接分割线***********************/\n");
printf("testList->xListEnd->pxPrevious %#X \n", (int)testList.xListEnd.pxPrevious);
printf("ListItem1->pxPrevious %#X \n", (int)ListItem1.pxPrevious);
printf("ListItem2->pxPrevious %#X \n", (int)ListItem2.pxPrevious);
printf("/***************************结束*****************************/\n");
printf("按下K1按键继续!\r\n\r\n");
while (key_scan(KEY1_GPIO_Port, KEY1_Pin) != KEY_ON);
vListInsert(&testList, &ListItem3);
printf("\n/*******************添加列表项ListItem3**********************/\n");
printf("testList->xListEnd->pxNext %#X \n", (int)testList.xListEnd.pxNext);
printf("ListItem1->pxNext %#X \n", (int)ListItem1.pxNext);
printf("ListItem3->pxNext %#X \n", (int)ListItem3.pxNext);
printf("ListItem2->pxNext %#X \n", (int)ListItem2.pxNext);
printf("/**********************前后向连接分割线***********************/\n");
printf("testList->xListEnd->pxPrevious %#X \n", (int)testList.xListEnd.pxPrevious);
printf("ListItem1->pxPrevious %#X \n", (int)ListItem1.pxPrevious);
printf("ListItem3->pxPrevious %#X \n", (int)ListItem3.pxPrevious);
printf("ListItem2->pxPrevious %#X \n", (int)ListItem2.pxPrevious);
printf("/***************************结束*****************************/\n");
printf("按下K1按键继续!\r\n\r\n");
while (key_scan(KEY1_GPIO_Port, KEY1_Pin) != KEY_ON);
uxListRemove(&ListItem2);
printf("\n/*******************删除列表项ListItem2**********************/\n");
printf("testList->xListEnd->pxNext %#X \n", (int)testList.xListEnd.pxNext);
printf("ListItem1->pxNext %#X \n", (int)ListItem1.pxNext);
printf("ListItem3->pxNext %#X \n", (int)ListItem3.pxNext);
printf("/**********************前后向连接分割线***********************/\n");
printf("testList->xListEnd->pxPrevious %#X \n", (int)testList.xListEnd.pxPrevious);
printf("ListItem1->pxPrevious %#X \n", (int)ListItem1.pxPrevious);
printf("ListItem3->pxPrevious %#X \n", (int)ListItem3.pxPrevious);
printf("/***************************结束*****************************/\n");
printf("按下K1按键继续!\r\n\r\n");
while (key_scan(KEY1_GPIO_Port, KEY1_Pin) != KEY_ON);
testList.pxIndex = testList.pxIndex->pxNext;
vListInsertEnd(&testList, &ListItem2);
printf("\n/*****************在末尾添加列表项ListItem2******************/\n");
printf("testList.pxIndex %#X \n", (int)testList.pxIndex);
printf("testList->xListEnd->pxNext %#X \n", (int)testList.xListEnd.pxNext);
printf("ListItem2->pxNext %#X \n", (int)ListItem2.pxNext);
printf("ListItem1->pxNext %#X \n", (int)ListItem1.pxNext);
printf("ListItem3->pxNext %#X \n", (int)ListItem3.pxNext);
printf("/**********************前后向连接分割线***********************/\n");
printf("testList->xListEnd->pxPrevious %#X \n", (int)testList.xListEnd.pxPrevious);
printf("ListItem2->pxPrevious %#X \n", (int)ListItem2.pxPrevious);
printf("ListItem1->pxPrevious %#X \n", (int)ListItem1.pxPrevious);
printf("ListItem3->pxPrevious %#X \n", (int)ListItem3.pxPrevious);
printf("/***************************结束*****************************/\n");
printf("按下K1按键继续!\r\n\r\n");
while (key_scan(KEY1_GPIO_Port, KEY1_Pin) != KEY_ON);
printf("list_task开始任务调度\n");
printf("list_task run!\n");
程序执行结果如下:
/*********************列表和列表项地址************************/
项目 地址
testList 0X20000080
testList->pxIndex 0X20000088
testList->xListEnd 0X20000088
ListItem1 0X20000094
ListItem2 0X200000A8
ListItem3 0X200000BC
/***************************结束*****************************/
按下K1按键继续!
/*******************添加列表项ListItem1**********************/
项目 地址
testList->xListEnd->pxNext 0X20000094
ListItem1->pxNext 0X20000088
/**********************前后向连接分割线***********************/
testList->xListEnd->pxPrevious 0X20000094
ListItem1->pxPrevious 0X20000088
/***************************结束*****************************/
按下K1按键继续!
/*******************添加列表项ListItem2**********************/
项目 地址
testList->xListEnd->pxNext 0X20000094
ListItem1->pxNext 0X200000A8
ListItem2->pxNext 0X20000088
/**********************前后向连接分割线***********************/
testList->xListEnd->pxPrevious 0X200000A8
ListItem1->pxPrevious 0X20000088
ListItem2->pxPrevious 0X20000094
/***************************结束*****************************/
按下K1按键继续!
/*******************添加列表项ListItem3**********************/
项目 地址
testList->xListEnd->pxNext 0X20000094
ListItem1->pxNext 0X200000BC
ListItem3->pxNext 0X200000A8
ListItem2->pxNext 0X20000088
/**********************前后向连接分割线***********************/
testList->xListEnd->pxPrevious 0X200000A8
ListItem1->pxPrevious 0X20000088
ListItem3->pxPrevious 0X20000094
ListItem2->pxPrevious 0X200000BC
/***************************结束*****************************/
按下K1按键继续!
/*******************删除列表项ListItem2**********************/
项目 地址
testList->xListEnd->pxNext 0X20000094
ListItem1->pxNext 0X200000BC
ListItem3->pxNext 0X20000088
/**********************前后向连接分割线***********************/
testList->xListEnd->pxPrevious 0X200000BC
ListItem1->pxPrevious 0X20000088
ListItem3->pxPrevious 0X20000094
/***************************结束*****************************/
按下K1按键继续!
/*****************在末尾添加列表项ListItem2******************/
项目 地址
testList.pxIndex 0X20000094
testList->xListEnd->pxNext 0X200000A8
ListItem2->pxNext 0X20000094
ListItem1->pxNext 0X200000BC
ListItem3->pxNext 0X20000088
/**********************前后向连接分割线***********************/
testList->xListEnd->pxPrevious 0X200000BC
ListItem2->pxPrevious 0X20000088
ListItem1->pxPrevious 0X200000A8
ListItem3->pxPrevious 0X20000094
/***************************结束*****************************/
按下K1按键继续!
list_task开始任务调度
list_task run!
list_task run!
list_task run!
list_task run!
list_task run!
转载于:https://blog.csdn.net/dingyc_ee/article/details/104071570
商业资讯 2021-7-29 14:59